DXE Phase

  • Overview
  • DXE Core
  • DXE Dispatcher
  • EFI System Table
  • DXE Driver - Non-Driver Model
  • DXE Driver - Driver Model
  • Protocol & Handle
  • 执行流程图
  • 涉及元件及功能
  • DXE architecture protocol种类及其功能
  • DxeMain()


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, …)
    可以参考:

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上。可以参考:

Handle, 也叫对象(Object), 其本质是一个VOID型指针, 是protocol的载体

bios dxe_初始化

执行流程图

几乎所有的硬件的初始化都在DXE这做完,同时产生efi system table, 来提供各种service供所面阶段使用。最后把控制权交给bds来boot os.

bios dxe_Core_02

涉及元件及功能

  1. DXE Core,可视为dxe的核心,用来dispatch dxe driver 和产生efi system
    table,以提供boot service, runtime service, dxe service,负责DXE基础服务和执行流程.
  2. dxe driver, 被dxe core 所读取,用来做各种硬件的初始化,产生protocol和其他service.
  3. dxe dispatcher: dxe core 的一部分,以正确的顺序来搜寻和执行dxe driver,负责调度执行DXE驱动,初始化系统设备。 DXE提供的基础服务包括系统表、启动服务、Run Time Services.
  4. dxe architecture protocol: 由dxe driver所产生,是dxe core和hardware沟通的唯一介面,所以没有install 完全不能开机。
  5. 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 }
};
  1. security: 提供 DXE core 验证 firmware volume中的程序是否可用。
  2. cpu: 提供cpu的service如管理cache,管理中断,取得处理器频率,查询处理器的timer.

typedef struct _EFI_METRONOME_ARCH_PROTOCOL {
        EFI_METRONOME_WAIT_FOR_TICK          WaitForTIck;

         UINT32                              TickPeriod;

}  EFI_METRONOME_ARCH_PROTOCOL;

提供一个微小的延时,百万分之一秒为单位。

  1. 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的呢,

bios dxe_Core_03