/** @file | |
Copyright (c) 2014 - 2020, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "UefiPayloadEntry.h" | |
/** | |
Callback function to build resource descriptor HOB | |
This function build a HOB based on the memory map entry info. | |
@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; | |
Type = (MemoryMapEntry->Type == 1) ? EFI_RESOURCE_SYSTEM_MEMORY : 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; | |
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)); | |
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; | |
// | |
// Parse memory info and build memory HOBs | |
// | |
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)); | |
} | |
// | |
// 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 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; | |
} |