Skip to content

Commit

Permalink
UefiPayloadPkg: Add support for finding FVs in the UPL FDT
Browse files Browse the repository at this point in the history
While EDK2-based implementations of UPL Platform Init copy the entire FIT
binary into memory, the coreboot implementation loads entries in the images node
into memory individually. This means that the assumption that all FVs
directly follow each other is incorrect. It's also assumed that payloads
don't need access to their FIT header.

Therefore, add support for parsing `/options/upl-images@<addr>/image`.

Signed-off-by: Benjamin Doron <[email protected]>
  • Loading branch information
benjamindoron committed Dec 12, 2024
1 parent ecc1de3 commit c206fb9
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 37 deletions.
69 changes: 58 additions & 11 deletions UefiPayloadPkg/Library/FdtParserLib/FdtParserLib.c
Original file line number Diff line number Diff line change
Expand Up @@ -401,23 +401,27 @@ ParseOptions (
OUT EFI_BOOT_MODE *BootMode
)
{
INT32 SubNode;
FDT_NODE_HEADER *NodePtr;
UNIVERSAL_PAYLOAD_BASE *PayloadBase;
CONST FDT_PROPERTY *PropertyPtr;
CONST CHAR8 *TempStr;
INT32 TempLen;
UINT32 *Data32;
UINT64 *Data64;
UINT64 StartAddress;
UINT8 SizeOfMemorySpace;
INT32 SubNode;
INT32 ISubNode;
FDT_NODE_HEADER *NodePtr;
UNIVERSAL_PAYLOAD_BASE *PayloadBase;
CONST FDT_PROPERTY *PropertyPtr;
CONST CHAR8 *TempStr;
INT32 TempLen;
UINT32 *Data32;
UINT64 *Data64;
UINT64 StartAddress;
UINT32 NumberOfBytes;
UINT8 SizeOfMemorySpace;
EFI_HOB_FIRMWARE_VOLUME *FvHob;

for (SubNode = FdtFirstSubnode (Fdt, Node); SubNode >= 0; SubNode = FdtNextSubnode (Fdt, SubNode)) {
NodePtr = (FDT_NODE_HEADER *)((CONST CHAR8 *)Fdt + SubNode + Fdt32ToCpu (((FDT_HEADER *)Fdt)->OffsetDtStruct));
DEBUG ((DEBUG_INFO, "\n SubNode(%08X) %a", SubNode, NodePtr->Name));

if (AsciiStrnCmp (NodePtr->Name, "upl-images@", AsciiStrLen ("upl-images@")) == 0) {
DEBUG ((DEBUG_INFO, " Found image@ node \n"));

//
// Build PayloadBase HOB .
//
Expand All @@ -441,9 +445,52 @@ ParseOptions (

PayloadBase->Entry = (EFI_PHYSICAL_ADDRESS)StartAddress;
}
} else if (AsciiStrCmp (NodePtr->Name, "upl-images") == 0) {
DEBUG ((DEBUG_INFO, " Found upl-images node \n"));

//
// Create an empty FvHob for the DXE FV that contains DXE core.
//
BuildFvHob ((EFI_PHYSICAL_ADDRESS)0, 0);

DEBUG ((DEBUG_INFO, "UPL FVs found in UPL FDT\n"));
for (ISubNode = FdtFirstSubnode (Fdt, SubNode); ISubNode >= 0; ISubNode = FdtNextSubnode (Fdt, ISubNode)) {
NodePtr = (FDT_NODE_HEADER *)((CONST CHAR8 *)Fdt + ISubNode + Fdt32ToCpu (((FDT_HEADER *)Fdt)->OffsetDtStruct));
DEBUG ((DEBUG_INFO, "\n SubNode(%08X) %a", ISubNode, NodePtr->Name));

// NB: This is not specced!
PropertyPtr = FdtGetProperty (Fdt, ISubNode, "name", &TempLen);
if (TempLen <= 0) {
ASSERT (FALSE);
continue;
}
TempStr = (CHAR8 *)(PropertyPtr->Data);

PropertyPtr = FdtGetProperty (Fdt, ISubNode, "reg", &TempLen);
if (TempLen <= 0) {
ASSERT (FALSE);
continue;
}
Data64 = (UINT64 *)(PropertyPtr->Data);
StartAddress = Fdt64ToCpu (*Data64);
NumberOfBytes = Fdt32ToCpu (*(Data64 + 1));
DEBUG ((DEBUG_INFO, "\n Image %a", TempStr));
DEBUG ((DEBUG_INFO, " [0x%X, 0x%X)\n", StartAddress, NumberOfBytes));

//
// Patch the first FV or create a new one, as required.
//
if (AsciiStrnCmp (TempStr, "uefi-fv", AsciiStrLen ("uefi-fv")) == 0) {
FvHob = GetFirstHob (EFI_HOB_TYPE_FV);
FvHob->BaseAddress = StartAddress;
FvHob->Length = NumberOfBytes;
} else {
BuildFvHob (StartAddress, NumberOfBytes);
}
}
}

if (AsciiStrnCmp (NodePtr->Name, "upl-params", AsciiStrLen ("upl-params")) == 0) {
if (AsciiStrCmp (NodePtr->Name, "upl-params") == 0) {
PropertyPtr = FdtGetProperty (Fdt, SubNode, "addr-width", &TempLen);
if (TempLen > 0) {
Data32 = (UINT32 *)(PropertyPtr->Data);
Expand Down
64 changes: 38 additions & 26 deletions UefiPayloadPkg/UefiPayloadEntry/FitUniversalPayloadEntry.c
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,16 @@ BuildFitLoadablesFvHob (
return EFI_UNSUPPORTED;
}

if (GetFirstHob (EFI_HOB_TYPE_FV) != NULL) {
DEBUG ((DEBUG_INFO, "Platform Init already passed necessary UPL FVs\n"));
return EFI_UNSUPPORTED;
}

//
// Create an empty FvHob for the DXE FV that contains DXE core.
//
BuildFvHob ((EFI_PHYSICAL_ADDRESS)0, 0);

Status = FdtCheckHeader (Fdt);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
Expand Down Expand Up @@ -413,15 +423,16 @@ CreatNewHobForHoblist (
@retval EFI_SUCCESS If it completed successfully.
@retval Others If it failed to build required HOBs.
**/
EFI_STATUS
VOID
FitBuildHobs (
IN UINTN NewFdtBase,
OUT EFI_FIRMWARE_VOLUME_HEADER **DxeFv
IN UINTN NewFdtBase
)
{
UINT8 *GuidHob;
UINT32 FdtSize;
EFI_FIRMWARE_VOLUME_HEADER *DxeFv;
EFI_HOB_FIRMWARE_VOLUME *FvHob;
EFI_STATUS Status;
UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTable;
ACPI_BOARD_INFO *AcpiBoardInfo;
UNIVERSAL_PAYLOAD_DEVICE_TREE *Fdt;
Expand Down Expand Up @@ -469,20 +480,17 @@ FitBuildHobs (
}
}

//
// Create an empty FvHob for the DXE FV that contains DXE core.
//
BuildFvHob ((EFI_PHYSICAL_ADDRESS)0, 0);

BuildFitLoadablesFvHob (DxeFv);
//
// Update DXE FV information to first fv hob in the hob list, which
// is the empty FvHob created before.
//
FvHob = GetFirstHob (EFI_HOB_TYPE_FV);
FvHob->BaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)*DxeFv;
FvHob->Length = (*DxeFv)->FvLength;
return EFI_SUCCESS;
Status = BuildFitLoadablesFvHob (&DxeFv);
if (!EFI_ERROR (Status)) {
DEBUG ((DEBUG_INFO, "UPL FVs found by parsing FIT header\n"));
FvHob = GetFirstHob (EFI_HOB_TYPE_FV);
FvHob->BaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)DxeFv;
FvHob->Length = DxeFv->FvLength;
}
}

/**
Expand All @@ -496,24 +504,22 @@ FitUplEntryPoint (
IN UINTN BootloaderParameter
)
{
EFI_STATUS Status;
PHYSICAL_ADDRESS DxeCoreEntryPoint;
EFI_PEI_HOB_POINTERS Hob;
EFI_FIRMWARE_VOLUME_HEADER *DxeFv;

#if FixedPcdGetBool (PcdHandOffFdtEnable) == 1
VOID *FdtBaseResvd;
EFI_STATUS Status;
EFI_HOB_FIRMWARE_VOLUME *DxeFvHob;
PHYSICAL_ADDRESS DxeCoreEntryPoint;
EFI_PEI_HOB_POINTERS Hob;
#if FixedPcdGetBool (PcdHandOffFdtEnable) == 1
PHYSICAL_ADDRESS HobListPtr;
VOID *FdtBase;
#endif
VOID *FdtBaseResvd;
#endif

if (FixedPcdGetBool (PcdHandOffFdtEnable)) {
mHobList = (VOID *)NULL;
} else {
mHobList = (VOID *)BootloaderParameter;
}

DxeFv = NULL;
FdtBaseResvd = 0;
// Call constructor for all libraries
ProcessLibraryConstructorList ();
Expand All @@ -522,7 +528,8 @@ FitUplEntryPoint (
DEBUG ((DEBUG_INFO, "sizeof(UINTN) = 0x%x\n", sizeof (UINTN)));
DEBUG ((DEBUG_INFO, "BootloaderParameter = 0x%x\n", BootloaderParameter));

DEBUG ((DEBUG_INFO, "Start init Hobs...\n"));
DEBUG ((DEBUG_INFO, "Start init HOBs...\n"));

#if FixedPcdGetBool (PcdHandOffFdtEnable) == 1
HobListPtr = UplInitHob ((VOID *)BootloaderParameter);

Expand All @@ -542,7 +549,7 @@ FitUplEntryPoint (
#endif

// Build HOB based on information from Bootloader
Status = FitBuildHobs ((UINTN)FdtBaseResvd, &DxeFv);
FitBuildHobs ((UINTN)FdtBaseResvd);

// Call constructor for all libraries again since hobs were built
ProcessLibraryConstructorList ();
Expand All @@ -554,8 +561,13 @@ FitUplEntryPoint (
PrintHob (mHobList);
);

FixUpPcdDatabase (DxeFv);
Status = UniversalLoadDxeCore (DxeFv, &DxeCoreEntryPoint);
//
// Fetch the FvHob for the DXE FV that we've now populated.
//
DxeFvHob = GetFirstHob (EFI_HOB_TYPE_FV);

FixUpPcdDatabase ((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)DxeFvHob->BaseAddress);
Status = UniversalLoadDxeCore ((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)DxeFvHob->BaseAddress, &DxeCoreEntryPoint);
ASSERT_EFI_ERROR (Status);

Hob.HandoffInformationTable = (EFI_HOB_HANDOFF_INFO_TABLE *)GetFirstHob (EFI_HOB_TYPE_HANDOFF);
Expand Down

0 comments on commit c206fb9

Please sign in to comment.