Files
system76-edk2/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
Patrick Rudolph 1e5e58d39b UefiPayloadPkg/UefiPayloadEntry: Improve bootloader memrange parsing
Currently several DXE crash due to invalid memory resource settings.
The PciHostBridgeDxe which expects the MMCONF and PCI Aperature
to be EfiMemoryMappedIO, but currently those regions are (partly)
mapped as EfiReservedMemoryType.

coreboot and slimbootloader provide an e820 compatible memory map,
which doesn't work well with EDK2 as the e820 spec is missing MMIO regions.
In e820 'reserved' could either mean "DRAM used by boot firmware" or "MMIO
in use and not detectable by OS".

Guess Top of lower usable DRAM (TOLUD) by walking the bootloader provided
memory ranges. Memory types of RAM, ACPI and ACPI NVS below 4 GiB are used
to increment TOLUD and reserved memory ranges touching TOLUD at the base
are also assumed to be reserved DRAM, which increment TOLUD.

Then mark everything reserved below TOLUD as EfiReservedMemoryType and
everything reserved above TOLUD as EfiMemoryMappedIO.

This fixes assertions seen in PciHostBridgeDxe.

Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
Reviewed-by: Maurice Ma <maurice.ma@intel.com>
Reviewed-by: Guo Dong <guo.dong@intel.com>
2021-06-22 18:04:36 +00:00

621 lines
21 KiB
C

/** @file
Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "UefiPayloadEntry.h"
STATIC UINT32 mTopOfLowerUsableDram = 0;
/**
Callback function to build resource descriptor HOB
This function build a HOB based on the memory map entry info.
It creates only EFI_RESOURCE_MEMORY_MAPPED_IO and EFI_RESOURCE_MEMORY_RESERVED
resources.
@param MemoryMapEntry Memory map entry info got from bootloader.
@param Params A pointer to ACPI_BOARD_INFO.
@retval EFI_SUCCESS Successfully build a HOB.
@retval EFI_INVALID_PARAMETER Invalid parameter provided.
**/
EFI_STATUS
MemInfoCallbackMmio (
IN MEMROY_MAP_ENTRY *MemoryMapEntry,
IN VOID *Params
)
{
EFI_PHYSICAL_ADDRESS Base;
EFI_RESOURCE_TYPE Type;
UINT64 Size;
EFI_RESOURCE_ATTRIBUTE_TYPE Attribue;
ACPI_BOARD_INFO *AcpiBoardInfo;
AcpiBoardInfo = (ACPI_BOARD_INFO *)Params;
if (AcpiBoardInfo == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// Skip types already handled in MemInfoCallback
//
if (MemoryMapEntry->Type == E820_RAM || MemoryMapEntry->Type == E820_ACPI) {
return EFI_SUCCESS;
}
if (MemoryMapEntry->Base == AcpiBoardInfo->PcieBaseAddress) {
//
// MMCONF is always MMIO
//
Type = EFI_RESOURCE_MEMORY_MAPPED_IO;
} else if (MemoryMapEntry->Base < mTopOfLowerUsableDram) {
//
// It's in DRAM and thus must be reserved
//
Type = EFI_RESOURCE_MEMORY_RESERVED;
} else if ((MemoryMapEntry->Base < 0x100000000ULL) && (MemoryMapEntry->Base >= mTopOfLowerUsableDram)) {
//
// It's not in DRAM, must be MMIO
//
Type = EFI_RESOURCE_MEMORY_MAPPED_IO;
} else {
Type = EFI_RESOURCE_MEMORY_RESERVED;
}
Base = MemoryMapEntry->Base;
Size = MemoryMapEntry->Size;
Attribue = EFI_RESOURCE_ATTRIBUTE_PRESENT |
EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
EFI_RESOURCE_ATTRIBUTE_TESTED |
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE;
BuildResourceDescriptorHob (Type, Attribue, (EFI_PHYSICAL_ADDRESS)Base, Size);
DEBUG ((DEBUG_INFO , "buildhob: base = 0x%lx, size = 0x%lx, type = 0x%x\n", Base, Size, Type));
if (MemoryMapEntry->Type == E820_UNUSABLE ||
MemoryMapEntry->Type == E820_DISABLED) {
BuildMemoryAllocationHob (Base, Size, EfiUnusableMemory);
} else if (MemoryMapEntry->Type == E820_PMEM) {
BuildMemoryAllocationHob (Base, Size, EfiPersistentMemory);
}
return EFI_SUCCESS;
}
/**
Callback function to find TOLUD (Top of Lower Usable DRAM)
Estimate where TOLUD (Top of Lower Usable DRAM) resides. The exact position
would require platform specific code.
@param MemoryMapEntry Memory map entry info got from bootloader.
@param Params Not used for now.
@retval EFI_SUCCESS Successfully updated mTopOfLowerUsableDram.
**/
EFI_STATUS
FindToludCallback (
IN MEMROY_MAP_ENTRY *MemoryMapEntry,
IN VOID *Params
)
{
//
// This code assumes that the memory map on this x86 machine below 4GiB is continous
// until TOLUD. In addition it assumes that the bootloader provided memory tables have
// no "holes" and thus the first memory range not covered by e820 marks the end of
// usable DRAM. In addition it's assumed that every reserved memory region touching
// usable RAM is also covering DRAM, everything else that is marked reserved thus must be
// MMIO not detectable by bootloader/OS
//
//
// Skip memory types not RAM or reserved
//
if ((MemoryMapEntry->Type == E820_UNUSABLE) || (MemoryMapEntry->Type == E820_DISABLED) ||
(MemoryMapEntry->Type == E820_PMEM)) {
return EFI_SUCCESS;
}
//
// Skip resources above 4GiB
//
if ((MemoryMapEntry->Base + MemoryMapEntry->Size) > 0x100000000ULL) {
return EFI_SUCCESS;
}
if ((MemoryMapEntry->Type == E820_RAM) || (MemoryMapEntry->Type == E820_ACPI) ||
(MemoryMapEntry->Type == E820_NVS)) {
//
// It's usable DRAM. Update TOLUD.
//
if (mTopOfLowerUsableDram < (MemoryMapEntry->Base + MemoryMapEntry->Size)) {
mTopOfLowerUsableDram = (UINT32)(MemoryMapEntry->Base + MemoryMapEntry->Size);
}
} else {
//
// It might be 'reserved DRAM' or 'MMIO'.
//
// If it touches usable DRAM at Base assume it's DRAM as well,
// as it could be bootloader installed tables, TSEG, GTT, ...
//
if (mTopOfLowerUsableDram == MemoryMapEntry->Base) {
mTopOfLowerUsableDram = (UINT32)(MemoryMapEntry->Base + MemoryMapEntry->Size);
}
}
return EFI_SUCCESS;
}
/**
Callback function to build resource descriptor HOB
This function build a HOB based on the memory map entry info.
Only add EFI_RESOURCE_SYSTEM_MEMORY.
@param MemoryMapEntry Memory map entry info got from bootloader.
@param Params Not used for now.
@retval RETURN_SUCCESS Successfully build a HOB.
**/
EFI_STATUS
MemInfoCallback (
IN MEMROY_MAP_ENTRY *MemoryMapEntry,
IN VOID *Params
)
{
EFI_PHYSICAL_ADDRESS Base;
EFI_RESOURCE_TYPE Type;
UINT64 Size;
EFI_RESOURCE_ATTRIBUTE_TYPE Attribue;
//
// Skip everything not known to be usable DRAM.
// It will be added later.
//
if ((MemoryMapEntry->Type != E820_RAM) && (MemoryMapEntry->Type != E820_ACPI) &&
(MemoryMapEntry->Type != E820_NVS)) {
return RETURN_SUCCESS;
}
Type = EFI_RESOURCE_SYSTEM_MEMORY;
Base = MemoryMapEntry->Base;
Size = MemoryMapEntry->Size;
Attribue = EFI_RESOURCE_ATTRIBUTE_PRESENT |
EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
EFI_RESOURCE_ATTRIBUTE_TESTED |
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE;
if (Base >= BASE_4GB) {
// Remove tested attribute to avoid DXE core to dispatch driver to memory above 4GB
Attribue &= ~EFI_RESOURCE_ATTRIBUTE_TESTED;
}
BuildResourceDescriptorHob (Type, Attribue, (EFI_PHYSICAL_ADDRESS)Base, Size);
DEBUG ((DEBUG_INFO , "buildhob: base = 0x%lx, size = 0x%lx, type = 0x%x\n", Base, Size, Type));
if (MemoryMapEntry->Type == E820_ACPI) {
BuildMemoryAllocationHob (Base, Size, EfiACPIReclaimMemory);
} else if (MemoryMapEntry->Type == E820_NVS) {
BuildMemoryAllocationHob (Base, Size, EfiACPIMemoryNVS);
}
return RETURN_SUCCESS;
}
/**
Find the board related info from ACPI table
@param AcpiTableBase ACPI table start address in memory
@param AcpiBoardInfo Pointer to the acpi board info strucutre
@retval RETURN_SUCCESS Successfully find out all the required information.
@retval RETURN_NOT_FOUND Failed to find the required info.
**/
RETURN_STATUS
ParseAcpiInfo (
IN UINT64 AcpiTableBase,
OUT ACPI_BOARD_INFO *AcpiBoardInfo
)
{
EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
UINT32 *Entry32;
UINTN Entry32Num;
EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
UINT64 *Entry64;
UINTN Entry64Num;
UINTN Idx;
UINT32 *Signature;
EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER *MmCfgHdr;
EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE *MmCfgBase;
Rsdp = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)(UINTN)AcpiTableBase;
DEBUG ((DEBUG_INFO, "Rsdp at 0x%p\n", Rsdp));
DEBUG ((DEBUG_INFO, "Rsdt at 0x%x, Xsdt at 0x%lx\n", Rsdp->RsdtAddress, Rsdp->XsdtAddress));
//
// Search Rsdt First
//
Fadt = NULL;
MmCfgHdr = NULL;
Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->RsdtAddress);
if (Rsdt != NULL) {
Entry32 = (UINT32 *)(Rsdt + 1);
Entry32Num = (Rsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 2;
for (Idx = 0; Idx < Entry32Num; Idx++) {
Signature = (UINT32 *)(UINTN)Entry32[Idx];
if (*Signature == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
Fadt = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *)Signature;
DEBUG ((DEBUG_INFO, "Found Fadt in Rsdt\n"));
}
if (*Signature == EFI_ACPI_5_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE) {
MmCfgHdr = (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER *)Signature;
DEBUG ((DEBUG_INFO, "Found MM config address in Rsdt\n"));
}
if ((Fadt != NULL) && (MmCfgHdr != NULL)) {
goto Done;
}
}
}
//
// Search Xsdt Second
//
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->XsdtAddress);
if (Xsdt != NULL) {
Entry64 = (UINT64 *)(Xsdt + 1);
Entry64Num = (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >> 3;
for (Idx = 0; Idx < Entry64Num; Idx++) {
Signature = (UINT32 *)(UINTN)Entry64[Idx];
if (*Signature == EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
Fadt = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *)Signature;
DEBUG ((DEBUG_INFO, "Found Fadt in Xsdt\n"));
}
if (*Signature == EFI_ACPI_5_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE) {
MmCfgHdr = (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER *)Signature;
DEBUG ((DEBUG_INFO, "Found MM config address in Xsdt\n"));
}
if ((Fadt != NULL) && (MmCfgHdr != NULL)) {
goto Done;
}
}
}
if (Fadt == NULL) {
return RETURN_NOT_FOUND;
}
Done:
AcpiBoardInfo->PmCtrlRegBase = Fadt->Pm1aCntBlk;
AcpiBoardInfo->PmTimerRegBase = Fadt->PmTmrBlk;
AcpiBoardInfo->ResetRegAddress = Fadt->ResetReg.Address;
AcpiBoardInfo->ResetValue = Fadt->ResetValue;
AcpiBoardInfo->PmEvtBase = Fadt->Pm1aEvtBlk;
AcpiBoardInfo->PmGpeEnBase = Fadt->Gpe0Blk + Fadt->Gpe0BlkLen / 2;
if (MmCfgHdr != NULL) {
MmCfgBase = (EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE *)((UINT8*) MmCfgHdr + sizeof (*MmCfgHdr));
AcpiBoardInfo->PcieBaseAddress = MmCfgBase->BaseAddress;
AcpiBoardInfo->PcieBaseSize = (MmCfgBase->EndBusNumber + 1 - MmCfgBase->StartBusNumber) * 4096 * 32 * 8;
} else {
AcpiBoardInfo->PcieBaseAddress = 0;
AcpiBoardInfo->PcieBaseSize = 0;
}
DEBUG ((DEBUG_INFO, "PmCtrl Reg 0x%lx\n", AcpiBoardInfo->PmCtrlRegBase));
DEBUG ((DEBUG_INFO, "PmTimer Reg 0x%lx\n", AcpiBoardInfo->PmTimerRegBase));
DEBUG ((DEBUG_INFO, "Reset Reg 0x%lx\n", AcpiBoardInfo->ResetRegAddress));
DEBUG ((DEBUG_INFO, "Reset Value 0x%x\n", AcpiBoardInfo->ResetValue));
DEBUG ((DEBUG_INFO, "PmEvt Reg 0x%lx\n", AcpiBoardInfo->PmEvtBase));
DEBUG ((DEBUG_INFO, "PmGpeEn Reg 0x%lx\n", AcpiBoardInfo->PmGpeEnBase));
DEBUG ((DEBUG_INFO, "PcieBaseAddr 0x%lx\n", AcpiBoardInfo->PcieBaseAddress));
DEBUG ((DEBUG_INFO, "PcieBaseSize 0x%lx\n", AcpiBoardInfo->PcieBaseSize));
//
// Verify values for proper operation
//
ASSERT(Fadt->Pm1aCntBlk != 0);
ASSERT(Fadt->PmTmrBlk != 0);
ASSERT(Fadt->ResetReg.Address != 0);
ASSERT(Fadt->Pm1aEvtBlk != 0);
ASSERT(Fadt->Gpe0Blk != 0);
DEBUG_CODE_BEGIN ();
BOOLEAN SciEnabled;
//
// Check the consistency of SCI enabling
//
//
// Get SCI_EN value
//
if (Fadt->Pm1CntLen == 4) {
SciEnabled = (IoRead32 (Fadt->Pm1aCntBlk) & BIT0)? TRUE : FALSE;
} else {
//
// if (Pm1CntLen == 2), use 16 bit IO read;
// if (Pm1CntLen != 2 && Pm1CntLen != 4), use 16 bit IO read as a fallback
//
SciEnabled = (IoRead16 (Fadt->Pm1aCntBlk) & BIT0)? TRUE : FALSE;
}
if (!(Fadt->Flags & EFI_ACPI_5_0_HW_REDUCED_ACPI) &&
(Fadt->SmiCmd == 0) &&
!SciEnabled) {
//
// The ACPI enabling status is inconsistent: SCI is not enabled but ACPI
// table does not provide a means to enable it through FADT->SmiCmd
//
DEBUG ((DEBUG_ERROR, "ERROR: The ACPI enabling status is inconsistent: SCI is not"
" enabled but the ACPI table does not provide a means to enable it through FADT->SmiCmd."
" This may cause issues in OS.\n"));
}
DEBUG_CODE_END ();
return RETURN_SUCCESS;
}
/**
It will build HOBs based on information from bootloaders.
@retval EFI_SUCCESS If it completed successfully.
@retval Others If it failed to build required HOBs.
**/
EFI_STATUS
BuildHobFromBl (
VOID
)
{
EFI_STATUS Status;
SYSTEM_TABLE_INFO SysTableInfo;
SYSTEM_TABLE_INFO *NewSysTableInfo;
ACPI_BOARD_INFO AcpiBoardInfo;
ACPI_BOARD_INFO *NewAcpiBoardInfo;
EFI_PEI_GRAPHICS_INFO_HOB GfxInfo;
EFI_PEI_GRAPHICS_INFO_HOB *NewGfxInfo;
EFI_PEI_GRAPHICS_DEVICE_INFO_HOB GfxDeviceInfo;
EFI_PEI_GRAPHICS_DEVICE_INFO_HOB *NewGfxDeviceInfo;
UNIVERSAL_PAYLOAD_SMBIOS_TABLE *SmBiosTableHob;
UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTableHob;
//
// First find TOLUD
//
DEBUG ((DEBUG_INFO , "Guessing Top of Lower Usable DRAM:\n"));
Status = ParseMemoryInfo (FindToludCallback, NULL);
if (EFI_ERROR(Status)) {
return Status;
}
DEBUG ((DEBUG_INFO , "Assuming TOLUD = 0x%x\n", mTopOfLowerUsableDram));
//
// Parse memory info and build memory HOBs for Usable RAM
//
DEBUG ((DEBUG_INFO , "Building ResourceDescriptorHobs for usable memory:\n"));
Status = ParseMemoryInfo (MemInfoCallback, NULL);
if (EFI_ERROR(Status)) {
return Status;
}
//
// Create guid hob for frame buffer information
//
Status = ParseGfxInfo (&GfxInfo);
if (!EFI_ERROR (Status)) {
NewGfxInfo = BuildGuidHob (&gEfiGraphicsInfoHobGuid, sizeof (GfxInfo));
ASSERT (NewGfxInfo != NULL);
CopyMem (NewGfxInfo, &GfxInfo, sizeof (GfxInfo));
DEBUG ((DEBUG_INFO, "Created graphics info hob\n"));
}
Status = ParseGfxDeviceInfo (&GfxDeviceInfo);
if (!EFI_ERROR (Status)) {
NewGfxDeviceInfo = BuildGuidHob (&gEfiGraphicsDeviceInfoHobGuid, sizeof (GfxDeviceInfo));
ASSERT (NewGfxDeviceInfo != NULL);
CopyMem (NewGfxDeviceInfo, &GfxDeviceInfo, sizeof (GfxDeviceInfo));
DEBUG ((DEBUG_INFO, "Created graphics device info hob\n"));
}
//
// Create guid hob for system tables like acpi table and smbios table
//
Status = ParseSystemTable(&SysTableInfo);
ASSERT_EFI_ERROR (Status);
if (!EFI_ERROR (Status)) {
NewSysTableInfo = BuildGuidHob (&gUefiSystemTableInfoGuid, sizeof (SYSTEM_TABLE_INFO));
ASSERT (NewSysTableInfo != NULL);
CopyMem (NewSysTableInfo, &SysTableInfo, sizeof (SYSTEM_TABLE_INFO));
DEBUG ((DEBUG_INFO, "Detected Acpi Table at 0x%lx, length 0x%x\n", SysTableInfo.AcpiTableBase, SysTableInfo.AcpiTableSize));
DEBUG ((DEBUG_INFO, "Detected Smbios Table at 0x%lx, length 0x%x\n", SysTableInfo.SmbiosTableBase, SysTableInfo.SmbiosTableSize));
}
//
// Creat SmBios table Hob
//
SmBiosTableHob = BuildGuidHob (&gUniversalPayloadSmbiosTableGuid, sizeof (UNIVERSAL_PAYLOAD_SMBIOS_TABLE));
ASSERT (SmBiosTableHob != NULL);
SmBiosTableHob->Header.Revision = UNIVERSAL_PAYLOAD_SMBIOS_TABLE_REVISION;
SmBiosTableHob->Header.Length = sizeof (UNIVERSAL_PAYLOAD_SMBIOS_TABLE);
SmBiosTableHob->SmBiosEntryPoint = SysTableInfo.SmbiosTableBase;
DEBUG ((DEBUG_INFO, "Create smbios table gUniversalPayloadSmbiosTableGuid guid hob\n"));
//
// Creat ACPI table Hob
//
AcpiTableHob = BuildGuidHob (&gUniversalPayloadAcpiTableGuid, sizeof (UNIVERSAL_PAYLOAD_ACPI_TABLE));
ASSERT (AcpiTableHob != NULL);
AcpiTableHob->Header.Revision = UNIVERSAL_PAYLOAD_ACPI_TABLE_REVISION;
AcpiTableHob->Header.Length = sizeof (UNIVERSAL_PAYLOAD_ACPI_TABLE);
AcpiTableHob->Rsdp = SysTableInfo.AcpiTableBase;
DEBUG ((DEBUG_INFO, "Create smbios table gUniversalPayloadAcpiTableGuid guid hob\n"));
//
// Create guid hob for acpi board information
//
Status = ParseAcpiInfo (SysTableInfo.AcpiTableBase, &AcpiBoardInfo);
ASSERT_EFI_ERROR (Status);
if (!EFI_ERROR (Status)) {
NewAcpiBoardInfo = BuildGuidHob (&gUefiAcpiBoardInfoGuid, sizeof (ACPI_BOARD_INFO));
ASSERT (NewAcpiBoardInfo != NULL);
CopyMem (NewAcpiBoardInfo, &AcpiBoardInfo, sizeof (ACPI_BOARD_INFO));
DEBUG ((DEBUG_INFO, "Create acpi board info guid hob\n"));
}
//
// Parse memory info and build memory HOBs for reserved DRAM and MMIO
//
DEBUG ((DEBUG_INFO , "Building ResourceDescriptorHobs for reserved memory:\n"));
Status = ParseMemoryInfo (MemInfoCallbackMmio, &AcpiBoardInfo);
if (EFI_ERROR(Status)) {
return Status;
}
//
// Parse platform specific information.
//
Status = ParsePlatformInfo ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "Error when parsing platform info, Status = %r\n", Status));
return Status;
}
return EFI_SUCCESS;
}
/**
This function will build some generic HOBs that doesn't depend on information from bootloaders.
**/
VOID
BuildGenericHob (
VOID
)
{
UINT32 RegEax;
UINT8 PhysicalAddressBits;
EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute;
// The UEFI payload FV
BuildMemoryAllocationHob (PcdGet32 (PcdPayloadFdMemBase), PcdGet32 (PcdPayloadFdMemSize), EfiBootServicesData);
//
// Build CPU memory space and IO space hob
//
AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
if (RegEax >= 0x80000008) {
AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
PhysicalAddressBits = (UINT8) RegEax;
} else {
PhysicalAddressBits = 36;
}
BuildCpuHob (PhysicalAddressBits, 16);
//
// Report Local APIC range, cause sbl HOB to be NULL, comment now
//
ResourceAttribute = (
EFI_RESOURCE_ATTRIBUTE_PRESENT |
EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
EFI_RESOURCE_ATTRIBUTE_TESTED
);
BuildResourceDescriptorHob (EFI_RESOURCE_MEMORY_MAPPED_IO, ResourceAttribute, 0xFEC80000, SIZE_512KB);
BuildMemoryAllocationHob ( 0xFEC80000, SIZE_512KB, EfiMemoryMappedIO);
}
/**
Entry point to the C language phase of UEFI payload.
@retval It will not return if SUCCESS, and return error when passing bootloader parameter.
**/
EFI_STATUS
EFIAPI
PayloadEntry (
IN UINTN BootloaderParameter
)
{
EFI_STATUS Status;
PHYSICAL_ADDRESS DxeCoreEntryPoint;
EFI_HOB_HANDOFF_INFO_TABLE *HandoffHobTable;
UINTN MemBase;
UINTN MemSize;
UINTN HobMemBase;
UINTN HobMemTop;
EFI_PEI_HOB_POINTERS Hob;
// Call constructor for all libraries
ProcessLibraryConstructorList ();
DEBUG ((DEBUG_INFO, "GET_BOOTLOADER_PARAMETER() = 0x%lx\n", GET_BOOTLOADER_PARAMETER()));
DEBUG ((DEBUG_INFO, "sizeof(UINTN) = 0x%x\n", sizeof(UINTN)));
// Initialize floating point operating environment to be compliant with UEFI spec.
InitializeFloatingPointUnits ();
// HOB region is used for HOB and memory allocation for this module
MemBase = PcdGet32 (PcdPayloadFdMemBase);
HobMemBase = ALIGN_VALUE (MemBase + PcdGet32 (PcdPayloadFdMemSize), SIZE_1MB);
HobMemTop = HobMemBase + FixedPcdGet32 (PcdSystemMemoryUefiRegionSize);
// DXE core assumes the memory below HOB region could be used, so include the FV region memory into HOB range.
MemSize = HobMemTop - MemBase;
HandoffHobTable = HobConstructor ((VOID *)MemBase, MemSize, (VOID *)HobMemBase, (VOID *)HobMemTop);
// Build HOB based on information from Bootloader
Status = BuildHobFromBl ();
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "BuildHobFromBl Status = %r\n", Status));
return Status;
}
// Build other HOBs required by DXE
BuildGenericHob ();
// Load the DXE Core
Status = LoadDxeCore (&DxeCoreEntryPoint);
ASSERT_EFI_ERROR (Status);
DEBUG ((DEBUG_INFO, "DxeCoreEntryPoint = 0x%lx\n", DxeCoreEntryPoint));
//
// Mask off all legacy 8259 interrupt sources
//
IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF);
IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF);
Hob.HandoffInformationTable = HandoffHobTable;
HandOffToDxeCore (DxeCoreEntryPoint, Hob);
// Should not get here
CpuDeadLoop ();
return EFI_SUCCESS;
}