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

BDS 执行平台相关动作

代码

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

流程

1 决定启动时变量来源

有 Flash → 直接用,不恢复
没 Flash → 从磁盘恢复一次

恢复是读取加写回

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

2 获取当前启动模式

  BootMode = GetBootModeHob ();DEBUG ((DEBUG_INFO, "Boot Mode:%x\n", BootMode));

3 显示logo

  BootLogoEnableLogo ();

3.1 定位相关协议

  Status = gBS->LocateProtocol (&gEdkiiPlatformLogoProtocolGuid, NULL, (VOID **)&PlatformLogo);if (EFI_ERROR (Status)) {return EFI_UNSUPPORTED;}//// Try to open GOP first//Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);if (EFI_ERROR (Status)) {return EFI_UNSUPPORTED;}//// Try to open Boot Logo Protocol.//Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **)&BootLogo);if (EFI_ERROR (Status)) {BootLogo = NULL;}//// Try to open Boot Logo 2 Protocol.//Status = gBS->LocateProtocol (&gEdkiiBootLogo2ProtocolGuid, NULL, (VOID **)&BootLogo2);if (EFI_ERROR (Status)) {BootLogo2 = NULL;}

3.2 擦除光标

  gST->ConOut->EnableCursor (gST->ConOut, FALSE);

3.3 获取 logo 尺寸

  SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;

3.4 获取映像

    Status = PlatformLogo->GetImage (PlatformLogo,&Instance,&Image,&Attribute,&OffsetX,&OffsetY);if (EFI_ERROR (Status)) {break;}if (Blt != NULL) {FreePool (Blt);}Blt = Image.Bitmap;

3.5 定位位置

    switch (Attribute) {case EdkiiPlatformLogoDisplayAttributeLeftTop:DestX = 0;DestY = 0;break;case EdkiiPlatformLogoDisplayAttributeCenterTop:DestX = (SizeOfX - Image.Width) / 2;DestY = 0;break;case EdkiiPlatformLogoDisplayAttributeRightTop:DestX = SizeOfX - Image.Width;DestY = 0;break;case EdkiiPlatformLogoDisplayAttributeCenterLeft:DestX = 0;DestY = (SizeOfY - Image.Height) / 2;break;case EdkiiPlatformLogoDisplayAttributeCenter:DestX = (SizeOfX - Image.Width) / 2;DestY = (SizeOfY - Image.Height) / 2;break;case EdkiiPlatformLogoDisplayAttributeCenterRight:DestX = SizeOfX - Image.Width;DestY = (SizeOfY - Image.Height) / 2;break;case EdkiiPlatformLogoDisplayAttributeLeftBottom:DestX = 0;DestY = SizeOfY - Image.Height;break;case EdkiiPlatformLogoDisplayAttributeCenterBottom:DestX = (SizeOfX - Image.Width) / 2;DestY = SizeOfY - Image.Height;break;case EdkiiPlatformLogoDisplayAttributeRightBottom:DestX = SizeOfX - Image.Width;DestY = SizeOfY - Image.Height;break;default:ASSERT (FALSE);continue;break;}DestX += OffsetX;DestY += OffsetY;

3.6 显示

if ((DestX >= 0) && (DestY >= 0)) {Status = GraphicsOutput->Blt (GraphicsOutput,Blt,EfiBltBufferToVideo,0,0,(UINTN)DestX,(UINTN)DestY,Image.Width,Image.Height,Image.Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));//// Report displayed Logo information.//if (!EFI_ERROR (Status)) {NumberOfLogos++;if (NumberOfLogos == 1) {//// The first Logo.//LogoDestX  = (UINTN)DestX;LogoDestY  = (UINTN)DestY;LogoWidth  = Image.Width;LogoHeight = Image.Height;} else {//// Merge new logo with old one.//NewDestX   = MIN ((UINTN)DestX, LogoDestX);NewDestY   = MIN ((UINTN)DestY, LogoDestY);LogoWidth  = MAX ((UINTN)DestX + Image.Width, LogoDestX + LogoWidth) - NewDestX;LogoHeight = MAX ((UINTN)DestY + Image.Height, LogoDestY + LogoHeight) - NewDestY;LogoDestX = NewDestX;LogoDestY = NewDestY;}}}

在这里插入图片描述

3.7 通告已显示 logo 信息

  if (NumberOfLogos == 1) {//// Only one logo displayed, use its Blt buffer directly for BootLogo protocol.//LogoBlt = Blt;Status  = EFI_SUCCESS;} else {//// More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.//if (Blt != NULL) {FreePool (Blt);}//// Ensure the LogoHeight * LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow//if (LogoHeight > MAX_UINTN / LogoWidth / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) {return EFI_UNSUPPORTED;}BufferSize = LogoWidth * LogoHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);LogoBlt = AllocatePool (BufferSize);if (LogoBlt == NULL) {return EFI_OUT_OF_RESOURCES;}Status = GraphicsOutput->Blt (GraphicsOutput,LogoBlt,EfiBltVideoToBltBuffer,LogoDestX,LogoDestY,0,0,LogoWidth,LogoHeight,LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));}

4 设置 PCI 中断线寄存器并启用 ACPI SCI_EN

SCI_EN - System Control Interrupt Enable

  PciAcpiInitialization ();
VOID
PciAcpiInitialization ()
{UINTN  Pmba;//// Query Host Bridge DID to determine platform type//mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);switch (mHostBridgeDevId) {case INTEL_82441_DEVICE_ID:Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);//// 00:01.0 ISA Bridge (PIIX4) LNK routing targets//PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), PciHostIrqs[0]); // APciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), PciHostIrqs[1]); // BPciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), PciHostIrqs[2]); // CPciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), PciHostIrqs[3]); // Dbreak;case INTEL_Q35_MCH_DEVICE_ID:Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);//// 00:1f.0 LPC Bridge (Q35) LNK routing targets//PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), PciHostIrqs[0]); // APciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), PciHostIrqs[1]); // BPciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), PciHostIrqs[2]); // CPciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), PciHostIrqs[3]); // DPciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), PciHostIrqs[0]); // EPciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), PciHostIrqs[1]); // FPciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), PciHostIrqs[2]); // GPciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), PciHostIrqs[3]); // Hbreak;case MICROVM_PSEUDO_DEVICE_ID:case CLOUDHV_DEVICE_ID:return;default:if (XenDetected ()) {//// There is no PCI bus in this case.//return;}DEBUG ((DEBUG_ERROR,"%a: Unknown Host Bridge Device ID: 0x%04x\n",__func__,mHostBridgeDevId));ASSERT (FALSE);return;}//// Initialize PCI_INTERRUPT_LINE for applicable present PCI devices//VisitAllPciInstances (SetPciIntLine);//// Set ACPI SCI_EN bit in PMCNTRL//IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);
}

4.1 查询主桥 DID 以确定平台类型

Q35_MCH 就是 Intel Q35 芯片组里的 Memory Controller Hub(MCH),也就是俗称的北桥

  mHostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);switch (mHostBridgeDevId) {case INTEL_82441_DEVICE_ID:Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);//// 00:01.0 ISA Bridge (PIIX4) LNK routing targets//PciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x60), PciHostIrqs[0]); // APciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x61), PciHostIrqs[1]); // BPciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x62), PciHostIrqs[2]); // CPciWrite8 (PCI_LIB_ADDRESS (0, 1, 0, 0x63), PciHostIrqs[3]); // Dbreak;case INTEL_Q35_MCH_DEVICE_ID:Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);//// 00:1f.0 LPC Bridge (Q35) LNK routing targets//PciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x60), PciHostIrqs[0]); // APciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x61), PciHostIrqs[1]); // BPciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x62), PciHostIrqs[2]); // CPciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x63), PciHostIrqs[3]); // DPciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x68), PciHostIrqs[0]); // EPciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x69), PciHostIrqs[1]); // FPciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6a), PciHostIrqs[2]); // GPciWrite8 (PCI_LIB_ADDRESS (0, 0x1f, 0, 0x6b), PciHostIrqs[3]); // Hbreak;case MICROVM_PSEUDO_DEVICE_ID:case CLOUDHV_DEVICE_ID:return;default:if (XenDetected ()) {//// There is no PCI bus in this case.//return;}DEBUG ((DEBUG_ERROR,"%a: Unknown Host Bridge Device ID: 0x%04x\n",__func__,mHostBridgeDevId));ASSERT (FALSE);return;}

4.2 为 PCI 设备初始化 PCI_INTERRUPT_LINE 寄存器

Interrupt Line 寄存器告诉操作系统/固件该 PCI 设备当前连到中断控制器的哪条 IRQ 线

Interrupt Line 寄存器仅作软件标签使用,不改变硬件实际走的中断路由;真正的电平/边沿触发由芯片组内部的 PIRQ/INTx→IRQ 映射表决定

  VisitAllPciInstances (SetPciIntLine);
EFI_STATUS
VisitAllPciInstances (IN VISIT_PCI_INSTANCE_CALLBACK  CallBackFunction)
{return VisitAllInstancesOfProtocol (&gEfiPciIoProtocolGuid,VisitingAPciInstance,(VOID *)(UINTN)CallBackFunction);
}

4.3 在 PMCNTRL 寄存器中设置 ACPI SCI_EN 位

  IoOr16 ((PciRead32 (Pmba) & ~BIT0) + 4, BIT0);

通过Pmba(Power Management Base Address)加上偏移,指向 PMCNTRL(Power Management Control)寄存器

字段说明
SCI_EN0置 1 → 打开 SCI 中断,OS 才能收到 ACPI 事件
BM_RLD1Bus-Master Reload,控制 BM_STS 自动清零
GBL_RLS2Global Release,写 1 触发一次 GBL_STS
SLP_TYPx10–12睡眠类型编码(S0/S3/S4/S5…)
SLP_EN13写 1 按 SLP_TYPx 进入睡眠
AlwaysZero14–15保留

Power Management
├─ 状态寄存器组
├─ 控制寄存器组
├─ 睡眠类型表
└─ 事件/使能寄存器

5 将 QEMU 的 bootorder 写入 EFI 变量

  TryRunningQemuKernel ();
VOID
EFIAPI
StoreQemuBootOrder (VOID)
{RETURN_STATUS         Status;FIRMWARE_CONFIG_ITEM  FwCfgItem;UINTN                 FwCfgSize;CHAR8                 *FwCfg;EFI_STATUS            EfiStatus;EXTRA_ROOT_BUS_MAP    *ExtraPciRoots;CONST CHAR8           *FwCfgPtr;UINTN                 TranslatedSize;CHAR16                Translated[TRANSLATION_OUTPUT_SIZE];UINTN                 VariableIndex = 0;CHAR16                VariableName[20];Status = QemuFwCfgFindFile ("bootorder", &FwCfgItem, &FwCfgSize);if (RETURN_ERROR (Status)) {return;}if (FwCfgSize == 0) {return;}FwCfg = AllocatePool (FwCfgSize);if (FwCfg == NULL) {return;}QemuFwCfgSelectItem (FwCfgItem);QemuFwCfgReadBytes (FwCfgSize, FwCfg);if (FwCfg[FwCfgSize - 1] != '\0') {Status = RETURN_INVALID_PARAMETER;goto FreeFwCfg;}DEBUG ((DEBUG_VERBOSE, "%a: FwCfg:\n", __func__));DEBUG ((DEBUG_VERBOSE, "%a\n", FwCfg));DEBUG ((DEBUG_VERBOSE, "%a: FwCfg: <end>\n", __func__));if (FeaturePcdGet (PcdQemuBootOrderPciTranslation)) {EfiStatus = CreateExtraRootBusMap (&ExtraPciRoots);if (EFI_ERROR (EfiStatus)) {Status = (RETURN_STATUS)EfiStatus;goto FreeFwCfg;}} else {ExtraPciRoots = NULL;}//// Translate each OpenFirmware path to a UEFI devpath prefix.//FwCfgPtr       = FwCfg;TranslatedSize = ARRAY_SIZE (Translated);Status         = TranslateOfwPath (&FwCfgPtr,ExtraPciRoots,Translated,&TranslatedSize);while (Status == EFI_SUCCESS ||Status == EFI_UNSUPPORTED){if (Status == EFI_SUCCESS) {EFI_DEVICE_PATH_PROTOCOL  *DevicePath;//// Convert the UEFI devpath prefix to binary representation.//ASSERT (Translated[TranslatedSize] == L'\0');DevicePath = ConvertTextToDevicePath (Translated);if (DevicePath == NULL) {Status = RETURN_OUT_OF_RESOURCES;goto FreeExtraPciRoots;}UnicodeSPrint (VariableName,sizeof (VariableName),L"VMMBootOrder%04x",VariableIndex++);DEBUG ((DEBUG_INFO, "%a: %s = %s\n", __func__, VariableName, Translated));gRT->SetVariable (VariableName,&gVMMBootOrderGuid,EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,GetDevicePathSize (DevicePath),DevicePath);FreePool (DevicePath);}//// Move to the next OFW devpath.//TranslatedSize = ARRAY_SIZE (Translated);Status         = TranslateOfwPath (&FwCfgPtr,ExtraPciRoots,Translated,&TranslatedSize);}FreeExtraPciRoots:if (ExtraPciRoots != NULL) {DestroyExtraRootBusMap (ExtraPciRoots);}FreeFwCfg:FreePool (FwCfg);
}

5.1 在 QEMU 的 fw_cfg 接口查找 bootorder 文件

  Status = QemuFwCfgFindFile ("bootorder", &FwCfgItem, &FwCfgSize);if (RETURN_ERROR (Status)) {return;}if (FwCfgSize == 0) {return;}

FwCfgSize == 0直接返回
表示是空文件

6 处理 QEMU 的 -kernel 命令行参数

-kernel 是一个命令行选项,用于指定一个 内核镜像文件,QEMU 会将其加载到内存中,并将启动权交给它,而不是从虚拟机的硬盘或光驱启动

  TryRunningQemuKernel ();
EFI_STATUS
TryRunningQemuKernel (VOID)
{EFI_STATUS  Status;EFI_HANDLE  KernelImageHandle;Status = QemuLoadKernelImage (&KernelImageHandle);if (EFI_ERROR (Status)) {return Status;}//// Signal the EVT_SIGNAL_READY_TO_BOOT event//EfiSignalEventReadyToBoot ();REPORT_STATUS_CODE (EFI_PROGRESS_CODE,(EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));//// Start the image.//Status = QemuStartKernelImage (&KernelImageHandle);if (EFI_ERROR (Status)) {DEBUG ((DEBUG_ERROR,"%a: QemuStartKernelImage(): %r\n",__func__,Status));}QemuUnloadKernelImage (KernelImageHandle);return Status;
}

6.1 加载-kernel 镜像

  Status = QemuLoadKernelImage (&KernelImageHandle);if (EFI_ERROR (Status)) {return Status;}

内核镜像加载失败

7 执行特定于平台的连接序列

  if (FeaturePcdGet (PcdBootRestrictToFirmware)) {RestrictBootOptionsToFirmware ();} else {PlatformBdsConnectSequence ();EfiBootManagerRefreshAllBootOption ();}

8 判断是否把 UEFI Shell 列成可启动项

UEFI Shell 是一个基于 UEFI 标准的命令行工具,它在启动过程中提供了一个交互式环境,允许用户直接与固件和硬件交互

  BOOLEAN        ShellEnabled;RETURN_STATUS  RetStatus;RetStatus = QemuFwCfgParseBool ("opt/org.tianocore/EFIShellSupport",&ShellEnabled);if (RETURN_ERROR (RetStatus)) {ShellEnabled = TRUE;}

9 将 UefiShell 注册为可启动选项

  PlatformRegisterFvBootOption (&gUefiShellFileGuid,L"EFI Internal Shell",LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_APP,ShellEnabled);

10 将 Grub 注册为可启动选项

  PlatformRegisterFvBootOption (&gGrubFileGuid,L"Grub Bootloader",LOAD_OPTION_ACTIVE,TRUE);

Grub - Grand Unified Bootloader

11 移除所有无法解析设备路径的启动选项

  RemoveStaleFvFileOptions ();
VOID
RemoveStaleFvFileOptions (VOID)
{EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions;UINTN                         BootOptionCount;UINTN                         Index;BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,LoadOptionTypeBoot);for (Index = 0; Index < BootOptionCount; ++Index) {EFI_DEVICE_PATH_PROTOCOL  *Node1, *Node2;EFI_STATUS                Status;//// If the device path starts with neither MemoryMapped(...) nor Fv(...),// then keep the boot option.//Node1 = BootOptions[Index].FilePath;if (!((DevicePathType (Node1) == HARDWARE_DEVICE_PATH) &&(DevicePathSubType (Node1) == HW_MEMMAP_DP)) &&!((DevicePathType (Node1) == MEDIA_DEVICE_PATH) &&(DevicePathSubType (Node1) == MEDIA_PIWG_FW_VOL_DP))){continue;}//// If the second device path node is not FvFile(...), then keep the boot// option.//Node2 = NextDevicePathNode (Node1);if ((DevicePathType (Node2) != MEDIA_DEVICE_PATH) ||(DevicePathSubType (Node2) != MEDIA_PIWG_FW_FILE_DP)){continue;}// If file is in firmware then keep the entryif (FileIsInFv (BootOptions[Index].FilePath)) {continue;}//// Delete the boot option.//Status = EfiBootManagerDeleteLoadOptionVariable (BootOptions[Index].OptionNumber,LoadOptionTypeBoot);DEBUG_CODE_BEGIN ();CHAR16  *DevicePathString;DevicePathString = ConvertDevicePathToText (BootOptions[Index].FilePath,FALSE,FALSE);DEBUG ((EFI_ERROR (Status) ? DEBUG_WARN : DEBUG_VERBOSE,"%a: removing stale Boot#%04x %s: %r\n",__func__,(UINT32)BootOptions[Index].OptionNumber,DevicePathString == NULL ? L"<unavailable>" : DevicePathString,Status));if (DevicePathString != NULL) {FreePool (DevicePathString);}DEBUG_CODE_END ();}EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
}

12 根据配置设定启动顺序

  SetBootOrderFromQemu ();
RETURN_STATUS
EFIAPI
SetBootOrderFromQemu (VOID)
{RETURN_STATUS         Status;FIRMWARE_CONFIG_ITEM  FwCfgItem;UINTN                 FwCfgSize;CHAR8                 *FwCfg;CONST CHAR8           *FwCfgPtr;BOOT_ORDER     BootOrder;ACTIVE_OPTION  *ActiveOption;UINTN          ActiveCount;EXTRA_ROOT_BUS_MAP  *ExtraPciRoots;UINTN                         TranslatedSize;CHAR16                        Translated[TRANSLATION_OUTPUT_SIZE];EFI_BOOT_MANAGER_LOAD_OPTION  *BootOptions;UINTN                         BootOptionCount;Status = QemuFwCfgFindFile ("bootorder", &FwCfgItem, &FwCfgSize);if (Status != RETURN_SUCCESS) {return Status;}if (FwCfgSize == 0) {return RETURN_NOT_FOUND;}FwCfg = AllocatePool (FwCfgSize);if (FwCfg == NULL) {return RETURN_OUT_OF_RESOURCES;}QemuFwCfgSelectItem (FwCfgItem);QemuFwCfgReadBytes (FwCfgSize, FwCfg);if (FwCfg[FwCfgSize - 1] != '\0') {Status = RETURN_INVALID_PARAMETER;goto ErrorFreeFwCfg;}DEBUG ((DEBUG_VERBOSE, "%a: FwCfg:\n", __func__));DEBUG ((DEBUG_VERBOSE, "%a\n", FwCfg));DEBUG ((DEBUG_VERBOSE, "%a: FwCfg: <end>\n", __func__));FwCfgPtr = FwCfg;BootOrder.Produced  = 0;BootOrder.Allocated = 1;BootOrder.Data      = AllocatePool (BootOrder.Allocated * sizeof (*BootOrder.Data));if (BootOrder.Data == NULL) {Status = RETURN_OUT_OF_RESOURCES;goto ErrorFreeFwCfg;}BootOptions = EfiBootManagerGetLoadOptions (&BootOptionCount,LoadOptionTypeBoot);if (BootOptions == NULL) {Status = RETURN_NOT_FOUND;goto ErrorFreeBootOrder;}Status = CollectActiveOptions (BootOptions,BootOptionCount,&ActiveOption,&ActiveCount);if (RETURN_ERROR (Status)) {goto ErrorFreeBootOptions;}if (FeaturePcdGet (PcdQemuBootOrderPciTranslation)) {Status = CreateExtraRootBusMap (&ExtraPciRoots);if (EFI_ERROR (Status)) {goto ErrorFreeActiveOption;}} else {ExtraPciRoots = NULL;}//// translate each OpenFirmware path//TranslatedSize = ARRAY_SIZE (Translated);Status         = TranslateOfwPath (&FwCfgPtr,ExtraPciRoots,Translated,&TranslatedSize);while (Status == RETURN_SUCCESS ||Status == RETURN_UNSUPPORTED ||Status == RETURN_PROTOCOL_ERROR ||Status == RETURN_BUFFER_TOO_SMALL){if (Status == RETURN_SUCCESS) {UINTN  Idx;//// match translated OpenFirmware path against all active boot options//for (Idx = 0; Idx < ActiveCount; ++Idx) {if (!ActiveOption[Idx].Appended &&Match (Translated,TranslatedSize, // contains length, not size, in CHAR16's hereActiveOption[Idx].BootOption->FilePath)){//// match found, store ID and continue with next OpenFirmware path//Status = BootOrderAppend (&BootOrder, &ActiveOption[Idx]);if (Status != RETURN_SUCCESS) {goto ErrorFreeExtraPciRoots;}}} // scanned all active boot options}   // translation successfulTranslatedSize = ARRAY_SIZE (Translated);Status         = TranslateOfwPath (&FwCfgPtr,ExtraPciRoots,Translated,&TranslatedSize);} // scanning of OpenFirmware paths doneif ((Status == RETURN_NOT_FOUND) && (BootOrder.Produced > 0)) {//// No more OpenFirmware paths, some matches found: rewrite BootOrder NvVar.// Some of the active boot options that have not been selected over fw_cfg// should be preserved at the end of the boot order.//Status = BootOrderComplete (&BootOrder, ActiveOption, ActiveCount);if (RETURN_ERROR (Status)) {goto ErrorFreeExtraPciRoots;}//// See Table 10 in the UEFI Spec 2.3.1 with Errata C for the required// attributes.//Status = gRT->SetVariable (L"BootOrder",&gEfiGlobalVariableGuid,EFI_VARIABLE_NON_VOLATILE |EFI_VARIABLE_BOOTSERVICE_ACCESS |EFI_VARIABLE_RUNTIME_ACCESS,BootOrder.Produced * sizeof (*BootOrder.Data),BootOrder.Data);if (EFI_ERROR (Status)) {DEBUG ((DEBUG_ERROR,"%a: setting BootOrder: %r\n",__func__,Status));goto ErrorFreeExtraPciRoots;}DEBUG ((DEBUG_INFO, "%a: setting BootOrder: success\n", __func__));PruneBootVariables (ActiveOption, ActiveCount);}ErrorFreeExtraPciRoots:if (ExtraPciRoots != NULL) {DestroyExtraRootBusMap (ExtraPciRoots);}ErrorFreeActiveOption:FreePool (ActiveOption);ErrorFreeBootOptions:EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);ErrorFreeBootOrder:FreePool (BootOrder.Data);ErrorFreeFwCfg:FreePool (FwCfg);return Status;
}

由于FwCfgSize = 0 返回 RETURN_NOT_FOUND;

13 注册状态码处理器并打印到 UEFI 控制台

打印事项包括 Boot Manager 在 LoadImage() 与 StartImage() 过程中的准备步骤及返回码

  PlatformBmPrintScRegisterHandler ();
EFI_STATUS
EFIAPI
PlatformBmPrintScRegisterHandler (VOID)
{EFI_STATUS                Status;EFI_RSC_HANDLER_PROTOCOL  *StatusCodeRouter;EFI_EVENT                 ExitBootEvent;Status = gBS->LocateProtocol (&gEfiRscHandlerProtocolGuid,NULL /* Registration */,(VOID **)&StatusCodeRouter);ASSERT_EFI_ERROR (Status);if (EFI_ERROR (Status)) {return Status;}//// Set the EFI_STATUS_CODE_VALUE convenience variables.//mLoadPrep = PcdGet32 (PcdProgressCodeOsLoaderLoad);mLoadFail = (EFI_SOFTWARE_DXE_BS_DRIVER |EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR);mStartPrep = PcdGet32 (PcdProgressCodeOsLoaderStart);mStartFail = (EFI_SOFTWARE_DXE_BS_DRIVER |EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED);//// Register the handler callback.//Status = StatusCodeRouter->Register (HandleStatusCode, TPL_CALLBACK);if (EFI_ERROR (Status)) {DEBUG ((DEBUG_ERROR,"%a:%a: failed to register status code handler: %r\n",gEfiCallerBaseName,__func__,Status));return Status;}//// Status code reporting and routing/handling extend into OS runtime. Since// we don't want our handler to survive the BDS phase, we have to unregister// the callback at ExitBootServices(). (See EFI_RSC_HANDLER_PROTOCOL in// Volume 3 of the Platform Init spec.)//Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, // TypeTPL_CALLBACK,                  // NotifyTplUnregisterAtExitBootServices,  // NotifyFunctionStatusCodeRouter,              // NotifyContext&ExitBootEvent                 // Event);if (EFI_ERROR (Status)) {//// We have to unregister the callback right now, and fail the function.//DEBUG ((DEBUG_ERROR,"%a:%a: failed to create ExitBootServices() event: ""%r\n",gEfiCallerBaseName,__func__,Status));StatusCodeRouter->Unregister (HandleStatusCode);return Status;}return EFI_SUCCESS;
}

13.1 加载协议

  Status = gBS->LocateProtocol (&gEfiRscHandlerProtocolGuid,NULL /* Registration */,(VOID **)&StatusCodeRouter);ASSERT_EFI_ERROR (Status);if (EFI_ERROR (Status)) {return Status;}

13.2 设置用于 EFI_STATUS_CODE_VALUE 的便捷变量

  mLoadPrep = PcdGet32 (PcdProgressCodeOsLoaderLoad);mLoadFail = (EFI_SOFTWARE_DXE_BS_DRIVER |EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR);mStartPrep = PcdGet32 (PcdProgressCodeOsLoaderStart);mStartFail = (EFI_SOFTWARE_DXE_BS_DRIVER |EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED);

13.3 注册处理器回调函数

  Status = StatusCodeRouter->Register (HandleStatusCode, TPL_CALLBACK);if (EFI_ERROR (Status)) {DEBUG ((DEBUG_ERROR,"%a:%a: failed to register status code handler: %r\n",gEfiCallerBaseName,__func__,Status));return Status;}

13.4 注册事件回调函数

确保 ExitBootServices() 被调用时注销状态码处理器

  Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, // TypeTPL_CALLBACK,                  // NotifyTplUnregisterAtExitBootServices,  // NotifyFunctionStatusCodeRouter,              // NotifyContext&ExitBootEvent                 // Event);if (EFI_ERROR (Status)) {//// We have to unregister the callback right now, and fail the function.//DEBUG ((DEBUG_ERROR,"%a:%a: failed to create ExitBootServices() event: ""%r\n",gEfiCallerBaseName,__func__,Status));StatusCodeRouter->Unregister (HandleStatusCode);return Status;}

BDS 启动选项类别

固件卷里的固定应用

  • FvFile EFI Shell
  • FvFile Boot Manager Menu
  • FvFile GRUB 镜像

可启动的外设/分区

  • 硬盘、SSD、NVMe
  • USB、SD、光驱
  • 网络:IPv4/IPv6 PXE 启动项

平台额外条目

  • QEMU:-kernel 传进来的镜像
  • VMware:虚拟 EFI 光驱里插入的 ISO
  • 厂商 Recovery
  • 安全引导相关
http://www.dtcms.com/a/605554.html

相关文章:

  • 代码随想录打卡day27:509.斐波那契数列、70.爬楼梯
  • 怎么接单做网站上优化
  • 11月3-5年Web前端开发面试需要达到的强度
  • 网站搭建吧网站开发计入什么科目
  • C++---万能指针 void* (不绑定具体数据类型,能指向任意类型的内存地址)
  • 感知 - 调控 - 追溯:档案馆恒温恒湿全闭环控制系统方案
  • Microsoft Excel 效率专题:创建下拉列表,规范数据输入
  • 网站服务器建立怎么在网站做浮动图标
  • 安装SAP Business one for HANA之前的准备
  • C语言编译软件的获取 | 如何高效选择和下载适合的编译器
  • 数据分析案例详解:基于smardaten实现智慧交通运营指标数据分析展示
  • 竞价网站asp网站设置
  • 软件设计模式-外观模式
  • 谷歌推“Cameyo”方案,助力企业从Win系统转型ChromeOS
  • 论文阅读——CenterNet
  • 石家庄网站建设网站湖南网站备案
  • 请人做网站 说我要求多怎么用polylang做网站
  • 易缴缴:注册资金实缴领域的专业领航者
  • DuckDB适合做什么工作?
  • Java 大视界 -- Java 大数据在智能物流仓储货位优化与库存周转率提升中的应用实战
  • 感知机原理及C++代码实现:AI神经网络入门
  • kanass实战教程系列(5) - 开发团队如何通过kanass有效管控开发任务
  • 建网站如何收费wordpress 论坛app
  • 返利网站做鹊桥推广中国建设银行购物网站
  • ADI推出基于VS Code的IDE开发环境一条龙软件CodeFusion Studio V2.0发布,AI端到端,图形化配置和ELF可视化
  • Prompt提示词工程概述
  • List vs Set:深入剖析Java两大集合的核心区别与实战应用
  • 抖音综合智能营销截流系统:基于 AI 算法的精准获客解决方案
  • 基于多源数据融合与机器学习算法的MATLAB小麦产量预估系统
  • MCP之Prompt提示词工程