/** @file | |
Memory Detection for RiscVVirt Machines. | |
Copyright (c) 2021, Hewlett Packard Enterprise Development LP. All rights reserved.<BR> | |
Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> | |
Copyright (c) 2025, Ventana Micro Systems Inc. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "PlatformSecLib.h" | |
VOID | |
BuildMemoryTypeHob ( | |
VOID | |
) | |
{ | |
EFI_MEMORY_TYPE_INFORMATION Info[6]; | |
Info[0].Type = EfiACPIReclaimMemory; | |
Info[0].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiACPIReclaimMemory); | |
Info[1].Type = EfiACPIMemoryNVS; | |
Info[1].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiACPIMemoryNVS); | |
Info[2].Type = EfiReservedMemoryType; | |
Info[2].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiReservedMemoryType); | |
Info[3].Type = EfiRuntimeServicesData; | |
Info[3].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiRuntimeServicesData); | |
Info[4].Type = EfiRuntimeServicesCode; | |
Info[4].NumberOfPages = PcdGet32 (PcdMemoryTypeEfiRuntimeServicesCode); | |
// Terminator for the list | |
Info[5].Type = EfiMaxMemoryType; | |
Info[5].NumberOfPages = 0; | |
BuildGuidDataHob (&gEfiMemoryTypeInformationGuid, &Info, sizeof (Info)); | |
} | |
/** | |
Create memory range resource HOB using the memory base | |
address and size. | |
@param MemoryBase Memory range base address. | |
@param MemorySize Memory range size. | |
**/ | |
STATIC | |
VOID | |
AddMemoryBaseSizeHob ( | |
IN EFI_PHYSICAL_ADDRESS MemoryBase, | |
IN UINT64 MemorySize | |
) | |
{ | |
BuildResourceDescriptorHob ( | |
EFI_RESOURCE_SYSTEM_MEMORY, | |
EFI_RESOURCE_ATTRIBUTE_PRESENT | | |
EFI_RESOURCE_ATTRIBUTE_INITIALIZED | | |
EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE | | |
EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE | | |
EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE | | |
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE | | |
EFI_RESOURCE_ATTRIBUTE_TESTED, | |
MemoryBase, | |
MemorySize | |
); | |
} | |
/** | |
Create memory range resource HOB using memory base | |
address and top address of the memory range. | |
@param MemoryBase Memory range base address. | |
@param MemoryLimit Memory range size. | |
**/ | |
STATIC | |
VOID | |
AddMemoryRangeHob ( | |
IN EFI_PHYSICAL_ADDRESS MemoryBase, | |
IN EFI_PHYSICAL_ADDRESS MemoryLimit | |
) | |
{ | |
AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase)); | |
} | |
/** | |
Publish system RAM and reserve memory regions. | |
**/ | |
STATIC | |
VOID | |
InitializeRamRegions ( | |
IN EFI_PHYSICAL_ADDRESS SystemMemoryBase, | |
IN UINT64 SystemMemorySize | |
) | |
{ | |
AddMemoryRangeHob ( | |
SystemMemoryBase, | |
SystemMemoryBase + SystemMemorySize | |
); | |
} | |
/** Get the number of cells for a given property | |
@param[in] Fdt Pointer to Device Tree (DTB) | |
@param[in] Node Node | |
@param[in] Name Name of the property | |
@return Number of cells. | |
**/ | |
STATIC | |
INT32 | |
GetNumCells ( | |
IN VOID *Fdt, | |
IN INT32 Node, | |
IN CONST CHAR8 *Name | |
) | |
{ | |
CONST INT32 *Prop; | |
INT32 Len; | |
UINT32 Val; | |
Prop = FdtGetProp (Fdt, Node, Name, &Len); | |
if (Prop == NULL) { | |
return Len; | |
} | |
if (Len != sizeof (*Prop)) { | |
return -FDT_ERR_BADNCELLS; | |
} | |
Val = Fdt32ToCpu (*Prop); | |
if (Val > FDT_MAX_NCELLS) { | |
return -FDT_ERR_BADNCELLS; | |
} | |
return (INT32)Val; | |
} | |
/** Mark reserved memory ranges in the EFI memory map | |
* As per DT spec v0.4 Section 3.5.4, | |
* "Reserved regions with the no-map property must be listed in the | |
* memory map with type EfiReservedMemoryType. All other reserved | |
* regions must be listed with type EfiBootServicesData." | |
@param FdtPointer Pointer to FDT | |
**/ | |
STATIC | |
VOID | |
AddReservedMemoryMap ( | |
IN VOID *FdtPointer | |
) | |
{ | |
CONST INT32 *RegProp; | |
INT32 Node; | |
INT32 SubNode; | |
INT32 Len; | |
EFI_PHYSICAL_ADDRESS Addr; | |
UINT64 Size; | |
INTN NumRsv, i; | |
INT32 NumAddrCells, NumSizeCells; | |
NumRsv = FdtGetNumberOfReserveMapEntries (FdtPointer); | |
/* Look for an existing entry and add it to the efi mem map. */ | |
for (i = 0; i < NumRsv; i++) { | |
if (FdtGetReserveMapEntry (FdtPointer, i, &Addr, &Size) != 0) { | |
continue; | |
} | |
BuildMemoryAllocationHob ( | |
Addr, | |
Size, | |
EfiReservedMemoryType | |
); | |
} | |
/* process reserved-memory */ | |
Node = FdtSubnodeOffset (FdtPointer, 0, "reserved-memory"); | |
if (Node >= 0) { | |
NumAddrCells = GetNumCells (FdtPointer, Node, "#address-cells"); | |
if (NumAddrCells <= 0) { | |
return; | |
} | |
NumSizeCells = GetNumCells (FdtPointer, Node, "#size-cells"); | |
if (NumSizeCells <= 0) { | |
return; | |
} | |
FdtForEachSubnode (SubNode, FdtPointer, Node) { | |
RegProp = FdtGetProp (FdtPointer, SubNode, "reg", &Len); | |
if ((RegProp != 0) && (Len == ((NumAddrCells + NumSizeCells) * sizeof (INT32)))) { | |
Addr = Fdt32ToCpu (RegProp[0]); | |
if (NumAddrCells > 1) { | |
Addr = (Addr << 32) | Fdt32ToCpu (RegProp[1]); | |
} | |
RegProp += NumAddrCells; | |
Size = Fdt32ToCpu (RegProp[0]); | |
if (NumSizeCells > 1) { | |
Size = (Size << 32) | Fdt32ToCpu (RegProp[1]); | |
} | |
DEBUG (( | |
DEBUG_INFO, | |
"%a: Adding Reserved Memory Addr = 0x%llx, Size = 0x%llx\n", | |
__func__, | |
Addr, | |
Size | |
)); | |
if (FdtGetProp (FdtPointer, SubNode, "no-map", &Len)) { | |
BuildMemoryAllocationHob ( | |
Addr, | |
Size, | |
EfiReservedMemoryType | |
); | |
} else { | |
BuildMemoryAllocationHob ( | |
Addr, | |
Size, | |
EfiBootServicesData | |
); | |
} | |
} | |
} | |
} | |
} | |
/** | |
Perform Memory initialization. | |
@param FdtPointer The pointer to the device tree. | |
@return EFI_SUCCESS The platform initialized successfully. | |
@retval Others - As the error code indicates | |
**/ | |
EFI_STATUS | |
EFIAPI | |
MemoryInitialization ( | |
VOID *FdtPointer | |
) | |
{ | |
CONST UINT64 *RegProp; | |
CONST CHAR8 *Type; | |
UINT64 CurBase, CurSize; | |
INT32 Node, Prev; | |
INT32 Len; | |
// Look for the lowest memory node | |
for (Prev = 0; ; Prev = Node) { | |
Node = FdtNextNode (FdtPointer, Prev, NULL); | |
if (Node < 0) { | |
break; | |
} | |
// Check for memory node | |
Type = FdtGetProp (FdtPointer, Node, "device_type", &Len); | |
if (Type && (AsciiStrnCmp (Type, "memory", Len) == 0)) { | |
// Get the 'reg' property of this node. For now, we will assume | |
// two 8 byte quantities for base and size, respectively. | |
RegProp = FdtGetProp (FdtPointer, Node, "reg", &Len); | |
if ((RegProp != 0) && (Len == (2 * sizeof (UINT64)))) { | |
CurBase = Fdt64ToCpu (ReadUnaligned64 (RegProp)); | |
CurSize = Fdt64ToCpu (ReadUnaligned64 (RegProp + 1)); | |
DEBUG (( | |
DEBUG_INFO, | |
"%a: System RAM @ 0x%lx - 0x%lx\n", | |
__func__, | |
CurBase, | |
CurBase + CurSize - 1 | |
)); | |
InitializeRamRegions ( | |
CurBase, | |
CurSize | |
); | |
} else { | |
DEBUG (( | |
DEBUG_ERROR, | |
"%a: Failed to parse FDT memory node\n", | |
__func__ | |
)); | |
} | |
} | |
} | |
AddReservedMemoryMap (FdtPointer); | |
/* Make sure SEC is booting with bare mode */ | |
ASSERT ((RiscVGetSupervisorAddressTranslationRegister () & SATP64_MODE) == (SATP_MODE_OFF << SATP64_MODE_SHIFT)); | |
BuildMemoryTypeHob (); | |
return EFI_SUCCESS; | |
} |