Files
system76-edk2/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
Guo Dong 7c4ab1c2ef UefiPayloadPkg: Remove PEI phase from Payload
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3100

It is not necessary to have a PEI phase in the UEFI payload since no
specific PEI task is required. This patch adds a UefiPayloadEntry
driver to get UEFI Payload required information from the bootloaders,
convert them into a HOB list, load DXE core and transfer control to it.

Here is the change details:
1) Removed PEI phase, including Peicore, BlSupportPei, SecCore, etc.
2) Added UefiPayloadEntry driver. this is the only driver before DXE core.
3) Added Pure X64 support, dropped Pure IA32 (Could add later if required)
   64bit payload with 32bit entry point is still supported.
4) Use one DSC file UefiPayloadPkg.dsc to support X64 and IA32X64 build.
   Removed UefiPayloadIa32.dsc and UefiPayloadIa32X64.dsc

Tested with SBL and coreboot on QEMU.

Signed-off-by: Guo Dong <guo.dong@intel.com>
Reviewed-by: Maurice Ma <maurice.ma@intel.com>
Reviewed-by: Benjamin You <benjamin.you@intel.com>
2020-12-02 23:10:22 +00:00

416 lines
14 KiB
C

/** @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;
}