Memory layout in CLoud Hypervisor for arm is changed and is different with Qemu, thus we should build its own PeiMemInfoLib. The main change in the memory layout is that normal ram may not contiguous under 4G. The top 64M under 4G is reserved for 32bit device. What this patch does: 1. get all of the memory node from DT; 2. Init page table for each memory node; 3. Add all of the memory nodes to Hob; Reviewed-by: Sami Mujawar <sami.mujawar@arm.com> Signed-off-by: Jianyong Wu <jianyong.wu@arm.com>
244 lines
7.6 KiB
C
244 lines
7.6 KiB
C
/** @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",
|
|
__FUNCTION__,
|
|
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",
|
|
__FUNCTION__,
|
|
CLOUDHV_MAX_MEM_NODE_NUM
|
|
));
|
|
break;
|
|
}
|
|
} else {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"%a: Failed to parse FDT memory node\n",
|
|
__FUNCTION__
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// 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", __FUNCTION__));
|
|
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",
|
|
__FUNCTION__,
|
|
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;
|
|
}
|