DXE流程
进入点
DxeCoreEntryPoint = 0x6f0fdf0
DOS Header = 06f0d000

VOID
EFIAPI
_ModuleEntryPoint (IN VOID  *HobStart)
{//// Cache a pointer to the HobList//gHobList = HobStart;//// Call the DXE Core entry point//ProcessModuleEntryPointList (HobStart);//// Should never return//ASSERT (FALSE);CpuDeadLoop ();
}
VOID
EFIAPI
ProcessModuleEntryPointList (IN VOID  *HobStart){DxeMain (HobStart);
}
DxeMain
代码总览:
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//DEBUG((DEBUG_INFO,"Entry DxeMain\n"));//断点无效等到初始化debug时可用__debugbreak();VectorInfoList = NULL;GuidHob        = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart);if (GuidHob != NULL) {VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *)(GET_GUID_HOB_DATA (GuidHob));}Status = InitializeCpuExceptionHandlers (VectorInfoList);ASSERT_EFI_ERROR (Status);//// Setup Stack Guard//if (PcdGetBool (PcdCpuStackGuard)) {Status = InitializeSeparateExceptionStacks (NULL, NULL);ASSERT_EFI_ERROR (Status);}//// Initialize Debug Agent to support source level debug in DXE phase//InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_CORE, HobStart, NULL);__debugbreak();//// Initialize Memory Services//CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength);MemoryProfileInit (HobStart);//// Start the Handle Services.//Status = CoreInitializeHandleServices ();ASSERT_EFI_ERROR (Status);//// Start the Image Services.//Status = CoreInitializeImageServices (HobStart);ASSERT_EFI_ERROR (Status);//// Initialize the Global Coherency Domain Services//Status = CoreInitializeGcdServices (&HobStart, MemoryBaseAddress, MemoryLength);ASSERT_EFI_ERROR (Status);//// 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;//// Update DXE Core Loaded Image Protocol with allocated UEFI System Table//gDxeCoreLoadedImage->SystemTable = gDxeCoreST;//// Call constructor for all libraries//ProcessLibraryConstructorList (gDxeCoreImageHandle, gDxeCoreST);PERF_CROSSMODULE_END ("PEI");PERF_CROSSMODULE_BEGIN ("DXE");//// Log MemoryBaseAddress and MemoryLength again (from// CoreInitializeMemoryServices()), now that library constructors have// executed.//DEBUG ((DEBUG_INFO,"%a: MemoryBaseAddress=0x%Lx MemoryLength=0x%Lx\n",__func__,MemoryBaseAddress,MemoryLength));//// Report DXE Core image information to the PE/COFF Extra Action Library//ZeroMem (&ImageContext, sizeof (ImageContext));ImageContext.ImageAddress  = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreLoadedImage->ImageBase;ImageContext.PdbPointer    = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);ImageContext.SizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)ImageContext.ImageAddress);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;PeCoffLoaderRelocateImageExtraAction (&ImageContext);//// Install the DXE Services Table into the EFI System Tables's Configuration Table//Status = CoreInstallConfigurationTable (&gEfiDxeServicesTableGuid, gDxeCoreDS);ASSERT_EFI_ERROR (Status);//// Install the HOB List into the EFI System Tables's Configuration Table//Status = CoreInstallConfigurationTable (&gEfiHobListGuid, HobStart);ASSERT_EFI_ERROR (Status);//// Install Memory Type Information Table into the EFI System Tables's Configuration Table//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.//if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {Status = CoreInstallConfigurationTable (&gLoadFixedAddressConfigurationTableGuid, &gLoadModuleAtFixAddressConfigurationTable);ASSERT_EFI_ERROR (Status);}//// Report Status Code here for DXE_ENTRY_POINT once it is available//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.//CoreInitializeDebugImageInfoTable ();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_FV) {DEBUG ((DEBUG_INFO | DEBUG_LOAD,"FV Hob            0x%0lx - 0x%0lx\n",Hob.FirmwareVolume->BaseAddress,Hob.FirmwareVolume->BaseAddress + Hob.FirmwareVolume->Length - 1));} else 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));DEBUG ((DEBUG_INFO | DEBUG_LOAD,"                  %g - %g\n",&Hob.FirmwareVolume2->FvName,&Hob.FirmwareVolume2->FileName));} else if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV3) {DEBUG ((DEBUG_INFO | DEBUG_LOAD,"FV3 Hob           0x%0lx - 0x%0lx - 0x%x - 0x%x\n",Hob.FirmwareVolume3->BaseAddress,Hob.FirmwareVolume3->BaseAddress + Hob.FirmwareVolume3->Length - 1,Hob.FirmwareVolume3->AuthenticationStatus,Hob.FirmwareVolume3->ExtractedFv));if (Hob.FirmwareVolume3->ExtractedFv) {DEBUG ((DEBUG_INFO | DEBUG_LOAD,"                  %g - %g\n",&Hob.FirmwareVolume3->FvName,&Hob.FirmwareVolume3->FileName));}}}DEBUG_CODE_END ();//// Initialize the Event Services//Status = CoreInitializeEventServices ();ASSERT_EFI_ERROR (Status);//// Give the debug agent a chance to initialize with events.//InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_CORE_LATE, HobStart, NULL);MemoryProfileInstallProtocol ();CoreInitializeMemoryAttributesTable ();CoreInitializeMemoryProtection ();//// Get persisted vector hand-off info from GUIDeed HOB again due to HobStart may be updated,// and install configuration table//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);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.////// Publish the EFI, Tiano, and Custom Decompress protocols for use by other DXE components//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.//CoreNotifyOnProtocolInstallation ();//// Produce Firmware Volume Protocols, one for each FV in the HOB list.//Status = FwVolBlockDriverInit (gDxeCoreImageHandle, gDxeCoreST);ASSERT_EFI_ERROR (Status);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//CoreInitializeDispatcher ();//// Invoke the DXE Dispatcher//CoreDispatcher ();//// Display Architectural protocols that were not loaded if this is DEBUG build//DEBUG_CODE_BEGIN ();CoreDisplayMissingArchProtocols ();DEBUG_CODE_END ();//// Display any drivers that were not dispatched because dependency expression// evaluated to false if this is a debug build//DEBUG_CODE_BEGIN ();CoreDisplayDiscoveredNotDispatched ();DEBUG_CODE_END ();//// Assert if the Architectural Protocols are not present.//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//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//gBds->Entry (gBds);//// BDS should never return//ASSERT (FALSE);CpuDeadLoop ();UNREACHABLE ();
}
1 设置默认的异常处理程序
  VectorInfoList = NULL;GuidHob        = GetNextGuidHob (&gEfiVectorHandoffInfoPpiGuid, HobStart);if (GuidHob != NULL) {VectorInfoList = (EFI_VECTOR_HANDOFF_INFO *)(GET_GUID_HOB_DATA (GuidHob));}Status = InitializeCpuExceptionHandlers (VectorInfoList);ASSERT_EFI_ERROR (Status);
通过HOB获取持久化向量传递信息,然后去初始化CPU异常处理程序
EFI_STATUS
EFIAPI
InitializeCpuExceptionHandlers (IN EFI_VECTOR_HANDOFF_INFO  *VectorInfo OPTIONAL)
{InitializeSpinLock (&mExceptionHandlerData.DisplayMessageSpinLock);return InitializeCpuExceptionHandlersWorker (VectorInfo, &mExceptionHandlerData);
}
2 设置栈保护
  if (PcdGetBool (PcdCpuStackGuard)) {Status = InitializeSeparateExceptionStacks (NULL, NULL);ASSERT_EFI_ERROR (Status);}
EFI_STATUS
EFIAPI
InitializeSeparateExceptionStacks (IN     VOID   *Buffer,IN OUT UINTN  *BufferSize)
{UINTN       LocalBufferSize;EFI_STATUS  Status;if ((Buffer == NULL) && (BufferSize == NULL)) {SetMem (mBuffer, sizeof (mBuffer), 0);LocalBufferSize = sizeof (mBuffer);Status          = ArchSetupExceptionStack (mBuffer, &LocalBufferSize);ASSERT_EFI_ERROR (Status);return Status;} else {return ArchSetupExceptionStack (Buffer, BufferSize);}
}
3 初始化早期Debug代理
  InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_CORE, HobStart, NULL);
VOID
EFIAPI
InitializeDebugAgent (IN UINT32                InitFlag,IN VOID                  *Context  OPTIONAL,IN DEBUG_AGENT_CONTINUE  Function  OPTIONAL)
{UINT64               *MailboxLocation;DEBUG_AGENT_MAILBOX  *Mailbox;BOOLEAN              InterruptStatus;VOID                 *HobList;IA32_DESCRIPTOR      IdtDescriptor;IA32_DESCRIPTOR      *Ia32Idtr;IA32_IDT_ENTRY       *Ia32IdtEntry;BOOLEAN              PeriodicMode;UINTN                TimerCycle;if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) {//// Check if CPU APIC Timer is working, otherwise initialize it.//InitializeLocalApicSoftwareEnable (TRUE);GetApicTimerState (NULL, &PeriodicMode, NULL);TimerCycle = GetApicTimerInitCount ();if (!PeriodicMode || (TimerCycle == 0)) {InitializeDebugTimer (NULL, FALSE);}//// Invoked by AP, enable interrupt to let AP could receive IPI from other processors//EnableInterrupts ();return;}//// Disable Debug Timer interrupt//SaveAndSetDebugTimerInterrupt (FALSE);//// Save and disable original interrupt status//InterruptStatus = SaveAndDisableInterrupts ();//// Try to get mailbox firstly//HobList         = NULL;Mailbox         = NULL;MailboxLocation = NULL;switch (InitFlag) {case DEBUG_AGENT_INIT_DXE_LOAD://// Check if Debug Agent has been initialized before//if (IsDebugAgentInitialzed ()) {DEBUG ((DEBUG_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n"));}mMultiProcessorDebugSupport = TRUE;//// Save original IDT table//AsmReadIdtr (&IdtDescriptor);mSaveIdtTableSize = IdtDescriptor.Limit + 1;mSavedIdtTable    = AllocateCopyPool (mSaveIdtTableSize, (VOID *)IdtDescriptor.Base);//// Check if Debug Agent initialized in DXE phase//Mailbox = GetMailboxFromConfigurationTable ();if (Mailbox == NULL) {//// Try to get mailbox from GUIDed HOB build in PEI//HobList = GetHobList ();Mailbox = GetMailboxFromHob (HobList);}//// Set up Debug Agent Environment and try to connect HOST if required//SetupDebugAgentEnvironment (Mailbox);//// For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol// For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor()//InternalConstructorWorker ();//// Enable Debug Timer interrupt//SaveAndSetDebugTimerInterrupt (TRUE);//// Enable interrupt to receive Debug Timer interrupt//EnableInterrupts ();mDebugAgentInitialized = TRUE;FindAndReportModuleImageInfo (SIZE_4KB);*(EFI_STATUS *)Context = EFI_SUCCESS;break;case DEBUG_AGENT_INIT_DXE_UNLOAD:if (mDebugAgentInitialized) {if (IsHostAttached ()) {*(EFI_STATUS *)Context = EFI_ACCESS_DENIED;//// Enable Debug Timer interrupt again//SaveAndSetDebugTimerInterrupt (TRUE);} else {//// Restore original IDT table//AsmReadIdtr (&IdtDescriptor);IdtDescriptor.Limit = (UINT16)(mSaveIdtTableSize - 1);CopyMem ((VOID *)IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize);AsmWriteIdtr (&IdtDescriptor);FreePool (mSavedIdtTable);mDebugAgentInitialized = FALSE;*(EFI_STATUS *)Context = EFI_SUCCESS;}} else {*(EFI_STATUS *)Context = EFI_NOT_STARTED;}//// Restore interrupt state.//SetInterruptState (InterruptStatus);break;case DEBUG_AGENT_INIT_DXE_CORE:mDxeCoreFlag                = TRUE;mMultiProcessorDebugSupport = TRUE;//// Try to get mailbox from GUIDed HOB build in PEI//HobList = Context;Mailbox = GetMailboxFromHob (HobList);//// Set up Debug Agent Environment and try to connect HOST if required//SetupDebugAgentEnvironment (Mailbox);//// Enable Debug Timer interrupt//SaveAndSetDebugTimerInterrupt (TRUE);//// Enable interrupt to receive Debug Timer interrupt//EnableInterrupts ();break;case DEBUG_AGENT_INIT_S3:if (Context != NULL) {Ia32Idtr        =  (IA32_DESCRIPTOR *)Context;Ia32IdtEntry    = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);MailboxLocation = (UINT64 *)((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);VerifyMailboxChecksum (Mailbox);}//// Save Mailbox pointer in global variable//mMailboxPointer = Mailbox;//// Set up Debug Agent Environment and try to connect HOST if required//SetupDebugAgentEnvironment (Mailbox);//// Disable interrupt//DisableInterrupts ();FindAndReportModuleImageInfo (SIZE_4KB);if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) {//// If Boot Script entry break is set, code will be break at here.//CpuBreakpoint ();}break;case DEBUG_AGENT_INIT_REINITIALIZE:case DEBUG_AGENT_INIT_DXE_CORE_LATE:break;default://// Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this// Debug Agent library instance.//DEBUG ((DEBUG_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));CpuDeadLoop ();break;}
}
4 初始化内存服务

图来源于 “ UEFI Platform Initialization Specification Version 1.8 ”

图来源于 “ Unified Extensible Firmware Interface (UEFl) Specification, Release 2.11 ”
  CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength);MemoryProfileInit (HobStart);
EFI_STATUS
CoreInitializeMemoryServices (IN  VOID                  **HobStart,OUT EFI_PHYSICAL_ADDRESS  *MemoryBaseAddress,OUT UINT64                *MemoryLength)
{EFI_PEI_HOB_POINTERS         Hob;EFI_MEMORY_TYPE_INFORMATION  *EfiMemoryTypeInformation;UINTN                        DataSize;BOOLEAN                      Found;EFI_HOB_HANDOFF_INFO_TABLE   *PhitHob;EFI_HOB_RESOURCE_DESCRIPTOR  *ResourceHob;EFI_HOB_RESOURCE_DESCRIPTOR  *PhitResourceHob;EFI_HOB_RESOURCE_DESCRIPTOR  *MemoryTypeInformationResourceHob;UINTN                        Count;EFI_PHYSICAL_ADDRESS         BaseAddress;UINT64                       Length;UINT64                       Attributes;UINT64                       Capabilities;EFI_PHYSICAL_ADDRESS         TestedMemoryBaseAddress;UINT64                       TestedMemoryLength;EFI_PHYSICAL_ADDRESS         HighAddress;EFI_HOB_GUID_TYPE            *GuidHob;UINT32                       ReservedCodePageNumber;UINT64                       MinimalMemorySizeNeeded;//// Point at the first HOB.  This must be the PHIT HOB.//Hob.Raw = *HobStart;ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);//// Initialize the spin locks and maps in the memory services.// Also fill in the memory services into the EFI Boot Services Table//CoreInitializePool ();//// Initialize Local Variables//PhitResourceHob = NULL;ResourceHob     = NULL;BaseAddress     = 0;Length          = 0;Attributes      = 0;//// Cache the PHIT HOB for later use//PhitHob = Hob.HandoffInformationTable;if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {ReservedCodePageNumber  = PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);ReservedCodePageNumber += PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);//// cache the Top address for loading modules at Fixed Address//gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop+ EFI_PAGES_TO_SIZE (ReservedCodePageNumber);}//// See if a Memory Type Information HOB is available//MemoryTypeInformationResourceHob = NULL;GuidHob                          = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);if (GuidHob != NULL) {EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);DataSize                 = GET_GUID_HOB_DATA_SIZE (GuidHob);if ((EfiMemoryTypeInformation != NULL) && (DataSize > 0) && (DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION))) {CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize);//// Look for Resource Descriptor HOB with a ResourceType of System Memory// and an Owner GUID of gEfiMemoryTypeInformationGuid. If more than 1 is// found, then set MemoryTypeInformationResourceHob to NULL.//Count = 0;for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {continue;}ResourceHob = Hob.ResourceDescriptor;if (!CompareGuid (&ResourceHob->Owner, &gEfiMemoryTypeInformationGuid)) {continue;}Count++;if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {continue;}if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {continue;}if (ResourceHob->ResourceLength >= CalculateTotalMemoryBinSizeNeeded ()) {MemoryTypeInformationResourceHob = ResourceHob;}}if (Count > 1) {MemoryTypeInformationResourceHob = NULL;}}}//// Include the total memory bin size needed to make sure memory bin could be allocated successfully.//MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded ();//// Find the Resource Descriptor HOB that contains PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop//Found = FALSE;for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {//// Skip all HOBs except Resource Descriptor HOBs//if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {continue;}//// Skip Resource Descriptor HOBs that do not describe tested system memory//ResourceHob = Hob.ResourceDescriptor;if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {continue;}if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {continue;}//// Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop//if (PhitHob->EfiFreeMemoryBottom < ResourceHob->PhysicalStart) {continue;}if (PhitHob->EfiFreeMemoryTop > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {continue;}//// Cache the resource descriptor HOB for the memory region described by the PHIT HOB//PhitResourceHob = ResourceHob;Found           = TRUE;//// If a Memory Type Information Resource HOB was found and is the same// Resource HOB that describes the PHIT HOB, then ignore the Memory Type// Information Resource HOB.//if (MemoryTypeInformationResourceHob == PhitResourceHob) {MemoryTypeInformationResourceHob = NULL;}//// Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB//Attributes  = PhitResourceHob->ResourceAttribute;BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);Length      = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));if (Length < MinimalMemorySizeNeeded) {//// If that range is not large enough to intialize the DXE Core, then// Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop//BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom);Length      = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress);// This region is required to have no memory allocation inside it, skip check for entries in HOB Listif (Length < MinimalMemorySizeNeeded) {//// If that range is not large enough to intialize the DXE Core, then// Compute range between the start of the Resource Descriptor HOB and the start of the HOB List//BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);Length      = PageAlignLength ((UINT64)((UINTN)*HobStart - BaseAddress));FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));}}break;}//// Assert if a resource descriptor HOB for the memory region described by the PHIT was not found//ASSERT (Found);//// Take the range in the resource descriptor HOB for the memory region described// by the PHIT as higher priority if it is big enough. It can make the memory bin// allocated to be at the same memory region with PHIT that has more better compatibility// to avoid memory fragmentation for some code practices assume and allocate <4G ACPI memory.//if (Length < MinimalMemorySizeNeeded) {//// Search all the resource descriptor HOBs from the highest possible addresses down for a memory// region that is big enough to initialize the DXE core.  Always skip the PHIT Resource HOB// and the Memory Type Information Resource HOB. The max address must be within the physically// addressable range for the processor.//HighAddress = MAX_ALLOC_ADDRESS;for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {//// Skip the Resource Descriptor HOB that contains the PHIT//if (Hob.ResourceDescriptor == PhitResourceHob) {continue;}//// Skip the Resource Descriptor HOB that contains Memory Type Information bins//if (Hob.ResourceDescriptor == MemoryTypeInformationResourceHob) {continue;}//// Skip all HOBs except Resource Descriptor HOBs//if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {continue;}//// Skip Resource Descriptor HOBs that do not describe tested system memory below MAX_ALLOC_ADDRESS//ResourceHob = Hob.ResourceDescriptor;if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {continue;}if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {continue;}if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > (EFI_PHYSICAL_ADDRESS)MAX_ALLOC_ADDRESS) {continue;}//// Skip Resource Descriptor HOBs that are below a previously found Resource Descriptor HOB//if ((HighAddress != (EFI_PHYSICAL_ADDRESS)MAX_ALLOC_ADDRESS) && (ResourceHob->PhysicalStart <= HighAddress)) {continue;}//// Skip Resource Descriptor HOBs that are not large enough to initilize the DXE Core//TestedMemoryBaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);TestedMemoryLength      = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - TestedMemoryBaseAddress);FindLargestFreeRegion (&TestedMemoryBaseAddress, &TestedMemoryLength, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));if (TestedMemoryLength < MinimalMemorySizeNeeded) {continue;}//// Save the range described by the Resource Descriptor that is large enough to initilize the DXE Core//BaseAddress = TestedMemoryBaseAddress;Length      = TestedMemoryLength;Attributes  = ResourceHob->ResourceAttribute;HighAddress = ResourceHob->PhysicalStart;}}DEBUG ((DEBUG_INFO, "CoreInitializeMemoryServices:\n"));DEBUG ((DEBUG_INFO, "  BaseAddress - 0x%lx Length - 0x%lx MinimalMemorySizeNeeded - 0x%lx\n", BaseAddress, Length, MinimalMemorySizeNeeded));//// If no memory regions are found that are big enough to initialize the DXE core, then ASSERT().//ASSERT (Length >= MinimalMemorySizeNeeded);//// Convert the Resource HOB Attributes to an EFI Memory Capabilities mask//if ((Attributes & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable, Attributes);} else {Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);}if (MemoryTypeInformationResourceHob != NULL) {//// If a Memory Type Information Resource HOB was found, then use the address// range of the  Memory Type Information Resource HOB as the preferred// address range for the Memory Type Information bins.//CoreSetMemoryTypeInformationRange (MemoryTypeInformationResourceHob->PhysicalStart,MemoryTypeInformationResourceHob->ResourceLength);}//// Declare the very first memory region, so the EFI Memory Services are available.//CoreAddMemoryDescriptor (EfiConventionalMemory,BaseAddress,RShiftU64 (Length, EFI_PAGE_SHIFT),Capabilities);*MemoryBaseAddress = BaseAddress;*MemoryLength      = Length;return EFI_SUCCESS;
}
4.1 指出第一个HOB(PHIT HOB)
PHIT HOB是整个 HOB 列表的表头,由 PEI 阶段创建,必须放在列表最前面,用来告诉 DXE 阶段 HOB 列表在哪、有多大、当前内存布局怎样
  Hob.Raw = *HobStart;ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);
4.2 初始化池
在 DXE 内核里划出一块常驻内存,做成固定大小的空闲链表
  CoreInitializePool ();
VOID
CoreInitializePool (VOID)
{UINTN  Type;UINTN  Index;for (Type = 0; Type < EfiMaxMemoryType; Type++) {mPoolHead[Type].Signature  = 0;mPoolHead[Type].Used       = 0;mPoolHead[Type].MemoryType = (EFI_MEMORY_TYPE)Type;for (Index = 0; Index < MAX_POOL_LIST; Index++) {InitializeListHead (&mPoolHead[Type].FreeList[Index]);}}
}
4.3 缓存 PHIT HOB
  PhitHob = Hob.HandoffInformationTable;if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {ReservedCodePageNumber  = PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);ReservedCodePageNumber += PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);//// cache the Top address for loading modules at Fixed Address//gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress = PhitHob->EfiMemoryTop+ EFI_PAGES_TO_SIZE (ReservedCodePageNumber);}
4.4 检查内存类型信息表 HOB 是否有效

  MemoryTypeInformationResourceHob = NULL;GuidHob                          = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);if (GuidHob != NULL) {EfiMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);DataSize                 = GET_GUID_HOB_DATA_SIZE (GuidHob);if ((EfiMemoryTypeInformation != NULL) && (DataSize > 0) && (DataSize <= (EfiMaxMemoryType + 1) * sizeof (EFI_MEMORY_TYPE_INFORMATION))) {CopyMem (&gMemoryTypeInformation, EfiMemoryTypeInformation, DataSize);//// Look for Resource Descriptor HOB with a ResourceType of System Memory// and an Owner GUID of gEfiMemoryTypeInformationGuid. If more than 1 is// found, then set MemoryTypeInformationResourceHob to NULL.//Count = 0;for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {continue;}ResourceHob = Hob.ResourceDescriptor;if (!CompareGuid (&ResourceHob->Owner, &gEfiMemoryTypeInformationGuid)) {continue;}Count++;if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {continue;}if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {continue;}if (ResourceHob->ResourceLength >= CalculateTotalMemoryBinSizeNeeded ()) {MemoryTypeInformationResourceHob = ResourceHob;}}if (Count > 1) {MemoryTypeInformationResourceHob = NULL;}}}
4.5 计算所需的内存 bin 大小
内存 bin 大小是某个 Type 在内存类型信息里要的页数
  MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded ();
UINT64
CalculateTotalMemoryBinSizeNeeded (VOID)
{UINTN   Index;UINT64  TotalSize;//// Loop through each memory type in the order specified by the gMemoryTypeInformation[] array//TotalSize = 0;for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {TotalSize += LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT);}return TotalSize;
}
4.6 查找资源描述表 HOB
  Found = FALSE;for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {//// Skip all HOBs except Resource Descriptor HOBs//if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {continue;}//// Skip Resource Descriptor HOBs that do not describe tested system memory//ResourceHob = Hob.ResourceDescriptor;if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {continue;}if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {continue;}//// Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop//if (PhitHob->EfiFreeMemoryBottom < ResourceHob->PhysicalStart) {continue;}if (PhitHob->EfiFreeMemoryTop > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {continue;}//// Cache the resource descriptor HOB for the memory region described by the PHIT HOB//PhitResourceHob = ResourceHob;Found           = TRUE;//// If a Memory Type Information Resource HOB was found and is the same// Resource HOB that describes the PHIT HOB, then ignore the Memory Type// Information Resource HOB.//if (MemoryTypeInformationResourceHob == PhitResourceHob) {MemoryTypeInformationResourceHob = NULL;}//// Compute range between PHIT EfiMemoryTop and the end of the Resource Descriptor HOB//Attributes  = PhitResourceHob->ResourceAttribute;BaseAddress = PageAlignAddress (PhitHob->EfiMemoryTop);Length      = PageAlignLength (ResourceHob->PhysicalStart + ResourceHob->ResourceLength - BaseAddress);FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));if (Length < MinimalMemorySizeNeeded) {//// If that range is not large enough to intialize the DXE Core, then// Compute range between PHIT EfiFreeMemoryBottom and PHIT EfiFreeMemoryTop//BaseAddress = PageAlignAddress (PhitHob->EfiFreeMemoryBottom);Length      = PageAlignLength (PhitHob->EfiFreeMemoryTop - BaseAddress);// This region is required to have no memory allocation inside it, skip check for entries in HOB Listif (Length < MinimalMemorySizeNeeded) {//// If that range is not large enough to intialize the DXE Core, then// Compute range between the start of the Resource Descriptor HOB and the start of the HOB List//BaseAddress = PageAlignAddress (ResourceHob->PhysicalStart);Length      = PageAlignLength ((UINT64)((UINTN)*HobStart - BaseAddress));FindLargestFreeRegion (&BaseAddress, &Length, (EFI_HOB_MEMORY_ALLOCATION *)GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION));}}break;}
4.7 生成 EFI 内存能力掩码
将资源描述表 HOB 里记录的那段物理内存的硬件属性翻译成 UEFI 规范定义的 EFI_MEMORY_CAPABILITIES 位掩码
  if ((Attributes & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable, Attributes);} else {Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);}
4.8 为所需的内存类型划分区域
  CoreAddMemoryDescriptor (EfiConventionalMemory,BaseAddress,RShiftU64 (Length, EFI_PAGE_SHIFT),Capabilities);*MemoryBaseAddress = BaseAddress;*MemoryLength      = Length;
VOID
CoreAddMemoryDescriptor (IN EFI_MEMORY_TYPE       Type,IN EFI_PHYSICAL_ADDRESS  Start,IN UINT64                NumberOfPages,IN UINT64                Attribute)
{EFI_PHYSICAL_ADDRESS  End;EFI_STATUS            Status;UINTN                 Index;UINTN                 FreeIndex;if ((Start & EFI_PAGE_MASK) != 0) {return;}if ((Type >= EfiMaxMemoryType) && (Type < MEMORY_TYPE_OEM_RESERVED_MIN)) {return;}CoreAcquireMemoryLock ();End = Start + LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT) - 1;CoreAddRange (Type, Start, End, Attribute);CoreFreeMemoryMapStack ();CoreReleaseMemoryLock ();ApplyMemoryProtectionPolicy (EfiMaxMemoryType,Type,Start,LShiftU64 (NumberOfPages, EFI_PAGE_SHIFT));//// If Loading Module At Fixed Address feature is enabled. try to allocate memory with Runtime code & Boot time code type//if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {CoreLoadingFixedAddressHook ();}//// Check to see if the statistics for the different memory types have already been established//if (mMemoryTypeInformationInitialized) {return;}//// Loop through each memory type in the order specified by the gMemoryTypeInformation[] array//for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {//// Make sure the memory type in the gMemoryTypeInformation[] array is valid//Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);if ((UINT32)Type > EfiMaxMemoryType) {continue;}if (gMemoryTypeInformation[Index].NumberOfPages != 0) {//// Allocate pages for the current memory type from the top of available memory//Status = CoreAllocatePages (AllocateAnyPages,Type,gMemoryTypeInformation[Index].NumberOfPages,&mMemoryTypeStatistics[Type].BaseAddress);if (EFI_ERROR (Status)) {//// If an error occurs allocating the pages for the current memory type, then// free all the pages allocates for the previous memory types and return.  This// operation with be retied when/if more memory is added to the system//for (FreeIndex = 0; FreeIndex < Index; FreeIndex++) {//// Make sure the memory type in the gMemoryTypeInformation[] array is valid//Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[FreeIndex].Type);if ((UINT32)Type > EfiMaxMemoryType) {continue;}if (gMemoryTypeInformation[FreeIndex].NumberOfPages != 0) {CoreFreePages (mMemoryTypeStatistics[Type].BaseAddress,gMemoryTypeInformation[FreeIndex].NumberOfPages);mMemoryTypeStatistics[Type].BaseAddress    = 0;mMemoryTypeStatistics[Type].MaximumAddress = MAX_ALLOC_ADDRESS;}}return;}//// Compute the address at the top of the current statistics//mMemoryTypeStatistics[Type].MaximumAddress =mMemoryTypeStatistics[Type].BaseAddress +LShiftU64 (gMemoryTypeInformation[Index].NumberOfPages, EFI_PAGE_SHIFT) - 1;//// If the current base address is the lowest address so far, then update the default// maximum address//if (mMemoryTypeStatistics[Type].BaseAddress < mDefaultMaximumAddress) {mDefaultMaximumAddress = mMemoryTypeStatistics[Type].BaseAddress - 1;}}}//// There was enough system memory for all the the memory types were allocated.  So,// those memory areas can be freed for future allocations, and all future memory// allocations can occur within their respective bins//for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {//// Make sure the memory type in the gMemoryTypeInformation[] array is valid//Type = (EFI_MEMORY_TYPE)(gMemoryTypeInformation[Index].Type);if ((UINT32)Type > EfiMaxMemoryType) {continue;}if (gMemoryTypeInformation[Index].NumberOfPages != 0) {CoreFreePages (mMemoryTypeStatistics[Type].BaseAddress,gMemoryTypeInformation[Index].NumberOfPages);mMemoryTypeStatistics[Type].NumberOfPages   = gMemoryTypeInformation[Index].NumberOfPages;gMemoryTypeInformation[Index].NumberOfPages = 0;}}//// If the number of pages reserved for a memory type is 0, then all allocations for that type// should be in the default range.//for (Type = (EFI_MEMORY_TYPE)0; Type < EfiMaxMemoryType; Type++) {for (Index = 0; gMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {if (Type == (EFI_MEMORY_TYPE)gMemoryTypeInformation[Index].Type) {mMemoryTypeStatistics[Type].InformationIndex = Index;}}mMemoryTypeStatistics[Type].CurrentNumberOfPages = 0;if (mMemoryTypeStatistics[Type].MaximumAddress == MAX_ALLOC_ADDRESS) {mMemoryTypeStatistics[Type].MaximumAddress = mDefaultMaximumAddress;}}mMemoryTypeInformationInitialized = TRUE;
}
5 初始化内存配置文件
VOID
MemoryProfileInit (IN VOID  *HobStart)
{MEMORY_PROFILE_CONTEXT_DATA  *ContextData;if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {return;}ContextData = GetMemoryProfileContext ();if (ContextData != NULL) {return;}mMemoryProfileGettingStatus = FALSE;if ((PcdGet8 (PcdMemoryProfilePropertyMask) & BIT7) != 0) {mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_DISABLE;} else {mMemoryProfileRecordingEnable = MEMORY_PROFILE_RECORDING_ENABLE;}mMemoryProfileDriverPathSize = PcdGetSize (PcdMemoryProfileDriverPath);mMemoryProfileDriverPath     = AllocateCopyPool (mMemoryProfileDriverPathSize, PcdGetPtr (PcdMemoryProfileDriverPath));mMemoryProfileContextPtr     = &mMemoryProfileContext;RegisterDxeCore (HobStart, &mMemoryProfileContext);DEBUG ((DEBUG_INFO, "MemoryProfileInit MemoryProfileContext - 0x%x\n", &mMemoryProfileContext));
}
6 启动句柄服务
EFI_STATUS
CoreInitializeHandleServices (VOID)
{gOrderedHandleList = OrderedCollectionInit (PointerCompare, PointerCompare);if (gOrderedHandleList == NULL) {return EFI_OUT_OF_RESOURCES;}return EFI_SUCCESS;
}
RED_BLACK_TREE *
EFIAPI
OrderedCollectionInit (IN RED_BLACK_TREE_USER_COMPARE  UserStructCompare,IN RED_BLACK_TREE_KEY_COMPARE   KeyCompare)
{RED_BLACK_TREE  *Tree;Tree = AllocatePool (sizeof *Tree);if (Tree == NULL) {return NULL;}Tree->Root              = NULL;Tree->UserStructCompare = UserStructCompare;Tree->KeyCompare        = KeyCompare;if (FeaturePcdGet (PcdValidateOrderedCollection)) {RedBlackTreeValidate (Tree);}return Tree;
}
7 启动映像服务
EFI_STATUS
CoreInitializeImageServices (IN  VOID  *HobStart)
{EFI_STATUS                 Status;LOADED_IMAGE_PRIVATE_DATA  *Image;EFI_PHYSICAL_ADDRESS       DxeCoreImageBaseAddress;UINT64                     DxeCoreImageLength;VOID                       *DxeCoreEntryPoint;EFI_PEI_HOB_POINTERS       DxeCoreHob;//// Searching for image hob//DxeCoreHob.Raw = HobStart;while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {//// Find Dxe Core HOB//break;}DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);}ASSERT (DxeCoreHob.Raw != NULL);DxeCoreImageBaseAddress = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;DxeCoreImageLength      = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength;DxeCoreEntryPoint       = (VOID *)(UINTN)DxeCoreHob.MemoryAllocationModule->EntryPoint;gDxeCoreFileName        = &DxeCoreHob.MemoryAllocationModule->ModuleName;//// Initialize the fields for an internal driver//Image = &mCorePrivateImage;Image->EntryPoint     = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint;Image->ImageBasePage  = DxeCoreImageBaseAddress;Image->NumberOfPages  = (UINTN)(EFI_SIZE_TO_PAGES ((UINTN)(DxeCoreImageLength)));Image->Tpl            = gEfiCurrentTpl;Image->Info.ImageBase = (VOID *)(UINTN)DxeCoreImageBaseAddress;Image->Info.ImageSize = DxeCoreImageLength;//// Install the protocol interfaces for this image//Status = CoreInstallProtocolInterface (&Image->Handle,&gEfiLoadedImageProtocolGuid,EFI_NATIVE_INTERFACE,&Image->Info);ASSERT_EFI_ERROR (Status);mCurrentImage = Image;//// Fill in DXE globals//mDxeCoreImageMachineType = PeCoffLoaderGetMachineType (Image->Info.ImageBase);gDxeCoreImageHandle      = Image->Handle;gDxeCoreLoadedImage      = &Image->Info;//// Create the PE/COFF emulator protocol registration event//Status = CoreCreateEvent (EVT_NOTIFY_SIGNAL,TPL_CALLBACK,PeCoffEmuProtocolNotify,NULL,&mPeCoffEmuProtocolRegistrationEvent);ASSERT_EFI_ERROR (Status);//// Register for protocol notifications on this event//Status = CoreRegisterProtocolNotify (&gEdkiiPeCoffImageEmulatorProtocolGuid,mPeCoffEmuProtocolRegistrationEvent,&mPeCoffEmuProtocolNotifyRegistration);ASSERT_EFI_ERROR (Status);InitializeListHead (&mAvailableEmulators);ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);return Status;
}
寻找映像HOB -> 初始化内部映像的字段 -> 为映像安装协议接口 -> 填充 DXE 全局变量 -> 创建 PE/COFF 仿真器协议的注册事件 -> 为此事件注册协议通知
安装协议接口
https://blog.csdn.net/degen_/article/details/153976229
创建协议注册事件
https://blog.csdn.net/degen_/article/details/154009562
注册协议通知
https://blog.csdn.net/degen_/article/details/154015552
8 初始化全局一致性域(GCD)服务
GCD服务用于管理平台中的系统内存、内存映射I/O和I/O资源。调度服务用于调用DXE调度器,并修改DXE调度器跟踪的DXE驱动的状态。
  Status = CoreInitializeGcdServices (&HobStart, MemoryBaseAddress, MemoryLength);
EFI_STATUS
CoreInitializeGcdServices (IN OUT VOID              **HobStart,IN EFI_PHYSICAL_ADDRESS  MemoryBaseAddress,IN UINT64                MemoryLength)
{EFI_PEI_HOB_POINTERS             Hob;VOID                             *NewHobList;EFI_HOB_HANDOFF_INFO_TABLE       *PhitHob;UINT8                            SizeOfMemorySpace;UINT8                            SizeOfIoSpace;EFI_HOB_RESOURCE_DESCRIPTOR      *ResourceHob;EFI_PHYSICAL_ADDRESS             BaseAddress;UINT64                           Length;EFI_STATUS                       Status;EFI_GCD_MAP_ENTRY                *Entry;EFI_GCD_MEMORY_TYPE              GcdMemoryType;EFI_GCD_IO_TYPE                  GcdIoType;EFI_GCD_MEMORY_SPACE_DESCRIPTOR  Descriptor;EFI_HOB_MEMORY_ALLOCATION        *MemoryHob;EFI_HOB_FIRMWARE_VOLUME          *FirmwareVolumeHob;UINTN                            NumberOfDescriptors;EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *MemorySpaceMap;UINTN                            Index;UINT64                           Capabilities;EFI_HOB_CPU                      *CpuHob;EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *MemorySpaceMapHobList;//// Cache the PHIT HOB for later use//PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart);//// Get the number of address lines in the I/O and Memory space for the CPU//CpuHob = GetFirstHob (EFI_HOB_TYPE_CPU);ASSERT (CpuHob != NULL);SizeOfMemorySpace = CpuHob->SizeOfMemorySpace;SizeOfIoSpace     = CpuHob->SizeOfIoSpace;//// Initialize the GCD Memory Space Map//Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate);ASSERT (Entry != NULL);Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1;InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link);CoreDumpGcdMemorySpaceMap (TRUE);//// Initialize the GCD I/O Space Map//Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate);ASSERT (Entry != NULL);Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1;InsertHeadList (&mGcdIoSpaceMap, &Entry->Link);CoreDumpGcdIoSpaceMap (TRUE);//// Walk the HOB list and add all resource descriptors to the GCD//for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {GcdMemoryType = EfiGcdMemoryTypeNonExistent;GcdIoType     = EfiGcdIoTypeNonExistent;if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {ResourceHob = Hob.ResourceDescriptor;switch (ResourceHob->ResourceType) {case EFI_RESOURCE_SYSTEM_MEMORY:if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {GcdMemoryType = EfiGcdMemoryTypeMoreReliable;} else {GcdMemoryType = EfiGcdMemoryTypeSystemMemory;}}if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {GcdMemoryType = EfiGcdMemoryTypeReserved;}if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {GcdMemoryType = EfiGcdMemoryTypeReserved;}if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == EFI_RESOURCE_ATTRIBUTE_PERSISTENT) {GcdMemoryType = EfiGcdMemoryTypePersistent;}// Mark special purpose memory as system memory, if it was system memory in the HOB// However, if this is also marked as persistent, let persistent take precedenceif ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_SPECIAL_PURPOSE) == EFI_RESOURCE_ATTRIBUTE_SPECIAL_PURPOSE) {GcdMemoryType = EfiGcdMemoryTypeSystemMemory;}break;case EFI_RESOURCE_MEMORY_MAPPED_IO:case EFI_RESOURCE_FIRMWARE_DEVICE:GcdMemoryType = EfiGcdMemoryTypeMemoryMappedIo;break;case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT:case EFI_RESOURCE_MEMORY_RESERVED:GcdMemoryType = EfiGcdMemoryTypeReserved;break;case EFI_RESOURCE_MEMORY_UNACCEPTED:GcdMemoryType = EfiGcdMemoryTypeUnaccepted;break;case EFI_RESOURCE_IO:GcdIoType = EfiGcdIoTypeIo;break;case EFI_RESOURCE_IO_RESERVED:GcdIoType = EfiGcdIoTypeReserved;break;}if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) {//// Validate the Resource HOB Attributes//CoreValidateResourceDescriptorHobAttributes (ResourceHob->ResourceAttribute);//// Convert the Resource HOB Attributes to an EFI Memory Capabilities mask//Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (GcdMemoryType,ResourceHob->ResourceAttribute);Status = CoreInternalAddMemorySpace (GcdMemoryType,ResourceHob->PhysicalStart,ResourceHob->ResourceLength,Capabilities);}if (GcdIoType != EfiGcdIoTypeNonExistent) {Status = CoreAddIoSpace (GcdIoType,ResourceHob->PhysicalStart,ResourceHob->ResourceLength);}}}//// Allocate first memory region from the GCD by the DXE core//Status = CoreGetMemorySpaceDescriptor (MemoryBaseAddress, &Descriptor);if (!EFI_ERROR (Status)) {ASSERT ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||(Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable));Status = CoreAllocateMemorySpace (EfiGcdAllocateAddress,Descriptor.GcdMemoryType,0,MemoryLength,&MemoryBaseAddress,gDxeCoreImageHandle,NULL);}//// Walk the HOB list and allocate all memory space that is consumed by memory allocation HOBs,// and Firmware Volume HOBs.  Also update the EFI Memory Map with the memory allocation HOBs.//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) {MemoryHob   = Hob.MemoryAllocation;BaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;Status      = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor);if (!EFI_ERROR (Status)) {Status = CoreAllocateMemorySpace (EfiGcdAllocateAddress,Descriptor.GcdMemoryType,0,MemoryHob->AllocDescriptor.MemoryLength,&BaseAddress,gDxeCoreImageHandle,NULL);if (!EFI_ERROR (Status) &&((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||(Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable))){CoreAddMemoryDescriptor (MemoryHob->AllocDescriptor.MemoryType,MemoryHob->AllocDescriptor.MemoryBaseAddress,RShiftU64 (MemoryHob->AllocDescriptor.MemoryLength, EFI_PAGE_SHIFT),Descriptor.Capabilities & (~EFI_MEMORY_RUNTIME));}}}if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {FirmwareVolumeHob = Hob.FirmwareVolume;BaseAddress       = FirmwareVolumeHob->BaseAddress;Status            = CoreAllocateMemorySpace (EfiGcdAllocateAddress,EfiGcdMemoryTypeMemoryMappedIo,0,FirmwareVolumeHob->Length,&BaseAddress,gDxeCoreImageHandle,NULL);}}//// Add and allocate the remaining unallocated system memory to the memory services.//Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);ASSERT (Status == EFI_SUCCESS);MemorySpaceMapHobList = NULL;for (Index = 0; Index < NumberOfDescriptors; Index++) {if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||(MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable)){if (MemorySpaceMap[Index].ImageHandle == NULL) {BaseAddress = PageAlignAddress (MemorySpaceMap[Index].BaseAddress);Length      = PageAlignLength (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress);if ((Length == 0) || (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress)) {continue;}if (((UINTN)MemorySpaceMap[Index].BaseAddress <= (UINTN)(*HobStart)) &&((UINTN)(MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) >= (UINTN)PhitHob->EfiFreeMemoryBottom)){//// Skip the memory space that covers HOB List, it should be processed// after HOB List relocation to avoid the resources allocated by others// to corrupt HOB List before its relocation.//MemorySpaceMapHobList = &MemorySpaceMap[Index];continue;}CoreAddMemoryDescriptor (EfiConventionalMemory,BaseAddress,RShiftU64 (Length, EFI_PAGE_SHIFT),MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME));Status = CoreAllocateMemorySpace (EfiGcdAllocateAddress,MemorySpaceMap[Index].GcdMemoryType,0,Length,&BaseAddress,gDxeCoreImageHandle,NULL);}}}//// Relocate HOB List to an allocated pool buffer.// The relocation should be at after all the tested memory resources added// (except the memory space that covers HOB List) to the memory services,// because the memory resource found in CoreInitializeMemoryServices()// may have not enough remaining resource for HOB List.//NewHobList = AllocateCopyPool ((UINTN)PhitHob->EfiFreeMemoryBottom - (UINTN)(*HobStart),*HobStart);ASSERT (NewHobList != NULL);*HobStart = NewHobList;gHobList  = NewHobList;if (MemorySpaceMapHobList != NULL) {//// Add and allocate the memory space that covers HOB List to the memory services// after HOB List relocation.//BaseAddress = PageAlignAddress (MemorySpaceMapHobList->BaseAddress);Length      = PageAlignLength (MemorySpaceMapHobList->BaseAddress + MemorySpaceMapHobList->Length - BaseAddress);CoreAddMemoryDescriptor (EfiConventionalMemory,BaseAddress,RShiftU64 (Length, EFI_PAGE_SHIFT),MemorySpaceMapHobList->Capabilities & (~EFI_MEMORY_RUNTIME));Status = CoreAllocateMemorySpace (EfiGcdAllocateAddress,MemorySpaceMapHobList->GcdMemoryType,0,Length,&BaseAddress,gDxeCoreImageHandle,NULL);}CoreFreePool (MemorySpaceMap);return EFI_SUCCESS;
}
8.1 缓存PHIT HOB
  PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart);
8.2 获取 CPU 在 I/O 和内存空间中的地址线数量
通过CPU HOB
  CpuHob = GetFirstHob (EFI_HOB_TYPE_CPU);ASSERT (CpuHob != NULL);SizeOfMemorySpace = CpuHob->SizeOfMemorySpace;SizeOfIoSpace     = CpuHob->SizeOfIoSpace;
8.3 初始化 GCD 内存空间映射
GCD Memory Space 状态:
- EfiGcdMemoryTypeNonExistent
 - EfiGcdMemoryTypeSystemMemory
 - EfiGcdMemoryTypeMemoryMappedIo
 - EfiGcdMemoryTypeReserved

图来源于 “ UEFI Platform Initialization Specification Version 1.8 ” 
  Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdMemorySpaceMapEntryTemplate);ASSERT (Entry != NULL);Entry->EndAddress = LShiftU64 (1, SizeOfMemorySpace) - 1;InsertHeadList (&mGcdMemorySpaceMap, &Entry->Link);CoreDumpGcdMemorySpaceMap (TRUE);
8.4 初始化 GCD I/O 空间映射
GCD I/O Space 状态:
- EfiGcdIoTypeNonExistent
 - EfiGcdIoTypeIo
 - EfiGcdIoTypeReserved

 
图来源于 “ UEFI Platform Initialization Specification Version 1.8 ”
  Entry = AllocateCopyPool (sizeof (EFI_GCD_MAP_ENTRY), &mGcdIoSpaceMapEntryTemplate);ASSERT (Entry != NULL);Entry->EndAddress = LShiftU64 (1, SizeOfIoSpace) - 1;InsertHeadList (&mGcdIoSpaceMap, &Entry->Link);CoreDumpGcdIoSpaceMap (TRUE);
8.5 添加资源描述符到 GCD
遍历 HOB 列表,将所有资源描述符添加到 GCD 中
  for (Hob.Raw = *HobStart; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {GcdMemoryType = EfiGcdMemoryTypeNonExistent;GcdIoType     = EfiGcdIoTypeNonExistent;if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {ResourceHob = Hob.ResourceDescriptor;switch (ResourceHob->ResourceType) {case EFI_RESOURCE_SYSTEM_MEMORY:if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == TESTED_MEMORY_ATTRIBUTES) {if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {GcdMemoryType = EfiGcdMemoryTypeMoreReliable;} else {GcdMemoryType = EfiGcdMemoryTypeSystemMemory;}}if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == INITIALIZED_MEMORY_ATTRIBUTES) {GcdMemoryType = EfiGcdMemoryTypeReserved;}if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) == PRESENT_MEMORY_ATTRIBUTES) {GcdMemoryType = EfiGcdMemoryTypeReserved;}if ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_PERSISTENT) == EFI_RESOURCE_ATTRIBUTE_PERSISTENT) {GcdMemoryType = EfiGcdMemoryTypePersistent;}// Mark special purpose memory as system memory, if it was system memory in the HOB// However, if this is also marked as persistent, let persistent take precedenceif ((ResourceHob->ResourceAttribute & EFI_RESOURCE_ATTRIBUTE_SPECIAL_PURPOSE) == EFI_RESOURCE_ATTRIBUTE_SPECIAL_PURPOSE) {GcdMemoryType = EfiGcdMemoryTypeSystemMemory;}break;case EFI_RESOURCE_MEMORY_MAPPED_IO:case EFI_RESOURCE_FIRMWARE_DEVICE:GcdMemoryType = EfiGcdMemoryTypeMemoryMappedIo;break;case EFI_RESOURCE_MEMORY_MAPPED_IO_PORT:case EFI_RESOURCE_MEMORY_RESERVED:GcdMemoryType = EfiGcdMemoryTypeReserved;break;case EFI_RESOURCE_MEMORY_UNACCEPTED:GcdMemoryType = EfiGcdMemoryTypeUnaccepted;break;case EFI_RESOURCE_IO:GcdIoType = EfiGcdIoTypeIo;break;case EFI_RESOURCE_IO_RESERVED:GcdIoType = EfiGcdIoTypeReserved;break;}if (GcdMemoryType != EfiGcdMemoryTypeNonExistent) {//// Validate the Resource HOB Attributes//CoreValidateResourceDescriptorHobAttributes (ResourceHob->ResourceAttribute);//// Convert the Resource HOB Attributes to an EFI Memory Capabilities mask//Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (GcdMemoryType,ResourceHob->ResourceAttribute);Status = CoreInternalAddMemorySpace (GcdMemoryType,ResourceHob->PhysicalStart,ResourceHob->ResourceLength,Capabilities);}if (GcdIoType != EfiGcdIoTypeNonExistent) {Status = CoreAddIoSpace (GcdIoType,ResourceHob->PhysicalStart,ResourceHob->ResourceLength);}}}
8.6 从 GCD 分配第一个内存区域
  Status = CoreGetMemorySpaceDescriptor (MemoryBaseAddress, &Descriptor);if (!EFI_ERROR (Status)) {ASSERT ((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||(Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable));Status = CoreAllocateMemorySpace (EfiGcdAllocateAddress,Descriptor.GcdMemoryType,0,MemoryLength,&MemoryBaseAddress,gDxeCoreImageHandle,NULL);}
8.7 分配被占用的内存空间并更新到内存映射
遍历 HOB 列表,分配被内存分配 HOB 和固件卷 HOB 占用的内存空间并将内存分配 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) {MemoryHob   = Hob.MemoryAllocation;BaseAddress = MemoryHob->AllocDescriptor.MemoryBaseAddress;Status      = CoreGetMemorySpaceDescriptor (BaseAddress, &Descriptor);if (!EFI_ERROR (Status)) {Status = CoreAllocateMemorySpace (EfiGcdAllocateAddress,Descriptor.GcdMemoryType,0,MemoryHob->AllocDescriptor.MemoryLength,&BaseAddress,gDxeCoreImageHandle,NULL);if (!EFI_ERROR (Status) &&((Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||(Descriptor.GcdMemoryType == EfiGcdMemoryTypeMoreReliable))){CoreAddMemoryDescriptor (MemoryHob->AllocDescriptor.MemoryType,MemoryHob->AllocDescriptor.MemoryBaseAddress,RShiftU64 (MemoryHob->AllocDescriptor.MemoryLength, EFI_PAGE_SHIFT),Descriptor.Capabilities & (~EFI_MEMORY_RUNTIME));}}}if (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_FV) {FirmwareVolumeHob = Hob.FirmwareVolume;BaseAddress       = FirmwareVolumeHob->BaseAddress;Status            = CoreAllocateMemorySpace (EfiGcdAllocateAddress,EfiGcdMemoryTypeMemoryMappedIo,0,FirmwareVolumeHob->Length,&BaseAddress,gDxeCoreImageHandle,NULL);}}
8.8 添加并分配未分配的系统内存到内存服务
  Status = CoreGetMemorySpaceMap (&NumberOfDescriptors, &MemorySpaceMap);ASSERT (Status == EFI_SUCCESS);MemorySpaceMapHobList = NULL;for (Index = 0; Index < NumberOfDescriptors; Index++) {if ((MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeSystemMemory) ||(MemorySpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeMoreReliable)){if (MemorySpaceMap[Index].ImageHandle == NULL) {BaseAddress = PageAlignAddress (MemorySpaceMap[Index].BaseAddress);Length      = PageAlignLength (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length - BaseAddress);if ((Length == 0) || (MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length < BaseAddress)) {continue;}if (((UINTN)MemorySpaceMap[Index].BaseAddress <= (UINTN)(*HobStart)) &&((UINTN)(MemorySpaceMap[Index].BaseAddress + MemorySpaceMap[Index].Length) >= (UINTN)PhitHob->EfiFreeMemoryBottom)){//// Skip the memory space that covers HOB List, it should be processed// after HOB List relocation to avoid the resources allocated by others// to corrupt HOB List before its relocation.//MemorySpaceMapHobList = &MemorySpaceMap[Index];continue;}CoreAddMemoryDescriptor (EfiConventionalMemory,BaseAddress,RShiftU64 (Length, EFI_PAGE_SHIFT),MemorySpaceMap[Index].Capabilities & (~EFI_MEMORY_RUNTIME));Status = CoreAllocateMemorySpace (EfiGcdAllocateAddress,MemorySpaceMap[Index].GcdMemoryType,0,Length,&BaseAddress,gDxeCoreImageHandle,NULL);}}}
8.9 重定位 HOB 列表到已分配的系统内存(池缓冲区)中
  NewHobList = AllocateCopyPool ((UINTN)PhitHob->EfiFreeMemoryBottom - (UINTN)(*HobStart),*HobStart);ASSERT (NewHobList != NULL);*HobStart = NewHobList;gHobList  = NewHobList;if (MemorySpaceMapHobList != NULL) {//// Add and allocate the memory space that covers HOB List to the memory services// after HOB List relocation.//BaseAddress = PageAlignAddress (MemorySpaceMapHobList->BaseAddress);Length      = PageAlignLength (MemorySpaceMapHobList->BaseAddress + MemorySpaceMapHobList->Length - BaseAddress);CoreAddMemoryDescriptor (EfiConventionalMemory,BaseAddress,RShiftU64 (Length, EFI_PAGE_SHIFT),MemorySpaceMapHobList->Capabilities & (~EFI_MEMORY_RUNTIME));Status = CoreAllocateMemorySpace (EfiGcdAllocateAddress,MemorySpaceMapHobList->GcdMemoryType,0,Length,&BaseAddress,gDxeCoreImageHandle,NULL);}CoreFreePool (MemorySpaceMap);
9 分配 EFI 系统表和 EFI 运行时服务表
9.1 EFI系统表
typedef struct {////// The table header for the EFI System Table.///EFI_TABLE_HEADER                   Hdr;////// A pointer to a null terminated string that identifies the vendor/// that produces the system firmware for the platform.///CHAR16                             *FirmwareVendor;////// A firmware vendor specific value that identifies the revision/// of the system firmware for the platform.///UINT32                             FirmwareRevision;////// The handle for the active console input device. This handle must support/// EFI_SIMPLE_TEXT_INPUT_PROTOCOL and EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL. If/// there is no active console, these protocols must still be present.///EFI_HANDLE                         ConsoleInHandle;////// A pointer to the EFI_SIMPLE_TEXT_INPUT_PROTOCOL interface that is/// associated with ConsoleInHandle.///EFI_SIMPLE_TEXT_INPUT_PROTOCOL     *ConIn;////// The handle for the active console output device. This handle must support the/// EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. If there is no active console, these protocols/// must still be present.///EFI_HANDLE                         ConsoleOutHandle;////// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface/// that is associated with ConsoleOutHandle.///EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *ConOut;////// The handle for the active standard error console device./// This handle must support the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL. If there/// is no active console, this protocol must still be present.///EFI_HANDLE                         StandardErrorHandle;////// A pointer to the EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL interface/// that is associated with StandardErrorHandle.///EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *StdErr;////// A pointer to the EFI Runtime Services Table.///EFI_RUNTIME_SERVICES               *RuntimeServices;////// A pointer to the EFI Boot Services Table.///EFI_BOOT_SERVICES                  *BootServices;////// The number of system configuration tables in the buffer ConfigurationTable.///UINTN                              NumberOfTableEntries;////// A pointer to the system configuration tables./// The number of entries in the table is NumberOfTableEntries.///EFI_CONFIGURATION_TABLE            *ConfigurationTable;
} EFI_SYSTEM_TABLE;
9.2 EFI 运行时服务表
typedef struct {////// The table header for the EFI Runtime Services Table.///EFI_TABLE_HEADER                  Hdr;//// Time Services//EFI_GET_TIME                      GetTime;EFI_SET_TIME                      SetTime;EFI_GET_WAKEUP_TIME               GetWakeupTime;EFI_SET_WAKEUP_TIME               SetWakeupTime;//// Virtual Memory Services//EFI_SET_VIRTUAL_ADDRESS_MAP       SetVirtualAddressMap;EFI_CONVERT_POINTER               ConvertPointer;//// Variable Services//EFI_GET_VARIABLE                  GetVariable;EFI_GET_NEXT_VARIABLE_NAME        GetNextVariableName;EFI_SET_VARIABLE                  SetVariable;//// Miscellaneous Services//EFI_GET_NEXT_HIGH_MONO_COUNT      GetNextHighMonotonicCount;EFI_RESET_SYSTEM                  ResetSystem;//// UEFI 2.0 Capsule Services//EFI_UPDATE_CAPSULE                UpdateCapsule;EFI_QUERY_CAPSULE_CAPABILITIES    QueryCapsuleCapabilities;//// Miscellaneous UEFI 2.0 Service//EFI_QUERY_VARIABLE_INFO           QueryVariableInfo;
} EFI_RUNTIME_SERVICES;
9.3 实现流程
  gDxeCoreST = AllocateRuntimeCopyPool (sizeof (EFI_SYSTEM_TABLE), &mEfiSystemTableTemplate);ASSERT (gDxeCoreST != NULL);gDxeCoreRT = AllocateRuntimeCopyPool (sizeof (EFI_RUNTIME_SERVICES), &mEfiRuntimeServicesTableTemplate);ASSERT (gDxeCoreRT != NULL);gDxeCoreST->RuntimeServices = gDxeCoreRT;
VOID *
EFIAPI
AllocateRuntimeCopyPool (IN UINTN       AllocationSize,IN CONST VOID  *Buffer)
{VOID  *NewBuffer;NewBuffer = InternalAllocateCopyPool (EfiRuntimeServicesData, AllocationSize, Buffer);if (NewBuffer != NULL) {MemoryProfileLibRecord ((PHYSICAL_ADDRESS)(UINTN)RETURN_ADDRESS (0),MEMORY_PROFILE_ACTION_LIB_ALLOCATE_RUNTIME_COPY_POOL,EfiRuntimeServicesData,NewBuffer,AllocationSize,NULL);}return NewBuffer;
}
10 用ST更新 DXE 已加载的映像协议
  gDxeCoreLoadedImage->SystemTable = gDxeCoreST;
11 调用所有库的构造函数

  ProcessLibraryConstructorList (gDxeCoreImageHandle, gDxeCoreST);PERF_CROSSMODULE_END ("PEI");PERF_CROSSMODULE_BEGIN ("DXE");
VOID
EFIAPI
ProcessLibraryConstructorList (IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable)
{EFI_STATUS  Status;Status = BaseDebugLibSerialPortConstructor ();ASSERT_RETURN_ERROR (Status);Status = UefiBootServicesTableLibConstructor (ImageHandle, SystemTable);ASSERT_EFI_ERROR (Status);Status = UefiRuntimeServicesTableLibConstructor (ImageHandle, SystemTable);ASSERT_EFI_ERROR (Status);Status = AcpiTimerLibConstructor ();ASSERT_RETURN_ERROR (Status);Status = UefiLibConstructor (ImageHandle, SystemTable);ASSERT_EFI_ERROR (Status);Status = DxeExtractGuidedSectionLibConstructor (ImageHandle, SystemTable);ASSERT_EFI_ERROR (Status);Status = DxeDebugAgentLibConstructor (ImageHandle, SystemTable);ASSERT_EFI_ERROR (Status);Status = LzmaDecompressLibConstructor ();ASSERT_RETURN_ERROR (Status);}
11.1 初始化串口库
RETURN_STATUS
EFIAPI
BaseDebugLibSerialPortConstructor (VOID)
{return SerialPortInitialize ();
}
RETURN_STATUS
EFIAPI
SerialPortInitialize (VOID)
{UINTN  Divisor;UINT8  OutputData;UINT8  Data;//// Map 5..8 to 0..3//Data = (UINT8)(gData - (UINT8)5);   //3//// Calculate divisor for baud generator//Divisor = 115200 / gBps;   //// Set communications format//OutputData = (UINT8)((DLAB << 7) | (gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data);//10xx0103//    1              0                      0           1             3IoWrite8 (gUartBase + LCR_OFFSET, OutputData);//// Configure baud rate//IoWrite8 (gUartBase + BAUD_HIGH_OFFSET, (UINT8)(Divisor >> 8));IoWrite8 (gUartBase + BAUD_LOW_OFFSET, (UINT8)(Divisor & 0xff));//// Switch back to bank 0//OutputData = (UINT8)((gBreakSet << 6) | (gParity << 3) | (gStop << 2) | Data);IoWrite8 (gUartBase + LCR_OFFSET, OutputData);return RETURN_SUCCESS;
}
11.2 缓存启动服务表指针
EFI_STATUS
EFIAPI
UefiBootServicesTableLibConstructor (IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable)
{//// Cache the Image Handle//gImageHandle = ImageHandle;ASSERT (gImageHandle != NULL);//// Cache pointer to the EFI System Table//gST = SystemTable;ASSERT (gST != NULL);//// Cache pointer to the EFI Boot Services Table//gBS = SystemTable->BootServices;ASSERT (gBS != NULL);return EFI_SUCCESS;
}
11.3 缓存运行时服务表指针
EFI_STATUS
EFIAPI
UefiRuntimeServicesTableLibConstructor (IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable)
{//// Cache pointer to the EFI Runtime Services Table//gRT = SystemTable->RuntimeServices;ASSERT (gRT != NULL);return EFI_SUCCESS;
}
11.4 缓存 ACPI 计时器计数地址
RETURN_STATUS
EFIAPI
AcpiTimerLibConstructor (VOID)
{UINT16  HostBridgeDevId;UINTN   Pmba;UINT32  PmbaAndVal;UINT32  PmbaOrVal;UINTN   AcpiCtlReg;UINT8   AcpiEnBit;//// Query Host Bridge DID to determine platform type//HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);switch (HostBridgeDevId) {case INTEL_82441_DEVICE_ID:Pmba       = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;PmbaOrVal  = PIIX4_PMBA_VALUE;AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);AcpiEnBit  = PIIX4_PMREGMISC_PMIOSE;break;case INTEL_Q35_MCH_DEVICE_ID:Pmba       = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;PmbaOrVal  = ICH9_PMBASE_VALUE;AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);AcpiEnBit  = ICH9_ACPI_CNTL_ACPI_EN;break;case CLOUDHV_DEVICE_ID:mAcpiTimerIoAddr =  CLOUDHV_ACPI_TIMER_IO_ADDRESS;return RETURN_SUCCESS;default:DEBUG ((DEBUG_ERROR,"%a: Unknown Host Bridge Device ID: 0x%04x\n",__func__,HostBridgeDevId));ASSERT (FALSE);return RETURN_UNSUPPORTED;}//// Check to see if the Power Management Base Address is already enabled//if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {//// If the Power Management Base Address is not programmed,// then program it now.//PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);//// Enable PMBA I/O port decodes//PciOr8 (AcpiCtlReg, AcpiEnBit);}mAcpiTimerIoAddr = (PciRead32 (Pmba) & ~PMBA_RTE) + ACPI_TIMER_OFFSET;return RETURN_SUCCESS;
}
11.5 初始化通用 UEFI 辅助函数库(当前阶段为空)
EFI_STATUS
EFIAPI
UefiLibConstructor (IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable)
{return EFI_SUCCESS;
}
11.6 分配全局内存去存储已注册的 GUID 和处理器列表
RETURN_STATUS
EFIAPI
DxeExtractGuidedSectionLibConstructor (IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable)
{return ReallocateExtractHandlerTable ();
}
RETURN_STATUS
EFIAPI
ReallocateExtractHandlerTable (VOID)
{//// Reallocate memory for GuidTable//mExtractHandlerGuidTable = ReallocatePool (mMaxNumberOfExtractHandler * sizeof (GUID),(mMaxNumberOfExtractHandler + EXTRACT_HANDLER_TABLE_SIZE) * sizeof (GUID),mExtractHandlerGuidTable);if (mExtractHandlerGuidTable == NULL) {goto Done;}//// Reallocate memory for Decode handler Table//mExtractDecodeHandlerTable = ReallocatePool (mMaxNumberOfExtractHandler * sizeof (EXTRACT_GUIDED_SECTION_DECODE_HANDLER),(mMaxNumberOfExtractHandler + EXTRACT_HANDLER_TABLE_SIZE) * sizeof (EXTRACT_GUIDED_SECTION_DECODE_HANDLER),mExtractDecodeHandlerTable);if (mExtractDecodeHandlerTable == NULL) {goto Done;}//// Reallocate memory for GetInfo handler Table//mExtractGetInfoHandlerTable = ReallocatePool (mMaxNumberOfExtractHandler * sizeof (EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER),(mMaxNumberOfExtractHandler + EXTRACT_HANDLER_TABLE_SIZE) * sizeof (EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER),mExtractGetInfoHandlerTable);if (mExtractGetInfoHandlerTable == NULL) {goto Done;}//// Increase max handler number//mMaxNumberOfExtractHandler = mMaxNumberOfExtractHandler + EXTRACT_HANDLER_TABLE_SIZE;return RETURN_SUCCESS;Done:if (mExtractHandlerGuidTable != NULL) {FreePool (mExtractHandlerGuidTable);}if (mExtractDecodeHandlerTable != NULL) {FreePool (mExtractDecodeHandlerTable);}if (mExtractGetInfoHandlerTable != NULL) {FreePool (mExtractGetInfoHandlerTable);}return RETURN_OUT_OF_RESOURCES;
}
11.7 调试代理的构造函数
RETURN_STATUS
EFIAPI
DxeDebugAgentLibConstructor (IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable)
{if (mDxeCoreFlag) {//// Invoke internal constructor function only when DXE core links this library instance//InternalConstructorWorker ();}return RETURN_SUCCESS;
}
VOID
InternalConstructorWorker (VOID)
{EFI_STATUS               Status;EFI_PHYSICAL_ADDRESS     Address;BOOLEAN                  DebugTimerInterruptState;DEBUG_AGENT_MAILBOX      *Mailbox;DEBUG_AGENT_MAILBOX      *NewMailbox;EFI_HOB_GUID_TYPE        *GuidHob;EFI_VECTOR_HANDOFF_INFO  *VectorHandoffInfo;//// Check persisted vector handoff info//Status  = EFI_SUCCESS;GuidHob = GetFirstGuidHob (&gEfiVectorHandoffInfoPpiGuid);if ((GuidHob != NULL) && !mDxeCoreFlag) {//// Check if configuration table is installed or not if GUIDed HOB existed,// only when Debug Agent is not linked by DXE Core//Status = EfiGetSystemConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID **)&VectorHandoffInfo);}if ((GuidHob == NULL) || (Status != EFI_SUCCESS)) {//// Install configuration table for persisted vector handoff info if GUIDed HOB cannot be found or// configuration table does not exist//Status = gBS->InstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *)&mVectorHandoffInfoDebugAgent[0]);if (EFI_ERROR (Status)) {DEBUG ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for persisted vector handoff info!\n"));CpuDeadLoop ();}}//// Install EFI Serial IO protocol on debug port//InstallSerialIo ();Address = 0;Status  = gBS->AllocatePages (AllocateAnyPages,EfiACPIMemoryNVS,EFI_SIZE_TO_PAGES (sizeof (DEBUG_AGENT_MAILBOX) + PcdGet16 (PcdDebugPortHandleBufferSize)),&Address);if (EFI_ERROR (Status)) {DEBUG ((DEBUG_ERROR, "DebugAgent: Cannot install configuration table for mailbox!\n"));CpuDeadLoop ();}DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (FALSE);NewMailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)Address;//// Copy Mailbox and Debug Port Handle buffer to new location in ACPI NVS memory, because original Mailbox// and Debug Port Handle buffer may be free at runtime, SMM debug agent needs to access them//Mailbox = GetMailboxPointer ();CopyMem (NewMailbox, Mailbox, sizeof (DEBUG_AGENT_MAILBOX));CopyMem (NewMailbox + 1, (VOID *)(UINTN)Mailbox->DebugPortHandle, PcdGet16 (PcdDebugPortHandleBufferSize));//// Update Debug Port Handle in new Mailbox//UpdateMailboxContent (NewMailbox, DEBUG_MAILBOX_DEBUG_PORT_HANDLE_INDEX, (UINT64)(UINTN)(NewMailbox + 1));mMailboxPointer = NewMailbox;DebugTimerInterruptState = SaveAndSetDebugTimerInterrupt (DebugTimerInterruptState);Status = gBS->InstallConfigurationTable (&gEfiDebugAgentGuid, (VOID *)mMailboxPointer);if (EFI_ERROR (Status)) {DEBUG ((DEBUG_ERROR, "DebugAgent: Failed to install configuration for mailbox!\n"));CpuDeadLoop ();}
}
11.8 注册 Lzma 解压和 Lzma 解压前信息获取处理器
EFI_STATUS
EFIAPI
LzmaDecompressLibConstructor (VOID)
{return ExtractGuidedSectionRegisterHandlers (&gLzmaCustomDecompressGuid,LzmaGuidedSectionGetInfo,LzmaGuidedSectionExtraction);
}
RETURN_STATUS
EFIAPI
ExtractGuidedSectionRegisterHandlers (IN CONST  GUID                                     *SectionGuid,IN        EXTRACT_GUIDED_SECTION_GET_INFO_HANDLER  GetInfoHandler,IN        EXTRACT_GUIDED_SECTION_DECODE_HANDLER    DecodeHandler)
{UINT32  Index;VOID    *GuidData;//// Check input parameter.//ASSERT (SectionGuid != NULL);ASSERT (GetInfoHandler != NULL);ASSERT (DecodeHandler != NULL);//// Search the match registered GetInfo handler for the input guided section.//for (Index = 0; Index < mNumberOfExtractHandler; Index++) {if (CompareGuid (&mExtractHandlerGuidTable[Index], SectionGuid)) {//// If the guided handler has been registered before, only update its handler.//mExtractDecodeHandlerTable[Index]  = DecodeHandler;mExtractGetInfoHandlerTable[Index] = GetInfoHandler;return RETURN_SUCCESS;}}//// Check the global table is enough to contain new Handler.//if (mNumberOfExtractHandler >= mMaxNumberOfExtractHandler) {if (ReallocateExtractHandlerTable () != RETURN_SUCCESS) {return RETURN_OUT_OF_RESOURCES;}}//// Register new Handler and guid value.//CopyGuid (&mExtractHandlerGuidTable[mNumberOfExtractHandler], SectionGuid);mExtractDecodeHandlerTable[mNumberOfExtractHandler]    = DecodeHandler;mExtractGetInfoHandlerTable[mNumberOfExtractHandler++] = GetInfoHandler;//// Install the Guided Section GUID configuration table to record the GUID itself.// Then the content of the configuration table buffer will be the same as the GUID value itself.//GuidData = AllocateCopyPool (sizeof (GUID), (VOID *)SectionGuid);if (GuidData != NULL) {gBS->InstallConfigurationTable ((EFI_GUID *)SectionGuid, GuidData);}return RETURN_SUCCESS;
}
12 报告 DXE Core 映像信息
  ZeroMem (&ImageContext, sizeof (ImageContext));ImageContext.ImageAddress  = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreLoadedImage->ImageBase;ImageContext.PdbPointer    = PeCoffLoaderGetPdbPointer ((VOID *)(UINTN)ImageContext.ImageAddress);ImageContext.SizeOfHeaders = PeCoffGetSizeOfHeaders ((VOID *)(UINTN)ImageContext.ImageAddress);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;PeCoffLoaderRelocateImageExtraAction (&ImageContext);
13 安装 DXE 服务表到配置表
  Status = CoreInstallConfigurationTable (&gEfiDxeServicesTableGuid, gDxeCoreDS);ASSERT_EFI_ERROR (Status);
EFI_STATUS
EFIAPI
CoreInstallConfigurationTable (IN EFI_GUID  *Guid,IN VOID      *Table)
{UINTN                    Index;EFI_CONFIGURATION_TABLE  *EfiConfigurationTable;EFI_CONFIGURATION_TABLE  *OldTable;//// If Guid is NULL, then this operation cannot be performed//if (Guid == NULL) {return EFI_INVALID_PARAMETER;}EfiConfigurationTable = gDxeCoreST->ConfigurationTable;//// Search all the table for an entry that matches Guid//for (Index = 0; Index < gDxeCoreST->NumberOfTableEntries; Index++) {if (CompareGuid (Guid, &(gDxeCoreST->ConfigurationTable[Index].VendorGuid))) {break;}}if (Index < gDxeCoreST->NumberOfTableEntries) {//// A match was found, so this is either a modify or a delete operation//if (Table != NULL) {//// If Table is not NULL, then this is a modify operation.// Modify the table entry and return.//gDxeCoreST->ConfigurationTable[Index].VendorTable = Table;//// Signal Configuration Table change//CoreNotifySignalList (Guid);return EFI_SUCCESS;}//// A match was found and Table is NULL, so this is a delete operation.//gDxeCoreST->NumberOfTableEntries--;//// Copy over deleted entry//CopyMem (&(EfiConfigurationTable[Index]),&(gDxeCoreST->ConfigurationTable[Index + 1]),(gDxeCoreST->NumberOfTableEntries - Index) * sizeof (EFI_CONFIGURATION_TABLE));} else {//// No matching GUIDs were found, so this is an add operation.//if (Table == NULL) {//// If Table is NULL on an add operation, then return an error.//return EFI_NOT_FOUND;}//// Assume that Index == gDxeCoreST->NumberOfTableEntries//if ((Index * sizeof (EFI_CONFIGURATION_TABLE)) >= mSystemTableAllocateSize) {//// Allocate a table with one additional entry.//mSystemTableAllocateSize += (CONFIG_TABLE_SIZE_INCREASED * sizeof (EFI_CONFIGURATION_TABLE));EfiConfigurationTable     = AllocateRuntimePool (mSystemTableAllocateSize);if (EfiConfigurationTable == NULL) {//// If a new table could not be allocated, then return an error.//return EFI_OUT_OF_RESOURCES;}if (gDxeCoreST->ConfigurationTable != NULL) {//// Copy the old table to the new table.//CopyMem (EfiConfigurationTable,gDxeCoreST->ConfigurationTable,Index * sizeof (EFI_CONFIGURATION_TABLE));//// Record the old table pointer.//OldTable = gDxeCoreST->ConfigurationTable;//// As the CoreInstallConfigurationTable() may be re-entered by CoreFreePool()// in its calling stack, updating System table to the new table pointer must// be done before calling CoreFreePool() to free the old table.// It can make sure the gDxeCoreST->ConfigurationTable point to the new table// and avoid the errors of use-after-free to the old table by the reenter of// CoreInstallConfigurationTable() in CoreFreePool()'s calling stack.//gDxeCoreST->ConfigurationTable = EfiConfigurationTable;//// Free the old table after updating System Table to the new table pointer.//CoreFreePool (OldTable);} else {//// Update System Table//gDxeCoreST->ConfigurationTable = EfiConfigurationTable;}}//// Fill in the new entry//CopyGuid ((VOID *)&EfiConfigurationTable[Index].VendorGuid, Guid);EfiConfigurationTable[Index].VendorTable = Table;//// This is an add operation, so increment the number of table entries//gDxeCoreST->NumberOfTableEntries++;}//// Fix up the CRC-32 in the EFI System Table//CalculateEfiHdrCrc (&gDxeCoreST->Hdr);//// Signal Configuration Table change//CoreNotifySignalList (Guid);return EFI_SUCCESS;
}
14 安装 HOB 列表到配置表
  Status = CoreInstallConfigurationTable (&gEfiHobListGuid, HobStart);ASSERT_EFI_ERROR (Status);
与前面安装DXE服务表流程相同
15 安装内存类型信息表到配置表
  Status = CoreInstallConfigurationTable (&gEfiHobListGuid, HobStart);ASSERT_EFI_ERROR (Status);
与前面安装DXE服务表流程相同
16 若支持固定地址加载模块功能则安装对应配置表
  if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {Status = CoreInstallConfigurationTable (&gLoadFixedAddressConfigurationTableGuid, &gLoadModuleAtFixAddressConfigurationTable);ASSERT_EFI_ERROR (Status);}
OVMF不支持
17 DXE 入口点可用即报告状态代码
  REPORT_STATUS_CODE (EFI_PROGRESS_CODE,(EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_ENTRY_POINT));
EFI_STATUS
EFIAPI
ReportStatusCode (IN EFI_STATUS_CODE_TYPE   Type,IN EFI_STATUS_CODE_VALUE  Value)
{return InternalReportStatusCode (Type, Value, 0, &gEfiCallerIdGuid, NULL);
}
EFI_STATUS
InternalReportStatusCode (IN EFI_STATUS_CODE_TYPE   Type,IN EFI_STATUS_CODE_VALUE  Value,IN UINT32                 Instance,IN CONST EFI_GUID         *CallerId OPTIONAL,IN EFI_STATUS_CODE_DATA   *Data     OPTIONAL)
{if ((ReportProgressCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE)) ||(ReportErrorCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE)) ||(ReportDebugCodeEnabled () && (((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE))){//// If mReportStatusCodeLibStatusCodeProtocol is NULL, then check if Report Status Code Protocol is available in system.//InternalGetReportStatusCode ();if (mReportStatusCodeLibStatusCodeProtocol == NULL) {return EFI_UNSUPPORTED;}//// A Report Status Code Protocol is present in system, so pass in all the parameters to the service.//return mReportStatusCodeLibStatusCodeProtocol->ReportStatusCode (Type, Value, Instance, (EFI_GUID *)CallerId, Data);}return EFI_UNSUPPORTED;
}
VOID
InternalGetReportStatusCode (VOID)
{EFI_STATUS  Status;if (mReportStatusCodeLibStatusCodeProtocol != NULL) {return;}//// Check gBS just in case ReportStatusCode is called before gBS is initialized.//if ((gBS != NULL) && (gBS->LocateProtocol != NULL)) {Status = gBS->LocateProtocol (&gEfiStatusCodeRuntimeProtocolGuid, NULL, (VOID **)&mReportStatusCodeLibStatusCodeProtocol);if (EFI_ERROR (Status)) {mReportStatusCodeLibStatusCodeProtocol = NULL;}}
}
18 创建对齐系统表指针结构并安装调试映像信息配置表
对齐系统表指针结构用于外部调试器定位系统表
  CoreInitializeDebugImageInfoTable ();CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL,gDxeCoreLoadedImage,gDxeCoreImageHandle);
18.1 CoreInitializeDebugImageInfoTable
VOID
CoreInitializeDebugImageInfoTable (VOID)
{EFI_STATUS            Status;UINTN                 Pages;EFI_PHYSICAL_ADDRESS  Memory;UINTN                 AlignedMemory;UINTN                 AlignmentMask;UINTN                 UnalignedPages;UINTN                 RealPages;//// Allocate 4M aligned page for the structure and fill in the data.// Ideally we would update the CRC now as well, but the service may not yet be available.// See comments in the CoreUpdateDebugTableCrc32() function below for details.//Pages         = EFI_SIZE_TO_PAGES (sizeof (EFI_SYSTEM_TABLE_POINTER));AlignmentMask = SIZE_4MB - 1;RealPages     = Pages + EFI_SIZE_TO_PAGES (SIZE_4MB);//// Attempt to allocate memory below PcdMaxEfiSystemTablePointerAddress// If PcdMaxEfiSystemTablePointerAddress is 0, then allocate memory below// MAX_ADDRESS//Memory = PcdGet64 (PcdMaxEfiSystemTablePointerAddress);if (Memory == 0) {Memory = MAX_ADDRESS;}Status = CoreAllocatePages (AllocateMaxAddress,EfiBootServicesData,RealPages,&Memory);if (EFI_ERROR (Status)) {if (PcdGet64 (PcdMaxEfiSystemTablePointerAddress) != 0) {DEBUG ((DEBUG_INFO, "Allocate memory for EFI_SYSTEM_TABLE_POINTER below PcdMaxEfiSystemTablePointerAddress failed. \Retry to allocate memroy as close to the top of memory as feasible.\n"));}//// If the initial memory allocation fails, then reattempt allocation// as close to the top of memory as feasible.//Status = CoreAllocatePages (AllocateAnyPages,EfiBootServicesData,RealPages,&Memory);ASSERT_EFI_ERROR (Status);if (EFI_ERROR (Status)) {return;}}//// Free overallocated pages//AlignedMemory  = ((UINTN)Memory + AlignmentMask) & ~AlignmentMask;UnalignedPages = EFI_SIZE_TO_PAGES (AlignedMemory - (UINTN)Memory);if (UnalignedPages > 0) {//// Free first unaligned page(s).//Status = CoreFreePages (Memory, UnalignedPages);ASSERT_EFI_ERROR (Status);}Memory         = AlignedMemory + EFI_PAGES_TO_SIZE (Pages);UnalignedPages = RealPages - Pages - UnalignedPages;if (UnalignedPages > 0) {//// Free last unaligned page(s).//Status = CoreFreePages (Memory, UnalignedPages);ASSERT_EFI_ERROR (Status);}//// Set mDebugTable to the 4MB aligned allocated pages//mDebugTable = (EFI_SYSTEM_TABLE_POINTER  *)(AlignedMemory);ASSERT (mDebugTable != NULL);//// Initialize EFI_SYSTEM_TABLE_POINTER structure//mDebugTable->Signature          = EFI_SYSTEM_TABLE_SIGNATURE;mDebugTable->EfiSystemTableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)gDxeCoreST;mDebugTable->Crc32              = 0;//// Install the EFI_SYSTEM_TABLE_POINTER structure in the EFI System// Configuration Table//Status = CoreInstallConfigurationTable (&gEfiDebugImageInfoTableGuid, &mDebugInfoTableHeader);ASSERT_EFI_ERROR (Status);
}
分配一个 4 MiB 对齐的页面并填充数据 -> 尝试在 PcdMaxEfiSystemTablePointerAddress 以下分配内存 -> 释放超额分配的页面 -> 将 mDebugTable 设置为 4MB 对齐的已分配页面 -> 初始化 mDebugTable 结构 -> 安装DebugInfoTableHeader到配置表
18.2 CoreNewDebugImageInfoEntry
VOID
CoreNewDebugImageInfoEntry (IN  UINT32                     ImageInfoType,IN  EFI_LOADED_IMAGE_PROTOCOL  *LoadedImage,IN  EFI_HANDLE                 ImageHandle)
{EFI_DEBUG_IMAGE_INFO  *Table;EFI_DEBUG_IMAGE_INFO  *NewTable;UINTN                 Index;UINTN                 TableSize;//// Set the flag indicating that we're in the process of updating the table.//mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;Table = mDebugInfoTableHeader.EfiDebugImageInfoTable;if (mDebugInfoTableHeader.TableSize >= mMaxTableEntries) {////  Table is full, so re-allocate another page for a larger table...//TableSize = mMaxTableEntries * EFI_DEBUG_TABLE_ENTRY_SIZE;NewTable  = AllocateZeroPool (TableSize + EFI_PAGE_SIZE);if (NewTable == NULL) {mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;return;}//// Copy the old table into the new one//CopyMem (NewTable, Table, TableSize);//// Free the old table//CoreFreePool (Table);//// Update the table header//Table                                        = NewTable;mDebugInfoTableHeader.EfiDebugImageInfoTable = NewTable;//// Enlarge the max table entries and set the first empty entry index to// be the original max table entries.//mMaxTableEntries += EFI_PAGE_SIZE / EFI_DEBUG_TABLE_ENTRY_SIZE;}// We always put the next entry at the end of the currently consumed table (i.e. first free entry)Index = mDebugInfoTableHeader.TableSize;//// Allocate data for new entry//Table[Index].NormalImage = AllocateZeroPool (sizeof (EFI_DEBUG_IMAGE_INFO_NORMAL));if (Table[Index].NormalImage != NULL) {//// Update the entry//Table[Index].NormalImage->ImageInfoType               = (UINT32)ImageInfoType;Table[Index].NormalImage->LoadedImageProtocolInstance = LoadedImage;Table[Index].NormalImage->ImageHandle                 = ImageHandle;//// Increase the number of EFI_DEBUG_IMAGE_INFO elements and set the mDebugInfoTable in modified status.//mDebugInfoTableHeader.TableSize++;mDebugInfoTableHeader.UpdateStatus |= EFI_DEBUG_IMAGE_INFO_TABLE_MODIFIED;}mDebugInfoTableHeader.UpdateStatus &= ~EFI_DEBUG_IMAGE_INFO_UPDATE_IN_PROGRESS;
}
19 初始化事件服务
  Status = CoreInitializeEventServices ();ASSERT_EFI_ERROR (Status);
EFI_STATUS
CoreInitializeEventServices (VOID)
{UINTN  Index;for (Index = 0; Index <= TPL_HIGH_LEVEL; Index++) {InitializeListHead (&gEventQueue[Index]);}CoreInitializeTimer ();CoreCreateEventEx (EVT_NOTIFY_SIGNAL,TPL_NOTIFY,EfiEventEmptyFunction,NULL,&gIdleLoopEventGuid,&gIdleLoopEvent);return EFI_SUCCESS;
}
19.1 初始化双向链表的头节点
LIST_ENTRY *
EFIAPI
InitializeListHead (IN OUT  LIST_ENTRY  *ListHead){ASSERT (ListHead != NULL);ListHead->ForwardLink = ListHead;ListHead->BackLink    = ListHead;return ListHead;
}
19.2 初始化计时器支持
EFI_STATUS
EFIAPI
CoreCreateEventInternal (IN UINT32            Type,IN EFI_TPL           NotifyTpl,IN EFI_EVENT_NOTIFY  NotifyFunction  OPTIONAL,IN CONST VOID        *NotifyContext  OPTIONAL,IN CONST EFI_GUID    *EventGroup     OPTIONAL,OUT EFI_EVENT        *Event)
{EFI_STATUS  Status;IEVENT      *IEvent;INTN        Index;if (Event == NULL) {return EFI_INVALID_PARAMETER;}//// Check to make sure no reserved flags are set//Status = EFI_INVALID_PARAMETER;for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) {if (Type == mEventTable[Index]) {Status = EFI_SUCCESS;break;}}if (EFI_ERROR (Status)) {return EFI_INVALID_PARAMETER;}//// Convert Event type for pre-defined Event groups//if (EventGroup != NULL) {//// For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE// are not valid//if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) {return EFI_INVALID_PARAMETER;}if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) {Type = EVT_SIGNAL_EXIT_BOOT_SERVICES;} else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) {Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE;}} else {//// Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping//if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) {EventGroup = &gEfiEventExitBootServicesGuid;} else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) {EventGroup = &gEfiEventVirtualAddressChangeGuid;}}//// If it's a notify type of event, check its parameters//if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) {//// Check for an invalid NotifyFunction or NotifyTpl//if ((NotifyFunction == NULL) ||(NotifyTpl <= TPL_APPLICATION) ||(NotifyTpl >= TPL_HIGH_LEVEL)){return EFI_INVALID_PARAMETER;}} else {//// No notification needed, zero ignored values//NotifyTpl      = 0;NotifyFunction = NULL;NotifyContext  = NULL;}//// Allocate and initialize a new event structure.//if ((Type & EVT_RUNTIME) != 0) {IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT));} else {IEvent = AllocateZeroPool (sizeof (IEVENT));}if (IEvent == NULL) {return EFI_OUT_OF_RESOURCES;}IEvent->Signature = EVENT_SIGNATURE;IEvent->Type      = Type;IEvent->NotifyTpl      = NotifyTpl;IEvent->NotifyFunction = NotifyFunction;IEvent->NotifyContext  = (VOID *)NotifyContext;if (EventGroup != NULL) {CopyGuid (&IEvent->EventGroup, EventGroup);IEvent->ExFlag |= EVT_EXFLAG_EVENT_GROUP;}*Event = IEvent;if ((Type & EVT_RUNTIME) != 0) {//// Keep a list of all RT events so we can tell the RT AP.//IEvent->RuntimeData.Type           = Type;IEvent->RuntimeData.NotifyTpl      = NotifyTpl;IEvent->RuntimeData.NotifyFunction = NotifyFunction;IEvent->RuntimeData.NotifyContext  = (VOID *)NotifyContext;//// Work around the bug in the Platform Init specification (v1.7), reported// as Mantis#2017: "EFI_RUNTIME_EVENT_ENTRY.Event" should have type// EFI_EVENT, not (EFI_EVENT*). The PI spec documents the field correctly// as "The EFI_EVENT returned by CreateEvent()", but the type of the field// doesn't match the natural language description. Therefore we need an// explicit cast here.//IEvent->RuntimeData.Event = (EFI_EVENT *)IEvent;InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link);}CoreAcquireEventLock ();if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) {//// The Event's NotifyFunction must be queued whenever the event is signaled//InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink);}CoreReleaseEventLock ();//// Done//return EFI_SUCCESS;
}
19.3 为系统空闲循环提供通知事件
  CoreCreateEventEx (EVT_NOTIFY_SIGNAL,TPL_NOTIFY,EfiEventEmptyFunction,NULL,&gIdleLoopEventGuid,&gIdleLoopEvent);
20 给调试代理提供初始化事件的机会
  InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_CORE_LATE, HobStart, NULL);MemoryProfileInstallProtocol ();CoreInitializeMemoryAttributesTable ();CoreInitializeMemoryProtection ();
20.1 初始化后期Debug代理
VOID
EFIAPI
InitializeDebugAgent (IN UINT32                InitFlag,IN VOID                  *Context  OPTIONAL,IN DEBUG_AGENT_CONTINUE  Function  OPTIONAL)
{UINT64               *MailboxLocation;DEBUG_AGENT_MAILBOX  *Mailbox;BOOLEAN              InterruptStatus;VOID                 *HobList;IA32_DESCRIPTOR      IdtDescriptor;IA32_DESCRIPTOR      *Ia32Idtr;IA32_IDT_ENTRY       *Ia32IdtEntry;BOOLEAN              PeriodicMode;UINTN                TimerCycle;DEBUG((DEBUG_INFO,"DxeDebugAgentLib\n"));if (InitFlag == DEBUG_AGENT_INIT_DXE_AP) {//// Check if CPU APIC Timer is working, otherwise initialize it.//InitializeLocalApicSoftwareEnable (TRUE);GetApicTimerState (NULL, &PeriodicMode, NULL);TimerCycle = GetApicTimerInitCount ();if (!PeriodicMode || (TimerCycle == 0)) {InitializeDebugTimer (NULL, FALSE);}//// Invoked by AP, enable interrupt to let AP could receive IPI from other processors//EnableInterrupts ();return;}//// Disable Debug Timer interrupt//SaveAndSetDebugTimerInterrupt (FALSE);//// Save and disable original interrupt status//InterruptStatus = SaveAndDisableInterrupts ();//// Try to get mailbox firstly//HobList         = NULL;Mailbox         = NULL;MailboxLocation = NULL;switch (InitFlag) {case DEBUG_AGENT_INIT_DXE_LOAD://// Check if Debug Agent has been initialized before//if (IsDebugAgentInitialzed ()) {DEBUG ((DEBUG_INFO, "Debug Agent: The former agent will be overwritten by the new one!\n"));}mMultiProcessorDebugSupport = TRUE;//// Save original IDT table//AsmReadIdtr (&IdtDescriptor);mSaveIdtTableSize = IdtDescriptor.Limit + 1;mSavedIdtTable    = AllocateCopyPool (mSaveIdtTableSize, (VOID *)IdtDescriptor.Base);//// Check if Debug Agent initialized in DXE phase//Mailbox = GetMailboxFromConfigurationTable ();if (Mailbox == NULL) {//// Try to get mailbox from GUIDed HOB build in PEI//HobList = GetHobList ();Mailbox = GetMailboxFromHob (HobList);}//// Set up Debug Agent Environment and try to connect HOST if required//SetupDebugAgentEnvironment (Mailbox);//// For DEBUG_AGENT_INIT_S3, needn't to install configuration table and EFI Serial IO protocol// For DEBUG_AGENT_INIT_DXE_CORE, InternalConstructorWorker() will invoked in Constructor()//InternalConstructorWorker ();//// Enable Debug Timer interrupt//SaveAndSetDebugTimerInterrupt (TRUE);//// Enable interrupt to receive Debug Timer interrupt//EnableInterrupts ();mDebugAgentInitialized = TRUE;FindAndReportModuleImageInfo (SIZE_4KB);*(EFI_STATUS *)Context = EFI_SUCCESS;break;case DEBUG_AGENT_INIT_DXE_UNLOAD:if (mDebugAgentInitialized) {if (IsHostAttached ()) {*(EFI_STATUS *)Context = EFI_ACCESS_DENIED;//// Enable Debug Timer interrupt again//SaveAndSetDebugTimerInterrupt (TRUE);} else {//// Restore original IDT table//AsmReadIdtr (&IdtDescriptor);IdtDescriptor.Limit = (UINT16)(mSaveIdtTableSize - 1);CopyMem ((VOID *)IdtDescriptor.Base, mSavedIdtTable, mSaveIdtTableSize);AsmWriteIdtr (&IdtDescriptor);FreePool (mSavedIdtTable);mDebugAgentInitialized = FALSE;*(EFI_STATUS *)Context = EFI_SUCCESS;}} else {*(EFI_STATUS *)Context = EFI_NOT_STARTED;}//// Restore interrupt state.//SetInterruptState (InterruptStatus);break;case DEBUG_AGENT_INIT_DXE_CORE:mDxeCoreFlag                = TRUE;mMultiProcessorDebugSupport = TRUE;//// Try to get mailbox from GUIDed HOB build in PEI//HobList = Context;Mailbox = GetMailboxFromHob (HobList);//// Set up Debug Agent Environment and try to connect HOST if required//SetupDebugAgentEnvironment (Mailbox);//// Enable Debug Timer interrupt//SaveAndSetDebugTimerInterrupt (TRUE);//// Enable interrupt to receive Debug Timer interrupt//EnableInterrupts ();break;case DEBUG_AGENT_INIT_S3:if (Context != NULL) {Ia32Idtr        =  (IA32_DESCRIPTOR *)Context;Ia32IdtEntry    = (IA32_IDT_ENTRY *)(Ia32Idtr->Base);MailboxLocation = (UINT64 *)((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetLow +((UINTN)Ia32IdtEntry[DEBUG_MAILBOX_VECTOR].Bits.OffsetHigh << 16));Mailbox = (DEBUG_AGENT_MAILBOX *)(UINTN)(*MailboxLocation);VerifyMailboxChecksum (Mailbox);}//// Save Mailbox pointer in global variable//mMailboxPointer = Mailbox;//// Set up Debug Agent Environment and try to connect HOST if required//SetupDebugAgentEnvironment (Mailbox);//// Disable interrupt//DisableInterrupts ();FindAndReportModuleImageInfo (SIZE_4KB);if (GetDebugFlag (DEBUG_AGENT_FLAG_BREAK_BOOT_SCRIPT) == 1) {//// If Boot Script entry break is set, code will be break at here.//CpuBreakpoint ();}break;case DEBUG_AGENT_INIT_REINITIALIZE:case DEBUG_AGENT_INIT_DXE_CORE_LATE:break;default://// Only DEBUG_AGENT_INIT_PREMEM_SEC and DEBUG_AGENT_INIT_POSTMEM_SEC are allowed for this// Debug Agent library instance.//DEBUG ((DEBUG_ERROR, "Debug Agent: The InitFlag value is not allowed!\n"));CpuDeadLoop ();break;}
}
20.2 安装内存配置文件协议
VOID
MemoryProfileInstallProtocol (VOID)
{EFI_HANDLE  Handle;EFI_STATUS  Status;if (!IS_UEFI_MEMORY_PROFILE_ENABLED) {return;}Handle = NULL;Status = CoreInstallMultipleProtocolInterfaces (&Handle,&gEdkiiMemoryProfileGuid,&mProfileProtocol,NULL);ASSERT_EFI_ERROR (Status);
}
20.3 初始化内存状态表支持
VOID
EFIAPI
CoreInitializeMemoryAttributesTable (VOID)
{EFI_STATUS  Status;EFI_EVENT   ReadyToBootEvent;EFI_EVENT   EndOfDxeEvent;//// Construct the table at ReadyToBoot.//Status = CoreCreateEventInternal (EVT_NOTIFY_SIGNAL,TPL_CALLBACK,InstallMemoryAttributesTableOnReadyToBoot,NULL,&gEfiEventReadyToBootGuid,&ReadyToBootEvent);ASSERT_EFI_ERROR (Status);//// Construct the initial table at EndOfDxe,// then SMM can consume this information.// Use TPL_NOTIFY here, as such SMM code (TPL_CALLBACK)// can run after it.//Status = CoreCreateEventInternal (EVT_NOTIFY_SIGNAL,TPL_NOTIFY,InstallMemoryAttributesTableOnEndOfDxe,NULL,&gEfiEndOfDxeEventGroupGuid,&EndOfDxeEvent);ASSERT_EFI_ERROR (Status);return;
}
创建两个事件,分别在 ReadyToBoot 和 EndOfDxe 阶段触发
20.4 初始化内存保护支持
VOID
EFIAPI
CoreInitializeMemoryProtection (VOID)
{EFI_STATUS  Status;EFI_EVENT   Event;EFI_EVENT   EndOfDxeEvent;VOID        *Registration;mImageProtectionPolicy = PcdGet32 (PcdImageProtectionPolicy);InitializeListHead (&mProtectedImageRecordList);//// Sanity check the PcdDxeNxMemoryProtectionPolicy setting:// - code regions should have no EFI_MEMORY_XP attribute// - EfiConventionalMemory and EfiBootServicesData should use the//   same attribute//ASSERT ((GetPermissionAttributeForMemoryType (EfiBootServicesCode) & EFI_MEMORY_XP) == 0);ASSERT ((GetPermissionAttributeForMemoryType (EfiRuntimeServicesCode) & EFI_MEMORY_XP) == 0);ASSERT ((GetPermissionAttributeForMemoryType (EfiLoaderCode) & EFI_MEMORY_XP) == 0);ASSERT (GetPermissionAttributeForMemoryType (EfiBootServicesData) ==GetPermissionAttributeForMemoryType (EfiConventionalMemory));Status = CoreCreateEvent (EVT_NOTIFY_SIGNAL,TPL_CALLBACK,MemoryProtectionCpuArchProtocolNotify,NULL,&Event);ASSERT_EFI_ERROR (Status);//// Register for protocol notifactions on this event//Status = CoreRegisterProtocolNotify (&gEfiCpuArchProtocolGuid,Event,&Registration);ASSERT_EFI_ERROR (Status);// Register an event to populate the memory attribute protocolStatus = CoreCreateEvent (EVT_NOTIFY_SIGNAL,TPL_CALLBACK,MemoryAttributeProtocolNotify,NULL,&Event);// if we fail to create the event or the protocol notify, we should still continue, we won't be able to query the// memory attributes on FreePages(), so we may encounter a driver or bootloader that has not set attributes back to// RW, but this matches the state of the world before this protocol was introduced, so it is not a regression.if (EFI_ERROR (Status)) {DEBUG ((DEBUG_ERROR, "%a - Failed to create event for the Memory Attribute Protocol notification: %r\n", __func__, Status));ASSERT_EFI_ERROR (Status);}// Register for protocol notificationStatus = CoreRegisterProtocolNotify (&gEfiMemoryAttributeProtocolGuid,Event,&Registration);if (EFI_ERROR (Status)) {DEBUG ((DEBUG_ERROR, "%a - Failed to register for the Memory Attribute Protocol notification: %r\n", __func__, Status));ASSERT_EFI_ERROR (Status);}//// Register a callback to disable NULL pointer detection at EndOfDxe//if ((PcdGet8 (PcdNullPointerDetectionPropertyMask) & (BIT0|BIT7))== (BIT0|BIT7)){Status = CoreCreateEventEx (EVT_NOTIFY_SIGNAL,TPL_NOTIFY,DisableNullDetectionAtTheEndOfDxe,NULL,&gEfiEndOfDxeEventGroupGuid,&EndOfDxeEvent);ASSERT_EFI_ERROR (Status);}return;
}
21 再次获取持久化向量传递信息并安装配置表
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);Status = CoreInstallConfigurationTable (&gEfiVectorHandoffTableGuid, (VOID *)VectorInfo);ASSERT_EFI_ERROR (Status);}
22 发布 EFI、Tiano 和自定义解压缩协议
  Status = CoreInstallMultipleProtocolInterfaces (&mDecompressHandle,&gEfiDecompressProtocolGuid,&gEfiDecompress,NULL);ASSERT_EFI_ERROR (Status);
EFI_STATUS
EFIAPI
CoreInstallMultipleProtocolInterfaces (IN OUT EFI_HANDLE  *Handle,...)
{VA_LIST     Args;EFI_STATUS  Status;EFI_GUID    *Protocol;VOID        *Interface;EFI_TPL     OldTpl;UINTN       Index;EFI_HANDLE  OldHandle;if (Handle == NULL) {return EFI_INVALID_PARAMETER;}//// Syncronize with notifcations.//OldTpl    = CoreRaiseTpl (TPL_NOTIFY);OldHandle = *Handle;//// Check for duplicate device path and install the protocol interfaces//VA_START (Args, Handle);for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {//// If protocol is NULL, then it's the end of the list//Protocol = VA_ARG (Args, EFI_GUID *);if (Protocol == NULL) {break;}Interface = VA_ARG (Args, VOID *);//// Make sure you are installing on top a device path that has already been added.//if (CompareGuid (Protocol, &gEfiDevicePathProtocolGuid) &&IsDevicePathInstalled (Interface)){Status = EFI_ALREADY_STARTED;continue;}//// Install it//Status = CoreInstallProtocolInterface (Handle, Protocol, EFI_NATIVE_INTERFACE, Interface);}VA_END (Args);//// If there was an error, remove all the interfaces that were installed without any errors//if (EFI_ERROR (Status)) {//// Reset the va_arg back to the first argument.//VA_START (Args, Handle);for ( ; Index > 1; Index--) {Protocol  = VA_ARG (Args, EFI_GUID *);Interface = VA_ARG (Args, VOID *);CoreUninstallProtocolInterface (*Handle, Protocol, Interface);}VA_END (Args);*Handle = OldHandle;}//// Done//CoreRestoreTpl (OldTpl);return Status;
}
23 为架构协议和可选协议创建事件

 CoreNotifyOnProtocolInstallation ();
VOID
CoreNotifyOnProtocolInstallation (VOID)
{CoreNotifyOnProtocolEntryTable (mArchProtocols);CoreNotifyOnProtocolEntryTable (mOptionalProtocols);
}
VOID
CoreNotifyOnProtocolEntryTable (EFI_CORE_PROTOCOL_NOTIFY_ENTRY  *Entry)
{EFI_STATUS  Status;for ( ; Entry->ProtocolGuid != NULL; Entry++) {//// Create the event//Status = CoreCreateEvent (EVT_NOTIFY_SIGNAL,TPL_CALLBACK,GenericProtocolNotify,Entry,&Entry->Event);ASSERT_EFI_ERROR (Status);//// Register for protocol notifactions on this event//Status = CoreRegisterProtocolNotify (Entry->ProtocolGuid,Entry->Event,&Entry->Registration);ASSERT_EFI_ERROR (Status);}
}
24 生成固件卷协议
  Status = FwVolBlockDriverInit (gDxeCoreImageHandle, gDxeCoreST);ASSERT_EFI_ERROR (Status);Status = FwVolDriverInit (gDxeCoreImageHandle, gDxeCoreST);ASSERT_EFI_ERROR (Status);
24.1 FwVolBlockDriverInit
EFI_STATUS
EFIAPI
FwVolBlockDriverInit (IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable)
{EFI_PEI_HOB_POINTERS  FvHob;EFI_PEI_HOB_POINTERS  Fv3Hob;UINT32                AuthenticationStatus;//// Core Needs Firmware Volumes to function//FvHob.Raw = GetHobList ();while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {AuthenticationStatus = 0;//// Get the authentication status propagated from PEI-phase to DXE.//Fv3Hob.Raw = GetHobList ();while ((Fv3Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV3, Fv3Hob.Raw)) != NULL) {if ((Fv3Hob.FirmwareVolume3->BaseAddress == FvHob.FirmwareVolume->BaseAddress) &&(Fv3Hob.FirmwareVolume3->Length == FvHob.FirmwareVolume->Length)){AuthenticationStatus = Fv3Hob.FirmwareVolume3->AuthenticationStatus;break;}Fv3Hob.Raw = GET_NEXT_HOB (Fv3Hob);}//// Produce an FVB protocol for it//ProduceFVBProtocolOnBuffer (FvHob.FirmwareVolume->BaseAddress, FvHob.FirmwareVolume->Length, NULL, AuthenticationStatus, NULL);FvHob.Raw = GET_NEXT_HOB (FvHob);}return EFI_SUCCESS;
}
24.2 FwVolDriverInit
EFI_STATUS
EFIAPI
FwVolDriverInit (IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable)
{gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (&gEfiFirmwareVolumeBlockProtocolGuid,TPL_CALLBACK,NotifyFwVolBlock,NULL,&gEfiFwVolBlockNotifyReg);return EFI_SUCCESS;
}
EFI_EVENT
EFIAPI
EfiCreateProtocolNotifyEvent (IN  EFI_GUID          *ProtocolGuid,IN  EFI_TPL           NotifyTpl,IN  EFI_EVENT_NOTIFY  NotifyFunction,IN  VOID              *NotifyContext   OPTIONAL,OUT VOID              **Registration)
{EFI_STATUS  Status;EFI_EVENT   Event;ASSERT (ProtocolGuid != NULL);ASSERT (NotifyFunction != NULL);ASSERT (Registration != NULL);//// Create the event//Status = gBS->CreateEvent (EVT_NOTIFY_SIGNAL,NotifyTpl,NotifyFunction,NotifyContext,&Event);ASSERT_EFI_ERROR (Status);//// Register for protocol notifications on this event//Status = gBS->RegisterProtocolNotify (ProtocolGuid,Event,Registration);ASSERT_EFI_ERROR (Status);//// Kick the event so we will perform an initial pass of// current installed drivers//gBS->SignalEvent (Event);return Event;
}
25 生成段提取协议
  Status = InitializeSectionExtraction (gDxeCoreImageHandle, gDxeCoreST);ASSERT_EFI_ERROR (Status);
EFI_STATUS
EFIAPI
InitializeSectionExtraction (IN EFI_HANDLE        ImageHandle,IN EFI_SYSTEM_TABLE  *SystemTable)
{EFI_STATUS  Status;EFI_GUID    *ExtractHandlerGuidTable;UINTN       ExtractHandlerNumber;//// Get custom extract guided section method guid list//ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);Status = EFI_SUCCESS;//// Install custom guided extraction protocol//while (ExtractHandlerNumber-- > 0) {Status = CoreInstallProtocolInterface (&mSectionExtractionHandle,&ExtractHandlerGuidTable[ExtractHandlerNumber],EFI_NATIVE_INTERFACE,&mCustomGuidedSectionExtractionProtocol);ASSERT_EFI_ERROR (Status);}return Status;
}
26 初始化 DXE 调度器(建立回调机制)
  CoreInitializeDispatcher ();
VOID
CoreInitializeDispatcher (VOID)
{PERF_FUNCTION_BEGIN ();mFwVolEvent = EfiCreateProtocolNotifyEvent (&gEfiFirmwareVolume2ProtocolGuid,TPL_CALLBACK,CoreFwVolEventProtocolNotify,NULL,&mFwVolEventRegistration);PERF_FUNCTION_END ();
}
27 调用DXE调度器
  CoreDispatcher ();
EFI_STATUS
EFIAPI
CoreDispatcher (VOID)
{EFI_STATUS             Status;EFI_STATUS             ReturnStatus;LIST_ENTRY             *Link;EFI_CORE_DRIVER_ENTRY  *DriverEntry;BOOLEAN                ReadyToRun;EFI_EVENT              DxeDispatchEvent;PERF_FUNCTION_BEGIN ();if (gDispatcherRunning) {//// If the dispatcher is running don't let it be restarted.//return EFI_ALREADY_STARTED;}gDispatcherRunning = TRUE;Status = CoreCreateEventEx (EVT_NOTIFY_SIGNAL,TPL_NOTIFY,EfiEventEmptyFunction,NULL,&gEfiEventDxeDispatchGuid,&DxeDispatchEvent);if (EFI_ERROR (Status)) {return Status;}ReturnStatus = EFI_NOT_FOUND;do {//// Drain the Scheduled Queue//while (!IsListEmpty (&mScheduledQueue)) {DriverEntry = CR (mScheduledQueue.ForwardLink,EFI_CORE_DRIVER_ENTRY,ScheduledLink,EFI_CORE_DRIVER_ENTRY_SIGNATURE);//// Load the DXE Driver image into memory. If the Driver was transitioned from// Untrused to Scheduled it would have already been loaded so we may need to// skip the LoadImage//if ((DriverEntry->ImageHandle == NULL) && !DriverEntry->IsFvImage) {DEBUG ((DEBUG_INFO, "Loading driver %g\n", &DriverEntry->FileName));Status = CoreLoadImage (FALSE,gDxeCoreImageHandle,DriverEntry->FvFileDevicePath,NULL,0,&DriverEntry->ImageHandle);//// Update the driver state to reflect that it's been loaded//if (EFI_ERROR (Status)) {CoreAcquireDispatcherLock ();if (Status == EFI_SECURITY_VIOLATION) {//// Take driver from Scheduled to Untrused state//DriverEntry->Untrusted = TRUE;} else {//// The DXE Driver could not be loaded, and do not attempt to load or start it again.// Take driver from Scheduled to Initialized.//// This case include the Never Trusted state if EFI_ACCESS_DENIED is returned//DriverEntry->Initialized = TRUE;}DriverEntry->Scheduled = FALSE;RemoveEntryList (&DriverEntry->ScheduledLink);CoreReleaseDispatcherLock ();//// If it's an error don't try the StartImage//continue;}}CoreAcquireDispatcherLock ();DriverEntry->Scheduled   = FALSE;DriverEntry->Initialized = TRUE;RemoveEntryList (&DriverEntry->ScheduledLink);CoreReleaseDispatcherLock ();if (DriverEntry->IsFvImage) {//// Produce a firmware volume block protocol for FvImage so it gets dispatched from.//Status = CoreProcessFvImageFile (DriverEntry->Fv, DriverEntry->FvHandle, &DriverEntry->FileName);} else {REPORT_STATUS_CODE_WITH_EXTENDED_DATA (EFI_PROGRESS_CODE,(EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN),&DriverEntry->ImageHandle,sizeof (DriverEntry->ImageHandle));ASSERT (DriverEntry->ImageHandle != NULL);Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);REPORT_STATUS_CODE_WITH_EXTENDED_DATA (EFI_PROGRESS_CODE,(EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END),&DriverEntry->ImageHandle,sizeof (DriverEntry->ImageHandle));}ReturnStatus = EFI_SUCCESS;}//// Now DXE Dispatcher finished one round of dispatch, signal an event group// so that SMM Dispatcher get chance to dispatch SMM Drivers which depend// on UEFI protocols//if (!EFI_ERROR (ReturnStatus)) {CoreSignalEvent (DxeDispatchEvent);}//// Search DriverList for items to place on Scheduled Queue//ReadyToRun = FALSE;for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);if (DriverEntry->DepexProtocolError) {//// If Section Extraction Protocol did not let the Depex be read before retry the read//Status = CoreGetDepexSectionAndPreProccess (DriverEntry);}if (DriverEntry->Dependent) {if (CoreIsSchedulable (DriverEntry)) {CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);ReadyToRun = TRUE;}} else {if (DriverEntry->Unrequested) {DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));DEBUG ((DEBUG_DISPATCH, "  SOR                                             = Not Requested\n"));DEBUG ((DEBUG_DISPATCH, "  RESULT = FALSE\n"));}}}} while (ReadyToRun);//// Close DXE dispatch Event//CoreCloseEvent (DxeDispatchEvent);gDispatcherRunning = FALSE;PERF_FUNCTION_END ();return ReturnStatus;
}
27.1 判断设置条件
  PERF_FUNCTION_BEGIN ();if (gDispatcherRunning) {//// If the dispatcher is running don't let it be restarted.//return EFI_ALREADY_STARTED;}gDispatcherRunning = TRUE;
27.2 创建事件
  Status = CoreCreateEventEx (EVT_NOTIFY_SIGNAL,TPL_NOTIFY,EfiEventEmptyFunction,NULL,&gEfiEventDxeDispatchGuid,&DxeDispatchEvent);if (EFI_ERROR (Status)) {return Status;}ReturnStatus = EFI_NOT_FOUND;
27.3 耗尽调度队列
一次性把当前调度队列里所有已就绪的驱动映像全部加载并执行,直到队列为空
流程:
- 获取 DriverEntry
 - 加载 DXE Driver 映像到内存
 
https://blog.csdn.net/degen_/article/details/154175907
- 转交控制权给已加载映像的入口点
 
DXE Driver:
- DEVICEPATHDXE
 - PCDDXE
 - AMDSEVDXE
 - REPORTSTATUSCODEROUTERRUNTIMEDXE
 - RUNTIMEDXE
 - SECURITYSTUBDXE
 - EBCDXE
 - CPUIO2DXE
 - CPUDXE
 - INCOMPATIBLEPCIDEVICESUPPORTDXE
 - PCIHOTPLUGINITDXE
 - RESETSYSTEMRUNTIMEDXE
 - METRONOME
 - HIIDATABASE
 - ACPITABLEDXE
 - S3SAVESTATEDXE
 - DPCDXE
 - IOMMUDXE
 - VIRTHSTIDXE
 - SMMACCESS2DXE
 - SMMCOMMUNICATIONBUFFERDXE
 - RNGDXE
 - STATUSCODEHANDLERRUNTIMEDXE
 - LOCALAPICTIMERDXE
 - PCIHOSTBRIDGEDXE
 - SETUPBROWSER
 - SMBIOSDXE
 - QEMUFWCFGACPIPLATFORM
 - LOGODXE
 - QEMURAMFBDXE
 - SMMCONTROL2DXE
 - CPUS3DATADXE
 - WATCHDOGTIMER
 - DRIVERHEALTHMANAGERDXE
 - RAMDISKDXE
 - DISPLAYENGINE
 - SMBIOSPLATFORMDXE
 - PISMMIPL
 - PISMMCORE
 - CPUIO2SMM
 - SMMLOCKBOX
 - PISMMCPUDXESMM
 - FVBSERVICESSMM
 - VARIABLESMM
 - CPUHOTPLUGSMM
 - SMMFAULTTOLERANTWRITEDXE
 - BOOTSCRIPTEXECUTORDXE
 - VARIABLESMMRUNTIMEDXE
 - PCRTC
 - SECUREBOOTCONFIGDXE
 - MONOTONICCOUNTERRUNTIMEDXE
 - CAPSULERUNTIMEDXE
 - BDSDXE
 - PLATFORMDXE
 - PCIBUSDXE
 - VIRTIOPCIDEVICEDXE
 - VIRTIO10
 - VIRTIOBLKDXE
 - VIRTIOSCSIDXE
 - VIRTIOSERIALDXE
 - VIRTIOKEYBOARDDXE
 - CONPLATFORMDXE
 - CONSPLITTERDXE
 - GRAPHICSCONSOLEDXE
 - TERMINALDXE
 - QEMUKERNELLOADERFSDXE
 - DISKIODXE
 - PARTITIONDXE
 - ENGLISHDXE
 - SCSIBUS
 - SCSIDISK
 - SATACONTROLLER
 - ATAATAPIPASSTHRUDXE
 - ATABUSDXE
 - NVMEXPRESSDXE
 - SIOBUSDXE
 - PS2KEYBOARDDXE
 - BOOTGRAPHICSRESOURCETABLEDXE
 - FAT
 - UDFDXE
 - VIRTIOFSDXE
 - HASH2DXECRYPTO
 - VIRTIONETDXE
 - UHCIDXE
 - EHCIDXE
 - XHCIDXE
 - USBBUSDXE
 - USBKBDXE
 - USBMASSSTORAGEDXE
 - QEMUVIDEODXE
 - VIRTIOGPUDXE
 - VIRTIORNGDXE
 - SDMMCPCIHCDXE
 - SDDXE
 - EMMCDXE
 
27.4 整个系统正在等下一个阶段被唤醒

