当前位置: 首页 > news >正文

BdsEntry

代码

VOID
EFIAPI
BdsEntry (IN EFI_BDS_ARCH_PROTOCOL  *This)
{EFI_BOOT_MANAGER_LOAD_OPTION    *LoadOptions;UINTN                           LoadOptionCount;CHAR16                          *FirmwareVendor;EFI_EVENT                       HotkeyTriggered;UINT64                          OsIndication;UINTN                           DataSize;EFI_STATUS                      Status;UINT32                          BootOptionSupport;UINT16                          BootTimeOut;EDKII_VARIABLE_POLICY_PROTOCOL  *VariablePolicy;UINTN                           Index;EFI_BOOT_MANAGER_LOAD_OPTION    LoadOption;UINT16                          *BootNext;CHAR16                          BootNextVariableName[sizeof ("Boot####")];EFI_BOOT_MANAGER_LOAD_OPTION    BootManagerMenu;BOOLEAN                         BootFwUi;BOOLEAN                         PlatformRecovery;BOOLEAN                         BootSuccess;EFI_DEVICE_PATH_PROTOCOL        *FilePath;EFI_STATUS                      BootManagerMenuStatus;EFI_BOOT_MANAGER_LOAD_OPTION    PlatformDefaultBootOption;BOOLEAN                         PlatformDefaultBootOptionValid;HotkeyTriggered = NULL;Status          = EFI_SUCCESS;BootSuccess     = FALSE;//// Insert the performance probe//PERF_CROSSMODULE_END ("DXE");PERF_CROSSMODULE_BEGIN ("BDS");DEBUG ((DEBUG_INFO, "[Bds] Entry...\n"));//// Fill in FirmwareVendor and FirmwareRevision from PCDs//FirmwareVendor      = (CHAR16 *)PcdGetPtr (PcdFirmwareVendor);gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);ASSERT (gST->FirmwareVendor != NULL);gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);//// Fixup Tasble CRC after we updated Firmware Vendor and Revision//gST->Hdr.CRC32 = 0;gBS->CalculateCrc32 ((VOID *)gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);//// Validate Variable.//BdsFormalizeEfiGlobalVariable ();//// Mark the read-only variables if the Variable Lock protocol exists//Status = gBS->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid, NULL, (VOID **)&VariablePolicy);DEBUG ((DEBUG_INFO, "[BdsDxe] Locate Variable Policy protocol - %r\n", Status));if (!EFI_ERROR (Status)) {for (Index = 0; Index < ARRAY_SIZE (mReadOnlyVariables); Index++) {Status = RegisterBasicVariablePolicy (VariablePolicy,&gEfiGlobalVariableGuid,mReadOnlyVariables[Index],VARIABLE_POLICY_NO_MIN_SIZE,VARIABLE_POLICY_NO_MAX_SIZE,VARIABLE_POLICY_NO_MUST_ATTR,VARIABLE_POLICY_NO_CANT_ATTR,VARIABLE_POLICY_TYPE_LOCK_NOW);ASSERT_EFI_ERROR (Status);}}InitializeHwErrRecSupport ();//// Initialize L"Timeout" EFI global variable.//BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);if (BootTimeOut != 0xFFFF) {//// If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification// define same behavior between no value or 0xFFFF value for L"Timeout".//BdsDxeSetVariableAndReportStatusCodeOnError (EFI_TIME_OUT_VARIABLE_NAME,&gEfiGlobalVariableGuid,EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,sizeof (UINT16),&BootTimeOut);}//// Initialize L"BootOptionSupport" EFI global variable.// Lazy-ConIn implictly disables BDS hotkey.//BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;if (!PcdGetBool (PcdConInConnectOnDemand)) {BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);}Status = gRT->SetVariable (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,&gEfiGlobalVariableGuid,EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,sizeof (BootOptionSupport),&BootOptionSupport);//// Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.//ASSERT_EFI_ERROR (Status);//// Cache the "BootNext" NV variable before calling any PlatformBootManagerLib APIs// This could avoid the "BootNext" set by PlatformBootManagerLib be consumed in this boot.//GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **)&BootNext, &DataSize);if (DataSize != sizeof (UINT16)) {if (BootNext != NULL) {FreePool (BootNext);}BootNext = NULL;}//// Initialize the platform language variables//InitializeLanguage (TRUE);FilePath = FileDevicePath (NULL, EFI_REMOVABLE_MEDIA_FILE_NAME);if (FilePath == NULL) {DEBUG ((DEBUG_ERROR, "Fail to allocate memory for default boot file path. Unable to boot.\n"));CpuDeadLoop ();}PlatformDefaultBootOptionValid = EfiBootManagerInitializeLoadOption (&PlatformDefaultBootOption,LoadOptionNumberUnassigned,LoadOptionTypePlatformRecovery,LOAD_OPTION_ACTIVE,L"Default PlatformRecovery",FilePath,NULL,0) == EFI_SUCCESS;ASSERT (PlatformDefaultBootOptionValid == TRUE);//// System firmware must include a PlatformRecovery#### variable specifying// a short-form File Path Media Device Path containing the platform default// file path for removable media if the platform supports Platform Recovery.//if (PlatformDefaultBootOptionValid && PcdGetBool (PcdPlatformRecoverySupport)) {LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);if (EfiBootManagerFindLoadOption (&PlatformDefaultBootOption, LoadOptions, LoadOptionCount) == -1) {for (Index = 0; Index < LoadOptionCount; Index++) {//// The PlatformRecovery#### options are sorted by OptionNumber.// Find the the smallest unused number as the new OptionNumber.//if (LoadOptions[Index].OptionNumber != Index) {break;}}PlatformDefaultBootOption.OptionNumber = Index;Status                                 = EfiBootManagerLoadOptionToVariable (&PlatformDefaultBootOption);ASSERT_EFI_ERROR (Status);}EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);}FreePool (FilePath);//// Report Status Code to indicate connecting drivers will happen//REPORT_STATUS_CODE (EFI_PROGRESS_CODE,(EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS));//// Initialize ConnectConIn event before calling platform code.//if (PcdGetBool (PcdConInConnectOnDemand)) {Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,TPL_CALLBACK,BdsDxeOnConnectConInCallBack,NULL,&gConnectConInEventGuid,&gConnectConInEvent);if (EFI_ERROR (Status)) {gConnectConInEvent = NULL;}}//// Do the platform init, can be customized by OEM/IBV// Possible things that can be done in PlatformBootManagerBeforeConsole:// > Update console variable: 1. include hot-plug devices; 2. Clear ConIn and add SOL for AMT// > Register new Driver#### or Boot####// > Register new Key####: e.g.: F12// > Signal ReadyToLock event// > Authentication action: 1. connect Auth devices; 2. Identify auto logon user.//PERF_INMODULE_BEGIN ("PlatformBootManagerBeforeConsole");PlatformBootManagerBeforeConsole ();PERF_INMODULE_END ("PlatformBootManagerBeforeConsole");//// Initialize hotkey service//EfiBootManagerStartHotkeyService (&HotkeyTriggered);//// Execute Driver Options//LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);ProcessLoadOptions (LoadOptions, LoadOptionCount);EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);//// Connect consoles//PERF_INMODULE_BEGIN ("EfiBootManagerConnectAllDefaultConsoles");if (PcdGetBool (PcdConInConnectOnDemand)) {EfiBootManagerConnectConsoleVariable (ConOut);EfiBootManagerConnectConsoleVariable (ErrOut);//// Do not connect ConIn devices when lazy ConIn feature is ON.//} else {EfiBootManagerConnectAllDefaultConsoles ();}PERF_INMODULE_END ("EfiBootManagerConnectAllDefaultConsoles");//// Do the platform specific action after the console is ready// Possible things that can be done in PlatformBootManagerAfterConsole:// > Console post action://   > Dynamically switch output mode from 100x31 to 80x25 for certain senarino//   > Signal console ready platform customized event// > Run diagnostics like memory testing// > Connect certain devices// > Dispatch aditional option roms// > Special boot: e.g.: USB boot, enter UI//PERF_INMODULE_BEGIN ("PlatformBootManagerAfterConsole");PlatformBootManagerAfterConsole ();PERF_INMODULE_END ("PlatformBootManagerAfterConsole");//// If any component set PcdTestKeyUsed to TRUE because use of a test key// was detected, then display a warning message on the debug log and the console//if (PcdGetBool (PcdTestKeyUsed)) {DEBUG ((DEBUG_ERROR, "**********************************\n"));DEBUG ((DEBUG_ERROR, "**  WARNING: Test Key is used.  **\n"));DEBUG ((DEBUG_ERROR, "**********************************\n"));Print (L"**  WARNING: Test Key is used.  **\n");}//// Boot to Boot Manager Menu when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot//DataSize = sizeof (UINT64);Status   = gRT->GetVariable (EFI_OS_INDICATIONS_VARIABLE_NAME,&gEfiGlobalVariableGuid,NULL,&DataSize,&OsIndication);if (EFI_ERROR (Status)) {OsIndication = 0;}DEBUG_CODE_BEGIN ();EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  LoadOptionType;DEBUG ((DEBUG_INFO, "[Bds]OsIndication: %016x\n", OsIndication));DEBUG ((DEBUG_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {DEBUG ((DEBUG_INFO,"  %s Options:\n",mBdsLoadOptionName[LoadOptionType]));LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);for (Index = 0; Index < LoadOptionCount; Index++) {DEBUG ((DEBUG_INFO,"    %s%04x: %s \t\t 0x%04x\n",mBdsLoadOptionName[LoadOptionType],LoadOptions[Index].OptionNumber,LoadOptions[Index].Description,LoadOptions[Index].Attributes));}EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);}DEBUG ((DEBUG_INFO, "[Bds]=============End Load Options Dumping=============\n"));DEBUG_CODE_END ();//// BootManagerMenu doesn't contain the correct information when return status is EFI_NOT_FOUND.//BootManagerMenuStatus = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);BootFwUi         = (BOOLEAN)((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);PlatformRecovery = (BOOLEAN)((OsIndication & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY) != 0);//// Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS//if (BootFwUi || PlatformRecovery) {OsIndication &= ~((UINT64)(EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY));Status        = gRT->SetVariable (EFI_OS_INDICATIONS_VARIABLE_NAME,&gEfiGlobalVariableGuid,EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,sizeof (UINT64),&OsIndication);//// Changing the content without increasing its size with current variable implementation shouldn't fail.//ASSERT_EFI_ERROR (Status);}//// Launch Boot Manager Menu directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot//if (BootFwUi && (BootManagerMenuStatus != EFI_NOT_FOUND)) {//// Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI//if (PcdGetBool (PcdConInConnectOnDemand)) {BdsDxeOnConnectConInCallBack (NULL, NULL);}//// Directly enter the setup page.//EfiBootManagerBoot (&BootManagerMenu);}if (!PlatformRecovery) {//// Execute SysPrep####//LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);ProcessLoadOptions (LoadOptions, LoadOptionCount);EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);//// Execute Key####//PERF_INMODULE_BEGIN ("BdsWait");BdsWait (HotkeyTriggered);PERF_INMODULE_END ("BdsWait");//// BdsReadKeys() can be removed after all keyboard drivers invoke callback in timer callback.//BdsReadKeys ();EfiBootManagerHotkeyBoot ();if (BootNext != NULL) {//// Delete "BootNext" NV variable before transferring control to it to prevent loops.//Status = gRT->SetVariable (EFI_BOOT_NEXT_VARIABLE_NAME,&gEfiGlobalVariableGuid,0,0,NULL);//// Deleting NV variable shouldn't fail unless it doesn't exist.//ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);//// Boot to "BootNext"//UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &LoadOption);if (!EFI_ERROR (Status)) {EfiBootManagerBoot (&LoadOption);EfiBootManagerFreeLoadOption (&LoadOption);if ((LoadOption.Status == EFI_SUCCESS) &&(BootManagerMenuStatus != EFI_NOT_FOUND) &&(LoadOption.OptionNumber != BootManagerMenu.OptionNumber)){//// Boot to Boot Manager Menu upon EFI_SUCCESS// Exception: Do not boot again when the BootNext points to Boot Manager Menu.//EfiBootManagerBoot (&BootManagerMenu);}}}do {//// Retry to boot if any of the boot succeeds//LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeBoot);BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, (BootManagerMenuStatus != EFI_NOT_FOUND) ? &BootManagerMenu : NULL);EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);} while (BootSuccess);}if (BootManagerMenuStatus != EFI_NOT_FOUND) {EfiBootManagerFreeLoadOption (&BootManagerMenu);}if (!BootSuccess) {if (PcdGetBool (PcdPlatformRecoverySupport)) {LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);ProcessLoadOptions (LoadOptions, LoadOptionCount);EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);} else if (PlatformDefaultBootOptionValid) {//// When platform recovery is not enabled, still boot to platform default file path.//PlatformDefaultBootOptionValid = EfiBootManagerProcessLoadOption (&PlatformDefaultBootOption) == EFI_SUCCESS;}}if (PlatformDefaultBootOptionValid) {EfiBootManagerFreeLoadOption (&PlatformDefaultBootOption);}DEBUG ((DEBUG_ERROR, "[Bds] Unable to boot!\n"));PlatformBootManagerUnableToBoot ();CpuDeadLoop ();
}

流程

BdsEntry() 一被调用,就意味着固件正式进入了 BDS 阶段

1 插入性能检测接口

  PERF_CROSSMODULE_END ("DXE");PERF_CROSSMODULE_BEGIN ("BDS");

performance (PERF)

2 填写固件供应商和固件版本信息

  FirmwareVendor      = (CHAR16 *)PcdGetPtr (PcdFirmwareVendor);gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);ASSERT (gST->FirmwareVendor != NULL);gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);

3 修复表CRC

  gST->Hdr.CRC32 = 0;gBS->CalculateCrc32 ((VOID *)gST, sizeof (EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);

4 固化/修复 EFI 全局变量

  BdsFormalizeEfiGlobalVariable ();

4.1 固化控制台变量

  BdsFormalizeConsoleVariable (EFI_CON_IN_VARIABLE_NAME);BdsFormalizeConsoleVariable (EFI_CON_OUT_VARIABLE_NAME);BdsFormalizeConsoleVariable (EFI_ERR_OUT_VARIABLE_NAME);

在这里插入图片描述
在这里插入图片描述
通过全局变量ID确定变量的值和大小

EFI_STATUS
EFIAPI
GetEfiGlobalVariable2 (IN CONST CHAR16  *Name,OUT VOID         **Value,OUT UINTN        *Size OPTIONAL)
{return GetVariable2 (Name, &gEfiGlobalVariableGuid, Value, Size);
}

在这里插入图片描述
在这里插入图片描述

4.2 固化与 OSIndication 相关的变量

  BdsFormalizeOSIndicationVariable ();

OsIndications 是 UEFI 规范中定义的一个机制,用于在操作系统加载程序和固件之间传递特定的引导意图或状态信息。它是一个 64 位的位掩码,每个位代表一个特定的指示,操作系统可以通过设置这些位来通知固件某些特定的行为或需求

5 标记变量为只读

  Status = gBS->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid, NULL, (VOID **)&VariablePolicy);DEBUG ((DEBUG_INFO, "[BdsDxe] Locate Variable Policy protocol - %r\n", Status));if (!EFI_ERROR (Status)) {for (Index = 0; Index < ARRAY_SIZE (mReadOnlyVariables); Index++) {Status = RegisterBasicVariablePolicy (VariablePolicy,&gEfiGlobalVariableGuid,mReadOnlyVariables[Index],VARIABLE_POLICY_NO_MIN_SIZE,VARIABLE_POLICY_NO_MAX_SIZE,VARIABLE_POLICY_NO_MUST_ATTR,VARIABLE_POLICY_NO_CANT_ATTR,VARIABLE_POLICY_TYPE_LOCK_NOW);ASSERT_EFI_ERROR (Status);}}InitializeHwErrRecSupport ();

6 初始化 EFI 全局变量 L"Timeout"

  BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);if (BootTimeOut != 0xFFFF) {//// If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification// define same behavior between no value or 0xFFFF value for L"Timeout".//BdsDxeSetVariableAndReportStatusCodeOnError (EFI_TIME_OUT_VARIABLE_NAME,&gEfiGlobalVariableGuid,EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,sizeof (UINT16),&BootTimeOut);}

BootTimeout 就是固件在自动启动默认项之前,给用户按热键进 Boot Menu 的等待秒数
单位:秒(0 表示“不等待,立即启动默认项”;0xFFFF 表示“无限等待,直到用户手动选”)

7 初始化 EFI 全局变量 L"BootOptionSupport"

  BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP | EFI_BOOT_OPTION_SUPPORT_SYSPREP;if (!PcdGetBool (PcdConInConnectOnDemand)) {BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);}Status = gRT->SetVariable (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME,&gEfiGlobalVariableGuid,EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,sizeof (BootOptionSupport),&BootOptionSupport);

8 缓存 “BootNext” NV 变量在调用API之前

NV (Non-Volatile)非易失

  GetEfiGlobalVariable2 (EFI_BOOT_NEXT_VARIABLE_NAME, (VOID **)&BootNext, &DataSize);if (DataSize != sizeof (UINT16)) {if (BootNext != NULL) {FreePool (BootNext);}BootNext = NULL;}

9 初始化平台语言变量

  InitializeLanguage (TRUE);

10 初始化平台恢复类型的加载选项

维度Load OptionsBoot Options
本质数据结构功能/菜单层面的叫法
存储Boot#### 变量形式保存在 NVRAM同样用 Boot#### 变量,只是叫法不同
内容Attributes + DevicePath + OptionalData用户看到的 UEFI OS、Windows Boot Manager 等条目
用途告诉固件如何加载并启动某个镜像给用户/OS 提供可选的启动入口
可见性程序员调试、dump 时看结构用户界面、文档、Shell 里说的“启动项”

在平台恢复场景下,系统允许“加载选项数量为 0”是合法的,甚至是一种预期状态
在没有平台恢复选项时,创建一个默认的平台恢复选项

  FilePath = FileDevicePath (NULL, EFI_REMOVABLE_MEDIA_FILE_NAME);if (FilePath == NULL) {DEBUG ((DEBUG_ERROR, "Fail to allocate memory for default boot file path. Unable to boot.\n"));CpuDeadLoop ();}PlatformDefaultBootOptionValid = EfiBootManagerInitializeLoadOption (&PlatformDefaultBootOption,LoadOptionNumberUnassigned,LoadOptionTypePlatformRecovery,LOAD_OPTION_ACTIVE,L"Default PlatformRecovery",FilePath,NULL,0) == EFI_SUCCESS;ASSERT (PlatformDefaultBootOptionValid == TRUE);if (PlatformDefaultBootOptionValid && PcdGetBool (PcdPlatformRecoverySupport)) {LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypePlatformRecovery);if (EfiBootManagerFindLoadOption (&PlatformDefaultBootOption, LoadOptions, LoadOptionCount) == -1) {for (Index = 0; Index < LoadOptionCount; Index++) {//// The PlatformRecovery#### options are sorted by OptionNumber.// Find the the smallest unused number as the new OptionNumber.//if (LoadOptions[Index].OptionNumber != Index) {break;}}PlatformDefaultBootOption.OptionNumber = Index;Status                                 = EfiBootManagerLoadOptionToVariable (&PlatformDefaultBootOption);ASSERT_EFI_ERROR (Status);}EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);}FreePool (FilePath);
EFI_STATUS
EFIAPI
EfiBootManagerInitializeLoadOption (IN OUT EFI_BOOT_MANAGER_LOAD_OPTION    *Option,IN  UINTN                              OptionNumber,IN  EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  OptionType,IN  UINT32                             Attributes,IN  CHAR16                             *Description,IN  EFI_DEVICE_PATH_PROTOCOL           *FilePath,IN  UINT8                              *OptionalData    OPTIONAL,IN  UINT32                             OptionalDataSize)
{if ((Option == NULL) || (Description == NULL) || (FilePath == NULL)) {return EFI_INVALID_PARAMETER;}if (((OptionalData != NULL) && (OptionalDataSize == 0)) ||((OptionalData == NULL) && (OptionalDataSize != 0))){return EFI_INVALID_PARAMETER;}if ((UINT32)OptionType >= LoadOptionTypeMax) {return EFI_INVALID_PARAMETER;}ZeroMem (Option, sizeof (EFI_BOOT_MANAGER_LOAD_OPTION));Option->OptionNumber = OptionNumber;Option->OptionType   = OptionType;Option->Attributes   = Attributes;Option->Description  = AllocateCopyPool (StrSize (Description), Description);Option->FilePath     = DuplicateDevicePath (FilePath);if (OptionalData != NULL) {Option->OptionalData     = AllocateCopyPool (OptionalDataSize, OptionalData);Option->OptionalDataSize = OptionalDataSize;}return EFI_SUCCESS;
}

11 报告状态码以指示即将连接驱动程序

  REPORT_STATUS_CODE (EFI_PROGRESS_CODE,(EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS));

12 初始化 ConnectConIn 事件

确保在调用平台代码之前,输入设备已经准备好,可以接收用户输入

不需要初始化 ConnectConIn 事件的场景:

  • 系统设计不需要用户交互
  • 平台代码不依赖用户输入
  • 性能优化
  • 安全考虑
  • 硬件限制
  if (PcdGetBool (PcdConInConnectOnDemand)) {Status = gBS->CreateEventEx (EVT_NOTIFY_SIGNAL,TPL_CALLBACK,BdsDxeOnConnectConInCallBack,NULL,&gConnectConInEventGuid,&gConnectConInEvent);if (EFI_ERROR (Status)) {gConnectConInEvent = NULL;}}

13 执行平台初始化(可由 OEM/IBV 自行定制)

在 PlatformBootManagerBeforeConsole 阶段可完成的事项示例:

  • 更新控制台变量:1. 加入热插拔设备;2. 清空 ConIn 并添加 SOL(Serial Over LAN)以支持 AMT
  • 注册新的 Driver#### 或 Boot#### 选项
  • 注册新的按键选项,例如 F12
  • 发出 ReadyToLock 事件信号
  • 认证相关动作:1. 连接认证设备;2. 识别自动登录用户

平台初始化详细内容
https://blog.csdn.net/degen_/article/details/154655046

  PERF_INMODULE_BEGIN ("PlatformBootManagerBeforeConsole");PlatformBootManagerBeforeConsole ();PERF_INMODULE_END ("PlatformBootManagerBeforeConsole");
VOID
EFIAPI
PlatformBootManagerBeforeConsole (VOID)
{EFI_HANDLE     Handle;EFI_STATUS     Status;UINT16         FrontPageTimeout;RETURN_STATUS  PcdStatus;BOOLEAN        FirmwareSetupEnabled;DEBUG ((DEBUG_INFO, "PlatformBootManagerBeforeConsole\n"));InstallDevicePathCallback ();VisitAllInstancesOfProtocol (&gEfiPciRootBridgeIoProtocolGuid,ConnectRootBridge,NULL);//// Signal the ACPI platform driver that it can download QEMU ACPI tables.//EfiEventGroupSignal (&gRootBridgesConnectedEventGroupGuid);//// We can't signal End-of-Dxe earlier than this. Namely, End-of-Dxe triggers// the preparation of S3 system information. That logic has a hard dependency// on the presence of the FACS ACPI table. Since our ACPI tables are only// installed after PCI enumeration completes, we must not trigger the S3 save// earlier, hence we can't signal End-of-Dxe earlier.//EfiEventGroupSignal (&gEfiEndOfDxeEventGroupGuid);if (PcdGetBool (PcdAcpiS3Enable)) {//// Save the boot script too. Note that this will require us to emit the// DxeSmmReadyToLock event just below, which in turn locks down SMM.//SaveS3BootScript ();}//// We need to connect all trusted consoles for TCG PP. Here we treat all// consoles in OVMF to be trusted consoles.//// Cloud Hypervisor doesn't emulate any LPC bridge, which is why it must// rely on the serial I/O port to be connected as a console. It reuses the// definition from Xen as it is very generic.//PlatformInitializeConsole ((XenDetected () || PcdGet16 (PcdOvmfHostBridgePciDevId) == CLOUDHV_DEVICE_ID) ? gXenPlatformConsole : gPlatformConsole);//// Process TPM PPI request; this may require keyboard input//Tcg2PhysicalPresenceLibProcessRequest (NULL);//// Prevent further changes to LockBoxes or SMRAM.// Any TPM 2 Physical Presence Interface opcode must be handled before.//Handle = NULL;Status = gBS->InstallProtocolInterface (&Handle,&gEfiDxeSmmReadyToLockProtocolGuid,EFI_NATIVE_INTERFACE,NULL);ASSERT_EFI_ERROR (Status);//// Dispatch deferred images after EndOfDxe event and ReadyToLock// installation.//EfiBootManagerDispatchDeferredImages ();//// GPU passthrough only allows Console enablement after ROM image load//PlatformInitializeConsole (XenDetected () ? gXenPlatformConsole : gPlatformConsole);FrontPageTimeout = GetFrontPageTimeoutFromQemu ();PcdStatus        = PcdSet16S (PcdPlatformBootTimeOut, FrontPageTimeout);ASSERT_RETURN_ERROR (PcdStatus);//// Reflect the PCD in the standard Timeout variable.//Status = gRT->SetVariable (EFI_TIME_OUT_VARIABLE_NAME,&gEfiGlobalVariableGuid,(EFI_VARIABLE_NON_VOLATILE |EFI_VARIABLE_BOOTSERVICE_ACCESS |EFI_VARIABLE_RUNTIME_ACCESS),sizeof FrontPageTimeout,&FrontPageTimeout);DEBUG ((EFI_ERROR (Status) ? DEBUG_ERROR : DEBUG_VERBOSE,"%a: SetVariable(%s, %u): %r\n",__func__,EFI_TIME_OUT_VARIABLE_NAME,FrontPageTimeout,Status));Status = QemuFwCfgParseBool ("opt/org.tianocore/FirmwareSetupSupport",&FirmwareSetupEnabled);if (RETURN_ERROR (Status)) {FirmwareSetupEnabled = TRUE;}PlatformRegisterFvBootOption (&gUiAppFileGuid,L"EFI Firmware Setup",LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_APP,FirmwareSetupEnabled);if (!FeaturePcdGet (PcdBootRestrictToFirmware)) {PlatformRegisterOptionsAndKeys ();}//// Install both VIRTIO_DEVICE_PROTOCOL and (dependent) EFI_RNG_PROTOCOL// instances on Virtio PCI RNG devices.//VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid,ConnectVirtioPciRng,NULL);
}

14 初始化热键服务

UEFI 的启动管理里把“按键启动项”分成 普通快捷键 和 Continue/“继续”快捷键 两类

  • 普通快捷键
    让用户“一键”启动指定介质/OS
  • Continue 快捷键
    给所有快捷键都没匹配时一个兜底动作,避免系统卡死
  EfiBootManagerStartHotkeyService (&HotkeyTriggered);
EFI_STATUS
EFIAPI
EfiBootManagerStartHotkeyService (IN EFI_EVENT  *HotkeyTriggered)
{EFI_STATUS                   Status;EFI_BOOT_MANAGER_KEY_OPTION  *KeyOptions;UINTN                        KeyOptionCount;UINTN                        Index;EFI_EVENT                    Event;UINT32                       *BootOptionSupport;GetEfiGlobalVariable2 (EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME, (VOID **)&BootOptionSupport, NULL);if (BootOptionSupport != NULL) {if ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_KEY)  != 0) {mBmHotkeySupportCount = ((*BootOptionSupport & EFI_BOOT_OPTION_SUPPORT_COUNT) >> LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT));}FreePool (BootOptionSupport);}if (mBmHotkeySupportCount == 0) {DEBUG ((DEBUG_INFO, "Bds: BootOptionSupport NV variable forbids starting the hotkey service.\n"));return EFI_UNSUPPORTED;}Status = gBS->CreateEvent (EVT_NOTIFY_WAIT,TPL_CALLBACK,EfiEventEmptyFunction,NULL,&mBmHotkeyTriggered);ASSERT_EFI_ERROR (Status);if (HotkeyTriggered != NULL) {*HotkeyTriggered = mBmHotkeyTriggered;}KeyOptions = BmGetKeyOptions (&KeyOptionCount);for (Index = 0; Index < KeyOptionCount; Index++) {BmProcessKeyOption (&KeyOptions[Index]);}BmFreeKeyOptions (KeyOptions, KeyOptionCount);if (mBmContinueKeyOption != NULL) {BmProcessKeyOption (mBmContinueKeyOption);}//// Hook hotkey on every future SimpleTextInputEx instance when// SystemTable.ConsoleInHandle == NULL, which means the console// manager (ConSplitter) is absent.//if (gST->ConsoleInHandle == NULL) {EfiCreateProtocolNotifyEvent (&gEfiSimpleTextInputExProtocolGuid,TPL_CALLBACK,BmTxtInExCallback,NULL,&mBmTxtInExRegistration);}Status = EfiCreateEventReadyToBootEx (TPL_CALLBACK,BmStopHotkeyService,NULL,&Event);ASSERT_EFI_ERROR (Status);mBmHotkeyServiceStarted = TRUE;return Status;
}

15 执行驱动程序选项

  LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeDriver);ProcessLoadOptions (LoadOptions, LoadOptionCount);EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);

16 连接控制台

  PERF_INMODULE_BEGIN ("EfiBootManagerConnectAllDefaultConsoles");if (PcdGetBool (PcdConInConnectOnDemand)) {EfiBootManagerConnectConsoleVariable (ConOut);EfiBootManagerConnectConsoleVariable (ErrOut);//// Do not connect ConIn devices when lazy ConIn feature is ON.//} else {EfiBootManagerConnectAllDefaultConsoles ();}PERF_INMODULE_END ("EfiBootManagerConnectAllDefaultConsoles");

17 执行平台相关动作

实现:

  • 控制台后处理:
    根据某种场景需要,把输出模式从 100×31 动态切换到 80×25
    触发一个控制台已就绪的、平台自定义的事件
  • 运行诊断程序,例如内存测试
  • 连接特定设备,使其进入可用状态
  • 加载并执行额外的 Option ROM,如显卡/独立磁盘冗余阵列(RAID)/网络接口卡(NIC)等固件扩展
  • 特殊启动流程,例如强制 USB 启动,或直接进入厂商 UI(Boot Manager、Setup 界面)

详细内容
https://blog.csdn.net/degen_/article/details/154771275

VOID
EFIAPI
PlatformBootManagerAfterConsole (VOID)
{EFI_BOOT_MODE  BootMode;DEBUG ((DEBUG_INFO, "PlatformBootManagerAfterConsole\n"));if (PcdGetBool (PcdOvmfFlashVariablesEnable)) {DEBUG ((DEBUG_INFO,"PlatformBdsPolicyBehavior: not restoring NvVars ""from disk since flash variables appear to be supported.\n"));} else {//// Try to restore variables from the hard disk early so// they can be used for the other BDS connect operations.//PlatformBdsRestoreNvVarsFromHardDisk ();}//// Get current Boot Mode//BootMode = GetBootModeHob ();DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));//// Go the different platform policy with different boot mode// Notes: this part code can be change with the table policy//ASSERT (BootMode == BOOT_WITH_FULL_CONFIGURATION);//// Logo show//BootLogoEnableLogo ();//// Set PCI Interrupt Line registers and ACPI SCI_EN//PciAcpiInitialization ();//// Write qemu bootorder to efi variables//StoreQemuBootOrder ();//// Process QEMU's -kernel command line option//TryRunningQemuKernel ();//// Perform some platform specific connect sequence//if (FeaturePcdGet (PcdBootRestrictToFirmware)) {RestrictBootOptionsToFirmware ();} else {PlatformBdsConnectSequence ();EfiBootManagerRefreshAllBootOption ();}BOOLEAN        ShellEnabled;RETURN_STATUS  RetStatus;RetStatus = QemuFwCfgParseBool ("opt/org.tianocore/EFIShellSupport",&ShellEnabled);if (RETURN_ERROR (RetStatus)) {ShellEnabled = TRUE;}//// Register UEFI Shell//PlatformRegisterFvBootOption (&gUefiShellFileGuid,L"EFI Internal Shell",LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_APP,ShellEnabled);//// Register Grub//PlatformRegisterFvBootOption (&gGrubFileGuid,L"Grub Bootloader",LOAD_OPTION_ACTIVE,TRUE);RemoveStaleFvFileOptions ();SetBootOrderFromQemu ();PlatformBmPrintScRegisterHandler ();
}

18 读取 UEFI 全局变量 OsIndications

  DataSize = sizeof (UINT64);Status   = gRT->GetVariable (EFI_OS_INDICATIONS_VARIABLE_NAME,&gEfiGlobalVariableGuid,NULL,&DataSize,&OsIndication);if (EFI_ERROR (Status)) {OsIndication = 0;}

第一次启动时,变量不存在,GetVariable 会返回 EFI_NOT_FOUND,此时把 OsIndication 清零

19 开始转储加载选项

  DEBUG_CODE_BEGIN ();EFI_BOOT_MANAGER_LOAD_OPTION_TYPE  LoadOptionType;DEBUG ((DEBUG_INFO, "[Bds]OsIndication: %016x\n", OsIndication));DEBUG ((DEBUG_INFO, "[Bds]=============Begin Load Options Dumping ...=============\n"));for (LoadOptionType = 0; LoadOptionType < LoadOptionTypeMax; LoadOptionType++) {DEBUG ((DEBUG_INFO,"  %s Options:\n",mBdsLoadOptionName[LoadOptionType]));LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionType);for (Index = 0; Index < LoadOptionCount; Index++) {DEBUG ((DEBUG_INFO,"    %s%04x: %s \t\t 0x%04x\n",mBdsLoadOptionName[LoadOptionType],LoadOptions[Index].OptionNumber,LoadOptions[Index].Description,LoadOptions[Index].Attributes));}EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);}DEBUG ((DEBUG_INFO, "[Bds]=============End Load Options Dumping=============\n"));DEBUG_CODE_END ();

20 决定进入界面

  BootManagerMenuStatus = EfiBootManagerGetBootManagerMenu (&BootManagerMenu);BootFwUi         = (BOOLEAN)((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0);PlatformRecovery = (BOOLEAN)((OsIndication & EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY) != 0);if (BootFwUi || PlatformRecovery) {OsIndication &= ~((UINT64)(EFI_OS_INDICATIONS_BOOT_TO_FW_UI | EFI_OS_INDICATIONS_START_PLATFORM_RECOVERY));Status        = gRT->SetVariable (EFI_OS_INDICATIONS_VARIABLE_NAME,&gEfiGlobalVariableGuid,EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,sizeof (UINT64),&OsIndication);//// Changing the content without increasing its size with current variable implementation shouldn't fail.//ASSERT_EFI_ERROR (Status);}if (BootFwUi && (BootManagerMenuStatus != EFI_NOT_FOUND)) {//// Follow generic rule, Call BdsDxeOnConnectConInCallBack to connect ConIn before enter UI//if (PcdGetBool (PcdConInConnectOnDemand)) {BdsDxeOnConnectConInCallBack (NULL, NULL);}//// Directly enter the setup page.//EfiBootManagerBoot (&BootManagerMenu);}
  • EfiBootManagerGetBootManagerMenu 如果读失败,后面会直接弹 Setup 或默认菜单
  • BootFwUi = TRUE → 用户或 OS 要求进固件设置界面(BIOS Setup)
  • PlatformRecovery = TRUE → 要求启动平台恢复环境
    如果三个值全是0,则按正常启动顺序继续走

21 UEFI 的正常启动主流程

  if (!PlatformRecovery) {//// Execute SysPrep####//LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);ProcessLoadOptions (LoadOptions, LoadOptionCount);EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);//// Execute Key####//PERF_INMODULE_BEGIN ("BdsWait");BdsWait (HotkeyTriggered);PERF_INMODULE_END ("BdsWait");//// BdsReadKeys() can be removed after all keyboard drivers invoke callback in timer callback.//BdsReadKeys ();EfiBootManagerHotkeyBoot ();if (BootNext != NULL) {//// Delete "BootNext" NV variable before transferring control to it to prevent loops.//Status = gRT->SetVariable (EFI_BOOT_NEXT_VARIABLE_NAME,&gEfiGlobalVariableGuid,0,0,NULL);//// Deleting NV variable shouldn't fail unless it doesn't exist.//ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);//// Boot to "BootNext"//UnicodeSPrint (BootNextVariableName, sizeof (BootNextVariableName), L"Boot%04x", *BootNext);Status = EfiBootManagerVariableToLoadOption (BootNextVariableName, &LoadOption);if (!EFI_ERROR (Status)) {EfiBootManagerBoot (&LoadOption);EfiBootManagerFreeLoadOption (&LoadOption);if ((LoadOption.Status == EFI_SUCCESS) &&(BootManagerMenuStatus != EFI_NOT_FOUND) &&(LoadOption.OptionNumber != BootManagerMenu.OptionNumber)){//// Boot to Boot Manager Menu upon EFI_SUCCESS// Exception: Do not boot again when the BootNext points to Boot Manager Menu.//EfiBootManagerBoot (&BootManagerMenu);}}}do {//// Retry to boot if any of the boot succeeds//LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeBoot);BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, (BootManagerMenuStatus != EFI_NOT_FOUND) ? &BootManagerMenu : NULL);EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);} while (BootSuccess);}

21.1 执行 SysPrep#### 变量的启动项

    LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeSysPrep);ProcessLoadOptions (LoadOptions, LoadOptionCount);EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);

21.2 执行 Key#### 变量的启动项

    PERF_INMODULE_BEGIN ("BdsWait");BdsWait (HotkeyTriggered);PERF_INMODULE_END ("BdsWait");BdsReadKeys ();

21.3 检测热键并执行相应操作

    EfiBootManagerHotkeyBoot ();

21.4 尝试重新启动直到成功

    do {//// Retry to boot if any of the boot succeeds//LoadOptions = EfiBootManagerGetLoadOptions (&LoadOptionCount, LoadOptionTypeBoot);BootSuccess = BootBootOptions (LoadOptions, LoadOptionCount, (BootManagerMenuStatus != EFI_NOT_FOUND) ? &BootManagerMenu : NULL);EfiBootManagerFreeLoadOptions (LoadOptions, LoadOptionCount);} while (BootSuccess);
BOOLEAN
BootBootOptions (IN EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions,IN UINTN                         BootOptionCount,IN EFI_BOOT_MANAGER_LOAD_OPTION  *BootManagerMenu OPTIONAL)
{UINTN  Index;//// Report Status Code to indicate BDS starts attempting booting from the UEFI BootOrder list.//REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_ATTEMPT_BOOT_ORDER_EVENT));//// Attempt boot each boot option//for (Index = 0; Index < BootOptionCount; Index++) {//// According to EFI Specification, if a load option is not marked// as LOAD_OPTION_ACTIVE, the boot manager will not automatically// load the option.//if ((BootOptions[Index].Attributes & LOAD_OPTION_ACTIVE) == 0) {continue;}//// Boot#### load options with LOAD_OPTION_CATEGORY_APP are executables which are not// part of the normal boot processing. Boot options with reserved category values will be// ignored by the boot manager.//if ((BootOptions[Index].Attributes & LOAD_OPTION_CATEGORY) != LOAD_OPTION_CATEGORY_BOOT) {continue;}//// All the driver options should have been processed since// now boot will be performed.//EfiBootManagerBoot (&BootOptions[Index]);//// If the boot via Boot#### returns with a status of EFI_SUCCESS, platform firmware// supports boot manager menu, and if firmware is configured to boot in an// interactive mode, the boot manager will stop processing the BootOrder variable and// present a boot manager menu to the user.//if ((BootManagerMenu != NULL) && (BootOptions[Index].Status == EFI_SUCCESS)) {EfiBootManagerBoot (BootManagerMenu);break;}}return (BOOLEAN)(Index < BootOptionCount);
}
VOID
EFIAPI
EfiBootManagerBoot (IN  EFI_BOOT_MANAGER_LOAD_OPTION  *BootOption)
{EFI_STATUS                 Status;EFI_HANDLE                 ImageHandle;EFI_LOADED_IMAGE_PROTOCOL  *ImageInfo;UINT16                     Uint16;UINTN                      OptionNumber;UINTN                      OriginalOptionNumber;EFI_DEVICE_PATH_PROTOCOL   *FilePath;EFI_DEVICE_PATH_PROTOCOL   *RamDiskDevicePath;VOID                       *FileBuffer;UINTN                      FileSize;EFI_BOOT_LOGO_PROTOCOL     *BootLogo;EFI_EVENT                  LegacyBootEvent;if (BootOption == NULL) {return;}if ((BootOption->FilePath == NULL) || (BootOption->OptionType != LoadOptionTypeBoot)) {BootOption->Status = EFI_INVALID_PARAMETER;return;}//// 1. Create Boot#### for a temporary boot if there is no match Boot#### (i.e. a boot by selected a EFI Shell using "Boot From File")//OptionNumber = BmFindBootOptionInVariable (BootOption);if (OptionNumber == LoadOptionNumberUnassigned) {Status = BmGetFreeOptionNumber (LoadOptionTypeBoot, &Uint16);if (!EFI_ERROR (Status)) {//// Save the BootOption->OptionNumber to restore later//OptionNumber             = Uint16;OriginalOptionNumber     = BootOption->OptionNumber;BootOption->OptionNumber = OptionNumber;Status                   = EfiBootManagerLoadOptionToVariable (BootOption);BootOption->OptionNumber = OriginalOptionNumber;}if (EFI_ERROR (Status)) {DEBUG ((DEBUG_ERROR, "[Bds] Failed to create Boot#### for a temporary boot - %r!\n", Status));BootOption->Status = Status;return;}}//// 2. Set BootCurrent//Uint16 = (UINT16)OptionNumber;BmSetVariableAndReportStatusCodeOnError (L"BootCurrent",&gEfiGlobalVariableGuid,EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,sizeof (UINT16),&Uint16);//// 3. Signal the EVT_SIGNAL_READY_TO_BOOT event when we are about to load and execute//    the boot option.//if (BmIsBootManagerMenuFilePath (BootOption->FilePath)) {DEBUG ((DEBUG_INFO, "[Bds] Booting Boot Manager Menu.\n"));BmStopHotkeyService (NULL, NULL);} else {EfiSignalEventReadyToBoot ();//// Report Status Code to indicate ReadyToBoot was signalled//REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));//// 4. Repair system through DriverHealth protocol//BmRepairAllControllers (0);}PERF_START_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32)OptionNumber);//// 5. Adjust the different type memory page number just before booting//    and save the updated info into the variable for next boot to use//BmSetMemoryTypeInformationVariable ((BOOLEAN)((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_BOOT));//// 6. Load EFI boot option to ImageHandle//DEBUG_CODE_BEGIN ();if (BootOption->Description == NULL) {DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting from unknown device path\n"));} else {DEBUG ((DEBUG_INFO | DEBUG_LOAD, "[Bds]Booting %s\n", BootOption->Description));}DEBUG_CODE_END ();ImageHandle       = NULL;RamDiskDevicePath = NULL;if (DevicePathType (BootOption->FilePath) != BBS_DEVICE_PATH) {Status   = EFI_NOT_FOUND;FilePath = NULL;EfiBootManagerConnectDevicePath (BootOption->FilePath, NULL);FileBuffer = BmGetNextLoadOptionBuffer (LoadOptionTypeBoot, BootOption->FilePath, &FilePath, &FileSize);if (FileBuffer != NULL) {RamDiskDevicePath = BmGetRamDiskDevicePath (FilePath);REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));Status = gBS->LoadImage (TRUE,gImageHandle,FilePath,FileBuffer,FileSize,&ImageHandle);}if (FileBuffer != NULL) {FreePool (FileBuffer);}if (FilePath != NULL) {FreePool (FilePath);}if (EFI_ERROR (Status)) {//// With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created// with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.// If the caller doesn't have the option to defer the execution of an image, we should// unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.//if (Status == EFI_SECURITY_VIOLATION) {gBS->UnloadImage (ImageHandle);}//// Destroy the RAM disk//if (RamDiskDevicePath != NULL) {BmDestroyRamDisk (RamDiskDevicePath);FreePool (RamDiskDevicePath);}//// Report Status Code with the failure status to indicate that the failure to load boot option//BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR, Status);BootOption->Status = Status;return;}}//// Check to see if we should legacy BOOT. If yes then do the legacy boot// Write boot to OS performance data for Legacy boot//if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) && (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {if (mBmLegacyBoot != NULL) {//// Write boot to OS performance data for legacy boot.//PERF_CODE (//// Create an event to be signalled when Legacy Boot occurs to write performance data.//Status = EfiCreateEventLegacyBootEx (TPL_NOTIFY,BmEndOfBdsPerfCode,NULL,&LegacyBootEvent);ASSERT_EFI_ERROR (Status););mBmLegacyBoot (BootOption);} else {BootOption->Status = EFI_UNSUPPORTED;}PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32)OptionNumber);return;}//// Provide the image with its load options//Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo);ASSERT_EFI_ERROR (Status);if (!BmIsAutoCreateBootOption (BootOption)) {ImageInfo->LoadOptionsSize = BootOption->OptionalDataSize;ImageInfo->LoadOptions     = BootOption->OptionalData;}//// Clean to NULL because the image is loaded directly from the firmwares boot manager.//ImageInfo->ParentHandle = NULL;//// Before calling the image, enable the Watchdog Timer for 5 minutes period//gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);//// Write boot to OS performance data for UEFI boot//PERF_CODE (BmEndOfBdsPerfCode (NULL, NULL););REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));Status = gBS->StartImage (ImageHandle, &BootOption->ExitDataSize, &BootOption->ExitData);DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));BootOption->Status = Status;//// Destroy the RAM disk//if (RamDiskDevicePath != NULL) {BmDestroyRamDisk (RamDiskDevicePath);FreePool (RamDiskDevicePath);}if (EFI_ERROR (Status)) {//// Report Status Code with the failure status to indicate that boot failure//BmReportLoadFailure (EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED, Status);}PERF_END_EX (gImageHandle, "BdsAttempt", NULL, 0, (UINT32)OptionNumber);//// Clear the Watchdog Timer after the image returns//gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);//// Set Logo status invalid after trying one boot option//BootLogo = NULL;Status   = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **)&BootLogo);if (!EFI_ERROR (Status) && (BootLogo != NULL)) {Status = BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);ASSERT_EFI_ERROR (Status);}//// Clear Boot Current//Status = gRT->SetVariable (L"BootCurrent",&gEfiGlobalVariableGuid,0,0,NULL);//// Deleting variable with current variable implementation shouldn't fail.// When BootXXXX (e.g.: BootManagerMenu) boots BootYYYY, exiting BootYYYY causes BootCurrent deleted,// exiting BootXXXX causes deleting BootCurrent returns EFI_NOT_FOUND.//ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
}
  • 寻找/创建匹配的 Boot#### 变量
    在这里插入图片描述
  • 设置 BootCurrent 变量并记录当前启动项编号
  • 触发 EVT_SIGNAL_READY_TO_BOOT 事件
  • 通过 DriverHealth 协议 修复系统
  • 调整各类内存页数量并保存更新后的信息到变量供下次启动使用
  • 将 EFI 启动项加载为 ImageHandle
  • 检查是否应使用传统启动
  • 向映像提供其加载选项
  • 移交控制权到已加载映像的入口

https://blog.csdn.net/degen_/article/details/154834529

http://www.dtcms.com/a/611187.html

相关文章:

  • 网站备案后 如何建设tp框架做餐饮网站
  • 自动化 东莞网站建设如何提高用户和网站的互动性
  • Linux网络编程:(八)GCC/G++ 编译器完全指南:从编译原理到实战优化,手把手教你玩转 C/C++ 编译
  • 网站负责人拍照集团公司网站设计
  • 重钢建设公司官方网站电脑访问手机网站跳转
  • AI赋能多模态情绪识别
  • vue3 使用v-model开发弹窗组件
  • 淘宝网站建设的目标是什么石家庄网络营销哪家好做
  • vue3开发使用框架推荐
  • 郑州网站建设方案国内购物网站大全
  • Qt界面布局管理详解
  • RK3506 eMMC 固件重启崩溃问题(USB 触发)技术总结
  • RocketMQ DefaultMQPushConsumer vs DefaultLitePullConsumer
  • php和mysql网站毕业设计成都餐饮设计公司有哪些
  • 甘肃统计投资审核系统完成国产数据库替换:从MySQL到金仓的平稳跨越
  • 征求网站建设意见的通知seo优化网站排名
  • 电商网站流程优秀网络广告文案案例
  • 怎么做个人网站建设wordpress 迁移 工具
  • 两台arm服务器之间实现实时同步
  • 国外设计参考网站公司如何做网站宣传
  • 多用户自助建站系统wordpress iis 500.50
  • 福州网站建设需要多少钱ui设计的优势与不足
  • 网站建设方案书的内容网上学编程
  • 经典算法题之子集(四)
  • 自己动手写深度学习框架(反向传播)
  • 网站多大需要服务器活动手机网站开发
  • 网站推广原则做个网站大约多少钱
  • 政府机关选用GS 90盘位存储,保存Veeam备份数据
  • MySQL: 服务器性能优化全面指南:参数配置与数据库设计的最佳实践
  • 垫江集团网站建设商城外贸网站设计