summaryrefslogtreecommitdiffstats
path: root/ArmVirtPkg/Library
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2015-12-17 17:11:07 +0000
committerabiesheuvel <abiesheuvel@Edk2>2015-12-17 17:11:07 +0000
commit03b6bed17ea6fa224ca4d40fa1bd059283fbd9fb (patch)
treecc7190b8884351e00066bcd540c8e8213487b212 /ArmVirtPkg/Library
parentce44ee32d3c8e5ffac3c3c2608cabd485f30ddd9 (diff)
downloadedk2-03b6bed17ea6fa224ca4d40fa1bd059283fbd9fb.tar.gz
edk2-03b6bed17ea6fa224ca4d40fa1bd059283fbd9fb.tar.bz2
edk2-03b6bed17ea6fa224ca4d40fa1bd059283fbd9fb.zip
ArmVirtPkg/XenRelocatablePlatformLib: rewrite DTB memory node retrieval in C
Parsing the DTB early on using a handcoded assembly routine is a pointless waste of brain cycles, since the UEFI firmware always executes from RAM under Xen. So instead, set up a temporary stack in the memory region at the beginning of the image, and use the libfdt C library. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Acked-by: Laszlo Ersek <lersek@redhat.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19330 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'ArmVirtPkg/Library')
-rw-r--r--ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S237
-rw-r--r--ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/RelocatableVirtHelper.S51
-rw-r--r--ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/ArmXenRelocatablePlatformLib.inf3
-rw-r--r--ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/FdtParser.c91
4 files changed, 113 insertions, 269 deletions
diff --git a/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S b/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S
deleted file mode 100644
index 6eef9d7667..0000000000
--- a/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * 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 // recorded system RAM size
- xMEMBASE .req x1 // recorded system RAM base
-
- xLR .req x8 // our preserved link register
- xDTP .req x9 // pointer to traverse the DT structure
- xSTRTAB .req x10 // pointer to the DTB string table
- xMEMNODE .req x11 // bit field to record found properties
-
-#define HAVE_REG 0x1
-#define HAVE_DEVICE_TYPE 0x2
-
- .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
-
- /*
- * Check the DTB magic at offset 0
- */
- movz w4, #(FDT_MAGIC & 0xffff)
- movk w4, #(FDT_MAGIC >> 16), lsl #16
- 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:
- /*
- * Align the DT pointer xDTP to the next 32-bit boundary
- */
- 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, #HAVE_REG
- 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, #HAVE_DEVICE_TYPE
-
-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, #(HAVE_REG | HAVE_DEVICE_TYPE)
- bne next_tag
-
- ret xLR
-
-err_invalid_magic:
-err_unexpected_begin_tag:
-err_unexpected_tag:
-err_end_of_fdt:
- wfi
diff --git a/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/RelocatableVirtHelper.S b/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/RelocatableVirtHelper.S
index d6edc62efc..ae77492bf3 100644
--- a/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/RelocatableVirtHelper.S
+++ b/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/RelocatableVirtHelper.S
@@ -30,9 +30,6 @@ 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
@@ -43,17 +40,15 @@ GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdCoreCount)
// );
ASM_PFX(ArmPlatformPeiBootAction):
mov x29, x30 // preserve LR
+ mov x28, x0 // preserve DTB pointer
+ mov x27, x1 // preserve base of image pointer
//
// 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.
+ // reset, and x0 will be 0.
//
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
@@ -81,35 +76,29 @@ ASM_PFX(ArmPlatformPeiBootAction):
str x7, [x9]
//
+ // Discover the memory size and offset from the DTB, and record in the
+ // respective PCDs. This will also return false if a corrupt DTB is
+ // encountered. Since we are calling a C function, use the window at the
+ // beginning of the FD image as a temp stack.
+ //
+ adr x1, PcdGet64 (PcdSystemMemorySize)
+ adr x2, PcdGet64 (PcdSystemMemoryBase)
+ mov sp, x7
+ bl FindMemnode
+ cbz x0, .Lout
+
+ //
// Copy the DTB to the slack space right after the 64 byte arm64/Linux style
// image header at the base of this image (defined in the FDF), 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
+ add x27, x27, #0x40
+ str x27, [x8]
- adr x8, PcdGet64 (PcdSystemMemorySize)
- adr x9, PcdGet64 (PcdSystemMemoryBase)
- str x0, [x8]
- str x1, [x9]
+ mov x0, x27
+ mov x1, x28
+ bl CopyFdt
.Lout:
ret x29
diff --git a/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/ArmXenRelocatablePlatformLib.inf b/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/ArmXenRelocatablePlatformLib.inf
index 1afab21576..fce3e11922 100644
--- a/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/ArmXenRelocatablePlatformLib.inf
+++ b/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/ArmXenRelocatablePlatformLib.inf
@@ -32,14 +32,15 @@
IoLib
ArmLib
PrintLib
+ FdtLib
[Sources.common]
RelocatableVirt.c
XenVirtMem.c
+ FdtParser.c
[Sources.AARCH64]
AARCH64/RelocatableVirtHelper.S
- AARCH64/MemnodeParser.S
[FeaturePcd]
gEmbeddedTokenSpaceGuid.PcdCacheEnable
diff --git a/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/FdtParser.c b/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/FdtParser.c
new file mode 100644
index 0000000000..992932ee97
--- /dev/null
+++ b/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/FdtParser.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+
+#include <Uefi.h>
+#include <Include/libfdt.h>
+
+BOOLEAN
+FindMemnode (
+ IN VOID *DeviceTreeBlob,
+ OUT UINT64 *SystemMemoryBase,
+ OUT UINT64 *SystemMemorySize
+ )
+{
+ INT32 MemoryNode;
+ INT32 AddressCells;
+ INT32 SizeCells;
+ INT32 Length;
+ CONST INT32 *Prop;
+
+ if (fdt_check_header (DeviceTreeBlob) != 0) {
+ return FALSE;
+ }
+
+ //
+ // Look for a node called "memory" at the lowest level of the tree
+ //
+ MemoryNode = fdt_path_offset (DeviceTreeBlob, "/memory");
+ if (MemoryNode <= 0) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the #address-cells and #size-cells properties
+ // from the root node, or use the default if not provided.
+ //
+ AddressCells = 1;
+ SizeCells = 1;
+
+ Prop = fdt_getprop (DeviceTreeBlob, 0, "#address-cells", &Length);
+ if (Length == 4) {
+ AddressCells = fdt32_to_cpu (*Prop);
+ }
+
+ Prop = fdt_getprop (DeviceTreeBlob, 0, "#size-cells", &Length);
+ if (Length == 4) {
+ SizeCells = fdt32_to_cpu (*Prop);
+ }
+
+ //
+ // Now find the 'reg' property of the /memory node, and read the first
+ // range listed.
+ //
+ Prop = fdt_getprop (DeviceTreeBlob, MemoryNode, "reg", &Length);
+
+ if (Length < (AddressCells + SizeCells) * sizeof (INT32)) {
+ return FALSE;
+ }
+
+ if (AddressCells == 1) {
+ *SystemMemoryBase = fdt32_to_cpu (*Prop);
+ } else {
+ *SystemMemoryBase = fdt64_to_cpu (*(UINT64 *)Prop);
+ }
+ Prop += AddressCells;
+
+ if (SizeCells == 1) {
+ *SystemMemorySize = fdt32_to_cpu (*Prop);
+ } else {
+ *SystemMemorySize = fdt64_to_cpu (*(UINT64 *)Prop);
+ }
+
+ return TRUE;
+}
+
+VOID
+CopyFdt (
+ IN VOID *FdtDest,
+ IN VOID *FdtSource
+ )
+{
+ CopyMem (FdtDest, FdtSource, fdt_totalsize (FdtSource));
+}