UEFI下BootOption

先写一点:

使用场景

UEFI启动时候会有一个BootOrder,会根据BootOrder来依次启动相应的启动项

比如:硬盘启动-U盘启动-PXE启动-shell之类的

具体的可以在OS下使用efibootmgr命令查看

man efibootmgr可以查看相应命令,这里可以看github地址和相应说明

如apt-get install无法下载,

另外,man中提到了/sys/firmware/efi/var中会提供很多变量

我们经常在UEFI中使用SetVarible GetVarible,OS下也会使用这个的

这个文件夹恰好就有BootOption,BootCurrent(当前启动项),BootOrder,以及对应的GUID

根据GUID,可以找到是EFIGLOBLE(具体可以查一下)

启动项BootOption结构体

在bios界面经常有各种启动项,比如硬盘,和u盘启动下项,主要是通过BootOption来进行注册和调用的,我们先看下BootOption组成

//
// Common structure definition for DriverOption and BootOption
//
typedef struct {
  //
  // Data read from UEFI NV variables
  //
  UINTN                             OptionNumber;       // #### numerical value, could be LoadOptionNumberUnassigned
  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE OptionType;         // LoadOptionTypeBoot or LoadOptionTypeDriver
  UINT32                            Attributes;         // Load Option Attributes
  CHAR16                            *Description;       // Load Option Description
  EFI_DEVICE_PATH_PROTOCOL          *FilePath;          // Load Option Device Path
  UINT8                             *OptionalData;      // Load Option optional data to pass into image
  UINT32                            OptionalDataSize;   // Load Option size of OptionalData
  EFI_GUID                          VendorGuid;

  //
  // Used at runtime
  //
  EFI_STATUS                        Status;             // Status returned from boot attempt gBS->StartImage ()
  CHAR16                            *ExitData;          // Exit data returned from gBS->StartImage ()
  UINTN                             ExitDataSize;       // Size of ExitData
} EFI_BOOT_MANAGER_LOAD_OPTION;

每一个启动项都是一个EFI_BOOT_MANAGER_LOAD_OPTION类型变量

其中OptionNumber就是0,1,2,3,4,5依次递增

OptionType这里一般是               LoadOptionTypeBoot

Desciption就是描述,这里一般自定义,比如NVME(xx-xx-xx),然后会显示在bios界面上,当你选中这个描述,就会执行对应的FilePath.

FilePath就是比较重要的,比如PciRoot(0x0)/Pci(0xF,0x0)/Pci(0x0,0x0)/NVMe(0x1,3E-12-30-80-44-A7-79-64)/HD(6,GPT,C75CD876-DC80-4DF8-B6A4-7B2111703BA6,0x16E7B000,0x3C78000)

这是个NVME硬盘,然后选中这个NVME,根据这个FIlePath,代码会继续找这个NVME这个分区中的/boot/efi/BOOTARM64.EFI文件来打开这个.efi启动Grub界面。

如果BootOption不是这种NVME,比方说,你想要设置一个硬盘里面的/test/test.efi作为一个启动项,你可以使用PciRoot(0x0)/Pci(0xF,0x0)/Pci(0x0,0x0)/NVMe(0x1,3E-12-30-80-44-A7-79-64)/HD(6,GPT,C75CD876-DC80-4DF8-B6A4-7B2111703BA6,0x16E7B000,0x3C78000)/\\test\\test.efi

作为某个FilePath,然后使用

   Status = EfiBootManagerInitializeLoadOption (
               &BootOptions,
               LoadOptionNumberUnassigned,
               LoadOptionTypeBoot,
               LOAD_OPTION_ACTIVE,
               Description,
               FilePath,
               NULL,
               0
               );

这个函数来进行注册。第一个参数就是生成的EFI_BOOT_MANAGER_LOAD_OPTION结构体,是不需要进行初始化的。

生成nvme中某个目录下的FilePath

然后这里很多人就会不知道根据文件路径生成一个FilePath

下面是代码,

    EFI_STATUS                       Status;
    UINTN                            HandleCount;
    EFI_HANDLE                       *Handles;
    UINTN                            Index;
    EFI_SIMPLE_FILE_SYSTEM_PROTOCOL  *Fs;
    EFI_FILE_PROTOCOL                *RootFile;
    BOOLEAN                           HasOkrEfi = FALSE;

    Status = gBS->LocateHandleBuffer (
                      ByProtocol,
                      &gEfiSimpleFileSystemProtocolGuid,
                      NULL,
                      &HandleCount,
                      &Handles       
                      );             
    DEBUG((EFI_D_INFO, "%a:HandleCount:%d Status:%r\n",__FUNCTION__,HandleCount,Status));
    if(!EFI_ERROR(Status))
    {                                
      for (Index = 0; Index < HandleCount; Index++) {
        Status = gBS->HandleProtocol (
                        Handles[Index],
                        &gEfiSimpleFileSystemProtocolGuid,
                        (VOID**)&Fs
                        );
        Status = Fs->OpenVolume(Fs, &RootFile);
        if(IsFilePresentSize(RootFile,L"\\test\\test.efi")){
            return  Handles[Index];

        }
       }



BOOLEAN
IsFilePresentSize (

  EFI_FILE_PROTOCOL* RootFile,
  CHAR16             *FilePathName

){
  EFI_STATUS          Status;
  EFI_FILE_PROTOCOL   *File     = NULL;

  Status = RootFile->Open(
                       RootFile,
                       &File,
                       FilePathName,
                       EFI_FILE_MODE_READ,
                       0
                       );
  if(EFI_ERROR(Status)){
    DEBUG((EFI_D_ERROR, "Open %s:%r\n", FilePathName, Status));
   return FALSE;


  }
    return TRUE;
}

}

这个FilePathName,就是L"\\test\\test.efi

得到的这个 Handles[Index],就是有这个文件的Hanles,比如PciRoot(0x0)/Pci(0xF,0x0)/Pci(0x0,0x0)/NVMe(0x1,3E-12-30-80-44-A7-79-64)/HD(6,GPT,C75CD876-DC80-4DF8-B6A4-7B2111703BA6,0x16E7B000,0x3C78000)(这些是在shell中也会显示的Map)

这里 Handles[Index],再使用edk标准函数FileDevicePath 可以得到最终的目录DevicePath


 DevicePath =  FileDevicePath (Handles,L“\\test\\test.efi");
 Path = ConvertDevicePathToText(DevicePath, TRUE, TRUE);
 DEBUG((EFI_D_ERROR, "line %d. DevPath=%s\n", __LINE__,Path));

这个Handles就是上面传回来的Handles[Index];

最终的DevPath 打印出来就是DevPath=PciRoot(0x0)/Pci(0xF,0x0)/Pci(0x0,0x0)/NVMe(0x1,3E-12-30-80-44-A7-79-64)/HD(6,GPT,C75CD876-DC80-4DF8-B6A4-7B2111703BA6,0x16E7B000,0x3C78000)/\test\test.efi

生成fdf中包含的文件,比如Uefi Shell

VOID test(
  EFI_GUID                         *FileGuid,
  CHAR16                           *Description,
  UINT32                           Attributes
)
{
  EFI_STATUS                        Status;
  UINTN                             OptionIndex;
  EFI_BOOT_MANAGER_LOAD_OPTION      NewOption;
  EFI_BOOT_MANAGER_LOAD_OPTION      *BootOptions;
  UINTN                             BootOptionCount;
  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileNode;
  EFI_LOADED_IMAGE_PROTOCOL         *LoadedImage;
  EFI_DEVICE_PATH_PROTOCOL          *DevicePath;

  Status = gBS->HandleProtocol (gImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &LoadedImage);
  ASSERT_EFI_ERROR (Status);

  EfiInitializeFwVolDevicepathNode (&FileNode, FileGuid);
  DevicePath = AppendDevicePathNode (
                 DevicePathFromHandle (LoadedImage->DeviceHandle),
                 (EFI_DEVICE_PATH_PROTOCOL *) &FileNode
               );

  Status = EfiBootManagerInitializeLoadOption (
             &NewOption,
             LoadOptionNumberUnassigned,
             LoadOptionTypeBoot,
             Attributes,
             Description,
             DevicePath,
             NULL,
             0
           );

这个FileGuid,比如

gPkgTokenSpaceGuid.PcdFile|{ 0x76, 0x45, 0x74, 0xdf, 0x1f, 0x0d, 0xe8, 0x34, 0x43, 0x45, 0x34, 0x16, 0x55, 0x65, 0x34, 0x34 }|VOID*|0x40000045

和包含在inf中的.efi文件guid是一样的。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值