1、Boot Manager简介
UEFI Boot Manager 是一个符合UEFI规范的固件中的一个组件。它决定哪些drivers和applications在何时被加载。
当平台固件初始化完成,它将控制权转交给Boot Manager。
BootManager需要决定:
- 加载什么?
- 做出此类决定可能需要的与用户有何种交互?
Boot Manager 是一个可以通过修改global NVRAM variable来进行配置的固件策略引擎。
Boot Manager将尝试按global NVRAM Variable定义的顺序来加载 UEFI 驱动程序和 UEFI 应用程序(包括 UEFI OS 引导加载程序)。
2、UEFI的引导顺序
UEFI 的引导顺序包括以下内容:
- 从global定义的 NVRAM 变量中读取Boot Order List。
Boot Order List定义一个 NVRAM 变量顺序表。
每个NVRAM中包含有关要引导的内容的信息。并且定义了可以向用户显示的引导选项的名称。 - 该变量还包含指向硬件设备和该硬件上文件的指针包含要加载的 UEFI 映像的设备。
- 该变量还可能包含操作系统分区和目录的路径以及其他配置特定目录。
3、Global Variables
变量名称 | 长度 | 描述 |
---|---|---|
Boot#### | NV,BS,RT | 一个 启动选项。####是16进制数 |
BootCurrent | BS,RT | 当前启动项的序号。内容为一个UINT16数。 |
BootNext | NV,BS,RT | 下一次启动的启动选项。 |
BootOrder | NV,BS,RT | 启动项顺序列表。由一组UINT16数据组成。 |
BootOptionSupport | BS,RT | boot manager支持的启动项类型。UINT32型只读。 |
Key#### | NV,BS,RT | 描述热键和Boot#### 启动项之间的关系 |
4、Boot Manager Capabilities
Boot Manager可以通过全局变量 BootOptionSupport 报告其能力。 如果全局变量不存在,则安装程序或应用程序必须像返回值 0 一样操作。
#define EFI_BOOT_OPTION_SUPPORT_KEY 0x00000001
#define EFI_BOOT_OPTION_SUPPORT_APP 0x00000002
#define EFI_BOOT_OPTION_SUPPORT_SYSPREP 0x00000010
#define EFI_BOOT_OPTION_SUPPORT_COUNT 0x00000300
如果 EFI_BOOT_OPTION_SUPPORT_KEY 被置起,则boot manager 支持用热键启动Boot####启动项。
又如 EFI_BOOT_OPTION_SUPPORT_APP 被置起,则boot manager支持有LOAD_OPTION_CATEGORY_APP属性的启动项。
Boot Manager可支持通过热键来启动Boot####启动项。
如果支持,则应该在BootOptionSupport全局变量中报告 EFI_BOOT_OPTION_SUPPORT_KEY 的能力。
Boot Manger支持从console获取按键,并且从全局变量中匹配Key####和Boot####变量,匹配到可用的启动项则立即启动它。
5、启动机制
EFI可以通过使用 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL 或 EFI_LOAD_FILE_PROTOCOL 来启动。
- 支持EFI_SIMPLE_FILE_SYSTEM_PROTOCOL的设备必须实现文件系统协议才能使该设备可引导。
- 如果设备不想支持一个完整的文件系统,它可能会产生一个EFI_LOAD_FILE_PROTOCOL,用于直接启动镜像。
- Boot Manager会先尝试使用Simple File Protocol来启动,如果失败,则使用Load File Protocol。
6、如何列举启动项和启动项的设备路径
MdeModulePkg\Library\UefiBootManagerLib\BmBoot.c
**
**
6.1、启动项的类型:
DriverOrder:已排序的驱动程序加载选项列表。(未用)
SysPrepOrder:已排序的系统准备应用程序加载选项列表。(未用)
BootOrder:有序启动选项加载列表。(主要)
6.2、枚举启动项
按以下顺序搜索所有可能的可引导媒体:
1、Removable BlockIo: 引导选项仅指向可移动介质设备,如USB密钥、DVD、软盘等。
2、Fixed BlockIo:引导选项仅指向Fixed BlockIo设备,比如硬盘。
3、Non-BlockIo SimpleFileSystem:引导选项指向支持SimpleFileSystem协议,但不支持BlockIo协议
4、LoadFile:引导选项指向支持LoadFile协议
启动项的保存进行了两层variable
首先,列举的可能的可引导媒体数量已经保存到L“BootOrder”的全球变量中
然后,每个启动项的具体结构体EFI_BOOT_MANAGER_LOAD_OPTION保存到L“Boot####” 的全球变量中。
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;
6.3、接口调用流程
- 与Boot Manager的编程交互是通过global Variable完成的。
- 初始化时,Boot Manager读取包含 UEFI 环境变量中所有已发布加载选项的值。 通过使用 SetVariable() 函数,可以修改包含这些环境变量的数据。
- 此类修改保证在下一次系统启动后生效。 但是,Boot Manager也可选择改进此保证,并让更改对所有后续访问影响Boot Manager行为的变量立即生效,而无需任何形式的系统重置。
EfiBootManagerRefreshAllBootOption (): 刷新系统的所有启动选项,确保非易失性存储中的启动选项与当前有效的启动选项保持同步,同时根据系统设置决定新添加的启动选项插入的位置。
主要进行Setvarible "BootOrder"操作。
EfiBootManagerGetLoadOptions(): 这段代码定义了一个名为 EfiBootManagerGetLoadOptions 的 EFI 固件接口函数,用于根据 EFI 变量 “BootOrder”/“DriverOrder” 及其隐含的 “Boot####”/“Driver####” 变量获取指定类型的加载选项数组。其中,“####” 是 BootOrder 或 DriverOrder 变量中每个条目的 UINT16 值的十六进制表示。
主要进行Getvarible "BootOrder"操作。
UpdateBootManager(): 这段代码片段是一个名为UpdateBootManager的函数,它与EFI引导管理器进行交互以获取并更新可供用户选择的所有启动选项列表。该函数的目的是在系统固件(UEFI)中创建一个用于选择启动选项的交互式菜单。
主要在Setup上灵活创建启动项
L"Boot%04x"是L"BootOrder"的子集
1、GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &Size);
2、UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder【Index】);
GetVariable2 (OptionName, &gEfiGlobalVariableGuid, (VOID **) &BootOptionVar, &VariableSize);
BootOptionVar 为 启动项的具体结构体 EFI_BOOT_MANAGER_LOAD_OPTION 的初始地址。
Attributes = BootOptionVar ;
Attributes : LOAD_OPTION_CATEGORY_BOOT,LOAD_OPTION_ACTIVE,LOAD_OPTION_HIDDEN
在启动前调整不同类型的内存页码,并将更新后的信息保存到变量中,以便下次启动时使用
Description = BootOptionVar + sizeof (UINT32);
Description : L"UEFI Shell";L"UEFI Hard Drive";L"Kunlun Update Tool"
DevicePath = Attributes + (BmStrSize ((CHAR16 *) BootOptionVar, VariableSize - sizeof (UINT16) - sizeof (UINT32)));
DevicePath : PciBoot(0x0) /Pci(0x1,0x1)/Pci(0x0,0x0)/Nvme(0x1,10-48-B6-11-81-30-25-00)
3 、获取启动设备的devicepath,就可以连接控制器
EfiBootManagerVariableToLoadOption() 定义了一个名为EfiBootManagerVariableToLoadOption的EFI接口函数,其功能是从给定的变量名(如Boot####或Driver####)中构建对应的启动或驱动加载选项。此函数将变量名转换为EFI_BOOT_MANAGER_LOAD_OPTION结构体形式,以便进一步处理和操作。