【UEFI实战】SBL中的OsLoader代码分析

入口

对应的模块是PayloadPkg\OsLoader\OsLoader.inf,在BootloaderCorePkg\BootloaderCorePkg.dsc中的声明:

PayloadPkg/OsLoader/OsLoader.inf {
    <PcdsFixedAtBuild>
    	gPlatformCommonLibTokenSpaceGuid.PcdDebugOutputDeviceMask  | $(DEBUG_OUTPUT_DEVICE_MASK)
    <LibraryClasses>
        MemoryAllocationLib | BootloaderCommonPkg/Library/FullMemoryAllocationLib/FullMemoryAllocationLib.inf
        PayloadEntryLib     | PayloadPkg/Library/PayloadEntryLib/PayloadEntryLib.inf
        PayloadSupportLib   | PayloadPkg/Library/PayloadSupportLib/PayloadSupportLib.inf
        BootloaderLib       | PayloadPkg/Library/PayloadLib/PayloadLib.inf
        PlatformHookLib     | PayloadPkg/Library/PlatformHookLib/PlatformHookLib.inf
        AbSupportLib        | PayloadPkg/Library/AbSupportLib/AbSupportLib.inf
        SblParameterLib     | PayloadPkg/Library/SblParameterLib/SblParameterLib.inf
        TrustyBootLib       | PayloadPkg/Library/TrustyBootLib/TrustyBootLib.inf
}

OsLoader.inf的实现主体:

[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = OsLoader
  FILE_GUID                      = A257AA67-53F3-491B-8CFF-E9A4E2E2A514
  MODULE_TYPE                    = PEIM
  VERSION_STRING                 = 1.0

#
#  This flag specifies whether HII resource section is generated into PE image.
#
  UEFI_HII_RESOURCE_SECTION      = TRUE

#
# The following information is for reference only and not required by the build tools.
#
#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
#

[Sources]
  BlockIoTest.h
  OsLoader.h
  OsLoader.c
  BootOption.c
  BootConfig.c
  LoadImage.c
  PerformanceData.c
  BootParameters.c
  BlockIoTest.c
  KeyManagement.c
  PreOsSupport.c
  ModService.c
  ExtraModSupport.c

比较奇怪的是没有入口,不过似乎SBL的模块都没有入口。

通过代码可以找到OsLoader的入口:

/**
  Payload main entry.

  This function will continue Payload execution with a new memory based stack.

  @param  Param           parameter passed from SwitchStack().
  @param  PldBase         payload base passed from SwitchStack().

**/
VOID
EFIAPI
PayloadMain (
  IN  VOID             *Param,
  IN  VOID             *PldBase
  )

实际上SBL的模块入口是按照如下的调用逻辑:

SecEntry
SecStartup
SwitchStack
PayloadMain

最开始的SecEntry来自通用的Lib:ModuleEntryLib

流程

OsLoader的基本流程:

开始
获取启动项
进入Shell?
进入Shell
结束
遍历启动项
进入启动项?
CPU挂起

最终如果没有找到启动项就会挂起。

遍历启动项是通过一个while循环来完成的:

    while  (BootIdx < OsBootOptionList->OsBootOptionCount) {
      mCurrentBoot = CurrIdx;
      DEBUG ((DEBUG_INFO, "\n======== Try Booting with Boot Option %d ========\n", CurrIdx));

      // Get current boot option and try boot
      CopyMem ((VOID *)&OsBootOption, (VOID *)&OsBootOptionList->OsBootOption[CurrIdx], sizeof (OS_BOOT_OPTION));
      BootOsImage (&OsBootOption);

      // De-init the current boot devices
      // If USB keyboard console is used, don't DeInit USB yet at this moment.
      // It will be handled just before transfering to OS.
      if (!((OsBootOption.DevType == OsBootDeviceUsb) &&
          ((PcdGet32 (PcdConsoleInDeviceMask) & ConsoleInUsbKeyboard) != 0))) {
        MediaInitialize (0, DevDeinit);
      }

      if (OsBootOptionList->RestrictedBoot != 0) {
        // Restricted boot should not try other boot option
        break;
      } else {
        // Move to next boot option
        CurrIdx = GetNextBootOption (OsBootOptionList, CurrIdx);
        if (CurrIdx >= OsBootOptionList->OsBootOptionCount) {
          CurrIdx = 0;
        }
        BootIdx++;
      }
    }

这里最重要的函数是BootOsImage(),其流程如下:

开始
初始化启动设备
从启动设备找到分区
初始化启动设备上的文件系统
从文件系统中找到启动镜像
解析启动镜像
设置启动镜像
更新启动参数
启动镜像

如果执行过程中出错则会退出,以执行下一个启动项。

这里需要注意的是,跟UEFI不同,SBL先有启动项,然后才会初始化对应的设备,并从该设备找启动镜像,如果有的话就会启动。

下面再按照重点步骤分别介绍:

  1. 初始化启动设备,目前支持的设备有在BootloaderCommonPkg\Include\Guid\OsBootOptionGuid.h定义:
// Define OS boot media devices
typedef enum {
  OsBootDeviceSata,
  OsBootDeviceSd,
  OsBootDeviceEmmc,
  OsBootDeviceUfs,
  OsBootDeviceSpi,
  OsBootDeviceUsb,
  OsBootDeviceNvme,
  OsBootDeviceMemory,
  OsBootDeviceMax
} OS_BOOT_MEDIUM_TYPE;

相关的初始化接口在MediaSetInterfaceType()中会赋值,然后在之后的MediaInitialize()执行真正的初始化。

  1. 查找分区,SBL跟UEFI一样也支持GPT和MBR分区,设备初始化之后就是从设备中找到分区,通过FindGptPartitions()FindMbrPartitions()两个函数来寻找对应的分区。
  2. 下一步是从分区中寻找文件系统,支持的文件系统也可以在BootloaderCommonPkg\Include\Guid\OsBootOptionGuid.h找到:
typedef enum  {
  EnumFileSystemTypeFat,
  EnumFileSystemTypeExt2,
  EnumFileSystemTypeAuto,
  EnumFileSystemMax
} OS_FILE_SYSTEM_TYPE;

其实就是FAT和EXT2文件系统。

  1. 找到文件系统之后就可以在该文件系统上读取启动镜像并加载,最终启动该镜像。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值