当前位置: 首页 > 工具软件 > bds > 使用案例 >

BIOS的BDS阶段解析

姜兴业
2023-12-01

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();

  1. • 构造函数 安装 gEfiBdsArchProtocolGuid Protocol
  2. • DxeMain.c
    1. 文件最上面对gBS,gST,gRT全局变量进行初始化
    2. DxeMain()
      //函数结尾调用
      gBds->Entry (gBds);
  3. • BdsDxe.inf
    MODULE_TYPE = DXE_DRIVER
    ENTRY_POINT = BdsInitialize

3、BdsEntry()

3.1 代码流程

  1. 设置厂商及版本号
  2. 校验Variable,如果异常则进行删除
  3. 获取进度条时间
  4. 设置默认语言
  5. 前平台初始化
  6. 初始化热键服务
  7. 处理驱动程序
  8. 连接所有控制台设备
  9. 后平台初始化
  10. 获取启动菜单
  11. 判断是否进入Setup
  12. 等待按键按下,如果按键按下则,启动对应引导项
  13. 判断BootNext,如果不为空,则启动对应引导项
  14. 根据启动顺序依次尝试启动
    要想理解BDS的启动流程,主要理解两部分 Connect Controller和Boot
    Manger

3.2 Connect Controller

3.2.1 驱动初始化过程

  1. 硬件相关初始化(大部分在PEI阶段或DXE阶段进行)
  2. 前平台初始化中添加Driver####并更新DriverOrder
  3. 根据DriverOrder获取Driver####存储的DriverOption
  4. 根据DriverOption中的DevicePath进行Connect
  5. 加载DriverOption中DevicePath对应的Image,并运行该Image
  6. Disconnect Controller All
  7. 连接控制台
  8. Connect Controller All
  9. 连接控制台
  10. 后平台相关初始化,如串口等设备进行连接
    •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()

3.2.2 优先级顺序

  1. Context Override
    参数传入的Image Handle
  2. Platform Driver Override
    gEfiPlatformDriverOverrideProtocolGuid->GetDriver(ImageHandle)
  3. Driver Family Override
    支持gEfiDriverFamilyOverrideProtocolGuid
  4. Bus Specific Driver Override
    BusSpecificDriverOverride->GetDriver(ImageHandle)
  5. Driver Binding
    其他
  6. 根据版本号排序
    优先级排序源码分析
    |--> while 
      |--> if BusSpecificDriverOverride->GetDriver()
        |--> AddSortedDriverBindingProtocol(TRUE) // 函数内部进行递归
          |--> for
            |--> CoreHandleProtocol(DriverBinding)
            |--> if DriverBinding->ImageHandle == DriverBindingHandle
              |--> AddSortedDriverBindingProtocol(FALSE)
    |--> for AddSortedDriverBindingProtocol() // 5 添加剩下所有的
    |--> for 根据Version对最后添加的进行排序

3.2.3 连接设备控制器

  1. 在Start或Stop函数中执行Controller相关的一些初始化
  2. 在ControllerHandle下去安装一些Protocol去实现或管理Controller某些特定功能或数据
  3. Start中通常不会执行硬件初始化的操作
  4. 硬件相关初始化动作,大部分都是在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()         //递归调用

3.3 Boot Manger

概要:

3.3.1 BootManager运行流程

  1. 获取BootNext Variable
  2. 初始化平台恢复引导项
  3. 添加UEFIShell等引导项
  4. 获取Setup引导选项
  5. 添加Hotkey并注册CallBack
  6. 初始化Hotkey服务
  7. 删除无效的引导项
  8. 如果默认进入Setup,则启动该引导项
  9. 等待按键按下
  10. 如果有按键按下则启动按键对应引导选项
  11. 如果BootNext引导项存在,则启动该引导项
  12. 根据BootOrder获取引导选项
  13. 按照BootOrder中的顺序依次尝试启动
  14. 如果平台恢复选项启动,最后尝试启动平台恢复对应的启动引导选项

3.3.2 启动项与Hotkey

BdsEntry()

  1. 获取引导项
  2. 添加Key####
  3. 获取所有的Key####
  4. 将Key####中内容加入mBmHotkeyList链表
  5. 为Key####创建Callback
  6. 等待按键按下
  7. 启动 mBmHotkeyBootOption
    BmHotkeyCallback()
  8. 获取当前按键对应引导项
  9. 引导项保存至 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)

3.3.3 如何添加引导项

添加 UEFI Shell 启动选项

  1. 根据gUefiShellFileGuid获取设备节点信息
  2. 创建新DevicePath,指向该节点
  3. 添加至Boot#### Variable,需要DevicePath和描述符,返回对应的Number
  4. 根据Number设置 Key#### Variable
  5. 根据Key####中的Opation注册Callback函数
  6. Callback中根据Number获取的BootOption并记录在全局变量中
  7. 如果有按键按下则启动全局变量中的BootOption选项

添加 FileSystem 启动选项

  1. 获取所有的 BlockIo Protocol 对应的 Handle
  2. 依次获取 BlockIo Protocol
  3. 跳过逻辑分区
  4. 跳过 Fixed Block IO 和 可移动设备(USB,移动硬盘)
  5. 获取当前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. 初始化BootOption并加入BootOptions数组
  2. 获取所有的SimpleFileSystemProtocol对应的Handle
  3. 依次获取 SimpleFileSystemProtocol对应的IO设备
  4. 如果文件系统中可以搜索到.\EFI\BOOT\boot.efi 文件系统启动设备,加入BdsBootOptionList启动项
  5. 搜索包含PXE启动项的文件系统,加入到BdsBootOptionLis链表
  6. 核实是否有shell启动项,加入链表

添加 Network 启动选项

  1. 将连接地址全部转换为小写字母
  2. 判断是否是http或https的地址
  3. 初始化节点信息
  4. 创建device path, 指向该节点
  5. 根据链接地址更新节点信息
  6. 重新创建device path,指向该节点
  7. 根据device path等相关信息初始化 load option
  8. 将load option 加入 Boot#### Variable

3.3.4 如何启动引导项

引导流程

  1. 搜索该选项是否存在
  2. 设置BootCurrent
  3. gBS->LocateDevicePath(Handle)
  4. gBS->ConnectController(Handle)
  5. FileBuffer = BmGetNextLoadOptionBuffer(BootOption->FilePath) //获取引导文件
  6. gBS->LoadImage() //加载Image
  7. gBS->SetWatchdogTimer() //开启看门狗
  8. gBS->StartImage() //启动Image
  9. gBS->SetWatchdogTimer() //关闭看门狗
  10. gRT->SetVariable() //删除BootCurrent Variable
 类似资料: