new file mode 100644
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2014, Linaro Ltd. All rights reserved.
+ *
+ * This program and the accompanying materials
+ * are licensed and made available under the terms and conditions of the BSD License
+ * which accompanies this distribution. The full text of the license may be found at
+ * http://opensource.org/licenses/bsd-license.php
+ *
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+ */
+
+/*
+ * Theory of operation
+ * -------------------
+ *
+ * This code parses a Flattened Device Tree binary (DTB) to find the base of
+ * system RAM. It is written in assembly so that it can be executed before a
+ * stack has been set up.
+ *
+ * To find the base of system RAM, we have to traverse the FDT to find a memory
+ * node. In the context of this implementation, the first node that has a
+ * device_type property with the value 'memory' and a 'reg' property is
+ * acceptable, and the name of the node (memory[@xxx]) is ignored, as are any
+ * other nodes that match the above constraints.
+ *
+ * In pseudo code, this implementation does the following:
+ *
+ * for each node {
+ * have_device_type = false
+ * have_reg = false
+ *
+ * for each property {
+ * if property value == 'memory' {
+ * if property name == 'device_type' {
+ * have_device_type = true
+ * }
+ * } else {
+ * if property name == 'reg' {
+ * have_reg = true
+ * membase = property value[0]
+ * memsize = property value[1]
+ * }
+ * }
+ * }
+ * if have_device_type and have_reg {
+ * return membase and memsize
+ * }
+ * }
+ * return NOT_FOUND
+ */
+
+#define FDT_MAGIC 0xedfe0dd0
+
+#define FDT_BEGIN_NODE 0x1
+#define FDT_END_NODE 0x2
+#define FDT_PROP 0x3
+#define FDT_END 0x9
+
+ xMEMSIZE .req x0
+ xMEMBASE .req x1
+
+ xLR .req x8
+ xDTP .req x9
+ xSTRTAB .req x10
+ xMEMNODE .req x11
+
+ .text
+ .align 3
+_memory:
+ .asciz "memory"
+_reg:
+ .asciz "reg"
+_device_type:
+ .asciz "device_type"
+
+ /*
+ * Compare strings in x4 and x5, return in w7
+ */
+ .align 3
+strcmp:
+ ldrb w2, [x4], #1
+ ldrb w3, [x5], #1
+ subs w7, w2, w3
+ cbz w2, 0f
+ cbz w3, 0f
+ beq strcmp
+0: ret
+
+ .globl find_memnode
+find_memnode:
+ // preserve link register
+ mov xLR, x30
+ mov xDTP, x0
+ mov xMEMNODE, #0
+
+ /*
+ * Check the DTB magic at offset 0
+ */
+ movz w4, #:abs_g0_nc:FDT_MAGIC
+ movk w4, #:abs_g1:FDT_MAGIC
+ ldr w5, [xDTP]
+ cmp w4, w5
+ bne err_invalid_magic
+
+ /*
+ * Read the string offset and store it for later use
+ */
+ ldr w4, [xDTP, #12]
+ rev w4, w4
+ add xSTRTAB, xDTP, x4
+
+ /*
+ * Read the struct offset and add it to the DT pointer
+ */
+ ldr w5, [xDTP, #8]
+ rev w5, w5
+ add xDTP, xDTP, x5
+
+ /*
+ * Check current tag for FDT_BEGIN_NODE
+ */
+ ldr w5, [xDTP]
+ rev w5, w5
+ cmp w5, #FDT_BEGIN_NODE
+ bne err_unexpected_begin_tag
+
+begin_node:
+ mov xMEMNODE, #0
+ add xDTP, xDTP, #4
+
+ /*
+ * Advance xDTP past NULL terminated string
+ */
+0: ldrb w4, [xDTP], #1
+ cbnz w4, 0b
+
+next_tag:
+ add xDTP, xDTP, #3
+ and xDTP, xDTP, #~3
+
+ /*
+ * Read the next tag, could be BEGIN_NODE, END_NODE, PROP, END
+ */
+ ldr w5, [xDTP]
+ rev w5, w5
+ cmp w5, #FDT_BEGIN_NODE
+ beq begin_node
+ cmp w5, #FDT_END_NODE
+ beq end_node
+ cmp w5, #FDT_PROP
+ beq prop_node
+ cmp w5, #FDT_END
+ beq err_end_of_fdt
+ b err_unexpected_tag
+
+prop_node:
+ /*
+ * If propname == 'reg', record as membase and memsize
+ * If propname == 'device_type' and value == 'memory',
+ * set the 'is_memnode' flag for this node
+ */
+ ldr w6, [xDTP, #4]
+ add xDTP, xDTP, #12
+ rev w6, w6
+ mov x5, xDTP
+ adr x4, _memory
+ bl strcmp
+
+ /*
+ * Get handle to property name
+ */
+ ldr w5, [xDTP, #-4]
+ rev w5, w5
+ add x5, xSTRTAB, x5
+
+ cbz w7, check_device_type
+
+ /*
+ * Check for 'reg' property
+ */
+ adr x4, _reg
+ bl strcmp
+ cbnz w7, inc_and_next_tag
+
+ /*
+ * Extract two 64-bit quantities from the 'reg' property. These values
+ * will only be used if the node also turns out to have a device_type
+ * property with a value of 'memory'.
+ *
+ * NOTE: xDTP is only guaranteed to be 32 bit aligned, and we are most
+ * likely executing with the MMU off, so we cannot use 64 bit
+ * wide accesses here.
+ */
+ ldp w4, w5, [xDTP]
+ orr xMEMBASE, x4, x5, lsl #32
+ ldp w4, w5, [xDTP, #8]
+ orr xMEMSIZE, x4, x5, lsl #32
+ rev xMEMBASE, xMEMBASE
+ rev xMEMSIZE, xMEMSIZE
+ orr xMEMNODE, xMEMNODE, #2
+ b inc_and_next_tag
+
+check_device_type:
+ /*
+ * Check whether the current property's name is 'device_type'
+ */
+ adr x4, _device_type
+ bl strcmp
+ cbnz w7, inc_and_next_tag
+ orr xMEMNODE, xMEMNODE, #1
+
+inc_and_next_tag:
+ add xDTP, xDTP, x6
+ b next_tag
+
+end_node:
+ /*
+ * Check for device_type = memory and reg = xxxx
+ * If we have both, we are done
+ */
+ add xDTP, xDTP, #4
+ cmp xMEMNODE, #3
+ bne next_tag
+
+ ret xLR
+
+err_invalid_magic:
+err_unexpected_begin_tag:
+err_unexpected_tag:
+err_end_of_fdt:
+ wfi
new file mode 100644
@@ -0,0 +1,161 @@
+#
+# Copyright (c) 2011-2013, ARM Limited. All rights reserved.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+
+#include <AsmMacroIoLibV8.h>
+#include <Base.h>
+#include <Library/ArmLib.h>
+#include <Library/PcdLib.h>
+#include <AutoGen.h>
+
+.text
+.align 2
+
+GCC_ASM_EXPORT(ArmPlatformPeiBootAction)
+GCC_ASM_EXPORT(ArmPlatformIsPrimaryCore)
+GCC_ASM_EXPORT(ArmPlatformGetPrimaryCoreMpId)
+GCC_ASM_EXPORT(ArmPlatformGetCorePosition)
+GCC_ASM_EXPORT(ArmGetPhysAddrTop)
+
+GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdArmPrimaryCore)
+GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdArmPrimaryCoreMask)
+GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdCoreCount)
+
+.LFdtMagic:
+ .byte 0xd0, 0x0d, 0xfe, 0xed
+
+.LArm64LinuxMagic:
+ .byte 0x41, 0x52, 0x4d, 0x64
+
+ASM_PFX(ArmPlatformPeiBootAction):
+ mov x29, x30 // preserve LR
+
+ //
+ // If we are booting from RAM using the Linux kernel boot protocol, x0 will
+ // point to the DTB image in memory. Otherwise, we are just coming out of
+ // reset, and x0 will be 0. Check also the FDT magic.
+ //
+ cbz x0, .Lout
+ ldr w8, .LFdtMagic
+ ldr w9, [x0]
+ cmp w8, w9
+ bne .Lout
+
+ //
+ // The base of the runtime image has been preserved in x1. Check whether
+ // the expected magic number can be found in the header.
+ //
+ ldr w8, .LArm64LinuxMagic
+ ldr w9, [x1, #0x38]
+ cmp w8, w9
+ bne .Lout
+
+ //
+ //
+ // OK, so far so good. We have confirmed that we likely have a DTB and are
+ // booting via the arm64 Linux boot protocol. Update the base-of-image PCD
+ // to the actual relocated value, and add the shift of PcdFdBaseAddress to
+ // PcdFvBaseAddress as well
+ //
+ adr x8, PcdGet64 (PcdFdBaseAddress)
+ adr x9, PcdGet64 (PcdFvBaseAddress)
+ ldr x6, [x8]
+ ldr x7, [x9]
+ sub x7, x7, x6
+ add x7, x7, x1
+ str x1, [x8]
+ str x7, [x9]
+
+ //
+ // Copy the DTB to the slack space right after the header at the base of this
+ // image, and record the pointer in PcdDeviceTreeInitialBaseAddress.
+ //
+ adr x8, PcdGet64 (PcdDeviceTreeInitialBaseAddress)
+ add x1, x1, #0x40
+ str x1, [x8]
+
+ ldr w8, [x0, #4] // get DTB size (BE)
+ mov x9, x1
+ rev w8, w8
+ add x8, x8, x0
+0:ldp x6, x7, [x0], #16
+ stp x6, x7, [x9], #16
+ cmp x0, x8
+ blt 0b
+
+ //
+ // Discover the memory size and offset from the DTB, and record in the
+ // respective PCDs
+ //
+ mov x0, x1
+ bl find_memnode // returns (size, base) size in (x0, x1)
+ cbz x0, .Lout
+
+ adr x8, PcdGet64 (PcdSystemMemorySize)
+ adr x9, PcdGet64 (PcdSystemMemoryBase)
+ str x0, [x8]
+ str x1, [x9]
+
+.Lout:
+ ret x29
+
+//UINTN
+//ArmPlatformGetPrimaryCoreMpId (
+// VOID
+// );
+ASM_PFX(ArmPlatformGetPrimaryCoreMpId):
+ LoadConstantToReg (_gPcd_FixedAtBuild_PcdArmPrimaryCore, x0)
+ ldrh w0, [x0]
+ ret
+
+//UINTN
+//ArmPlatformIsPrimaryCore (
+// IN UINTN MpId
+// );
+ASM_PFX(ArmPlatformIsPrimaryCore):
+ mov x0, #1
+ ret
+
+//UINTN
+//ArmPlatformGetCorePosition (
+// IN UINTN MpId
+// );
+// With this function: CorePos = (ClusterId * 4) + CoreId
+ASM_PFX(ArmPlatformGetCorePosition):
+ and x1, x0, #ARM_CORE_MASK
+ and x0, x0, #ARM_CLUSTER_MASK
+ add x0, x1, x0, LSR #6
+ ret
+
+//EFI_PHYSICAL_ADDRESS
+//GetPhysAddrTop (
+// VOID
+// );
+ASM_PFX(ArmGetPhysAddrTop):
+ mrs x0, id_aa64mmfr0_el1
+ adr x1, .LPARanges
+ and x0, x0, #7
+ ldrb w1, [x1, x0]
+ mov x0, #1
+ lsl x0, x0, x1
+ ret
+
+//
+// Bits 0..2 of the AA64MFR0_EL1 system register encode the size of the
+// physical address space support on this CPU:
+// 0 == 32 bits, 1 == 36 bits, etc etc
+// 6 and 7 are reserved
+//
+.LPARanges:
+ .byte 32, 36, 40, 42, 44, 48, -1, -1
+
+ASM_FUNCTION_REMOVE_IF_UNREFERENCED
new file mode 100644
@@ -0,0 +1,59 @@
+#/* @file
+# Copyright (c) 2011-2014, ARM Limited. All rights reserved.
+# Copyright (c) 2014, Linaro Limited. All rights reserved.
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#*/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = ArmXenRelocatablePlatformLib
+ FILE_GUID = c8602718-4faa-4119-90ca-cae72509ac4c
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ArmPlatformLib|SEC PEIM
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ EmbeddedPkg/EmbeddedPkg.dec
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ ArmPlatformPkg/ArmVirtualizationPkg/ArmVirtualizationPkg.dec
+
+[LibraryClasses]
+ IoLib
+ ArmLib
+ PrintLib
+
+[Sources.common]
+ RelocatableVirt.c
+ XenVirtMem.c
+
+[Sources.AARCH64]
+ AARCH64/RelocatableVirtHelper.S
+ AARCH64/MemnodeParser.S
+
+[FeaturePcd]
+ gEmbeddedTokenSpaceGuid.PcdCacheEnable
+ gArmPlatformTokenSpaceGuid.PcdSystemMemoryInitializeInSec
+
+[PatchPcd]
+ gArmVirtualizationTokenSpaceGuid.PcdDeviceTreeInitialBaseAddress
+ gArmTokenSpaceGuid.PcdFdBaseAddress
+ gArmTokenSpaceGuid.PcdFvBaseAddress
+ gArmTokenSpaceGuid.PcdSystemMemoryBase
+ gArmTokenSpaceGuid.PcdSystemMemorySize
+
+[FixedPcd]
+ gArmPlatformTokenSpaceGuid.PcdCoreCount
+ gArmTokenSpaceGuid.PcdArmPrimaryCoreMask
+ gArmTokenSpaceGuid.PcdArmPrimaryCore
+ gArmTokenSpaceGuid.PcdFdSize
new file mode 100644
@@ -0,0 +1,71 @@
+/** @file
+*
+* Copyright (c) 2011-2013, ARM Limited. All rights reserved.
+* Copyright (c) 2014, Linaro Limited. All rights reserved.
+* Copyright (c) 2014, Red Hat, Inc.
+*
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Library/IoLib.h>
+#include <Library/ArmPlatformLib.h>
+#include <Library/DebugLib.h>
+#include <ArmPlatform.h>
+#include <Pi/PiBootMode.h>
+
+/**
+ Return the current Boot Mode
+
+ This function returns the boot reason on the platform
+
+ @return Return the current Boot Mode of the platform
+
+**/
+EFI_BOOT_MODE
+ArmPlatformGetBootMode (
+ VOID
+ )
+{
+ return BOOT_WITH_FULL_CONFIGURATION;
+}
+
+/**
+ This function is called by PrePeiCore, in the SEC phase.
+**/
+RETURN_STATUS
+ArmPlatformInitialize (
+ IN UINTN MpId
+ )
+{
+ //
+ // We are relying on ArmPlatformInitializeSystemMemory () being called from
+ // InitializeMemory (), which only occurs if the following feature is disabled
+ //
+ ASSERT (!FeaturePcdGet (PcdSystemMemoryInitializeInSec));
+ return RETURN_SUCCESS;
+}
+
+VOID
+ArmPlatformInitializeSystemMemory (
+ VOID
+ )
+{
+}
+
+VOID
+ArmPlatformGetPlatformPpiList (
+ OUT UINTN *PpiListSize,
+ OUT EFI_PEI_PPI_DESCRIPTOR **PpiList
+ )
+{
+ *PpiListSize = 0;
+ *PpiList = NULL;
+}
new file mode 100644
@@ -0,0 +1,83 @@
+/** @file
+*
+* Copyright (c) 2014, Linaro Limited. All rights reserved.
+*
+* This program and the accompanying materials
+* are licensed and made available under the terms and conditions of the BSD License
+* which accompanies this distribution. The full text of the license may be found at
+* http://opensource.org/licenses/bsd-license.php
+*
+* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+*
+**/
+
+#include <Library/ArmPlatformLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <ArmPlatform.h>
+
+// Number of Virtual Memory Map Descriptors
+#define MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS 2
+
+// DDR attributes
+#define DDR_ATTRIBUTES_CACHED ARM_MEMORY_REGION_ATTRIBUTE_WRITE_BACK
+#define DDR_ATTRIBUTES_UNCACHED ARM_MEMORY_REGION_ATTRIBUTE_UNCACHED_UNBUFFERED
+
+EFI_PHYSICAL_ADDRESS
+ArmGetPhysAddrTop (
+ VOID
+ );
+
+/**
+ 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
+
+**/
+VOID
+ArmPlatformGetVirtualMemoryMap (
+ IN ARM_MEMORY_REGION_DESCRIPTOR** VirtualMemoryMap
+ )
+{
+ ARM_MEMORY_REGION_DESCRIPTOR *VirtualMemoryTable;
+
+ ASSERT (VirtualMemoryMap != NULL);
+
+ VirtualMemoryTable = AllocatePages (
+ EFI_SIZE_TO_PAGES (
+ sizeof (ARM_MEMORY_REGION_DESCRIPTOR)
+ * MAX_VIRTUAL_MEMORY_MAP_DESCRIPTORS
+ )
+ );
+
+ if (VirtualMemoryTable == NULL) {
+ DEBUG ((EFI_D_ERROR, "%a: Error: Failed AllocatePages()\n", __FUNCTION__));
+ return;
+ }
+
+ //
+ // Map the entire physical memory space as cached. The only device
+ // we care about is the GIC, which will be stage 2 mapped as a device
+ // by the hypervisor, which will override the cached mapping we install
+ // here.
+ //
+ VirtualMemoryTable[0].PhysicalBase = 0x0;
+ VirtualMemoryTable[0].VirtualBase = 0x0;
+ VirtualMemoryTable[0].Length = ArmGetPhysAddrTop ();
+ VirtualMemoryTable[0].Attributes = DDR_ATTRIBUTES_CACHED;
+
+ // End of Table
+ ZeroMem (&VirtualMemoryTable[1], sizeof (ARM_MEMORY_REGION_DESCRIPTOR));
+
+ *VirtualMemoryMap = VirtualMemoryTable;
+}
Add a ArmPlatformLib instance that can deal with the self relocation and truly dynamic discovery of system RAM base and size. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> --- .../ArmVirtualizationPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S | 232 +++++++++++++++++++++++++++++++++++++++++++++++ .../ArmVirtualizationPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/RelocatableVirtHelper.S | 161 ++++++++++++++++++++++++++++++++ .../ArmVirtualizationPkg/Library/ArmXenRelocatablePlatformLib/ArmXenRelocatablePlatformLib.inf | 59 ++++++++++++ ArmPlatformPkg/ArmVirtualizationPkg/Library/ArmXenRelocatablePlatformLib/RelocatableVirt.c | 71 +++++++++++++++ ArmPlatformPkg/ArmVirtualizationPkg/Library/ArmXenRelocatablePlatformLib/XenVirtMem.c | 83 +++++++++++++++++ 5 files changed, 606 insertions(+)