blob: 98cc13870599c10bfab5029de9f7730a67099b72 [file] [log] [blame]
/** @file
Copyright (c) 2022, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <PiPei.h>
#include <Base.h>
#include <libfdt.h>
#include <Library/ArmLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/PcdLib.h>
#include <Library/PrePiLib.h>
#include "CloudHvVirtMemInfoLib.h"
CLOUDHV_MEM_NODE_INFO CloudHvMemNode[CLOUDHV_MAX_MEM_NODE_NUM];
/**
Get all of memory nodes info from DT. Store all of them into
CloudHvMemNode which will be consumed by ArmVirtGetMemoryMap.
@retval RETURN_SUCCESS Success.
@retval EFI_NOT_FOUND DT or the first memory node not found.
**/
RETURN_STATUS
EFIAPI
CloudHvVirtMemInfoPeiLibConstructor (
VOID
)
{
VOID *DeviceTreeBase;
EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttributes;
INT32 Node, Prev;
UINT64 FirMemNodeBase, FirMemNodeSize;
UINT64 CurBase, MemBase;
UINT64 CurSize;
CONST CHAR8 *Type;
INT32 Len;
CONST UINT64 *RegProp;
RETURN_STATUS PcdStatus;
UINT8 Index;
ZeroMem (CloudHvMemNode, sizeof (CloudHvMemNode));
FirMemNodeBase = 0;
FirMemNodeSize = 0;
Index = 0;
MemBase = FixedPcdGet64 (PcdSystemMemoryBase);
ResourceAttributes = (
EFI_RESOURCE_ATTRIBUTE_PRESENT |
EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
EFI_RESOURCE_ATTRIBUTE_TESTED
);
DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress);
if (DeviceTreeBase == NULL) {
return EFI_NOT_FOUND;
}
//
// Make sure we have a valid device tree blob
//
if (fdt_check_header (DeviceTreeBase) != 0) {
return EFI_NOT_FOUND;
}
//
// Look for the lowest memory node
//
for (Prev = 0; ; Prev = Node) {
Node = fdt_next_node (DeviceTreeBase, Prev, NULL);
if (Node < 0) {
break;
}
//
// Check for memory node
//
Type = fdt_getprop (DeviceTreeBase, Node, "device_type", &Len);
if ((Type != 0) && (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 = fdt_getprop (DeviceTreeBase, Node, "reg", &Len);
if ((RegProp != 0) && (Len == (2 * sizeof (UINT64)))) {
CurBase = fdt64_to_cpu (ReadUnaligned64 (RegProp));
CurSize = fdt64_to_cpu (ReadUnaligned64 (RegProp + 1));
DEBUG ((
DEBUG_INFO,
"%a: System RAM @ 0x%lx - 0x%lx\n",
__func__,
CurBase,
CurBase + CurSize - 1
));
// We should build Hob seperately for the memory node except the first one
if (CurBase != MemBase) {
BuildResourceDescriptorHob (
EFI_RESOURCE_SYSTEM_MEMORY,
ResourceAttributes,
CurBase,
CurSize
);
} else {
FirMemNodeBase = CurBase;
FirMemNodeSize = CurSize;
}
CloudHvMemNode[Index].Base = CurBase;
CloudHvMemNode[Index].Size = CurSize;
Index++;
if (Index >= CLOUDHV_MAX_MEM_NODE_NUM) {
DEBUG ((
DEBUG_WARN,
"%a: memory node larger than %d will not be included into Memory System\n",
__func__,
CLOUDHV_MAX_MEM_NODE_NUM
));
break;
}
} else {
DEBUG ((
DEBUG_ERROR,
"%a: Failed to parse FDT memory node\n",
__func__
));
}
}
}
//
// Make sure the start of DRAM matches our expectation
//
if (FixedPcdGet64 (PcdSystemMemoryBase) != FirMemNodeBase) {
return EFI_NOT_FOUND;
}
PcdStatus = PcdSet64S (PcdSystemMemorySize, FirMemNodeSize);
ASSERT_RETURN_ERROR (PcdStatus);
ASSERT (
(((UINT64)PcdGet64 (PcdFdBaseAddress) +
(UINT64)PcdGet32 (PcdFdSize)) <= FirMemNodeBase) ||
((UINT64)PcdGet64 (PcdFdBaseAddress) >= (FirMemNodeBase + FirMemNodeSize))
);
return RETURN_SUCCESS;
}
/**
Return the Virtual Memory Map of your platform
This Virtual Memory Map is used by MemoryInitPei Module to initialize the MMU
on your platform.
@param[out] VirtualMemoryMap Array of ARM_MEMORY_REGION_DESCRIPTOR
describing a Physical-to-Virtual Memory
mapping. This array must be ended by a
zero-filled entry. The allocated memory
will not be freed.
**/
VOID
ArmVirtGetMemoryMap (
OUT ARM_MEMORY_REGION_DESCRIPTOR **VirtualMemoryMap
)
{
ARM_MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable;
UINT8 Index, MemNodeIndex;
ASSERT (VirtualMemoryMap != NULL);
VirtualMemoryTable = AllocatePool (
sizeof (ARM_MEMORY_REGION_DESCRIPTOR) *
MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
);
if (VirtualMemoryTable == NULL) {
DEBUG ((DEBUG_ERROR, "%a: Error: Failed AllocatePool()\n", __func__));
return;
}
Index = 0;
MemNodeIndex = 0;
// System DRAM
while ((MemNodeIndex < CLOUDHV_MAX_MEM_NODE_NUM) && (CloudHvMemNode[MemNodeIndex].Size != 0)) {
VirtualMemoryTable[Index].PhysicalBase = CloudHvMemNode[MemNodeIndex].Base;
VirtualMemoryTable[Index].VirtualBase = CloudHvMemNode[MemNodeIndex].Base;
VirtualMemoryTable[Index].Length = CloudHvMemNode[MemNodeIndex].Size;
VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
DEBUG ((
DEBUG_INFO,
"%a: Dumping System DRAM Memory Node%d Map:\n"
"\tPhysicalBase: 0x%lX\n"
"\tVirtualBase: 0x%lX\n"
"\tLength: 0x%lX\n",
__func__,
MemNodeIndex,
VirtualMemoryTable[Index].PhysicalBase,
VirtualMemoryTable[Index].VirtualBase,
VirtualMemoryTable[Index].Length
));
Index++;
MemNodeIndex++;
}
// Memory mapped peripherals (UART, RTC, GIC, virtio-mmio, etc)
VirtualMemoryTable[Index].PhysicalBase = MACH_VIRT_PERIPH_BASE;
VirtualMemoryTable[Index].VirtualBase = MACH_VIRT_PERIPH_BASE;
VirtualMemoryTable[Index].Length = MACH_VIRT_PERIPH_SIZE;
VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
Index++;
// Map the FV region as normal executable memory
VirtualMemoryTable[Index].PhysicalBase = PcdGet64 (PcdFvBaseAddress);
VirtualMemoryTable[Index].VirtualBase = VirtualMemoryTable[Index].PhysicalBase;
VirtualMemoryTable[Index].Length = FixedPcdGet32 (PcdFvSize);
VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK;
Index++;
// Memory mapped for 32bit device (like TPM)
VirtualMemoryTable[Index].PhysicalBase = TOP_32BIT_DEVICE_BASE;
VirtualMemoryTable[Index].VirtualBase = TOP_32BIT_DEVICE_BASE;
VirtualMemoryTable[Index].Length = TOP_32BIT_DEVICE_SIZE;
VirtualMemoryTable[Index].Attributes = ARM_MEMORY_REGION_ATTRIBUTE_DEVICE;
Index++;
// End of Table
ZeroMem (&VirtualMemoryTable[Index], sizeof (ARM_MEMORY_REGION_DESCRIPTOR));
*VirtualMemoryMap = VirtualMemoryTable;
}