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.biesheu...@linaro.org>
Acked-by: Laszlo Ersek <ler...@redhat.com>
---
 ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S        
  | 237 --------------------
 
ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/RelocatableVirtHelper.S 
 |  51 ++---
 
ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/ArmXenRelocatablePlatformLib.inf
 |   3 +-
 ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/FdtParser.c                    
  |  91 ++++++++
 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 6eef9d7667e3..000000000000
--- 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 d6edc62efc0d..ae77492bf363 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 1afab21576ac..fce3e11922bc 100644
--- 
a/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/ArmXenRelocatablePlatformLib.inf
+++ 
b/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/ArmXenRelocatablePlatformLib.inf
@@ -32,14 +32,15 @@ [LibraryClasses]
   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 000000000000..992932ee9754
--- /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));
+}
-- 
2.5.0

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to