/** @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 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 = FALSE;
}
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);
if (PropertyPtr == NULL)
continue;
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, 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;
}
}
// Post processing: TODO: Need to look into it. Such cross dependency on DT nodes
// may not be good idea. Instead have this prop part of RB
mPciRootBridgeInfo->ResourceAssigned = (BOOLEAN)PciEnumDone;
((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;
}