> 文章列表 > BIOS的BDS阶段解析

BIOS的BDS阶段解析

BIOS的BDS阶段解析

1、概述
BDS全称:Boot Dev Select(启动设备选择)
主要功能是加载并连接驱动程序,管理并启动引导项。在引导操作系统之前会初始化设备(USB键盘鼠标,VGA设备等),然后通过Variable功能来控制启动顺序,根据启动策略加载对应的引导项,启动操作系统或应用程序。
BDS主要功能:
• 加载设备驱动程序
• 初始化控制台设备
• 创建引导启动项
• 启动操作系统或应用程序
如果加载启动项失败,系统将重新执行DXE dispatcher 以加载更多的驱动,然后重新尝试加载启动项。
BDS策略通过全局NVRAM变量配置。这些变量可以通过运行时服务的GetVariable()读取,通过SetVariable() 设置。例如,变量BootOrder定义了启动顺序,变量Boot###定义了各个启动项。
用户选中某个启动项(或系统进入默认的启动项)后,OS Loader 启动,系统进入TSL阶段。

2、如何进入BDS阶段
  此模块为BDS阶段- BdsEntry生成主入口。 当DxeCore分派此模块时,gEfiBdsArchProtocolGuid将被安装 ,包含BdsEntry接口。 DxeCore完成DXE阶段后,gEfiBdsArchProtocolGuid->BdsEntry将被调用。
通过方法BdsEntry();

• 构造函数 安装 gEfiBdsArchProtocolGuid Protocol
• DxeMain.c
文件最上面对gBS,gST,gRT全局变量进行初始化
DxeMain()
//函数结尾调用
gBds->Entry (gBds);
• BdsDxe.inf
MODULE_TYPE = DXE_DRIVER
ENTRY_POINT = BdsInitialize
3、BdsEntry()
3.1 代码流程
设置厂商及版本号
校验Variable,如果异常则进行删除
获取进度条时间
设置默认语言
前平台初始化
初始化热键服务
处理驱动程序
连接所有控制台设备
后平台初始化
获取启动菜单
判断是否进入Setup
等待按键按下,如果按键按下则,启动对应引导项
判断BootNext,如果不为空,则启动对应引导项
根据启动顺序依次尝试启动
要想理解BDS的启动流程,主要理解两部分 Connect Controller和Boot
Manger
3.2 Connect Controller
3.2.1 驱动初始化过程
硬件相关初始化(大部分在PEI阶段或DXE阶段进行)
前平台初始化中添加Driver####并更新DriverOrder
根据DriverOrder获取Driver####存储的DriverOption
根据DriverOption中的DevicePath进行Connect
加载DriverOption中DevicePath对应的Image,并运行该Image
Disconnect Controller All
连接控制台
Connect Controller All
连接控制台
后平台相关初始化,如串口等设备进行连接
•gBS->ConnectController()
• 排序
• 连接
将驱动安装到指定的设备控制器
• gBS->DisconnectController
将驱动从指定的设备控制器上卸载
.驱动初始化源码分析
|–> BdsEntry()
|–> PlatformBootManagerBeforeConsole() //前平台初始化
|–> LoadOptions = EfiBootManagerGetLoadOptions() //获取所有的DeviceOption
|–> ProcessLoadOptions(LoadOptions)
|–> for EfiBootManagerProcessLoadOption(LoadOptions)
|–> EfiBootManagerConnectDevicePath(LoadOption->FilePath) //Connect DevicePath
|–> while
|–> BmGetNextLoadOptionBuffer(LoadOption->FilePath) //Image
|–> gBS->LoadImage()
|–> gBS->StartImage()
|–> EfiBootManagerDisconnectAll()
|–> EfiBootManagerConnectAll()
|–> PlatformBootManagerAfterConsole()
1
2
3
4
5
6
7
8
9
10
11
12
13
3.2.2 优先级顺序
Context Override
参数传入的Image Handle
Platform Driver Override
gEfiPlatformDriverOverrideProtocolGuid->GetDriver(ImageHandle)
Driver Family Override
支持gEfiDriverFamilyOverrideProtocolGuid
Bus Specific Driver Override
BusSpecificDriverOverride->GetDriver(ImageHandle)
Driver Binding
其他
根据版本号排序
优先级排序源码分析
|–> while
|–> if BusSpecificDriverOverride->GetDriver()
|–> AddSortedDriverBindingProtocol(TRUE) // 函数内部进行递归
|–> for
|–> CoreHandleProtocol(DriverBinding)
|–> if DriverBinding->ImageHandle == DriverBindingHandle
|–> AddSortedDriverBindingProtocol(FALSE)
|–> for AddSortedDriverBindingProtocol() // 5 添加剩下所有的
|–> for 根据Version对最后添加的进行排序
1
2
3
4
5
6
7
8
9
3.2.3 连接设备控制器
在Start或Stop函数中执行Controller相关的一些初始化
在ControllerHandle下去安装一些Protocol去实现或管理Controller某些特定功能或数据
Start中通常不会执行硬件初始化的操作
硬件相关初始化动作,大部分都是在Pei Phase、Dxe 前期Non EFI Driver Model的Driver, 初始化Processor、Chipset或Platform,当然有些也通过Oprom 或file in an EFI System Partition来进行初始化。
连接设备控制器源码分析
|–> BdsEntry()
|–> ProcessLoadOptions()
|–> EfiBootManagerDisconnectAll()
|–> EfiBootManagerConnectAll()
|–> BmConnectAllDriversToAllControllers()
|–> gBS->LocateHandleBuffer()
|–> for gBS->ConnectController()

|–> CoreConnectController()
|–> CoreConnectSingleController()
|–> 排序
|–> for
|–> if DriverBinding->Supported() // 返回 Success
|–> DriverBinding->Start() // 一般用于安装 Protocol
|–> if //判断是否有子控制器
|–> CoreConnectController() //递归调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3.3 Boot Manger
概要:

3.3.1 BootManager运行流程
获取BootNext Variable
初始化平台恢复引导项
添加UEFIShell等引导项
获取Setup引导选项
添加Hotkey并注册CallBack
初始化Hotkey服务
删除无效的引导项
如果默认进入Setup,则启动该引导项
等待按键按下
如果有按键按下则启动按键对应引导选项
如果BootNext引导项存在,则启动该引导项
根据BootOrder获取引导选项
按照BootOrder中的顺序依次尝试启动
如果平台恢复选项启动,最后尝试启动平台恢复对应的启动引导选项
3.3.2 启动项与Hotkey
BdsEntry()

获取引导项
添加Key####
获取所有的Key####
将Key####中内容加入mBmHotkeyList链表
为Key####创建Callback
等待按键按下
启动 mBmHotkeyBootOption
BmHotkeyCallback()
获取当前按键对应引导项
引导项保存至 mBmHotkeyBootOption
|–> BdsEntry()
|–> PlatformBootManagerBeforeConsole() //前平台初始化
|–> PlatformRegisterOptionsAndKeys()
|–> EfiBootManagerGetBootManagerMenu() //获取Setup启动项
|–> EfiBootManagerAddKeyOptionVariable() //添加key#### Variable
|–> EfiBootManagerStartHotkeyService()
|–> BmGetKeyOptions()
|–> for BmProcessKeyOption()
|–> BmGenerateKeyShiftState()
|–> InsertTailList(mBmHotkeyList)
|–> BmRegisterHotkeyNotify()
|–>RegisterKeyNotify(BmHotkeyCallback) //注册callback
|–> BdsWait()
|–> while
|–> PlatformBootManagerWaitCallback() //显示
|–> BdsReadKeys()
|–> EfiBootManagerHotkeyBoot()
|–> EfiBootManagerBoot(&mBmHotkeyBootOption)
|–> BmHotkeyCallback()
|–> EfiBootManagerVariableToLoadOption(Hotkey->BootOption, &mBmHotkeyBootOption)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
3.3.3 如何添加引导项
添加 UEFI Shell 启动选项
根据gUefiShellFileGuid获取设备节点信息
创建新DevicePath,指向该节点
添加至Boot#### Variable,需要DevicePath和描述符,返回对应的Number
根据Number设置 Key#### Variable
根据Key####中的Opation注册Callback函数
Callback中根据Number获取的BootOption并记录在全局变量中
如果有按键按下则启动全局变量中的BootOption选项
添加 FileSystem 启动选项
获取所有的 BlockIo Protocol 对应的 Handle
依次获取 BlockIo Protocol
跳过逻辑分区
跳过 Fixed Block IO 和 可移动设备(USB,移动硬盘)
获取当前BlockHandle对应的设备路径类型
//ACPI boot type
#define BDS_EFI_ACPI_FLOPPY_BOOT 0x0201
//Message boot type
#define BDS_EFI_MESSAGE_ATAPI_BOOT 0x0301 // Type 03; Sub-Type 01
#define BDS_EFI_MESSAGE_SCSI_BOOT 0x0302 // Type 03; Sub-Type 02
#define BDS_EFI_MESSAGE_USB_DEVICE_BOOT 0x0305 // Type 03; Sub-Type 05
#define BDS_EFI_MESSAGE_SATA_BOOT 0x0312 // Type 03; Sub-Type 18
#define BDS_EFI_MESSAGE_MAC_BOOT 0x030b // Type 03; Sub-Type 11
#define BDS_EFI_MESSAGE_MISC_BOOT 0x03FF
//Media boot type
#define BDS_EFI_MEDIA_HD_BOOT 0x0401 // Type 04; Sub-Type 01
#define BDS_EFI_MEDIA_CDROM_BOOT 0x0402 // Type 04; Sub-Type 02
//BBS boot type
#define BDS_LEGACY_BBS_BOOT 0x0501 // Type 05; Sub-Type 01
#define BDS_EFI_UNSUPPORT 0xFFFF
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
初始化BootOption并加入BootOptions数组
获取所有的SimpleFileSystemProtocol对应的Handle
依次获取 SimpleFileSystemProtocol对应的IO设备
如果文件系统中可以搜索到.\\EFI\\BOOT\\boot.efi 文件系统启动设备,加入BdsBootOptionList启动项
搜索包含PXE启动项的文件系统,加入到BdsBootOptionLis链表
核实是否有shell启动项,加入链表
添加 Network 启动选项
将连接地址全部转换为小写字母
判断是否是http或https的地址
初始化节点信息
创建device path, 指向该节点
根据链接地址更新节点信息
重新创建device path,指向该节点
根据device path等相关信息初始化 load option
将load option 加入 Boot#### Variable
3.3.4 如何启动引导项
引导流程

搜索该选项是否存在
设置BootCurrent
gBS->LocateDevicePath(Handle)
gBS->ConnectController(Handle)
FileBuffer = BmGetNextLoadOptionBuffer(BootOption->FilePath) //获取引导文件
gBS->LoadImage() //加载Image
gBS->SetWatchdogTimer() //开启看门狗
gBS->StartImage() //启动Image
gBS->SetWatchdogTimer() //关闭看门狗
gRT->SetVariable() //删除BootCurrent Variable