入口
对应的模块是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
来自通用的Lib:ModuleEntryLib
。
流程
OsLoader的基本流程:
最终如果没有找到启动项就会挂起。
遍历启动项
是通过一个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先有启动项,然后才会初始化对应的设备,并从该设备找启动镜像,如果有的话就会启动。
下面再按照重点步骤分别介绍:
- 初始化启动设备,目前支持的设备有在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()
执行真正的初始化。
- 查找分区,SBL跟UEFI一样也支持GPT和MBR分区,设备初始化之后就是从设备中找到分区,通过
FindGptPartitions()
和FindMbrPartitions()
两个函数来寻找对应的分区。 - 下一步是从分区中寻找文件系统,支持的文件系统也可以在BootloaderCommonPkg\Include\Guid\OsBootOptionGuid.h找到:
typedef enum {
EnumFileSystemTypeFat,
EnumFileSystemTypeExt2,
EnumFileSystemTypeAuto,
EnumFileSystemMax
} OS_FILE_SYSTEM_TYPE;
其实就是FAT和EXT2文件系统。
- 找到文件系统之后就可以在该文件系统上读取启动镜像并加载,最终启动该镜像。