进入点
DxeCoreEntryPoint = 0x6f0fdf0
DOS Header = 06f0d000

C
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 ();
}
C
VOID
EFIAPI
ProcessModuleEntryPointList (
IN VOID *HobStart
)
{
DxeMain (HobStart);
}
DxeMain
代码总览:
C
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 设置默认的异常处理程序
C
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异常处理程序
C
EFI_STATUS
EFIAPI
InitializeCpuExceptionHandlers (
IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
)
{
InitializeSpinLock (&mExceptionHandlerData.DisplayMessageSpinLock);
return InitializeCpuExceptionHandlersWorker (VectorInfo, &mExceptionHandlerData);
}
2 设置栈保护
C
if (PcdGetBool (PcdCpuStackGuard)) {
Status = InitializeSeparateExceptionStacks (NULL, NULL);
ASSERT_EFI_ERROR (Status);
}
C
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代理
C
InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_CORE, HobStart, NULL);
C
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 "
C
CoreInitializeMemoryServices (&HobStart, &MemoryBaseAddress, &MemoryLength);
MemoryProfileInit (HobStart);
C
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 List
if (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 列表在哪、有多大、当前内存布局怎样
C
Hob.Raw = *HobStart;
ASSERT (GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_HANDOFF);
4.2 初始化池
在 DXE 内核里划出一块常驻内存,做成固定大小的空闲链表
C
CoreInitializePool ();
C
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
C
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 是否有效

C
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 在内存类型信息里要的页数
C
MinimalMemorySizeNeeded = MINIMUM_INITIAL_MEMORY_SIZE + CalculateTotalMemoryBinSizeNeeded ();
C
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
C
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 List
if (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 位掩码
C
if ((Attributes & EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) == EFI_RESOURCE_ATTRIBUTE_MORE_RELIABLE) {
Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeMoreReliable, Attributes);
} else {
Capabilities = CoreConvertResourceDescriptorHobAttributesToCapabilities (EfiGcdMemoryTypeSystemMemory, Attributes);
}
4.8 为所需的内存类型划分区域
C
CoreAddMemoryDescriptor (
EfiConventionalMemory,
BaseAddress,
RShiftU64 (Length, EFI_PAGE_SHIFT),
Capabilities
);
*MemoryBaseAddress = BaseAddress;
*MemoryLength = Length;
C
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 初始化内存配置文件
C
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 启动句柄服务
C
EFI_STATUS
CoreInitializeHandleServices (
VOID
)
{
gOrderedHandleList = OrderedCollectionInit (PointerCompare, PointerCompare);
if (gOrderedHandleList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
return EFI_SUCCESS;
}
C
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 启动映像服务
C
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
注册协议通知
8 初始化全局一致性域(GCD)服务
GCD服务用于管理平台中的系统内存、内存映射I/O和I/O资源。调度服务用于调用DXE调度器,并修改DXE调度器跟踪的DXE驱动的状态。
C
Status = CoreInitializeGcdServices (&HobStart, MemoryBaseAddress, MemoryLength);
C
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 precedence
if ((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
C
PhitHob = (EFI_HOB_HANDOFF_INFO_TABLE *)(*HobStart);
8.2 获取 CPU 在 I/O 和内存空间中的地址线数量
通过CPU HOB
C
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 "
C
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 "
C
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 中
C
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 precedence
if ((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 分配第一个内存区域
C
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 更新到内存映射中
C
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 添加并分配未分配的系统内存到内存服务
C
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 列表到已分配的系统内存(池缓冲区)中
C
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系统表
C
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 运行时服务表
C
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 实现流程
C
gDxeCoreST = AllocateRuntimeCopyPool (sizeof (EFI_SYSTEM_TABLE), &mEfiSystemTableTemplate);
ASSERT (gDxeCoreST != NULL);
gDxeCoreRT = AllocateRuntimeCopyPool (sizeof (EFI_RUNTIME_SERVICES), &mEfiRuntimeServicesTableTemplate);
ASSERT (gDxeCoreRT != NULL);
gDxeCoreST->RuntimeServices = gDxeCoreRT;
C
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 已加载的映像协议
C
gDxeCoreLoadedImage->SystemTable = gDxeCoreST;
11 调用所有库的构造函数

C
ProcessLibraryConstructorList (gDxeCoreImageHandle, gDxeCoreST);
PERF_CROSSMODULE_END ("PEI");
PERF_CROSSMODULE_BEGIN ("DXE");
C
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 初始化串口库
C
RETURN_STATUS
EFIAPI
BaseDebugLibSerialPortConstructor (
VOID
)
{
return SerialPortInitialize ();
}
C
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 3
IoWrite8 (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 缓存启动服务表指针
C
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 缓存运行时服务表指针
C
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 计时器计数地址
C
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 辅助函数库(当前阶段为空)
C
EFI_STATUS
EFIAPI
UefiLibConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return EFI_SUCCESS;
}
11.6 分配全局内存去存储已注册的 GUID 和处理器列表
C
RETURN_STATUS
EFIAPI
DxeExtractGuidedSectionLibConstructor (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return ReallocateExtractHandlerTable ();
}
C
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 调试代理的构造函数
C
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;
}
C
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 解压前信息获取处理器
C
EFI_STATUS
EFIAPI
LzmaDecompressLibConstructor (
VOID
)
{
return ExtractGuidedSectionRegisterHandlers (
&gLzmaCustomDecompressGuid,
LzmaGuidedSectionGetInfo,
LzmaGuidedSectionExtraction
);
}
C
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 映像信息
C
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 服务表到配置表
C
Status = CoreInstallConfigurationTable (&gEfiDxeServicesTableGuid, gDxeCoreDS);
ASSERT_EFI_ERROR (Status);
C
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 列表到配置表
C
Status = CoreInstallConfigurationTable (&gEfiHobListGuid, HobStart);
ASSERT_EFI_ERROR (Status);
与前面安装DXE服务表流程相同
15 安装内存类型信息表到配置表
C
Status = CoreInstallConfigurationTable (&gEfiHobListGuid, HobStart);
ASSERT_EFI_ERROR (Status);
与前面安装DXE服务表流程相同
16 若支持固定地址加载模块功能则安装对应配置表
C
if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
Status = CoreInstallConfigurationTable (&gLoadFixedAddressConfigurationTableGuid, &gLoadModuleAtFixAddressConfigurationTable);
ASSERT_EFI_ERROR (Status);
}
OVMF不支持
17 DXE 入口点可用即报告状态代码
C
REPORT_STATUS_CODE (
EFI_PROGRESS_CODE,
(EFI_SOFTWARE_DXE_CORE | EFI_SW_DXE_CORE_PC_ENTRY_POINT)
);
C
EFI_STATUS
EFIAPI
ReportStatusCode (
IN EFI_STATUS_CODE_TYPE Type,
IN EFI_STATUS_CODE_VALUE Value
)
{
return InternalReportStatusCode (Type, Value, 0, &gEfiCallerIdGuid, NULL);
}
C
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;
}
C
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 创建对齐系统表指针结构并安装调试映像信息配置表
对齐系统表指针结构用于外部调试器定位系统表
C
CoreInitializeDebugImageInfoTable ();
CoreNewDebugImageInfoEntry (
EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL,
gDxeCoreLoadedImage,
gDxeCoreImageHandle
);
18.1 CoreInitializeDebugImageInfoTable
C
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
C
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 初始化事件服务
C
Status = CoreInitializeEventServices ();
ASSERT_EFI_ERROR (Status);
C
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 初始化双向链表的头节点
C
LIST_ENTRY *
EFIAPI
InitializeListHead (
IN OUT LIST_ENTRY *ListHead
)
{
ASSERT (ListHead != NULL);
ListHead->ForwardLink = ListHead;
ListHead->BackLink = ListHead;
return ListHead;
}
19.2 初始化计时器支持
C
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 为系统空闲循环提供通知事件
C
CoreCreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
EfiEventEmptyFunction,
NULL,
&gIdleLoopEventGuid,
&gIdleLoopEvent
);
20 给调试代理提供初始化事件的机会
C
InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_CORE_LATE, HobStart, NULL);
MemoryProfileInstallProtocol ();
CoreInitializeMemoryAttributesTable ();
CoreInitializeMemoryProtection ();
20.1 初始化后期Debug代理
C
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 安装内存配置文件协议
C
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 初始化内存状态表支持
C
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 初始化内存保护支持
C
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 protocol
Status = 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 notification
Status = 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 获取持久化向量传递信息,并安装配置表。
C
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 和自定义解压缩协议
C
Status = CoreInstallMultipleProtocolInterfaces (
&mDecompressHandle,
&gEfiDecompressProtocolGuid,
&gEfiDecompress,
NULL
);
ASSERT_EFI_ERROR (Status);
C
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 为架构协议和可选协议创建事件

C
CoreNotifyOnProtocolInstallation ();
C
VOID
CoreNotifyOnProtocolInstallation (
VOID
)
{
CoreNotifyOnProtocolEntryTable (mArchProtocols);
CoreNotifyOnProtocolEntryTable (mOptionalProtocols);
}
C
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 生成固件卷协议
C
Status = FwVolBlockDriverInit (gDxeCoreImageHandle, gDxeCoreST);
ASSERT_EFI_ERROR (Status);
Status = FwVolDriverInit (gDxeCoreImageHandle, gDxeCoreST);
ASSERT_EFI_ERROR (Status);
24.1 FwVolBlockDriverInit
C
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
C
EFI_STATUS
EFIAPI
FwVolDriverInit (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
gEfiFwVolBlockEvent = EfiCreateProtocolNotifyEvent (
&gEfiFirmwareVolumeBlockProtocolGuid,
TPL_CALLBACK,
NotifyFwVolBlock,
NULL,
&gEfiFwVolBlockNotifyReg
);
return EFI_SUCCESS;
}
C
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 生成段提取协议
C
Status = InitializeSectionExtraction (gDxeCoreImageHandle, gDxeCoreST);
ASSERT_EFI_ERROR (Status);
C
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 调度器(建立回调机制)
C
CoreInitializeDispatcher ();
C
VOID
CoreInitializeDispatcher (
VOID
)
{
PERF_FUNCTION_BEGIN ();
mFwVolEvent = EfiCreateProtocolNotifyEvent (
&gEfiFirmwareVolume2ProtocolGuid,
TPL_CALLBACK,
CoreFwVolEventProtocolNotify,
NULL,
&mFwVolEventRegistration
);
PERF_FUNCTION_END ();
}
27 调用DXE调度器
C
CoreDispatcher ();
C
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 判断设置条件
C
PERF_FUNCTION_BEGIN ();
if (gDispatcherRunning) {
//
// If the dispatcher is running don't let it be restarted.
//
return EFI_ALREADY_STARTED;
}
gDispatcherRunning = TRUE;
27.2 创建事件
C
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 映像到内存
- 转交控制权给已加载映像的入口点
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 整个系统正在等下一个阶段被唤醒
