diff --git a/UefiPayloadPkg/Library/BuildFdtLib/BuildFdtLib.inf b/UefiPayloadPkg/Library/BuildFdtLib/BuildFdtLib.inf new file mode 100644 index 0000000000..12461a9606 --- /dev/null +++ b/UefiPayloadPkg/Library/BuildFdtLib/BuildFdtLib.inf @@ -0,0 +1,65 @@ +## @file +# Flat Device Tree Table Build Library. +# +# Copyright (c) 2024, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BuildFdtLib + FILE_GUID = 5DA69A29-C990-49EE-A4E6-BA5311A1ADAF + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = BuildFdtLib + + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + X86_BuildFdtLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + DebugLib + PcdLib + HobLib + FdtLib + +[Guids] + gUniversalPayloadDeviceTreeGuid + gEfiGraphicsInfoHobGuid + gEfiGraphicsDeviceInfoHobGuid + gUniversalPayloadAcpiTableGuid + gUniversalPayloadSerialPortInfoGuid + gEfiHobMemoryAllocModuleGuid + gEfiHobMemoryAllocStackGuid + gEfiHobMemoryAllocBspStoreGuid + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterBase + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialBaudRate + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialRegisterStride + gEfiMdeModulePkgTokenSpaceGuid.PcdSerialUseMmio + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress + +[Ppis] + gEdkiiPeiPciDevicePpiGuid ## CONSUMES + +[BuildOptions] + MSFT:*_*_*_CC_FLAGS = /wd4305 + GCC:*_*_IA32_CC_FLAGS = -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast + GCC:*_*_X64_CC_FLAGS = -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast + GCC:*_*_ARM_CC_FLAGS = -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast + GCC:*_*_AARCH64_CC_FLAGS = -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast + GCC:*_*_RISCV64_CC_FLAGS = -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast + GCC:*_*_LOONGARCH64_CC_FLAGS = -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast diff --git a/UefiPayloadPkg/Library/BuildFdtLib/X86_BuildFdtLib.c b/UefiPayloadPkg/Library/BuildFdtLib/X86_BuildFdtLib.c new file mode 100644 index 0000000000..8df78a0afc --- /dev/null +++ b/UefiPayloadPkg/Library/BuildFdtLib/X86_BuildFdtLib.c @@ -0,0 +1,945 @@ +/** @file + Copyright (c) 2024, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IGD_BUS_NUM 0x00 +#define IGD_DEV_NUM 0x02 +#define IGD_FUN_NUM 0x00 + +EDKII_PCI_DEVICE_PPI *mPciDevicePpi; +BOOLEAN mResourceAssigned; + +CHAR8 *mMemoryAllocType[] = { + "Reserved", + "LoaderCode", + "LoaderData", + "boot-code", + "boot-data", + "runtime-code", + "runtime-data", + "ConventionalMemory", + "UnusableMemory", + "acpi", + "acpi-nvs", + "mmio", + "MemoryMappedIOPortSpace", + "PalCode", + "PersistentMemory", +}; + +/** + The wrapper function of PeiServicesLocatePpi() for gEdkiiPeiPciDevicePpiGuid + and Save the PPI to mPciDevicePpi. + @retval EFI_SUCCESS If it locate gEdkiiPeiPciDevicePpiGuid successfully. + @retval EFI_NOT_FOUND If it can't find gEdkiiPeiPciDevicePpiGuid. +**/ +EFI_STATUS +EFIAPI +LocatePciDevicePpi ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor; + + mPciDevicePpi = NULL; + Status = PeiServicesLocatePpi ( + &gEdkiiPeiPciDevicePpiGuid, + 0, + &PpiDescriptor, + (void **)&mPciDevicePpi + ); + if (EFI_ERROR (Status) || (mPciDevicePpi == NULL)) { + return EFI_NOT_FOUND; + } + + return EFI_SUCCESS; +} + +/** + It will build FDT based on memory information from Hobs. + @param[in] FdtBase Address of the Fdt data. + @retval EFI_SUCCESS If it completed successfully. + @retval Others If it failed to build required FDT. +**/ +EFI_STATUS +BuildFdtForMemory ( + IN VOID *FdtBase + ) +{ + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + VOID *HobStart; + VOID *Fdt; + INT32 TempNode; + CHAR8 TempStr[32]; + UINT64 RegTmp[2]; + + Fdt = FdtBase; + + HobStart = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR); + // + // Scan resource descriptor hobs to set memory nodes + // + 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) { + ResourceHob = Hob.ResourceDescriptor; + // Memory + if (ResourceHob->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { + // DEBUG ((DEBUG_ERROR, "Found hob for memory: base %016lX length %016lX\n", ResourceHob->PhysicalStart, ResourceHob->ResourceLength)); + + Status = AsciiSPrint (TempStr, sizeof (TempStr), "memory@%lX", ResourceHob->PhysicalStart); + TempNode = FdtAddSubnode (Fdt, 0, TempStr); + ASSERT (TempNode > 0); + + RegTmp[0] = CpuToFdt64 (ResourceHob->PhysicalStart); + RegTmp[1] = CpuToFdt64 (ResourceHob->ResourceLength); + Status = FdtSetProp (Fdt, TempNode, "reg", &RegTmp, sizeof (RegTmp)); + ASSERT_EFI_ERROR (Status); + + Status = FdtSetProp (Fdt, TempNode, "device_type", "memory", (UINT32)(AsciiStrLen ("memory")+1)); + ASSERT_EFI_ERROR (Status); + } + } + } + + return Status; +} + +/** + It will build FDT based on memory allocation information from Hobs. + @param[in] FdtBase Address of the Fdt data. + @retval EFI_SUCCESS If it completed successfully. + @retval Others If it failed to build required FDT. +**/ +EFI_STATUS +BuildFdtForMemAlloc ( + IN VOID *FdtBase + ) +{ + EFI_STATUS Status; + EFI_PEI_HOB_POINTERS Hob; + VOID *HobStart; + VOID *Fdt; + INT32 ParentNode; + INT32 TempNode; + CHAR8 TempStr[32]; + UINT64 RegTmp[2]; + UINT32 AllocMemType; + EFI_GUID *AllocMemName; + UINT8 IsStackHob; + UINT8 IsBspStore; + UINT32 Data32; + + Fdt = FdtBase; + + ParentNode = FdtAddSubnode (Fdt, 0, "reserved-memory"); + ASSERT (ParentNode > 0); + + Data32 = CpuToFdt32 (2); + Status = FdtSetProp (Fdt, ParentNode, "#address-cells", &Data32, sizeof (UINT32)); + Status = FdtSetProp (Fdt, ParentNode, "#size-cells", &Data32, sizeof (UINT32)); + + HobStart = GetFirstHob (EFI_HOB_TYPE_MEMORY_ALLOCATION); + // + // Scan memory allocation hobs to set memory type + // + 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) { + AllocMemName = NULL; + IsStackHob = 0; + IsBspStore = 0; + if (CompareGuid (&(Hob.MemoryAllocationModule->MemoryAllocationHeader.Name), &gEfiHobMemoryAllocModuleGuid)) { + continue; + } else if (IsZeroGuid (&(Hob.MemoryAllocationModule->MemoryAllocationHeader.Name)) == FALSE) { + AllocMemName = &(Hob.MemoryAllocationModule->MemoryAllocationHeader.Name); + + if (CompareGuid (AllocMemName, &gEfiHobMemoryAllocStackGuid)) { + IsStackHob = 1; + } else if (CompareGuid (AllocMemName, &gEfiHobMemoryAllocBspStoreGuid)) { + IsBspStore = 1; + } + } + + DEBUG (( + DEBUG_ERROR, + "Found hob for rsvd memory alloc: base %016lX length %016lX type %x\n", + Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress, + Hob.MemoryAllocation->AllocDescriptor.MemoryLength, + Hob.MemoryAllocation->AllocDescriptor.MemoryType + )); + + AllocMemType = Hob.MemoryAllocation->AllocDescriptor.MemoryType; + if (IsStackHob == 1) { + Status = AsciiSPrint ( + TempStr, + sizeof (TempStr), + "%a@%lX", + "stackhob", + Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + ); + } else if (IsBspStore == 1) { + Status = AsciiSPrint ( + TempStr, + sizeof (TempStr), + "%a@%lX", + "bspstore", + Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + ); + } else { + Status = AsciiSPrint ( + TempStr, + sizeof (TempStr), + "%a@%lX", + mMemoryAllocType[AllocMemType], + Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress + ); + } + + if (AsciiStrCmp (mMemoryAllocType[AllocMemType], "ConventionalMemory") == 0) { + continue; + } + + if (AsciiStrCmp (mMemoryAllocType[AllocMemType], "mmio") == 0) { + Status = AsciiSPrint (TempStr, sizeof (TempStr), "mmio@%lX", Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress); + } else { + Status = AsciiSPrint (TempStr, sizeof (TempStr), "memory@%lX", Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress); + } + + TempNode = FdtAddSubnode (Fdt, ParentNode, TempStr); + DEBUG ((DEBUG_INFO, "FdtAddSubnode %x", TempNode)); + if (TempNode < 0) { + continue; + } + + RegTmp[0] = CpuToFdt64 (Hob.MemoryAllocation->AllocDescriptor.MemoryBaseAddress); + RegTmp[1] = CpuToFdt64 (Hob.MemoryAllocation->AllocDescriptor.MemoryLength); + Status = FdtSetProp (Fdt, TempNode, "reg", &RegTmp, sizeof (RegTmp)); + ASSERT_EFI_ERROR (Status); + + if (!(AsciiStrCmp (mMemoryAllocType[AllocMemType], "mmio") == 0)) { + Status = FdtSetProp (Fdt, TempNode, "compatible", mMemoryAllocType[AllocMemType], (UINT32)(AsciiStrLen (mMemoryAllocType[AllocMemType])+1)); + ASSERT_EFI_ERROR (Status); + } + } + } + + return Status; +} + +/** + It will build FDT based on serial information. + @param[in] ISANode ISANode. + @param[in] FdtBase Address of the Fdt data. + @retval EFI_SUCCESS If it completed successfully. + @retval Others If it failed to build required FDT. +**/ +EFI_STATUS +BuildFdtForSerial ( + IN INT32 ISANode, + IN VOID *FdtBase + ) +{ + EFI_STATUS Status; + VOID *Fdt; + INT32 TempNode; + UINT64 RegisterBase; + CHAR8 TempStr[32]; + UINT32 RegData[3]; + UINT32 Data32; + UINT64 Data64; + + Fdt = FdtBase; + RegisterBase = 0; + + // + // Create SerialPortInfo FDT node. + // + Status = AsciiSPrint (TempStr, sizeof (TempStr), "serial@%lX", (RegisterBase == 0) ? PcdGet64 (PcdSerialRegisterBase) : RegisterBase); + TempNode = FdtAddSubnode (Fdt, ISANode, TempStr); + ASSERT (TempNode > 0); + + Data32 = CpuToFdt32 (PcdGet32 (PcdSerialBaudRate)); + Status = FdtSetProp (Fdt, TempNode, "current-speed", &Data32, sizeof (Data32)); + ASSERT_EFI_ERROR (Status); + + if (PcdGetBool (PcdSerialUseMmio)) { + Data32 = 0; + RegData[0] = CpuToFdt32 (Data32); + } else { + Data32 = 1; + RegData[0] = CpuToFdt32 (Data32); + } + + Data64 = (RegisterBase == 0) ? PcdGet64 (PcdSerialRegisterBase) : RegisterBase; + Data32 = (UINT32)((Data64 & 0x0FFFFFFFF)); + RegData[1] = CpuToFdt32 (Data32); + RegData[2] = CpuToFdt32 (8); + Status = FdtSetProp (Fdt, TempNode, "reg", &RegData, sizeof (RegData)); + ASSERT_EFI_ERROR (Status); + + Data32 = CpuToFdt32 (1); + Status = FdtSetProp (Fdt, TempNode, "reg-io-width", &Data32, sizeof (Data32)); + ASSERT_EFI_ERROR (Status); + + Status = FdtSetProp (Fdt, TempNode, "compatible", "isa", (UINT32)(AsciiStrLen ("isa")+1)); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + It will build FDT based on serial information. + + @param[in] ISANode ISANode. + @param[in] FdtBase Address of the Fdt data. + @retval EFI_SUCCESS If it completed successfully. + @retval Others If it failed to build required FDT. +**/ +EFI_STATUS +BuildFdtForSerialLpss ( + IN INT32 ISANode, + IN VOID *FdtBase + ) +{ + EFI_HOB_GUID_TYPE *GuidHob; + EFI_STATUS Status; + UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO *SerialPortInfo; + VOID *Fdt; + INT32 TempNode; + UINT32 Data32; + UINT32 RegData[2]; + CHAR8 TempStr[32]; + + Status = EFI_SUCCESS; + SerialPortInfo = NULL; + Fdt = FdtBase; + + DEBUG ((DEBUG_INFO, "BuildFdtForSerialLpss start \n")); + GuidHob = GetFirstGuidHob (&gUniversalPayloadSerialPortInfoGuid); + while (GuidHob != NULL) { + SerialPortInfo = (UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO *)GET_GUID_HOB_DATA (GuidHob); + + if (!SerialPortInfo->UseMmio) { + GuidHob = GET_NEXT_HOB (GuidHob); + GuidHob = GetNextGuidHob (&gUniversalPayloadSerialPortInfoGuid, GuidHob); + continue; + } + + DEBUG ((DEBUG_INFO, "Create SerialPortInfo LPSS FDT node \n")); + // + // Create SerialPortInfo FDT node. + // + Status = AsciiSPrint (TempStr, sizeof (TempStr), "serial@%lX", SerialPortInfo->RegisterBase); + TempNode = FdtAddSubnode (Fdt, ISANode, TempStr); + ASSERT (TempNode > 0); + + Data32 = CpuToFdt32 (SerialPortInfo->BaudRate); + Status = FdtSetProp (Fdt, TempNode, "current-speed", &Data32, sizeof (Data32)); + ASSERT_EFI_ERROR (Status); + + RegData[0] = CpuToFdt32 ((UINT32)SerialPortInfo->RegisterBase); + RegData[1] = CpuToFdt32 (0x80); + Status = FdtSetProp (Fdt, TempNode, "reg", &RegData, sizeof (RegData)); + ASSERT_EFI_ERROR (Status); + + Data32 = CpuToFdt32 (4); + Status = FdtSetProp (Fdt, TempNode, "reg-io-width", &Data32, sizeof (Data32)); + ASSERT_EFI_ERROR (Status); + + Status = FdtSetProp (Fdt, TempNode, "compatible", "ns16550a", (UINT32)(AsciiStrLen ("ns16550a")+1)); + ASSERT_EFI_ERROR (Status); + + GuidHob = GET_NEXT_HOB (GuidHob); + GuidHob = GetNextGuidHob (&gUniversalPayloadSerialPortInfoGuid, GuidHob); + } + + return Status; +} + +/** + It will build FDT based on BuildFdtForPciRootBridge information. + @param[in] FdtBase Address of the Fdt data. + @retval EFI_SUCCESS If it completed successfully. + @retval Others If it failed to build required FDT. +**/ +EFI_STATUS +BuildFdtForPciRootBridge ( + IN VOID *FdtBase + ) +{ + EFI_STATUS Status; + VOID *Fdt; + INT32 TempNode; + INT32 GmaNode; + INT32 eSPINode; + CHAR8 TempStr[32]; + CHAR8 GmaStr[32]; + CHAR8 eSPIStr[32]; + UINT32 RegTmp[2]; + UINT32 RegData[21]; + UINT32 DMARegData[8]; + UINT32 Data32; + UINT64 Data64; + UINT8 BusNumber; + UINT8 BusLimit; + UINT8 BusBase; + UINT8 DevBase; + UINT8 FunBase; + EFI_HOB_GUID_TYPE *GuidHob; + UNIVERSAL_PAYLOAD_GENERIC_HEADER *GenericHeader; + UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *PciRootBridgeInfo; + UINT8 Index; + PCI_TYPE00 PciData; + UNIVERSAL_PAYLOAD_SERIAL_PORT_PARENT_DEVICE_INFO *SerialParent; + + Fdt = FdtBase; + BusNumber = 0; + BusLimit = 0; + BusBase = 0x80; + DevBase = 0x31; + FunBase = 0; + Status = EFI_SUCCESS; + PciRootBridgeInfo = NULL; + + DEBUG ((DEBUG_INFO, "%a: #1 \n", __func__)); + // + // Create BuildFdtForPciRootBridge FDT node. + // + + GuidHob = GetFirstGuidHob (&gUniversalPayloadPciRootBridgeInfoGuid); + if (GuidHob != NULL) { + GenericHeader = (UNIVERSAL_PAYLOAD_GENERIC_HEADER *)GET_GUID_HOB_DATA (GuidHob); + if ((sizeof (UNIVERSAL_PAYLOAD_GENERIC_HEADER) <= GET_GUID_HOB_DATA_SIZE (GuidHob)) && (GenericHeader->Length <= GET_GUID_HOB_DATA_SIZE (GuidHob))) { + if ((GenericHeader->Revision == UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES_REVISION) && (GenericHeader->Length >= sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES))) { + DEBUG ((DEBUG_INFO, "%a: #2 \n", __func__)); + + // + // UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES structure is used when Revision equals to UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES_REVISION + // + PciRootBridgeInfo = (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *)GET_GUID_HOB_DATA (GuidHob); + } + } + } + + GuidHob = GetFirstGuidHob (&gUniversalPayloadSerialPortParentDeviceInfoGuid); + if (GuidHob != NULL) { + SerialParent = (UNIVERSAL_PAYLOAD_SERIAL_PORT_PARENT_DEVICE_INFO *)GET_GUID_HOB_DATA (GuidHob); + BusBase = (SerialParent->ParentDevicePcieBaseAddress >> 20) & 0xFF; + DevBase = (SerialParent->ParentDevicePcieBaseAddress >> 15) & 0x1F; + FunBase = (SerialParent->ParentDevicePcieBaseAddress >> 12) & 0x07; + } + + DEBUG ((DEBUG_INFO, "PciRootBridgeInfo->Count %x\n", PciRootBridgeInfo->Count)); + DEBUG ((DEBUG_INFO, "PciRootBridge->Segment %x, \n", PciRootBridgeInfo->RootBridge[0].Segment)); + + DEBUG ((DEBUG_INFO, "PciRootBridge->Bus.Base %x, \n", PciRootBridgeInfo->RootBridge[0].Bus.Base)); + DEBUG ((DEBUG_INFO, "PciRootBridge->Bus.limit %x, \n", PciRootBridgeInfo->RootBridge[0].Bus.Limit)); + + DEBUG ((DEBUG_INFO, "PciRootBridge->Mem.Base %x, \n", PciRootBridgeInfo->RootBridge[0].Mem.Base)); + DEBUG ((DEBUG_INFO, "PciRootBridge->Mem.limit %x, \n", PciRootBridgeInfo->RootBridge[0].Mem.Limit)); + + DEBUG ((DEBUG_INFO, "PciRootBridge->MemAbove4G.Base %llx, \n", PciRootBridgeInfo->RootBridge[0].MemAbove4G.Base)); + DEBUG ((DEBUG_INFO, "PciRootBridge->MemAbove4G.limit %llx, \n", PciRootBridgeInfo->RootBridge[0].MemAbove4G.Limit)); + + DEBUG ((DEBUG_INFO, "PciRootBridge->PMem.Base %llx, \n", PciRootBridgeInfo->RootBridge[0].PMem.Base)); + DEBUG ((DEBUG_INFO, "PciRootBridge->PMem.limit %llx, \n", PciRootBridgeInfo->RootBridge[0].PMem.Limit)); + + DEBUG ((DEBUG_INFO, "PciRootBridge->Bus.Base %x, \n", PciRootBridgeInfo->RootBridge[1].Bus.Base)); + DEBUG ((DEBUG_INFO, "PciRootBridge->Bus.limit %x, \n", PciRootBridgeInfo->RootBridge[1].Bus.Limit)); + + DEBUG ((DEBUG_INFO, "PciRootBridge->Mem.Base %x, \n", PciRootBridgeInfo->RootBridge[1].Mem.Base)); + DEBUG ((DEBUG_INFO, "PciRootBridge->Mem.limit %x, \n", PciRootBridgeInfo->RootBridge[1].Mem.Limit)); + + DEBUG ((DEBUG_INFO, "PciRootBridge->MemAbove4G.Base %llx, \n", PciRootBridgeInfo->RootBridge[1].MemAbove4G.Base)); + DEBUG ((DEBUG_INFO, "PciRootBridge->MemAbove4G.limit %llx, \n", PciRootBridgeInfo->RootBridge[1].MemAbove4G.Limit)); + + DEBUG ((DEBUG_INFO, "PciRootBridge->PMem.Base %x, \n", PciRootBridgeInfo->RootBridge[1].PMem.Base)); + DEBUG ((DEBUG_INFO, "PciRootBridge->PMem.limit %x, \n", PciRootBridgeInfo->RootBridge[1].PMem.Limit)); + + if (PciRootBridgeInfo != NULL) { + for (Index = 0; Index < PciRootBridgeInfo->Count; Index++) { + UINTN PciExpressBaseAddress; + + mResourceAssigned = PciRootBridgeInfo->ResourceAssigned; + PciExpressBaseAddress = PcdGet64 (PcdPciExpressBaseAddress) + (PCI_LIB_ADDRESS (PciRootBridgeInfo->RootBridge[Index].Bus.Base, 0, 0, 0)); + Status = AsciiSPrint (TempStr, sizeof (TempStr), "pci-rb%d@%lX", Index, PciExpressBaseAddress); + TempNode = FdtAddSubnode (Fdt, 0, TempStr); + ASSERT (TempNode > 0); + SetMem (RegData, sizeof (RegData), 0); + + // non-reloc/non-prefetch/mmio, child-addr, parent-addr, length + Data32 = (N_NON_RELOCATABLE + SS_32BIT_MEMORY_SPACE); + RegData[0] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->Mem.Base RegData[0] %x, \n", Data32)); + + // child-addr + RegData[1] = CpuToFdt32 (0); + Data32 = (UINT32)PciRootBridgeInfo->RootBridge[Index].Mem.Base; + RegData[2] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->Mem.Base RegData[2] %x, \n", Data32)); + + // parent-addr + RegData[3] = CpuToFdt32 (0); + RegData[4] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->Mem.Base RegData[4] %x, \n", Data32)); + + // size + Data64 = (PciRootBridgeInfo->RootBridge[Index].Mem.Limit - PciRootBridgeInfo->RootBridge[Index].Mem.Base + 1); + if (Data64 & 0xFFFFFFFF00000000) { + Data32 = (UINT32)RShiftU64 ((Data64 & 0xFFFFFFFF00000000), 31); + } else { + Data32 = 0; + } + + DEBUG ((DEBUG_INFO, "PciRootBridge->Mem.size RegData[5] %x, \n", Data32)); + RegData[5] = CpuToFdt32 (Data32); + Data32 = (UINT32)((Data64 & 0x0FFFFFFFF)); + DEBUG ((DEBUG_INFO, "PciRootBridge->Mem.size RegData[6] %x, \n", Data32)); + + RegData[6] = CpuToFdt32 (Data32); + + // non-reloc/non-prefetch/64 mmio, child-addr, parent-addr, length + Data32 = (N_NON_RELOCATABLE + SS_64BIT_MEMORY_SPACE); + RegData[7] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->MemAbove4G.Base RegData[7] %x, \n", Data32)); + + // child-addr + Data64 = PciRootBridgeInfo->RootBridge[Index].MemAbove4G.Base; + Data32 = (UINT32)RShiftU64 ((Data64 & 0xFFFFFFFF00000000), 32); + + RegData[8] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->MemAbove4G.Base RegData[8] %x, \n", Data32)); + Data32 = (UINT32)((Data64 & 0x0FFFFFFFF)); + RegData[9] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->MemAbove4G.Base RegData[9] %x, \n", Data32)); + + // parent-addr + RegData[10] = RegData[8]; + RegData[11] = RegData[9]; + + // size + Data64 = (PciRootBridgeInfo->RootBridge[Index].MemAbove4G.Limit - PciRootBridgeInfo->RootBridge[Index].MemAbove4G.Base + 1); + if (Data64 & 0xFFFFFFFF00000000) { + Data32 = (UINT32)RShiftU64 ((Data64 & 0xFFFFFFFF00000000), 32); + } else { + Data32 = 0; + } + + RegData[12] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->MemAbove4G.size RegData[12] %x, \n", Data32)); + + Data32 = (UINT32)((Data64 & 0x0FFFFFFFF)); + RegData[13] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->MemAbove4G.size RegData[13] %x, \n", Data32)); + + // non-reloc/32bit/io, child-addr, parent-addr, length + Data32 = (N_NON_RELOCATABLE + SS_IO_SPACE); + + RegData[14] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->Io.base RegData[14] %x, \n", Data32)); + + Data32 = (UINT32)PciRootBridgeInfo->RootBridge[Index].Io.Base; + // child-addr + RegData[15] = CpuToFdt32 (0); + RegData[16] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->Io.base RegData[16] %x, \n", Data32)); + + // parent-addr + RegData[17] = CpuToFdt32 (0); + RegData[18] = CpuToFdt32 (Data32); + // size + Data64 = (PciRootBridgeInfo->RootBridge[Index].Io.Limit - PciRootBridgeInfo->RootBridge[Index].Io.Base + 1); + if (Data64 & 0xFFFFFFFF00000000) { + Data32 = (UINT32)RShiftU64 ((Data64 & 0xFFFFFFFF00000000), 32); + } else { + Data32 = 0; + } + + RegData[19] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->Io.base size [19] %x, \n", Data32)); + + Data32 = (UINT32)((Data64 & 0x0FFFFFFFF)); + RegData[20] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->Io.base size [20] %x, \n", Data32)); + + Status = FdtSetProp (Fdt, TempNode, "ranges", &RegData, sizeof (RegData)); + ASSERT_EFI_ERROR (Status); + + // non-reloc/non-prefetch/memory, child-addr, parent-addr, length + // indicate rb1 does not support above 4GB DMA + Data32 = (N_NON_RELOCATABLE + SS_32BIT_MEMORY_SPACE); + + DMARegData[0] = CpuToFdt32 (Data32); + DEBUG ((DEBUG_INFO, "PciRootBridge->DMA base RegData[0] %x, \n", Data32)); + + // child-addr + DMARegData[2] = CpuToFdt32 (0); + DMARegData[3] = CpuToFdt32 (0); + // parent-addr + DMARegData[4] = CpuToFdt32 (0); + DMARegData[5] = CpuToFdt32 (0); + // size + DMARegData[6] = CpuToFdt32 (1); + DMARegData[7] = CpuToFdt32 (0); + + Status = FdtSetProp (Fdt, TempNode, "dma-ranges", &DMARegData, sizeof (DMARegData)); + ASSERT_EFI_ERROR (Status); + + Data32 = CpuToFdt32 (2); + Status = FdtSetProp (Fdt, TempNode, "#size-cells", &Data32, sizeof (UINT32)); + + Data32 = CpuToFdt32 (3); + Status = FdtSetProp (Fdt, TempNode, "#address-cells", &Data32, sizeof (UINT32)); + + BusNumber = PciRootBridgeInfo->RootBridge[Index].Bus.Base & 0xFF; + RegTmp[0] = CpuToFdt32 (BusNumber); + BusLimit = PciRootBridgeInfo->RootBridge[Index].Bus.Limit & 0xFF; + RegTmp[1] = CpuToFdt32 (BusLimit); + DEBUG ((DEBUG_INFO, "PciRootBridge->BusNumber %x, \n", BusNumber)); + DEBUG ((DEBUG_INFO, "PciRootBridge->BusLimit %x, \n", BusLimit)); + + Status = FdtSetProp (Fdt, TempNode, "bus-range", &RegTmp, sizeof (RegTmp)); + ASSERT_EFI_ERROR (Status); + + Status = FdtSetProp (Fdt, TempNode, "compatible", "pci-rb", (UINT32)(AsciiStrLen ("pci-rb")+1)); + ASSERT_EFI_ERROR (Status); + + if (Index == 0) { + PciExpressBaseAddress = PcdGet64 (PcdPciExpressBaseAddress) + (PCI_LIB_ADDRESS (IGD_BUS_NUM, IGD_DEV_NUM, IGD_FUN_NUM, 0)); + Status = AsciiSPrint (GmaStr, sizeof (GmaStr), "gma@%lX", PciExpressBaseAddress); + GmaNode = FdtAddSubnode (Fdt, TempNode, GmaStr); + Status = LocatePciDevicePpi (); + if (!EFI_ERROR (Status)) { + Status = mPciDevicePpi->PciIo.Pci.Read ( + &mPciDevicePpi->PciIo, + (EFI_PCI_IO_PROTOCOL_WIDTH)EfiPciWidthUint16, + PCI_VENDOR_ID_OFFSET, + sizeof (PciData.Hdr.VendorId), + &(PciData.Hdr.VendorId) + ); + + Status = mPciDevicePpi->PciIo.Pci.Read ( + &mPciDevicePpi->PciIo, + (EFI_PCI_IO_PROTOCOL_WIDTH)EfiPciWidthUint16, + PCI_DEVICE_ID_OFFSET, + sizeof (PciData.Hdr.DeviceId), + &(PciData.Hdr.DeviceId) + ); + + Status = mPciDevicePpi->PciIo.Pci.Read ( + &mPciDevicePpi->PciIo, + (EFI_PCI_IO_PROTOCOL_WIDTH)EfiPciWidthUint8, + PCI_REVISION_ID_OFFSET, + sizeof (PciData.Hdr.RevisionID), + &(PciData.Hdr.RevisionID) + ); + + Status = mPciDevicePpi->PciIo.Pci.Read ( + &mPciDevicePpi->PciIo, + (EFI_PCI_IO_PROTOCOL_WIDTH)EfiPciWidthUint16, + PCI_SVID_OFFSET, + sizeof (PciData.Device.SubsystemVendorID), + &(PciData.Device.SubsystemVendorID) + ); + + Status = mPciDevicePpi->PciIo.Pci.Read ( + &mPciDevicePpi->PciIo, + (EFI_PCI_IO_PROTOCOL_WIDTH)EfiPciWidthUint16, + PCI_SID_OFFSET, + sizeof (PciData.Device.SubsystemID), + &(PciData.Device.SubsystemID) + ); + } + + Data32 = CpuToFdt32 (PciData.Device.SubsystemID); + Status = FdtSetProp (Fdt, GmaNode, "subsystem-id", &Data32, sizeof (UINT32)); + + Data32 = CpuToFdt32 (PciData.Device.SubsystemVendorID); + Status = FdtSetProp (Fdt, GmaNode, "subsystem-vendor-id", &Data32, sizeof (UINT32)); + + Data32 = CpuToFdt32 (PciData.Hdr.RevisionID); + Status = FdtSetProp (Fdt, GmaNode, "revision-id", &Data32, sizeof (UINT32)); + + Data32 = CpuToFdt32 (PciData.Hdr.DeviceId); + Status = FdtSetProp (Fdt, GmaNode, "device-id", &Data32, sizeof (UINT32)); + + Data32 = CpuToFdt32 (PciData.Hdr.VendorId); + Status = FdtSetProp (Fdt, GmaNode, "vendor-id", &Data32, sizeof (UINT32)); + } + + if (SerialParent != NULL) { + DEBUG ((DEBUG_INFO, "SerialParent->IsIsaCompatible :%x , SerialParent->ParentDevicePcieBaseAddress :%x\n", SerialParent->IsIsaCompatible, SerialParent->ParentDevicePcieBaseAddress)); + DEBUG ((DEBUG_INFO, "BusBase :%x , PciRootBridgeInfo->RootBridge[Index].Bus.Base :%x\n", BusBase, PciRootBridgeInfo->RootBridge[Index].Bus.Base)); + } + + { + if ((BusBase >= PciRootBridgeInfo->RootBridge[Index].Bus.Base) && (BusBase <= PciRootBridgeInfo->RootBridge[Index].Bus.Limit)) { + eSPINode = TempNode; + if (SerialParent != NULL) { + if (SerialParent->IsIsaCompatible) { + Status = AsciiSPrint (eSPIStr, sizeof (eSPIStr), "isa@%X,%X", DevBase, FunBase); + eSPINode = FdtAddSubnode (Fdt, TempNode, eSPIStr); + Status = FdtSetProp (Fdt, eSPINode, "compatible", "isa", (UINT32)(AsciiStrLen ("isa")+1)); + ASSERT_EFI_ERROR (Status); + Data32 = CpuToFdt32 (1); + Status = FdtSetProp (Fdt, eSPINode, "#size-cells", &Data32, sizeof (UINT32)); + Data32 = CpuToFdt32 (2); + Status = FdtSetProp (Fdt, eSPINode, "#address-cells", &Data32, sizeof (UINT32)); + Status = BuildFdtForSerial (eSPINode, FdtBase); + ASSERT_EFI_ERROR (Status); + } + } else { + Status = BuildFdtForSerialLpss (eSPINode, FdtBase); + ASSERT_EFI_ERROR (Status); + } + } + } + } + } + + DEBUG ((DEBUG_INFO, "%a: #3 \n", __func__)); + + return Status; +} + +/** + It will build FDT based on FrameBuffer. + @param[in] FdtBase Address of the Fdt data. + @retval EFI_SUCCESS If it completed successfully. + @retval Others If it failed to build required FDT. +**/ +EFI_STATUS +BuildFdtForFrameBuffer ( + IN VOID *FdtBase + ) +{ + EFI_STATUS Status; + VOID *Fdt; + INT32 TempNode; + UINT32 Data32; + CHAR8 TempStr[32]; + UINT64 RegData[2]; + EFI_HOB_GUID_TYPE *GuidHob; + EFI_PEI_GRAPHICS_INFO_HOB *GraphicsInfo; + + Fdt = FdtBase; + + GuidHob = GetFirstGuidHob (&gEfiGraphicsInfoHobGuid); + if (GuidHob != NULL) { + GraphicsInfo = (EFI_PEI_GRAPHICS_INFO_HOB *)(GET_GUID_HOB_DATA (GuidHob)); + Status = AsciiSPrint (TempStr, sizeof (TempStr), "framebuffer@%lX", GraphicsInfo->FrameBufferBase); + TempNode = FdtAddSubnode (Fdt, 0, TempStr); + ASSERT (TempNode > 0); + + Status = FdtSetProp (Fdt, TempNode, "display", "&gma", (UINT32)(AsciiStrLen ("&gma")+1)); + ASSERT_EFI_ERROR (Status); + + Status = FdtSetProp (Fdt, TempNode, "format", "a8r8g8b8", (UINT32)(AsciiStrLen ("a8r8g8b8")+1)); + ASSERT_EFI_ERROR (Status); + + Data32 = CpuToFdt32 (GraphicsInfo->GraphicsMode.VerticalResolution); + Status = FdtSetProp (Fdt, TempNode, "height", &Data32, sizeof (UINT32)); + ASSERT_EFI_ERROR (Status); + + Data32 = CpuToFdt32 (GraphicsInfo->GraphicsMode.HorizontalResolution); + Status = FdtSetProp (Fdt, TempNode, "width", &Data32, sizeof (UINT32)); + ASSERT_EFI_ERROR (Status); + + RegData[0] = CpuToFdt64 (GraphicsInfo->FrameBufferBase); + RegData[1] = CpuToFdt64 (GraphicsInfo->FrameBufferSize); + Status = FdtSetProp (Fdt, TempNode, "reg", &RegData, sizeof (RegData)); + ASSERT_EFI_ERROR (Status); + + Status = FdtSetProp (Fdt, TempNode, "compatible", "simple-framebuffer", (UINT32)(AsciiStrLen ("simple-framebuffer")+1)); + ASSERT_EFI_ERROR (Status); + } else { + Status = AsciiSPrint (TempStr, sizeof (TempStr), "framebuffer@%lX", 0xB0000000); + TempNode = FdtAddSubnode (Fdt, 0, TempStr); + ASSERT (TempNode > 0); + + Status = FdtSetProp (Fdt, TempNode, "display", "&gma", (UINT32)(AsciiStrLen ("&gma")+1)); + ASSERT_EFI_ERROR (Status); + + Status = FdtSetProp (Fdt, TempNode, "format", "a8r8g8b8", (UINT32)(AsciiStrLen ("a8r8g8b8")+1)); + ASSERT_EFI_ERROR (Status); + + Data32 = CpuToFdt32 (1024); + Status = FdtSetProp (Fdt, TempNode, "height", &Data32, sizeof (UINT32)); + ASSERT_EFI_ERROR (Status); + + Data32 = CpuToFdt32 (1280); + Status = FdtSetProp (Fdt, TempNode, "width", &Data32, sizeof (UINT32)); + ASSERT_EFI_ERROR (Status); + + RegData[0] = CpuToFdt64 (0xB0000000); + RegData[1] = CpuToFdt64 (0x500000); + Status = FdtSetProp (Fdt, TempNode, "reg", &RegData, sizeof (RegData)); + ASSERT_EFI_ERROR (Status); + + Status = FdtSetProp (Fdt, TempNode, "compatible", "simple-framebuffer", (UINT32)(AsciiStrLen ("simple-framebuffer")+1)); + ASSERT_EFI_ERROR (Status); + } + + return Status; +} + +/** + It will build FDT for UPL required data. + @param[in] FdtBase Address of the Fdt data. + @retval EFI_SUCCESS If it completed successfully. + @retval Others If it failed to build required FDT. +**/ +EFI_STATUS +BuildFdtForUplRequired ( + IN VOID *FdtBase + ) +{ + EFI_STATUS Status; + VOID *Fdt; + VOID *Fit; + INT32 ParentNode; + INT32 CustomNode; + INT32 UPLParaNode; + INT32 UPLImageNode; + EFI_HOB_CPU *CpuHob; + UINT64 Data64; + UINT32 Data32; + VOID *HobPtr; + EFI_BOOT_MODE BootMode; + CHAR8 TempStr[32]; + UINT8 *GuidHob; + UNIVERSAL_PAYLOAD_BASE *PayloadBase; + + Fdt = FdtBase; + Fit = NULL; + + // + // Create Hob list FDT node. + // + ParentNode = FdtAddSubnode (Fdt, 0, "options"); + ASSERT (ParentNode > 0); + + UPLParaNode = FdtAddSubnode (Fdt, ParentNode, "upl-params"); + ASSERT (UPLParaNode > 0); + + // + // Create CPU info FDT node + // + CpuHob = GetFirstHob (EFI_HOB_TYPE_CPU); + ASSERT (CpuHob != NULL); + + if (mResourceAssigned) { + Status = FdtSetProp (Fdt, UPLParaNode, "pci-enum-done", NULL, 0); + ASSERT_EFI_ERROR (Status); + } + + BootMode = GetBootModeHob (); + + Data32 = CpuToFdt32 ((UINT32)CpuHob->SizeOfMemorySpace); + Status = FdtSetProp (Fdt, UPLParaNode, "addr-width", &Data32, sizeof (Data32)); + ASSERT_EFI_ERROR (Status); + + if (BootMode == BOOT_WITH_FULL_CONFIGURATION) { + Status = FdtSetProp (Fdt, UPLParaNode, "boot-mode", "normal", (UINT32)(AsciiStrLen ("normal")+1)); + } else if (BootMode == BOOT_WITH_MINIMAL_CONFIGURATION) { + Status = FdtSetProp (Fdt, UPLParaNode, "boot-mode", "fast", (UINT32)(AsciiStrLen ("fast")+1)); + } else if (BootMode == BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS) { + Status = FdtSetProp (Fdt, UPLParaNode, "boot-mode", "full", (UINT32)(AsciiStrLen ("full")+1)); + } else if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) { + Status = FdtSetProp (Fdt, UPLParaNode, "boot-mode", "default", (UINT32)(AsciiStrLen ("default")+1)); + } else if (BootMode == BOOT_ON_S4_RESUME) { + Status = FdtSetProp (Fdt, UPLParaNode, "boot-mode", "s4", (UINT32)(AsciiStrLen ("s4")+1)); + } else if (BootMode == BOOT_ON_S3_RESUME) { + Status = FdtSetProp (Fdt, UPLParaNode, "boot-mode", "s3", (UINT32)(AsciiStrLen ("s3")+1)); + } else { + Status = FdtSetProp (Fdt, UPLParaNode, "boot-mode", "na", (UINT32)(AsciiStrLen ("na")+1)); + } + + ASSERT_EFI_ERROR (Status); + + Status = FdtSetProp (Fdt, UPLParaNode, "compatible", "upl", (UINT32)(AsciiStrLen ("upl")+1)); + ASSERT_EFI_ERROR (Status); + + GuidHob = GetFirstGuidHob (&gUniversalPayloadBaseGuid); + if (GuidHob != NULL) { + PayloadBase = (UNIVERSAL_PAYLOAD_BASE *)GET_GUID_HOB_DATA (GuidHob); + Fit = (VOID *)(UINTN)PayloadBase->Entry; + DEBUG ((DEBUG_INFO, "PayloadBase Entry = 0x%08x\n", PayloadBase->Entry)); + + Status = AsciiSPrint (TempStr, sizeof (TempStr), "upl-images@%lX", (UINTN)(Fit)); + UPLImageNode = FdtAddSubnode (Fdt, ParentNode, TempStr); + + Data64 = CpuToFdt64 ((UINTN)Fit); + Status = FdtSetProp (FdtBase, UPLImageNode, "addr", &Data64, sizeof (Data64)); + } + + CustomNode = FdtAddSubnode (Fdt, ParentNode, "upl-custom"); + ASSERT (CustomNode > 0); + + HobPtr = GetHobList (); + Data64 = CpuToFdt64 ((UINT64)(EFI_PHYSICAL_ADDRESS)HobPtr); + Status = FdtSetProp (Fdt, CustomNode, "hoblistptr", &Data64, sizeof (Data64)); + ASSERT_EFI_ERROR (Status); + + return Status; +} + +/** + It will build FDT for UPL consumed. + @param[in] FdtBase Address of the Fdt data. + @retval EFI_SUCCESS If it completed successfully. + @retval Others If it failed to build required FDT. +**/ +EFI_STATUS +BuildFdtForUPL ( + IN VOID *FdtBase + ) +{ + EFI_STATUS Status; + + // + // Build FDT for memory related + // + Status = BuildFdtForMemory (FdtBase); + ASSERT_EFI_ERROR (Status); + + Status = BuildFdtForMemAlloc (FdtBase); + ASSERT_EFI_ERROR (Status); + + Status = BuildFdtForPciRootBridge (FdtBase); + ASSERT_EFI_ERROR (Status); + + Status = BuildFdtForFrameBuffer (FdtBase); + ASSERT_EFI_ERROR (Status); + + Status = BuildFdtForUplRequired (FdtBase); + ASSERT_EFI_ERROR (Status); + + return Status; +} diff --git a/UefiPayloadPkg/Library/CustomFdtNodeParserLib/CustomFdtNodeParserLib.c b/UefiPayloadPkg/Library/CustomFdtNodeParserLib/CustomFdtNodeParserLib.c new file mode 100644 index 0000000000..0c454496dc --- /dev/null +++ b/UefiPayloadPkg/Library/CustomFdtNodeParserLib/CustomFdtNodeParserLib.c @@ -0,0 +1,164 @@ +/** @file + Copyright (c) 2024, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + Add a new HOB to the HOB List. + + @param HobType Type of the new HOB. + @param HobLength Length of the new HOB to allocate. + + @return NULL if there is no space to create a hob. + @return The address point to the new created hob. + +**/ +VOID * +EFIAPI +CreateHob ( + IN UINT16 HobType, + IN UINT16 HobLength + ); + +/** + Add HOB into HOB list + @param[in] Hob The HOB to be added into the HOB list. +**/ +VOID +AddNewHob ( + IN EFI_PEI_HOB_POINTERS *Hob + ); + +/** + Check the HOB and decide if it is need inside Payload + Payload maintainer may make decision which HOB is need or needn't + Then add the check logic in the function. + @param[in] Hob The HOB to check + @retval TRUE If HOB is need inside Payload + @retval FALSE If HOB is needn't inside Payload +**/ +BOOLEAN +EFIAPI +FitIsHobNeed ( + EFI_PEI_HOB_POINTERS Hob + ) +{ + if (FixedPcdGetBool (PcdHandOffFdtEnable)) { + if (Hob.Header->HobType == EFI_HOB_TYPE_HANDOFF) { + return FALSE; + } + + if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) { + if (CompareGuid (&Hob.MemoryAllocation->AllocDescriptor.Name, &gUniversalPayloadDeviceTreeGuid)) { + return FALSE; + } + + if (CompareGuid (&Hob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) { + return FALSE; + } + + if ((Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiReservedMemoryType) || + (Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiBootServicesCode) || + (Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiBootServicesData) || + (Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiRuntimeServicesCode) || + (Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiRuntimeServicesData) || + (Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiACPIReclaimMemory) || + (Hob.MemoryAllocation->AllocDescriptor.MemoryType == EfiACPIMemoryNVS)) + { + return FALSE; + } + } + + if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { + if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { + return FALSE; + } + } + + if (Hob.Header->HobType == EFI_HOB_TYPE_GUID_EXTENSION) { + if (CompareGuid (&Hob.Guid->Name, &gUniversalPayloadSerialPortInfoGuid)) { + return FALSE; + } + + if (CompareGuid (&Hob.Guid->Name, &gUniversalPayloadAcpiTableGuid)) { + return FALSE; + } + + if (CompareGuid (&Hob.Guid->Name, &gUniversalPayloadPciRootBridgeInfoGuid)) { + return FALSE; + } + } + } + + // Arrive here mean the HOB is need + return TRUE; +} + +/** + It will Parse FDT -custom node based on information from bootloaders. + @param[in] FdtBase The starting memory address of FdtBase + @param[in] HobList The starting memory address of New Hob list. + +**/ +UINTN +EFIAPI +CustomFdtNodeParser ( + IN VOID *FdtBase, + IN VOID *HobList + ) +{ + INT32 Node, CustomNode; + INT32 TempLen; + UINT64 *Data64; + UINTN CHobList; + CONST FDT_PROPERTY *PropertyPtr; + EFI_PEI_HOB_POINTERS Hob; + + CHobList = (UINTN)HobList; + + DEBUG ((DEBUG_INFO, "%a() #1 \n", __func__)); + + // + // Look for if exists hob list node + // + Node = FdtSubnodeOffsetNameLen (FdtBase, 0, "options", (INT32)AsciiStrLen ("options")); + if (Node > 0) { + DEBUG ((DEBUG_INFO, " Found options node (%08X)", Node)); + CustomNode = FdtSubnodeOffsetNameLen (FdtBase, Node, "upl-custom", (INT32)AsciiStrLen ("upl-custom")); + if (CustomNode > 0) { + DEBUG ((DEBUG_INFO, " Found upl-custom node (%08X)", CustomNode)); + PropertyPtr = FdtGetProperty (FdtBase, CustomNode, "hoblistptr", &TempLen); + Data64 = (UINT64 *)(PropertyPtr->Data); + CHobList = (UINTN)Fdt64ToCpu (*Data64); + DEBUG ((DEBUG_INFO, " Found hob list node (%08X)", CustomNode)); + DEBUG ((DEBUG_INFO, " -pointer %016lX\n", CHobList)); + } + } + + Hob.Raw = (UINT8 *)CHobList; + + // + // Since payload created new Hob, move all hobs except PHIT from boot loader hob list. + // + while (!END_OF_HOB_LIST (Hob)) { + if (FitIsHobNeed (Hob)) { + // Add this hob to payload HOB + AddNewHob (&Hob); + } + + Hob.Raw = GET_NEXT_HOB (Hob); + } + + return CHobList; +} diff --git a/UefiPayloadPkg/Library/CustomFdtNodeParserLib/CustomFdtNodeParserLib.inf b/UefiPayloadPkg/Library/CustomFdtNodeParserLib/CustomFdtNodeParserLib.inf new file mode 100644 index 0000000000..036ed4315d --- /dev/null +++ b/UefiPayloadPkg/Library/CustomFdtNodeParserLib/CustomFdtNodeParserLib.inf @@ -0,0 +1,46 @@ +## @file +# Custom FDT Node Parse Library. +# +# Copyright (c) 2024, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CustomFdtNodeParserLib + FILE_GUID = 732B2B8F-65AD-4BF8-A98F-6E0D330F7A60 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = CustomFdtNodeParserLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + CustomFdtNodeParserLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + BaseMemoryLib + DebugLib + FdtLib + HobLib + PcdLib + +[Guids] + gUniversalPayloadPciRootBridgeInfoGuid + gUniversalPayloadSerialPortInfoGuid + gUniversalPayloadDeviceTreeGuid + gUniversalPayloadAcpiTableGuid + gEfiHobMemoryAllocModuleGuid + +[Pcd] + gUefiPayloadPkgTokenSpaceGuid.PcdHandOffFdtEnable diff --git a/UefiPayloadPkg/Library/CustomFdtNodeParserNullLib/CustomFdtNodeParserNullLib.c b/UefiPayloadPkg/Library/CustomFdtNodeParserNullLib/CustomFdtNodeParserNullLib.c new file mode 100644 index 0000000000..4b2a8b9238 --- /dev/null +++ b/UefiPayloadPkg/Library/CustomFdtNodeParserNullLib/CustomFdtNodeParserNullLib.c @@ -0,0 +1,46 @@ +/** @file + Copyright (c) 2024, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ +#include +#include +#include + +/** + Check the HOB and decide if it is need inside Payload + Payload maintainer may make decision which HOB is need or needn't + Then add the check logic in the function. + @param[in] Hob The HOB to check + @retval TRUE If HOB is need inside Payload + @retval FALSE If HOB is needn't inside Payload +**/ +BOOLEAN +FitIsHobNeed ( + EFI_PEI_HOB_POINTERS Hob + ) +{ + return FALSE; +} + +/** + It will Parse FDT -custom node based on information from bootloaders. + @param[in] FdtBase The starting memory address of FdtBase. + @param[in] HobList The starting memory address of New Hob list. + @retval HobList The base address of Hoblist. + +**/ +UINTN +CustomFdtNodeParser ( + IN VOID *Fdt, + IN VOID *HobList + ) +{ + UINTN CHobList; + + CHobList = 0; + if (HobList != NULL) { + CHobList = (UINTN)HobList; + } + + return CHobList; +} diff --git a/UefiPayloadPkg/Library/CustomFdtNodeParserNullLib/CustomFdtNodeParserNullLib.inf b/UefiPayloadPkg/Library/CustomFdtNodeParserNullLib/CustomFdtNodeParserNullLib.inf new file mode 100644 index 0000000000..8410f04c9d --- /dev/null +++ b/UefiPayloadPkg/Library/CustomFdtNodeParserNullLib/CustomFdtNodeParserNullLib.inf @@ -0,0 +1,27 @@ +## @file +# Custom FDT Node Parse Library. +# +# Copyright (c) 2024, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = CustomFdtNodeParserLibNull + FILE_GUID = 386496E4-37DB-4531-BA0C-16D126E63C55 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = CustomFdtNodeParserLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + CustomFdtNodeParserNullLib.c + +[Packages] + MdePkg/MdePkg.dec diff --git a/UefiPayloadPkg/Library/FdtParserLib/FdtParseLib.inf b/UefiPayloadPkg/Library/FdtParserLib/FdtParseLib.inf new file mode 100644 index 0000000000..b9b7e90edc --- /dev/null +++ b/UefiPayloadPkg/Library/FdtParserLib/FdtParseLib.inf @@ -0,0 +1,64 @@ +## @file +# Coreboot Table Parse Library. +# +# Copyright (c) 2024, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FdtParseLib + FILE_GUID = 8956F72D-9626-4959-98B7-1BD4A3EA687E + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = FdtParseLib + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + FdtParserLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + DebugLib + PcdLib + HobLib + FdtLib + CustomFdtNodeParserLib + +[Guids] + gUniversalPayloadDeviceTreeGuid + gEfiGraphicsInfoHobGuid + gEfiGraphicsDeviceInfoHobGuid + gUniversalPayloadAcpiTableGuid + gUniversalPayloadSerialPortInfoGuid + +[Pcd.IA32,Pcd.X64] + gUefiPayloadPkgTokenSpaceGuid.PcdPayloadFdMemSize + gUefiPayloadPkgTokenSpaceGuid.PcdSystemMemoryUefiRegionSize + gUefiPayloadPkgTokenSpaceGuid.PcdHandOffFdtEnable + gUefiPayloadPkgTokenSpaceGuid.PcdPayloadFdMemBase + gUefiPayloadPkgTokenSpaceGuid.PcdPciReservedPMemBase + gUefiPayloadPkgTokenSpaceGuid.PcdPciReservedPMemLimit + gUefiPayloadPkgTokenSpaceGuid.PcdPciReservedPMemAbove4GBBase + gUefiPayloadPkgTokenSpaceGuid.PcdPciReservedPMemAbove4GBLimit + gUefiPayloadPkgTokenSpaceGuid.SizeOfIoSpace + + +[BuildOptions] + MSFT:*_*_*_CC_FLAGS = /wd4305 + GCC:*_*_IA32_CC_FLAGS = -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast + GCC:*_*_X64_CC_FLAGS = -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast + GCC:*_*_ARM_CC_FLAGS = -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast + GCC:*_*_AARCH64_CC_FLAGS = -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast + GCC:*_*_RISCV64_CC_FLAGS = -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast + GCC:*_*_LOONGARCH64_CC_FLAGS = -Wno-error=pointer-to-int-cast -Wno-error=int-to-pointer-cast diff --git a/UefiPayloadPkg/Library/FdtParserLib/FdtParserLib.c b/UefiPayloadPkg/Library/FdtParserLib/FdtParserLib.c new file mode 100644 index 0000000000..421b22904f --- /dev/null +++ b/UefiPayloadPkg/Library/FdtParserLib/FdtParserLib.c @@ -0,0 +1,944 @@ +/** @file + Copyright (c) 2024, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef enum { + ReservedMemory = 1, + Memory, + FrameBuffer, + PciRootBridge, + Options, + DoNothing +} FDT_NODE_TYPE; + +#define MEMORY_ATTRIBUTE_DEFAULT (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 ) + +#define ROOT_BRIDGE_SUPPORTS_DEFAULT (EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \ + EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 | \ + EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 | \ + EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | \ + EFI_PCI_IO_ATTRIBUTE_VGA_IO | \ + EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | \ + EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO | \ + EFI_PCI_IO_ATTRIBUTE_ISA_IO | \ + EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO ) + +extern VOID *mHobList; +UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES *mPciRootBridgeInfo = NULL; +INT32 mNode[0x500] = { 0 }; +UINT32 mNodeIndex = 0; + +/** + Build a Handoff Information Table HOB + + This function initialize a HOB region from EfiMemoryBegin to + EfiMemoryTop. And EfiFreeMemoryBottom and EfiFreeMemoryTop should + be inside the HOB region. + + @param[in] EfiMemoryBottom Total memory start address + @param[in] EfiMemoryTop Total memory end address. + @param[in] EfiFreeMemoryBottom Free memory start address + @param[in] EfiFreeMemoryTop Free memory end address. + + @return The pointer to the handoff HOB table. + +**/ +EFI_HOB_HANDOFF_INFO_TABLE * +EFIAPI +HobConstructor ( + IN VOID *EfiMemoryBottom, + IN VOID *EfiMemoryTop, + IN VOID *EfiFreeMemoryBottom, + IN VOID *EfiFreeMemoryTop + ); + +/** + It will record the memory node initialized. + + @param[in] Node memory node is going to parsing.. +**/ +VOID +RecordMemoryNode ( + INT32 Node + ) +{ + DEBUG ((DEBUG_INFO, "\n RecordMemoryNode %x , mNodeIndex :%x \n", Node, mNodeIndex)); + mNode[mNodeIndex] = Node; + mNodeIndex++; +} + +/** + Check the memory node if initialized. + + @param[in] Node memory node is going to parsing.. + + @return TRUE memory node was initialized. don't parse it again. + @return FALSE memory node wasn't initialized , go to parse it. +**/ +BOOLEAN +CheckMemoryNodeIfInit ( + INT32 Node + ) +{ + UINT32 i; + + for (i = 0; i < mNodeIndex; i++) { + if (mNode[i] == Node) { + return TRUE; + } + } + + return FALSE; +} + +/** + It will check device node from FDT. + + @param[in] NodeString Device node name string. + @param[in] Depth Check layer of Device node , only parse the 1st layer + + @return FDT_NODE_TYPE what type of the device node. +**/ +FDT_NODE_TYPE +CheckNodeType ( + CHAR8 *NodeString, + INT32 Depth + ) +{ + DEBUG ((DEBUG_INFO, "\n CheckNodeType %a \n", NodeString)); + if (AsciiStrnCmp (NodeString, "reserved-memory", AsciiStrLen ("reserved-memory")) == 0 ) { + return ReservedMemory; + } else if (AsciiStrnCmp (NodeString, "memory@", AsciiStrLen ("memory@")) == 0 ) { + return Memory; + } else if (AsciiStrnCmp (NodeString, "framebuffer@", AsciiStrLen ("framebuffer@")) == 0) { + return FrameBuffer; + } else if (AsciiStrnCmp (NodeString, "pci-rb", AsciiStrLen ("pci-rb")) == 0 ) { + return PciRootBridge; + } else if (AsciiStrCmp (NodeString, "options") == 0) { + return Options; + } else { + return DoNothing; + } +} + +/** + It will ParseMemory node from FDT. + + @param[in] Fdt Address of the Fdt data. + @param[in] SubNode first node of the PCI root bridge node. +**/ +VOID +ParseMemory ( + IN VOID *Fdt, + IN INT32 Node + ) +{ + UINT32 Attribute; + UINT8 ECCAttribute; + UINT32 ECCData, ECCData2; + INT32 Property; + CONST FDT_PROPERTY *PropertyPtr; + INT32 TempLen; + CONST CHAR8 *TempStr; + UINT64 *Data64; + UINT32 *Data32; + UINT64 StartAddress; + UINT64 NumberOfBytes; + + Attribute = MEMORY_ATTRIBUTE_DEFAULT; + ECCAttribute = 0; + ECCData = ECCData2 = 0; + for (Property = FdtFirstPropertyOffset (Fdt, Node); Property >= 0; Property = FdtNextPropertyOffset (Fdt, Property)) { + PropertyPtr = FdtGetPropertyByOffset (Fdt, Property, &TempLen); + TempStr = FdtGetString (Fdt, Fdt32ToCpu (PropertyPtr->NameOffset), NULL); + if (AsciiStrCmp (TempStr, "reg") == 0) { + Data64 = (UINT64 *)(PropertyPtr->Data); + StartAddress = Fdt64ToCpu (*Data64); + NumberOfBytes = Fdt64ToCpu (*(Data64 + 1)); + } else if (AsciiStrCmp (TempStr, "ecc-detection-bits") == 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + ECCData = Fdt32ToCpu (*Data32); + } else if (AsciiStrCmp (TempStr, "ecc-correction-bits") == 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + ECCData2 = Fdt32ToCpu (*Data32); + } + } + + if (ECCData == ECCData2) { + if (ECCData == 1) { + ECCAttribute = EFI_RESOURCE_ATTRIBUTE_SINGLE_BIT_ECC; + } else if (ECCData == 2) { + ECCAttribute = EFI_RESOURCE_ATTRIBUTE_MULTIPLE_BIT_ECC; + } + } + + if (ECCAttribute != 0) { + Attribute |= ECCAttribute; + } + + BuildResourceDescriptorHob (EFI_RESOURCE_SYSTEM_MEMORY, Attribute, StartAddress, NumberOfBytes); +} + +/** + It will ParseReservedMemory node from FDT. + + @param[in] Fdt Address of the Fdt data. + @param[in] SubNode first node of the PCI root bridge node. +**/ +VOID +ParseReservedMemory ( + IN VOID *Fdt, + IN INT32 Node + ) +{ + INT32 SubNode; + INT32 TempLen; + CONST CHAR8 *TempStr; + CONST FDT_PROPERTY *PropertyPtr; + UINT64 *Data64; + UINT64 StartAddress; + UINT64 NumberOfBytes; + UNIVERSAL_PAYLOAD_ACPI_TABLE *PlatformAcpiTable; + FDT_NODE_HEADER *NodePtr; + + PlatformAcpiTable = NULL; + + 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)); + PropertyPtr = FdtGetProperty (Fdt, SubNode, "reg", &TempLen); + ASSERT (TempLen > 0); + TempStr = (CHAR8 *)(PropertyPtr->Data); + if (TempLen > 0) { + Data64 = (UINT64 *)(PropertyPtr->Data); + StartAddress = Fdt64ToCpu (*Data64); + NumberOfBytes = Fdt64ToCpu (*(Data64 + 1)); + DEBUG ((DEBUG_INFO, "\n Property %a", TempStr)); + DEBUG ((DEBUG_INFO, " %016lX %016lX", StartAddress, NumberOfBytes)); + } + + RecordMemoryNode (SubNode); + + if (AsciiStrnCmp (NodePtr->Name, "mmio@", AsciiStrLen ("mmio@")) == 0) { + DEBUG ((DEBUG_INFO, " MemoryMappedIO")); + BuildMemoryAllocationHob (StartAddress, NumberOfBytes, EfiMemoryMappedIO); + } else { + PropertyPtr = FdtGetProperty (Fdt, SubNode, "compatible", &TempLen); + TempStr = (CHAR8 *)(PropertyPtr->Data); + if (AsciiStrnCmp (TempStr, "boot-code", AsciiStrLen ("boot-code")) == 0) { + DEBUG ((DEBUG_INFO, " boot-code")); + BuildMemoryAllocationHob (StartAddress, NumberOfBytes, EfiBootServicesCode); + } else if (AsciiStrnCmp (TempStr, "boot-data", AsciiStrLen ("boot-data")) == 0) { + DEBUG ((DEBUG_INFO, " boot-data")); + BuildMemoryAllocationHob (StartAddress, NumberOfBytes, EfiBootServicesData); + } else if (AsciiStrnCmp (TempStr, "runtime-code", AsciiStrLen ("runtime-code")) == 0) { + DEBUG ((DEBUG_INFO, " runtime-code")); + BuildMemoryAllocationHob (StartAddress, NumberOfBytes, EfiRuntimeServicesCode); + } else if (AsciiStrnCmp (TempStr, "runtime-data", AsciiStrLen ("runtime-data")) == 0) { + DEBUG ((DEBUG_INFO, " runtime-data")); + BuildMemoryAllocationHob (StartAddress, NumberOfBytes, EfiRuntimeServicesData); + } else if (AsciiStrnCmp (TempStr, "acpi", AsciiStrLen ("acpi")) == 0) { + DEBUG ((DEBUG_INFO, " acpi, StartAddress:%x, NumberOfBytes:%x", StartAddress, NumberOfBytes)); + BuildMemoryAllocationHob (StartAddress, NumberOfBytes, EfiBootServicesData); + PlatformAcpiTable = BuildGuidHob (&gUniversalPayloadAcpiTableGuid, sizeof (UNIVERSAL_PAYLOAD_ACPI_TABLE)); + if (PlatformAcpiTable != NULL) { + DEBUG ((DEBUG_INFO, " build gUniversalPayloadAcpiTableGuid , NumberOfBytes:%x", NumberOfBytes)); + PlatformAcpiTable->Rsdp = (EFI_PHYSICAL_ADDRESS)(UINTN)StartAddress; + PlatformAcpiTable->Header.Revision = UNIVERSAL_PAYLOAD_ACPI_TABLE_REVISION; + PlatformAcpiTable->Header.Length = sizeof (UNIVERSAL_PAYLOAD_ACPI_TABLE); + } + } else if (AsciiStrnCmp (TempStr, "acpi-nvs", AsciiStrLen ("acpi-nvs")) == 0) { + DEBUG ((DEBUG_INFO, " acpi-nvs")); + BuildMemoryAllocationHob (StartAddress, NumberOfBytes, EfiACPIMemoryNVS); + } else { + BuildMemoryAllocationHob (StartAddress, NumberOfBytes, EfiReservedMemoryType); + } + } + } +} + +/** + It will ParseFrameBuffer node from FDT. + + @param[in] Fdt Address of the Fdt data. + @param[in] SubNode first Sub node of the PCI root bridge node. + + @return GmaStr Graphic device node name string. +**/ +CHAR8 * +ParseFrameBuffer ( + IN VOID *Fdt, + IN INT32 Node + ) +{ + INT32 Property; + INT32 TempLen; + CONST FDT_PROPERTY *PropertyPtr; + CONST CHAR8 *TempStr; + UINT32 *Data32; + UINT64 FrameBufferBase; + UINT32 FrameBufferSize; + EFI_PEI_GRAPHICS_INFO_HOB *GraphicsInfo; + CHAR8 *GmaStr; + + GmaStr = "Gma"; + // + // Create GraphicInfo HOB. + // + GraphicsInfo = BuildGuidHob (&gEfiGraphicsInfoHobGuid, sizeof (EFI_PEI_GRAPHICS_INFO_HOB)); + ASSERT (GraphicsInfo != NULL); + if (GraphicsInfo == NULL) { + return GmaStr; + } + + ZeroMem (GraphicsInfo, sizeof (EFI_PEI_GRAPHICS_INFO_HOB)); + + for (Property = FdtFirstPropertyOffset (Fdt, Node); Property >= 0; Property = FdtNextPropertyOffset (Fdt, Property)) { + PropertyPtr = FdtGetPropertyByOffset (Fdt, Property, &TempLen); + TempStr = FdtGetString (Fdt, Fdt32ToCpu (PropertyPtr->NameOffset), NULL); + if (AsciiStrCmp (TempStr, "reg") == 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + FrameBufferBase = Fdt32ToCpu (*(Data32 + 0)); + FrameBufferSize = Fdt32ToCpu (*(Data32 + 1)); + GraphicsInfo->FrameBufferBase = FrameBufferBase; + GraphicsInfo->FrameBufferSize = (UINT32)FrameBufferSize; + } else if (AsciiStrCmp (TempStr, "width") == 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + GraphicsInfo->GraphicsMode.HorizontalResolution = Fdt32ToCpu (*Data32); + } else if (AsciiStrCmp (TempStr, "height") == 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + GraphicsInfo->GraphicsMode.VerticalResolution = Fdt32ToCpu (*Data32); + } else if (AsciiStrCmp (TempStr, "format") == 0) { + TempStr = (CHAR8 *)(PropertyPtr->Data); + if (AsciiStrCmp (TempStr, "a8r8g8b8") == 0) { + GraphicsInfo->GraphicsMode.PixelFormat = PixelRedGreenBlueReserved8BitPerColor; + } else if (AsciiStrCmp (TempStr, "a8b8g8r8") == 0) { + GraphicsInfo->GraphicsMode.PixelFormat = PixelBlueGreenRedReserved8BitPerColor; + } else { + GraphicsInfo->GraphicsMode.PixelFormat = PixelFormatMax; + } + } else if (AsciiStrCmp (TempStr, "display") == 0) { + GmaStr = (CHAR8 *)(PropertyPtr->Data); + GmaStr++; + DEBUG ((DEBUG_INFO, " display (%s)", GmaStr)); + } + } + + return GmaStr; +} + +/** + It will ParseOptions node from FDT. + + @param[in] Fdt Address of the Fdt data. + @param[in] SubNode first Sub node of the PCI root bridge node. + @param[out] PciEnumDone Init ParsePciRootBridge node for ParsePciRootBridge. + @param[out] BootMode Init the system boot mode +**/ +VOID +ParseOptions ( + IN VOID *Fdt, + IN INT32 Node, + OUT UINT8 *PciEnumDone, + 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; + + 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 . + // + PayloadBase = BuildGuidHob (&gUniversalPayloadBaseGuid, sizeof (UNIVERSAL_PAYLOAD_BASE)); + ASSERT (PayloadBase != NULL); + if (PayloadBase == NULL) { + return; + } + + PayloadBase->Header.Revision = UNIVERSAL_PAYLOAD_BASE_REVISION; + PayloadBase->Header.Length = sizeof (UNIVERSAL_PAYLOAD_BASE); + + PropertyPtr = FdtGetProperty (Fdt, SubNode, "addr", &TempLen); + + ASSERT (TempLen > 0); + if (TempLen > 0) { + Data64 = (UINT64 *)(PropertyPtr->Data); + StartAddress = Fdt64ToCpu (*Data64); + DEBUG ((DEBUG_INFO, "\n Property(00000000) entry")); + DEBUG ((DEBUG_INFO, " %016lX\n", StartAddress)); + + PayloadBase->Entry = (EFI_PHYSICAL_ADDRESS)StartAddress; + } + } + + if (AsciiStrnCmp (NodePtr->Name, "upl-params", AsciiStrLen ("upl-params")) == 0) { + PropertyPtr = FdtGetProperty (Fdt, SubNode, "addr-width", &TempLen); + if (TempLen > 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + DEBUG ((DEBUG_INFO, "\n Property(00000000) address_width")); + DEBUG ((DEBUG_INFO, " %X", Fdt32ToCpu (*Data32))); + SizeOfMemorySpace = (UINT8)Fdt32ToCpu (*Data32); + BuildCpuHob (SizeOfMemorySpace, PcdGet8 (SizeOfIoSpace)); + } + + PropertyPtr = FdtGetProperty (Fdt, SubNode, "pci-enum-done", &TempLen); + if (TempLen > 0) { + *PciEnumDone = 1; + DEBUG ((DEBUG_INFO, " Found PciEnumDone (%08X)\n", *PciEnumDone)); + } else { + *PciEnumDone = 0; + DEBUG ((DEBUG_INFO, " Not Found PciEnumDone \n")); + } + + PropertyPtr = FdtGetProperty (Fdt, SubNode, "boot-mode", &TempLen); + if (TempLen > 0) { + TempStr = (CHAR8 *)(PropertyPtr->Data); + if (AsciiStrCmp (TempStr, "normal") == 0) { + *BootMode = BOOT_WITH_FULL_CONFIGURATION; + } else if (AsciiStrCmp (TempStr, "fast") == 0) { + *BootMode = BOOT_WITH_MINIMAL_CONFIGURATION; + } else if (AsciiStrCmp (TempStr, "full") == 0) { + *BootMode = BOOT_WITH_FULL_CONFIGURATION_PLUS_DIAGNOSTICS; + } else if (AsciiStrCmp (TempStr, "default") == 0) { + *BootMode = BOOT_WITH_DEFAULT_SETTINGS; + } else if (AsciiStrCmp (TempStr, "s4") == 0) { + *BootMode = BOOT_ON_S4_RESUME; + } else if (AsciiStrCmp (TempStr, "s3") == 0) { + *BootMode = BOOT_ON_S3_RESUME; + } + } + } + } +} + +/** + It will Parsegraphic node from FDT. + + @param[in] Fdt Address of the Fdt data. + @param[in] SubNode first Sub node of the PCI root bridge node. +**/ +VOID +ParsegraphicNode ( + IN VOID *Fdt, + IN INT32 SubNode + ) +{ + EFI_PEI_GRAPHICS_DEVICE_INFO_HOB *GraphicsDev; + CONST FDT_PROPERTY *PropertyPtr; + UINT16 GmaID; + UINT32 *Data32; + INT32 TempLen; + + DEBUG ((DEBUG_INFO, " Found gma@ node \n")); + GraphicsDev = NULL; + // + // Build Graphic info HOB . + // + GraphicsDev = BuildGuidHob (&gEfiGraphicsDeviceInfoHobGuid, sizeof (EFI_PEI_GRAPHICS_DEVICE_INFO_HOB)); + ASSERT (GraphicsDev != NULL); + if (GraphicsDev == NULL) { + return; + } + + SetMem (GraphicsDev, sizeof (EFI_PEI_GRAPHICS_DEVICE_INFO_HOB), 0xFF); + PropertyPtr = FdtGetProperty (Fdt, SubNode, "vendor-id", &TempLen); + ASSERT (TempLen > 0); + if (TempLen > 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + GmaID = (UINT16)Fdt32ToCpu (*Data32); + DEBUG ((DEBUG_INFO, "\n vendor-id")); + DEBUG ((DEBUG_INFO, " %016lX\n", GmaID)); + GraphicsDev->VendorId = GmaID; + } + + PropertyPtr = FdtGetProperty (Fdt, SubNode, "device-id", &TempLen); + ASSERT (TempLen > 0); + if (TempLen > 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + GmaID = (UINT16)Fdt32ToCpu (*Data32); + DEBUG ((DEBUG_INFO, "\n device-id")); + DEBUG ((DEBUG_INFO, " %016lX\n", GmaID)); + GraphicsDev->DeviceId = GmaID; + } + + PropertyPtr = FdtGetProperty (Fdt, SubNode, "revision-id", &TempLen); + ASSERT (TempLen > 0); + if (TempLen > 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + GmaID = (UINT16)Fdt32ToCpu (*Data32); + DEBUG ((DEBUG_INFO, "\n revision-id")); + DEBUG ((DEBUG_INFO, " %016lX\n", GmaID)); + GraphicsDev->RevisionId = (UINT8)GmaID; + } + + PropertyPtr = FdtGetProperty (Fdt, SubNode, "subsystem-vendor-id", &TempLen); + ASSERT (TempLen > 0); + if (TempLen > 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + GmaID = (UINT16)Fdt32ToCpu (*Data32); + DEBUG ((DEBUG_INFO, "\n subsystem-vendor-id")); + DEBUG ((DEBUG_INFO, " %016lX\n", GmaID)); + GraphicsDev->SubsystemVendorId = GmaID; + } + + PropertyPtr = FdtGetProperty (Fdt, SubNode, "subsystem-id", &TempLen); + ASSERT (TempLen > 0); + if (TempLen > 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + GmaID = (UINT16)Fdt32ToCpu (*Data32); + DEBUG ((DEBUG_INFO, "\n subsystem-id")); + DEBUG ((DEBUG_INFO, " %016lX\n", GmaID)); + GraphicsDev->SubsystemId = GmaID; + } +} + +/** + It will ParseSerialPort node from FDT. + + @param[in] Fdt Address of the Fdt data. + @param[in] SubNode first Sub node of the PCI root bridge node. +**/ +VOID +ParseSerialPort ( + IN VOID *Fdt, + IN INT32 SubNode + ) +{ + UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO *Serial; + CONST FDT_PROPERTY *PropertyPtr; + INT32 TempLen; + CONST CHAR8 *TempStr; + UINT32 *Data32; + UINT32 Attribute; + + // + // Create SerialPortInfo HOB. + // + Serial = BuildGuidHob (&gUniversalPayloadSerialPortInfoGuid, sizeof (UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO)); + ASSERT (Serial != NULL); + if (Serial == NULL) { + return; + } + + Serial->Header.Revision = UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO_REVISION; + Serial->Header.Length = sizeof (UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO); + Serial->RegisterStride = 1; + Serial->UseMmio = 1; + + PropertyPtr = FdtGetProperty (Fdt, SubNode, "current-speed", &TempLen); + ASSERT (TempLen > 0); + if (TempLen > 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + DEBUG ((DEBUG_INFO, " %X", Fdt32ToCpu (*Data32))); + Serial->BaudRate = Fdt32ToCpu (*Data32); + } + + PropertyPtr = FdtGetProperty (Fdt, SubNode, "compatible", &TempLen); + TempStr = (CHAR8 *)(PropertyPtr->Data); + if (AsciiStrnCmp (TempStr, "isa", AsciiStrLen ("isa")) == 0) { + DEBUG ((DEBUG_INFO, " find serial compatible isa \n")); + Serial->UseMmio = 0; + PropertyPtr = FdtGetProperty (Fdt, SubNode, "reg", &TempLen); + ASSERT (TempLen > 0); + if (TempLen > 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + Attribute = Fdt32ToCpu (*(Data32 + 0)); + Serial->RegisterBase = Fdt32ToCpu (*(Data32 + 1)); + Serial->UseMmio = Attribute == 1 ? FALSE : TRUE; + DEBUG ((DEBUG_INFO, "\n in espi serial Property() %a", TempStr)); + DEBUG ((DEBUG_INFO, " StartAddress %016lX\n", Serial->RegisterBase)); + DEBUG ((DEBUG_INFO, " Attribute %016lX\n", Attribute)); + } + } else { + DEBUG ((DEBUG_INFO, " NOT serial compatible isa \n")); + PropertyPtr = FdtGetProperty (Fdt, SubNode, "reg", &TempLen); + ASSERT (TempLen > 0); + if (TempLen > 0) { + Data32 = (UINT32 *)(PropertyPtr->Data); + Serial->RegisterBase = Fdt32ToCpu (*Data32); + } + } +} + +/** + It will ParsePciRootBridge node from FDT. + + @param[in] Fdt Address of the Fdt data. + @param[in] Node first node of the Fdt data. + @param[in] PciEnumDone To use ParsePciRootBridge node. + @param[in] RootBridgeCount Number of pci RootBridge. + @param[in] GmaStr Graphic device node name string. + @param[in] index Index of ParsePciRootBridge node. +**/ +VOID +ParsePciRootBridge ( + IN VOID *Fdt, + IN INT32 Node, + IN UINT8 PciEnumDone, + IN UINT8 RootBridgeCount, + IN CHAR8 *GmaStr, + IN UINT8 *index + ) +{ + INT32 SubNode; + INT32 Property; + INT32 SSubNode; + FDT_NODE_HEADER *NodePtr; + CONST FDT_PROPERTY *PropertyPtr; + INT32 TempLen; + UINT32 *Data32; + UINT32 MemType; + CONST CHAR8 *TempStr; + UINT8 RbIndex; + UINTN HobDataSize; + UINT8 Base; + + RbIndex = *index; + HobDataSize = sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES) + RootBridgeCount *sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGE); + // + // Create PCI Root Bridge Info Hob. + // + if (mPciRootBridgeInfo == NULL) { + mPciRootBridgeInfo = BuildGuidHob (&gUniversalPayloadPciRootBridgeInfoGuid, HobDataSize); + ASSERT (mPciRootBridgeInfo != NULL); + if (mPciRootBridgeInfo == NULL) { + return; + } + + ZeroMem (mPciRootBridgeInfo, HobDataSize); + mPciRootBridgeInfo->Header.Length = sizeof (UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES); + mPciRootBridgeInfo->Header.Revision = UNIVERSAL_PAYLOAD_PCI_ROOT_BRIDGES_REVISION; + mPciRootBridgeInfo->Count = RootBridgeCount; + mPciRootBridgeInfo->ResourceAssigned = (BOOLEAN)PciEnumDone; + } + + 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, GmaStr, AsciiStrLen (GmaStr)) == 0) { + DEBUG ((DEBUG_INFO, " Found gma@ node \n")); + ParsegraphicNode (Fdt, SubNode); + } + + if (AsciiStrnCmp (NodePtr->Name, "isa", AsciiStrLen ("isa")) == 0) { + SSubNode = FdtFirstSubnode (Fdt, SubNode); // serial + ParseSerialPort (Fdt, SSubNode); + } + + if (AsciiStrnCmp (NodePtr->Name, "serial@", AsciiStrLen ("serial@")) == 0) { + ParseSerialPort (Fdt, SubNode); + } + } + + DEBUG ((DEBUG_INFO, " RbIndex :%x \n", RbIndex)); + + for (Property = FdtFirstPropertyOffset (Fdt, Node); Property >= 0; Property = FdtNextPropertyOffset (Fdt, Property)) { + PropertyPtr = FdtGetPropertyByOffset (Fdt, Property, &TempLen); + TempStr = FdtGetString (Fdt, Fdt32ToCpu (PropertyPtr->NameOffset), NULL); + + if (AsciiStrCmp (TempStr, "ranges") == 0) { + DEBUG ((DEBUG_INFO, " Found ranges Property TempLen (%08X), limit %x\n", TempLen, TempLen/sizeof (UINT32))); + + mPciRootBridgeInfo->RootBridge[RbIndex].AllocationAttributes = EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | EFI_PCI_HOST_BRIDGE_MEM64_DECODE; + mPciRootBridgeInfo->RootBridge[RbIndex].Supports = ROOT_BRIDGE_SUPPORTS_DEFAULT; + mPciRootBridgeInfo->RootBridge[RbIndex].PMemAbove4G.Base = PcdGet64 (PcdPciReservedPMemAbove4GBBase); + mPciRootBridgeInfo->RootBridge[RbIndex].PMemAbove4G.Limit = PcdGet64 (PcdPciReservedPMemAbove4GBLimit); + mPciRootBridgeInfo->RootBridge[RbIndex].PMem.Base = PcdGet32 (PcdPciReservedPMemBase); + mPciRootBridgeInfo->RootBridge[RbIndex].PMem.Limit = PcdGet32 (PcdPciReservedPMemLimit); + mPciRootBridgeInfo->RootBridge[RbIndex].UID = RbIndex; + mPciRootBridgeInfo->RootBridge[RbIndex].HID = EISA_PNP_ID (0x0A03); + + Data32 = (UINT32 *)(PropertyPtr->Data); + for (Base = 0; Base < TempLen/sizeof (UINT32); Base = Base + DWORDS_TO_NEXT_ADDR_TYPE) { + DEBUG ((DEBUG_INFO, " Base :%x \n", Base)); + MemType = Fdt32ToCpu (*(Data32 + Base)); + if (((MemType) & (SS_64BIT_MEMORY_SPACE)) == SS_64BIT_MEMORY_SPACE) { + DEBUG ((DEBUG_INFO, " To program 64 mm \n")); + mPciRootBridgeInfo->RootBridge[RbIndex].MemAbove4G.Base = Fdt32ToCpu (*(Data32 + Base + 2)) + LShiftU64 (Fdt32ToCpu (*(Data32 + Base + 1)), 32); + mPciRootBridgeInfo->RootBridge[RbIndex].MemAbove4G.Limit = mPciRootBridgeInfo->RootBridge[RbIndex].MemAbove4G.Base + LShiftU64 (Fdt32ToCpu (*(Data32 + Base + 5)), 32) + Fdt32ToCpu (*(Data32 + Base + 6)) -1; + } else if (((MemType) & (SS_32BIT_MEMORY_SPACE)) == SS_32BIT_MEMORY_SPACE) { + DEBUG ((DEBUG_INFO, " To program 32 mem \n")); + mPciRootBridgeInfo->RootBridge[RbIndex].Mem.Base = Fdt32ToCpu (*(Data32 + Base + 2)); + mPciRootBridgeInfo->RootBridge[RbIndex].Mem.Limit = mPciRootBridgeInfo->RootBridge[RbIndex].Mem.Base + Fdt32ToCpu (*(Data32 + Base + 6)) -1; + } else if (((MemType) & (SS_IO_SPACE)) == SS_IO_SPACE) { + DEBUG ((DEBUG_INFO, " To program Io\n")); + mPciRootBridgeInfo->RootBridge[RbIndex].Io.Base = Fdt32ToCpu (*(Data32 + Base + 2)); + mPciRootBridgeInfo->RootBridge[RbIndex].Io.Limit = mPciRootBridgeInfo->RootBridge[RbIndex].Io.Base + Fdt32ToCpu (*(Data32 + Base + 6)) -1; + } + } + + DEBUG ((DEBUG_INFO, "RootBridgeCount %x, index :%x\n", RootBridgeCount, RbIndex)); + + DEBUG ((DEBUG_INFO, "PciRootBridge->Mem.Base %x, \n", mPciRootBridgeInfo->RootBridge[RbIndex].Mem.Base)); + DEBUG ((DEBUG_INFO, "PciRootBridge->Mem.limit %x, \n", mPciRootBridgeInfo->RootBridge[RbIndex].Mem.Limit)); + + DEBUG ((DEBUG_INFO, "PciRootBridge->MemAbove4G.Base %llx, \n", mPciRootBridgeInfo->RootBridge[RbIndex].MemAbove4G.Base)); + DEBUG ((DEBUG_INFO, "PciRootBridge->MemAbove4G.limit %llx, \n", mPciRootBridgeInfo->RootBridge[RbIndex].MemAbove4G.Limit)); + + DEBUG ((DEBUG_INFO, "PciRootBridge->Io.Base %llx, \n", mPciRootBridgeInfo->RootBridge[RbIndex].Io.Base)); + DEBUG ((DEBUG_INFO, "PciRootBridge->Io.limit %llx, \n", mPciRootBridgeInfo->RootBridge[RbIndex].Io.Limit)); + } + + if (AsciiStrCmp (TempStr, "bus-range") == 0) { + DEBUG ((DEBUG_INFO, " Found bus-range Property TempLen (%08X)\n", TempLen)); + + Data32 = (UINT32 *)(PropertyPtr->Data); + mPciRootBridgeInfo->RootBridge[RbIndex].Bus.Base = Fdt32ToCpu (*Data32) & 0xFF; + mPciRootBridgeInfo->RootBridge[RbIndex].Bus.Limit = Fdt32ToCpu (*(Data32 + 1)) & 0xFF; + mPciRootBridgeInfo->RootBridge[RbIndex].Bus.Translation = 0; + + DEBUG ((DEBUG_INFO, "PciRootBridge->Bus.Base %x, index %x\n", mPciRootBridgeInfo->RootBridge[RbIndex].Bus.Base, RbIndex)); + DEBUG ((DEBUG_INFO, "PciRootBridge->Bus.limit %x, index %x\n", mPciRootBridgeInfo->RootBridge[RbIndex].Bus.Limit, RbIndex)); + } + } + + if (RbIndex > 0) { + RbIndex--; + } + + DEBUG ((DEBUG_INFO, "After updated RbIndex :%x \n", RbIndex)); + *index = RbIndex; +} + +/** + It will parse FDT based on DTB from bootloaders. + + @param[in] FdtBase Address of the Fdt data. + + @return The address to the new hob list +**/ +UINTN +EFIAPI +ParseDtb ( + IN VOID *FdtBase + ) +{ + VOID *Fdt; + INT32 Node; + INT32 Property; + INT32 Depth; + FDT_NODE_HEADER *NodePtr; + CONST FDT_PROPERTY *PropertyPtr; + CONST CHAR8 *TempStr; + INT32 TempLen; + UINT64 *Data64; + UINT64 StartAddress; + UINT64 NumberOfBytes; + UINTN MinimalNeededSize; + EFI_PHYSICAL_ADDRESS FreeMemoryBottom; + EFI_PHYSICAL_ADDRESS FreeMemoryTop; + EFI_PHYSICAL_ADDRESS MemoryBottom; + EFI_PHYSICAL_ADDRESS MemoryTop; + BOOLEAN IsHobConstructed; + UINTN NewHobList; + UINT8 RootBridgeCount; + UINT8 index; + UINTN HobDataSize; + UINT8 PciEnumDone; + UINT8 NodeType; + EFI_BOOT_MODE BootMode; + CHAR8 *GmaStr; + + Fdt = FdtBase; + Depth = 0; + MinimalNeededSize = FixedPcdGet32 (PcdSystemMemoryUefiRegionSize); + IsHobConstructed = FALSE; + NewHobList = 0; + RootBridgeCount = 0; + index = 0; + HobDataSize = 0; + PciEnumDone = 0; + BootMode = 0; + NodeType = 0; + + DEBUG ((DEBUG_INFO, "FDT = 0x%x %x\n", Fdt, Fdt32ToCpu (*((UINT32 *)Fdt)))); + DEBUG ((DEBUG_INFO, "Start parsing DTB data\n")); + DEBUG ((DEBUG_INFO, "MinimalNeededSize :%x\n", MinimalNeededSize)); + + for (Node = FdtNextNode (Fdt, 0, &Depth); Node >= 0; Node = FdtNextNode (Fdt, Node, &Depth)) { + NodePtr = (FDT_NODE_HEADER *)((CONST CHAR8 *)Fdt + Node + Fdt32ToCpu (((FDT_HEADER *)Fdt)->OffsetDtStruct)); + DEBUG ((DEBUG_INFO, "\n Node(%08x) %a Depth %x", Node, NodePtr->Name, Depth)); + // memory node + if (AsciiStrnCmp (NodePtr->Name, "memory@", AsciiStrLen ("memory@")) == 0) { + for (Property = FdtFirstPropertyOffset (Fdt, Node); Property >= 0; Property = FdtNextPropertyOffset (Fdt, Property)) { + PropertyPtr = FdtGetPropertyByOffset (Fdt, Property, &TempLen); + TempStr = FdtGetString (Fdt, Fdt32ToCpu (PropertyPtr->NameOffset), NULL); + if (AsciiStrCmp (TempStr, "reg") == 0) { + Data64 = (UINT64 *)(PropertyPtr->Data); + StartAddress = Fdt64ToCpu (*Data64); + NumberOfBytes = Fdt64ToCpu (*(Data64 + 1)); + DEBUG ((DEBUG_INFO, "\n Property(%08X) %a", Property, TempStr)); + DEBUG ((DEBUG_INFO, " %016lX %016lX", StartAddress, NumberOfBytes)); + if (!IsHobConstructed) { + if ((NumberOfBytes > MinimalNeededSize) && (StartAddress < BASE_4GB)) { + MemoryBottom = StartAddress + NumberOfBytes - MinimalNeededSize; + FreeMemoryBottom = MemoryBottom; + FreeMemoryTop = StartAddress + NumberOfBytes; + MemoryTop = FreeMemoryTop; + + DEBUG ((DEBUG_INFO, "MemoryBottom :0x%llx\n", MemoryBottom)); + DEBUG ((DEBUG_INFO, "FreeMemoryBottom :0x%llx\n", FreeMemoryBottom)); + DEBUG ((DEBUG_INFO, "FreeMemoryTop :0x%llx\n", FreeMemoryTop)); + DEBUG ((DEBUG_INFO, "MemoryTop :0x%llx\n", MemoryTop)); + mHobList = HobConstructor ((VOID *)(UINTN)MemoryBottom, (VOID *)(UINTN)MemoryTop, (VOID *)(UINTN)FreeMemoryBottom, (VOID *)(UINTN)FreeMemoryTop); + IsHobConstructed = TRUE; + NewHobList = (UINTN)mHobList; + break; + } + } + } + } + } // end of memory node + else { + PropertyPtr = FdtGetProperty (Fdt, Node, "compatible", &TempLen); + TempStr = (CHAR8 *)(PropertyPtr->Data); + if (AsciiStrnCmp (TempStr, "pci-rb", AsciiStrLen ("pci-rb")) == 0) { + RootBridgeCount++; + } + } + } + + index = RootBridgeCount - 1; + Depth = 0; + for (Node = FdtNextNode (Fdt, 0, &Depth); Node >= 0; Node = FdtNextNode (Fdt, Node, &Depth)) { + NodePtr = (FDT_NODE_HEADER *)((CONST CHAR8 *)Fdt + Node + Fdt32ToCpu (((FDT_HEADER *)Fdt)->OffsetDtStruct)); + DEBUG ((DEBUG_INFO, "\n Node(%08x) %a Depth %x", Node, NodePtr->Name, Depth)); + + NodeType = CheckNodeType (NodePtr->Name, Depth); + DEBUG ((DEBUG_INFO, "NodeType :0x%x\n", NodeType)); + switch (NodeType) { + case ReservedMemory: + DEBUG ((DEBUG_INFO, "ParseReservedMemory\n")); + ParseReservedMemory (Fdt, Node); + break; + case Memory: + DEBUG ((DEBUG_INFO, "ParseMemory\n")); + if (!CheckMemoryNodeIfInit (Node)) { + ParseMemory (Fdt, Node); + } else { + DEBUG ((DEBUG_INFO, "Memory has initialized\n")); + } + + break; + case FrameBuffer: + DEBUG ((DEBUG_INFO, "ParseFrameBuffer\n")); + GmaStr = ParseFrameBuffer (Fdt, Node); + break; + case PciRootBridge: + DEBUG ((DEBUG_INFO, "ParsePciRootBridge, index :%x\n", index)); + ParsePciRootBridge (Fdt, Node, PciEnumDone, RootBridgeCount, GmaStr, &index); + DEBUG ((DEBUG_INFO, "After ParsePciRootBridge, index :%x\n", index)); + break; + case Options: + DEBUG ((DEBUG_INFO, "ParseOptions\n")); + ParseOptions (Fdt, Node, &PciEnumDone, &BootMode); + break; + default: + DEBUG ((DEBUG_INFO, "ParseNothing\n")); + break; + } + } + + ((EFI_HOB_HANDOFF_INFO_TABLE *)(mHobList))->BootMode = BootMode; + DEBUG ((DEBUG_INFO, "\n")); + + return NewHobList; +} + +/** + It will Parse FDT -node based on information from bootloaders. + @param[in] FdtBase The starting memory address of FdtBase + @retval HobList The base address of Hoblist. + +**/ +UINTN +EFIAPI +FdtNodeParser ( + IN VOID *FdtBase + ) +{ + return ParseDtb (FdtBase); +} + +/** + It will initialize HOBs for UPL. + + @param[in] FdtBase Address of the Fdt data. + + @retval EFI_SUCCESS If it completed successfully. + @retval Others If it failed to initialize HOBs. +**/ +UINTN +EFIAPI +UplInitHob ( + IN VOID *FdtBase + ) +{ + UINTN NHobAddress; + + NHobAddress = 0; + // + // Check parameter type( + // + if (FdtCheckHeader (FdtBase) == 0) { + DEBUG ((DEBUG_INFO, "%a() FDT blob\n", __func__)); + NHobAddress = FdtNodeParser ((VOID *)FdtBase); + } else { + DEBUG ((DEBUG_INFO, "%a() HOb list\n", __func__)); + mHobList = FdtBase; + + return (UINTN)(mHobList); + } + + return NHobAddress; +} diff --git a/UefiPayloadPkg/Library/HobParseLib/HobParseLib.c b/UefiPayloadPkg/Library/HobParseLib/HobParseLib.c new file mode 100644 index 0000000000..98a5dcfeae --- /dev/null +++ b/UefiPayloadPkg/Library/HobParseLib/HobParseLib.c @@ -0,0 +1,280 @@ +/** @file + Copyright (c) 2024, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ + EFI_RESOURCE_ATTRIBUTE_TESTED | \ + EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \ + EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \ + EFI_RESOURCE_ATTRIBUTE_PERSISTENT ) + +#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \ + EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \ + EFI_RESOURCE_ATTRIBUTE_TESTED ) + +extern VOID *mHobList; + +/** + Add a new HOB to the HOB List. + + @param HobType Type of the new HOB. + @param HobLength Length of the new HOB to allocate. + + @return NULL if there is no space to create a hob. + @return The address point to the new created hob. + +**/ +VOID * +EFIAPI +CreateHob ( + IN UINT16 HobType, + IN UINT16 HobLength + ); + +/** + Build a Handoff Information Table HOB + + This function initialize a HOB region from EfiMemoryBegin to + EfiMemoryTop. And EfiFreeMemoryBottom and EfiFreeMemoryTop should + be inside the HOB region. + + @param[in] EfiMemoryBottom Total memory start address + @param[in] EfiMemoryTop Total memory end address. + @param[in] EfiFreeMemoryBottom Free memory start address + @param[in] EfiFreeMemoryTop Free memory end address. + + @return The pointer to the handoff HOB table. + +**/ +EFI_HOB_HANDOFF_INFO_TABLE * +EFIAPI +HobConstructor ( + IN VOID *EfiMemoryBottom, + IN VOID *EfiMemoryTop, + IN VOID *EfiFreeMemoryBottom, + IN VOID *EfiFreeMemoryTop + ); + +/** + Build ACPI board info HOB using infomation from ACPI table + + @param AcpiTableBase ACPI table start address in memory + + @retval A pointer to ACPI board HOB ACPI_BOARD_INFO. Null if build HOB failure. +**/ +ACPI_BOARD_INFO * +BuildHobFromAcpi ( + IN UINT64 AcpiTableBase + ); + +/** + * + Add HOB into HOB list + + @param[in] Hob The HOB to be added into the HOB list. +**/ +VOID +AddNewHob ( + IN EFI_PEI_HOB_POINTERS *Hob + ) +{ + EFI_PEI_HOB_POINTERS NewHob; + + if (Hob->Raw == NULL) { + return; + } + + NewHob.Header = CreateHob (Hob->Header->HobType, Hob->Header->HobLength); + + if (NewHob.Header != NULL) { + CopyMem (NewHob.Header + 1, Hob->Header + 1, Hob->Header->HobLength - sizeof (EFI_HOB_GENERIC_HEADER)); + } +} + +/** + Found the Resource Descriptor HOB that contains a range (Base, Top) + + @param[in] HobList Hob start address + @param[in] Base Memory start address + @param[in] Top Memory end address. + + @retval The pointer to the Resource Descriptor HOB. +**/ +EFI_HOB_RESOURCE_DESCRIPTOR * +FindResourceDescriptorByRange ( + IN VOID *HobList, + IN EFI_PHYSICAL_ADDRESS Base, + IN EFI_PHYSICAL_ADDRESS Top + ) +{ + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + + for (Hob.Raw = (UINT8 *)HobList; !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 (Base < ResourceHob->PhysicalStart) { + continue; + } + + if (Top > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) { + continue; + } + + return ResourceHob; + } + + return NULL; +} + +/** + Find the highest below 4G memory resource descriptor, except the input Resource Descriptor. + + @param[in] HobList Hob start address + @param[in] MinimalNeededSize Minimal needed size. + @param[in] ExceptResourceHob Ignore this Resource Descriptor. + + @retval The pointer to the Resource Descriptor HOB. +**/ +EFI_HOB_RESOURCE_DESCRIPTOR * +FindAnotherHighestBelow4GResourceDescriptor ( + IN VOID *HobList, + IN UINTN MinimalNeededSize, + IN EFI_HOB_RESOURCE_DESCRIPTOR *ExceptResourceHob + ) +{ + EFI_PEI_HOB_POINTERS Hob; + EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob; + EFI_HOB_RESOURCE_DESCRIPTOR *ReturnResourceHob; + + ReturnResourceHob = NULL; + + for (Hob.Raw = (UINT8 *)HobList; !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 if the Resource Descriptor HOB equals to ExceptResourceHob + // + if (ResourceHob == ExceptResourceHob) { + continue; + } + + // + // Skip Resource Descriptor HOBs that are beyond 4G + // + if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > BASE_4GB) { + continue; + } + + // + // Skip Resource Descriptor HOBs that are too small + // + if (ResourceHob->ResourceLength < MinimalNeededSize) { + continue; + } + + // + // Return the topest Resource Descriptor + // + if (ReturnResourceHob == NULL) { + ReturnResourceHob = ResourceHob; + } else { + if (ReturnResourceHob->PhysicalStart < ResourceHob->PhysicalStart) { + ReturnResourceHob = ResourceHob; + } + } + } + + return ReturnResourceHob; +} + +/** + Check the HOB and decide if it is need inside Payload + + Payload maintainer may make decision which HOB is need or needn't + Then add the check logic in the function. + + @param[in] Hob The HOB to check + + @retval TRUE If HOB is need inside Payload + @retval FALSE If HOB is needn't inside Payload +**/ +BOOLEAN +IsHobNeed ( + EFI_PEI_HOB_POINTERS Hob + ) +{ + if (Hob.Header->HobType == EFI_HOB_TYPE_HANDOFF) { + return FALSE; + } + + if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) { + if (CompareGuid (&Hob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) { + return FALSE; + } + } + + // Arrive here mean the HOB is need + return TRUE; +} diff --git a/UefiPayloadPkg/Library/HobParseLib/HobParseLib.inf b/UefiPayloadPkg/Library/HobParseLib/HobParseLib.inf new file mode 100644 index 0000000000..634c7ff567 --- /dev/null +++ b/UefiPayloadPkg/Library/HobParseLib/HobParseLib.inf @@ -0,0 +1,40 @@ +## @file +# UPL Hob Parse Library. +# +# Copyright (c) 2024, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = HobParseLib + FILE_GUID = EFB05FE7-604B-40DA-9A59-E2F998528754 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + LIBRARY_CLASS = HobParseLib|DXE_DRIVER DXE_RUNTIME_DRIVER SMM_CORE DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + HobParseLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiPayloadPkg/UefiPayloadPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + IoLib + DebugLib + PcdLib + HobLib + +[Pcd.IA32,Pcd.X64] + gUefiPayloadPkgTokenSpaceGuid.PcdSystemMemoryUefiRegionSize + gUefiPayloadPkgTokenSpaceGuid.PcdHandOffFdtEnable diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayloadPkg.dsc index e94a7db886..6199527a9a 100644 --- a/UefiPayloadPkg/UefiPayloadPkg.dsc +++ b/UefiPayloadPkg/UefiPayloadPkg.dsc @@ -318,6 +318,7 @@ FdtLib|MdePkg/Library/BaseFdtLib/BaseFdtLib.inf SmmRelocationLib|UefiCpuPkg/Library/SmmRelocationLib/SmmRelocationLib.inf HobPrintLib|MdeModulePkg/Library/HobPrintLib/HobPrintLib.inf + BuildFdtLib|UefiPayloadPkg/Library/BuildFdtLib/BuildFdtLib.inf [LibraryClasses.common] !if $(BOOTSPLASH_IMAGE)