DXE Phase
Overview
DXE ( Driver Execution Environment)阶段执行大部分系统初始化工作,进人此阶段时, 内存已经可以被完全使用,因而此阶段可以进行大量的复杂工作。从程序设计的角度讲, DXE阶段与PEI阶段相似,由于最终的OS 是64位的,所以要引导和启动OS就需要相应的64位环境同时从该阶段开始memory可用空间变多(不局限4G以内),可以使用更好的访问模式、启动性能。
DXE阶段及后面的程序在内存中执行
主要含有以下概念:
- DXE Core
- DXE Dispatcher
- System Table
- DXE Driver
- Protocol and Handle
DXE Core
DxeMain (),是DXE阶段执行的主函数,同时以参数的形式接收PEI阶段生成的HOB表。
- 创建EFI System Table,在随后被执行的DXE Driver中逐步完善此table。
- 生成Boot Services / Run Time Services / DXE Services.
- 负责调用Dispatcher,所有的DXE Driver在这个函数中被检测并执行。
- 当所有的DXE Driver被执行完成之后,接着会执行一个特殊的DXE Driver进而进入BDS阶段。
DXE Dispatcher
- 调用DXE Service里提供的服务函数去BIOS芯片里搜寻并执行DXE Driver。
- 检测并按照相应的顺序执行所有的DXE Driver:在每个driver的inf文件的[Depex]段里有该driver的依赖条件,当所有的依赖条件都成立时,该driver才被允许执行。
EFI System Table
- System Table是UEFI内核的全局结构体,是最重要的数据结构之一
- UEFI Driver利用System Table才可以访问UEFI内核、硬件资源和I/O设备。
- System Table指针作为Image入口函数的参数传递到用户空间,因此用户可以使用它。Image的入口函数有统一的格式,其函数原型如下:
typedef
EFI_STATUS
(EFIAPI *EFI_IMAGE_ENTRY_POINT)(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);
System Table包含了以下子结构体:
- Boot Services Table
- Runtime Service Table
- DXE Service Table
- System Configuration Tables
- 其他 (Console in/out, Handle Database, …)
可以参考:https://blog.csdn.net/weixin_45279063/article/details/116023011
DXE Driver - Non-Driver Model
Non-Driver Model特征:
- 在DXE早期阶段执行。
- 分步骤初始化CPU & chipset。
- 生成Architectural protocol供DXE Core或其它的DXE Driver使用。
DXE Driver - Driver Model
Driver Model特征:
- 符合标准的UEFI驱动模式。
- 执行此模组时不会对硬件进行初始化操作。
- 注册Driver binding protocol到handle database。
- 注册的protocol在BDS阶段被调用并对硬件进行操作。
Protocol & Handle
Protocols由一组数据结构和一个GUID组成,安装在handle上。可以参考:https://blog.csdn.net/weixin_45279063/article/details/116268076
Handle, 也叫对象(Object), 其本质是一个VOID型指针, 是protocol的载体
执行流程图
几乎所有的硬件的初始化都在DXE这做完,同时产生efi system table, 来提供各种service供所面阶段使用。最后把控制权交给bds来boot os.
涉及元件及功能
- DXE Core,可视为dxe的核心,用来dispatch dxe driver 和产生efi system
table,以提供boot service, runtime service, dxe service,负责DXE基础服务和执行流程. - dxe driver, 被dxe core 所读取,用来做各种硬件的初始化,产生protocol和其他service.
- dxe dispatcher: dxe core 的一部分,以正确的顺序来搜寻和执行dxe driver,负责调度执行DXE驱动,初始化系统设备。 DXE提供的基础服务包括系统表、启动服务、Run Time Services.
- dxe architecture protocol: 由dxe driver所产生,是dxe core和hardware沟通的唯一介面,所以没有install 完全不能开机。
- efi system table: 包含了许多pointer,如所有 efi system table, configuration table, handledatabase, and console device.
DXE architecture protocol种类及其功能
这些Protocol在UEFI BIOS运行的过程中会安装,且一定需要被安装,如果没有被安装的话,系统就会报错。
//
// DXE Core Global Variables for all of the Architectural Protocols.
// If a protocol is installed mArchProtocols[].Present will be TRUE.
//
// CoreNotifyOnArchProtocolInstallation () fills in mArchProtocols[].Event
// and mArchProtocols[].Registration as it creates events for every array
// entry.
//
EFI_CORE_PROTOCOL_NOTIFY_ENTRY mArchProtocols[] = {
{ &gEfiSecurityArchProtocolGuid, (VOID **)&gSecurity, NULL, NULL, FALSE },
{ &gEfiCpuArchProtocolGuid, (VOID **)&gCpu, NULL, NULL, FALSE },
{ &gEfiMetronomeArchProtocolGuid, (VOID **)&gMetronome, NULL, NULL, FALSE },
{ &gEfiTimerArchProtocolGuid, (VOID **)&gTimer, NULL, NULL, FALSE },
{ &gEfiBdsArchProtocolGuid, (VOID **)&gBds, NULL, NULL, FALSE },
{ &gEfiWatchdogTimerArchProtocolGuid, (VOID **)&gWatchdogTimer, NULL, NULL, FALSE },
{ &gEfiRuntimeArchProtocolGuid, (VOID **)&gRuntime, NULL, NULL, FALSE },
{ &gEfiVariableArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
{ &gEfiVariableWriteArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
{ &gEfiCapsuleArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
{ &gEfiMonotonicCounterArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
{ &gEfiResetArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
{ &gEfiRealTimeClockArchProtocolGuid, (VOID **)NULL, NULL, NULL, FALSE },
{ NULL, (VOID **)NULL, NULL, NULL, FALSE }
};
- security: 提供 DXE core 验证 firmware volume中的程序是否可用。
- cpu: 提供cpu的service如管理cache,管理中断,取得处理器频率,查询处理器的timer.
typedef struct _EFI_METRONOME_ARCH_PROTOCOL {
EFI_METRONOME_WAIT_FOR_TICK WaitForTIck;
UINT32 TickPeriod;
} EFI_METRONOME_ARCH_PROTOCOL;
提供一个微小的延时,百万分之一秒为单位。
- Timer: 提供固定时间的中断,使dxe core dispatch 完成所有driver后,会将控制权交给BDS.
在DXE运行结束,调用gBds->Entry (gBds), 但并不能显式的看到 gBds 是在哪里赋值的。其实bios 没有单独去locate BDS Architectural Protocol. 而是先整出上面这个结构体。然后一把 把这个结构体里面的成员的instance 挨个找到。
DxeMain()
CoreInstallConfigurationTable(
IN EFI_GUID *Guid,
IN VOID *Table
);
VOID
EFIAPI
DxeMain (
IN VOID *HobStart
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS MemoryBaseAddress;
UINT64 MemoryLength;
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
UINTN Index;
EFI_HOB_GUID_TYPE *GuidHob;
EFI_VECTOR_HANDOFF_INFO *VectorInfoList;
EFI_VECTOR_HANDOFF_INFO *VectorInfo;
VOID *EntryPoint;
//
// Setup the default exception handlers
// 设置默认的异常处理程序
VectorInfoList = NULL;
GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart);
if (GuidHob != NULL) {
VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *) (GET_GUID_HOB_DATA(GuidHob));
}
// 初始化所有CPU异常项,并提供默认的异常处理程序。调用者应该尝试获取一个正在使用的中断和/或异常向量数组,这些向量需要在PI 1.3规范中定义的
// EFI_VECTOR_HANDOFF_INFO中保存。如果调用者不能得到保留的向量列表或者它不存在,将VectorInfo设置为NULL。
// 如果VectorInfo不为空,则每个vector属性都会相应地初始化异常向量。
Status = InitializeCpuExceptionHandlers (VectorInfoList);
ASSERT_EFI_ERROR (Status);
//
// Initialize Debug Agent to support source level debug in DXE phase
// 此函数用于设置调试环境,以支持源代码级的调试。如果某些调试代理库实例有一些私人数据保存在堆栈中,这个函数必须工作模式不返回给调用者,
// 然后调用者需要结束后所有其他逻辑InitializeDebugAgent()成一个函数并将其传递到InitializeDebugAgent()。
// InitializeDebugAgent()负责在InitializeDebugAgent()的末尾调用传入函数。
// 如果参数函数不为空,调试代理库实例将通过在上下文中传递参数来调用它。如果Function()为空,调试代理库实例将在安装调试环境后返回。
InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_CORE, HobStart, NULL);
//
// Initialize Memory Services
// 初始化内存服务
// 外部函数。基于内存描述符HOBs初始化内存服务。这个函数负责启动内存映射,因此可以进行内存分配和资源分配。
// 这个函数的第一部分不能依赖任何内存服务,直到至少有一个内存描述符提供给内存服务。
CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength);
// 初始化内存概要文件。
MemoryProfileInit (HobStart);
//
// Allocate the EFI System Table and EFI Runtime Service Table from EfiRuntimeServicesData
// Use the templates to initialize the contents of the EFI System Table and EFI Runtime Services Table
// 调用内存服务,为系统表和运行时服务申请内存空间
gDxeCoreST = AllocateRuntimeCopyPool (sizeof (EFI_SYSTEM_TABLE), &mEfiSystemTableTemplate);
ASSERT (gDxeCoreST != NULL);
gDxeCoreRT = AllocateRuntimeCopyPool (sizeof (EFI_RUNTIME_SERVICES), &mEfiRuntimeServicesTableTemplate);
ASSERT (gDxeCoreRT != NULL);
gDxeCoreST->RuntimeServices = gDxeCoreRT;
//
// Start the Image Services.
// 初始化镜像服务,将映像服务添加到EFI引导服务表中,并为该映像安装协议接口。
Status = CoreInitializeImageServices (HobStart);
ASSERT_EFI_ERROR (Status);
//
// Initialize the Global Coherency Domain Services
// 初始化全局配置数据库服务
// 外部函数。基于内存描述符HOBs初始化GCD和内存服务。这个函数负责启动GCD映射和内存映射,
// 因此可以进行内存分配和资源分配。 HobStart将被重新定位到池缓冲区中。
Status = CoreInitializeGcdServices (&HobStart, MemoryBaseAddress, MemoryLength);
ASSERT_EFI_ERROR (Status);
//
// Call constructor for all libraries
// 调用所有库模块的构造函数,该函数由预处理的python脚本生成,位于
// edk2/Build/${CompiledPkgName}/DEBUG_GCC44/${ARCH}/MdeModulePkg/Core/Dxe/DxeMain/DEBUG 目录下的AutoGen.c 文件中。
// 根据由 inf 文件可知DXE模块所需的库,同时自动生成构造函数 ProcessLibraryConstructorList ()
ProcessLibraryConstructorList (gDxeCoreImageHandle, gDxeCoreST);
PERF_END (NULL,"PEI", NULL, 0) ;
PERF_START (NULL,"DXE", NULL, 0) ;
//
// Report DXE Core image information to the PE/COFF Extra Action Library
//
ZeroMem (&ImageContext, sizeof (ImageContext));
ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreLoadedImage->ImageBase;
// 返回一个指向PE/COFF映像的PDB文件名的指针,该映像已经通过PE/COFF加载器库函数加载到系统内存中。返回Pe32Data指定的PE/COFF图像的PDB文件名。
// 如果Pe32Data指定的PE/COFF图像不是有效的,则返回NULL。如果Pe32Data指定的PE/COFF映像不包含调试目录项,则返回NULL。如果Pe32Data指定的
// PE/COFF图像中的调试目录项不包含PDB文件名,则返回NULL。如果Pe32Data为空,则ASSERT()。
ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer ((VOID*)(UINTN)ImageContext.ImageAddress);
// 返回由Pe32Data指定的PE/COFF头的大小。如果Pe32Data为空,则ASSERT()。
ImageContext.SizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID*)(UINTN)ImageContext.ImageAddress);
// 检索并返回一个指向PE/COFF图像入口点的指针,该图像已经通过PE/COFF加载器库函数加载到系统内存中。检索Pe32Data指定的PE/COFF图像的入口点,
// 并在EntryPoint中返回这个入口点。如果无法从PE/COFF图像中检索入口点,则返回RETURN_INVALID_PARAMETER。否则返回RETURN_SUCCESS。
// 如果Pe32Data为空,则ASSERT()。如果EntryPoint为NULL,则ASSERT()。
Status = PeCoffLoaderGetEntryPoint ((VOID*)(UINTN)ImageContext.ImageAddress, &EntryPoint);
if (Status == EFI_SUCCESS) {
ImageContext.EntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)EntryPoint;
}
ImageContext.Handle = (VOID *)(UINTN)gDxeCoreLoadedImage->ImageBase;
ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
// 加载和重新定位PE/COFF映像后执行其他操作。如果ImageContext为NULL,则ASSERT()。
PeCoffLoaderRelocateImageExtraAction (&ImageContext);
//
// Install the DXE Services Table into the EFI System Tables's Configuration Table
// 将DXE Services表安装到EFI系统表的配置表中,函数启动服务,用于从EFI系统表中添加、修改或删除系统配置表。
Status = CoreInstallConfigurationTable (&gEfiDxeServicesTableGuid, gDxeCoreDS);
ASSERT_EFI_ERROR (Status);
//
// Install the HOB List into the EFI System Tables's Configuration Table
// 将HOB列表安装到EFI系统表的配置表中,
Status = CoreInstallConfigurationTable (&gEfiHobListGuid, HobStart);
ASSERT_EFI_ERROR (Status);
//
// Install Memory Type Information Table into the EFI System Tables's Configuration Table
// 将内存类型信息表安装到EFI系统表的配置表中
Status = CoreInstallConfigurationTable (&gEfiMemoryTypeInformationGuid, &gMemoryTypeInformation);
ASSERT_EFI_ERROR (Status);
//
// If Loading modules At fixed address feature is enabled, install Load moduels at fixed address
// Configuration Table so that user could easily to retrieve the top address to load Dxe and PEI
// Code and Tseg base to load SMM driver.
// 如果在固定地址功能加载模块,安装加载模块在固定地址配置表,这样用户可以很容易地检索顶部地址加载Dxe和PEI代码和Tseg base加载SMM驱动程序。
if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
Status = CoreInstallConfigurationTable (&gLoadFixedAddressConfigurationTableGuid, &gLoadModuleAtFixAddressConfigurationTable);
ASSERT_EFI_ERROR (Status);
}
//
// Report Status Code here for DXE_ENTRY_POINT once it is available
// 在这里报告DXE_ENTRY_POINT可用的状态代码。 如果状态代码类型已启用,则报告带有最小参数的状态代码。
// 如果由type指定的状态码类型在PcdReportStatusCodeProperyMask中启用,然后调用ReportStatusCode()传入类型和值。
REPORT_STATUS_CODE (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_ENTRY_POINT)
);
//
// Create the aligned system table pointer structure that is used by external
// debuggers to locate the system table... Also, install debug image info configuration table.
// 创建对齐的系统表指针结构,外部调试器使用它来定位系统表…另外,安装调试图像信息配置表。
// 创建并初始化DebugImageInfo表。还创建配置表并将其注册到系统表中。
CoreInitializeDebugImageInfoTable ();
// 在DebugImageInfo表中添加一个新的DebugImageInfo结构。如果表的大小不足以容纳另一个entry,则重新分配该表。
CoreNewDebugImageInfoEntry (
EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL,
gDxeCoreLoadedImage,
gDxeCoreImageHandle
);
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "HOBLIST address in DXE = 0x%p\n", HobStart));
DEBUG_CODE_BEGIN ();
EFI_PEI_HOB_POINTERS Hob;
for (Hob.Raw = HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Memory Allocation 0x%08x 0x%0lx - 0x%0lx\n", \
Hob.MemoryAllocation->AllocDescriptor.MemoryType, \
Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, \
Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + Hob.MemoryAllocation->AllocDescriptor.MemoryLength - 1));
}
}
for (Hob.Raw = HobStart; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV2) {
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "FV2 Hob 0x%0lx - 0x%0lx\n", Hob.FirmwareVolume2->BaseAddress, Hob.FirmwareVolume2->BaseAddress + Hob.FirmwareVolume2->Length - 1));
} else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {
DEBUG ((DEBUG_INFO | DEBUG_LOAD, "FV Hob 0x%0lx - 0x%0lx\n", Hob.FirmwareVolume->BaseAddress, Hob.FirmwareVolume->BaseAddress + Hob.FirmwareVolume->Length - 1));
}
}
DEBUG_CODE_END ();
//
// Initialize the Event Services
//
Status = CoreInitializeEventServices ();
ASSERT_EFI_ERROR (Status);
// 安装内存配置文件协议。
MemoryProfileInstallProtocol ();
// 初始化PropertiesTable支持。
CoreInitializePropertiesTable ();
// 初始化MemoryAttrubutesTable支持。
CoreInitializeMemoryAttributesTable ();
// 初始化内存保护支持。
CoreInitializeMemoryProtection ();
//
// Get persisted vector hand-off info from GUIDeed HOB again due to HobStart may be updated,
// and install configuration table
// 由于HobStart可能会被更新,所以再次从guided HOB获取持久化的矢量切换信息,并安装配置表
GuidHob = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart);
if (GuidHob != NULL) {
VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *) (GET_GUID_HOB_DATA(GuidHob));
VectorInfo = VectorInfoList;
Index = 1;
while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {
VectorInfo ++;
Index ++;
}
VectorInfo = AllocateCopyPool (sizeof (EFI_VECTOR_HANDOFF_INFO) * Index, (VOID *) VectorInfoList);
ASSERT (VectorInfo != NULL);
// 启动服务,用于从EFI系统表中添加、修改或删除系统配置表。
Status = CoreInstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *) VectorInfo);
ASSERT_EFI_ERROR (Status);
}
//
// Get the Protocols that were passed in from PEI to DXE through GUIDed HOBs
//
// These Protocols are not architectural. This implementation is sharing code between
// PEI and DXE in order to save FLASH space. These Protocols could also be implemented
// as part of the DXE Core. However, that would also require the DXE Core to be ported
// each time a different CPU is used, a different Decompression algorithm is used, or a
// different Image type is used. By placing these Protocols in PEI, the DXE Core remains
// generic, and only PEI and the Arch Protocols need to be ported from Platform to Platform,
// and from CPU to CPU.
// 获得从PEI传递到DXE通过GUIDed HOBs的协议。这些协议不是架构性的。这个实现是在PEI和DXE之间共享代码,以节省闪存空间。
// 这些协议也可以作为DXE核心的一部分来实现。但是,在每次使用不同的CPU、不同的解压缩算法或不同的映像类型时,这也需要移植DXE内核。
// 通过将这些协议放在PEI中,DXE核心仍然是通用的,只有PEI和Arch协议需要从一个平台移植到另一个平台,从一个CPU移植到另一个CPU。
//
// Publish the EFI, Tiano, and Custom Decompress protocols for use by other DXE components
// 发布EFI、Tiano和自定义解压缩协议,供其他DXE组件使用
// 在引导服务环境中安装协议接口列表。这个函数在循环中调用InstallProtocolInterface()。如果出现任何错误,
// 此函数添加的所有协议都将被删除。这基本上是一个节省空间的lib函数。
Status = CoreInstallMultipleProtocolInterfaces (
&mDecompressHandle,
&gEfiDecompressProtocolGuid, &gEfiDecompress,
NULL
);
ASSERT_EFI_ERROR (Status);
//
// Register for the GUIDs of the Architectural Protocols, so the rest of the
// EFI Boot Services and EFI Runtime Services tables can be filled in.
// Also register for the GUIDs of optional protocols.
// 注册体系结构协议的guid,这样就可以填充EFI引导服务和EFI运行时服务表的其余部分。还要注册可选协议的guid。
// 该函数为架构协议和可选协议创建一个事件,每次安装特定类型的协议时触发该事件。
CoreNotifyOnProtocolInstallation ();
//
// Produce Firmware Volume Protocols, one for each FV in the HOB list.
// 生产固件卷协议,为HOB列表中的每个FV提供一个。
// 这个例程使用FV hobs,并根据需要生成FW_VOL_BLOCK_PROTOCOL实例。
Status = FwVolBlockDriverInit (gDxeCoreImageHandle, gDxeCoreST);
ASSERT_EFI_ERROR (Status);
// 这个例程是驱动程序初始化入口点。它注册一个通知功能。这个通知函数负责动态地构建FV堆栈。
Status = FwVolDriverInit (gDxeCoreImageHandle, gDxeCoreST);
ASSERT_EFI_ERROR (Status);
//
// Produce the Section Extraction Protocol
// 该函数 节提取代码的入口点。初始化节提取接口的实例,并将其安装到一个新的句柄上。
Status = InitializeSectionExtraction (gDxeCoreImageHandle, gDxeCoreST);
ASSERT_EFI_ERROR (Status);
//
// Initialize the DXE Dispatcher
// 初始化DXE调度程序
PERF_START (NULL,"CoreInitializeDispatcher", "DxeMain", 0) ;
// 初始化分配器。初始化FV2协议加入系统时运行的通知函数。
CoreInitializeDispatcher ();
PERF_END (NULL,"CoreInitializeDispatcher", "DxeMain", 0) ;
//
// Invoke the DXE Dispatcher
//
PERF_START (NULL, "CoreDispatcher", "DxeMain", 0);
// 这是DXE的主调度程序,当没有更多的驱动程序需要运行时,它就会退出。释放mScheduledQueue,为每个驱动加载并启动一个PE映像。
// 搜索mDiscoveredList,查看是否可以将任何驱动程序放置在mScheduledQueue上。如果没有在mScheduledQueue上放置驱动程序,
// 则退出该函数。退出时,假设Bds()将被调用,当Bds()退出时,调度程序将被再次调用。
CoreDispatcher ();
PERF_END (NULL, "CoreDispatcher", "DxeMain", 0);
//
// Display Architectural protocols that were not loaded if this is DEBUG build
// 如果是调试构建,则显示未加载的架构协议
DEBUG_CODE_BEGIN ();
// 显示未加载的、DXE内核运行所需的架构协议。仅在调试构建中使用。
CoreDisplayMissingArchProtocols ();
DEBUG_CODE_END ();
//
// Display any drivers that were not dispatched because dependency expression
// evaluated to false if this is a debug build
// 如果这是一个调试构建,显示任何没有被分派的驱动程序,因为依赖表达式计算为false
DEBUG_CODE_BEGIN ();
// 遍历已发现的列表,查找任何已发现但未加载的驱动程序,因为依赖表达式被评估为false。
CoreDisplayDiscoveredNotDispatched ();
DEBUG_CODE_END ();
//
// Assert if the Architectural Protocols are not present.
// 如果体系结构协议不存在,则断言。
// 该函数如果所有AP服务可用则返回TRUE。
Status = CoreAllEfiServicesAvailable ();
if (EFI_ERROR(Status)) {
//
// Report Status code that some Architectural Protocols are not present.
// 报告一些架构协议不存在的状态代码。
REPORT_STATUS_CODE (
EFI_ERROR_CODE | EFI_ERROR_MAJOR,
(EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_EC_NO_ARCH)
);
}
ASSERT_EFI_ERROR (Status);
//
// Report Status code before transfer control to BDS
// 向BDS移交控制前报告状态码
REPORT_STATUS_CODE (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_HANDOFF_TO_NEXT)
);
//
// Transfer control to the BDS Architectural Protocol
// 传输控制到BDS架构协议
gBds->Entry (gBds);
//
// BDS should never return
//
ASSERT (FALSE);
CpuDeadLoop ();
UNREACHABLE ();
}
那么又是如何从DXE切换到BDS的呢,
可以参考https://blog.csdn.net/robinsongsog/article/details/109003375