]> git.proxmox.com Git - mirror_edk2.git/commitdiff
ArmVirtPkg/XenRelocatablePlatformLib: rewrite DTB memory node retrieval in C
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Thu, 17 Dec 2015 17:11:07 +0000 (17:11 +0000)
committerabiesheuvel <abiesheuvel@Edk2>
Thu, 17 Dec 2015 17:11:07 +0000 (17:11 +0000)
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

ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S [deleted file]
ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/RelocatableVirtHelper.S
ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/ArmXenRelocatablePlatformLib.inf
ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/FdtParser.c [new file with mode: 0644]

diff --git a/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S b/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S
deleted file mode 100644 (file)
index 6eef9d7..0000000
+++ /dev/null
@@ -1,237 +0,0 @@
-/*\r
- * Copyright (c) 2014, Linaro Ltd. All rights reserved.\r
- *\r
- * This program and the accompanying materials\r
- * are licensed and made available under the terms and conditions of the BSD License\r
- * which accompanies this distribution.  The full text of the license may be found at\r
- * http://opensource.org/licenses/bsd-license.php\r
- *\r
- * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
- */\r
-\r
-/*\r
- * Theory of operation\r
- * -------------------\r
- *\r
- * This code parses a Flattened Device Tree binary (DTB) to find the base of\r
- * system RAM. It is written in assembly so that it can be executed before a\r
- * stack has been set up.\r
- *\r
- * To find the base of system RAM, we have to traverse the FDT to find a memory\r
- * node. In the context of this implementation, the first node that has a\r
- * device_type property with the value 'memory' and a 'reg' property is\r
- * acceptable, and the name of the node (memory[@xxx]) is ignored, as are any\r
- * other nodes that match the above constraints.\r
- *\r
- * In pseudo code, this implementation does the following:\r
- *\r
- * for each node {\r
- *  have_device_type = false\r
- *  have_reg = false\r
- *\r
- *  for each property {\r
- *    if property value == 'memory' {\r
- *      if property name == 'device_type' {\r
- *        have_device_type = true\r
- *      }\r
- *    } else {\r
- *      if property name == 'reg' {\r
- *        have_reg = true\r
- *        membase = property value[0]\r
- *        memsize = property value[1]\r
- *      }\r
- *    }\r
- *  }\r
- *  if have_device_type and have_reg {\r
- *    return membase and memsize\r
- *  }\r
- * }\r
- * return NOT_FOUND\r
- */\r
-\r
-#define FDT_MAGIC    0xedfe0dd0\r
-\r
-#define FDT_BEGIN_NODE    0x1\r
-#define FDT_END_NODE    0x2\r
-#define FDT_PROP    0x3\r
-#define FDT_END      0x9\r
-\r
-  xMEMSIZE  .req  x0  // recorded system RAM size\r
-  xMEMBASE  .req  x1  // recorded system RAM base\r
-\r
-  xLR    .req  x8  // our preserved link register\r
-  xDTP    .req  x9  // pointer to traverse the DT structure\r
-  xSTRTAB    .req  x10  // pointer to the DTB string table\r
-  xMEMNODE  .req  x11  // bit field to record found properties\r
-\r
-#define HAVE_REG    0x1\r
-#define HAVE_DEVICE_TYPE  0x2\r
-\r
-  .text\r
-  .align  3\r
-_memory:\r
-  .asciz  "memory"\r
-_reg:\r
-  .asciz  "reg"\r
-_device_type:\r
-  .asciz  "device_type"\r
-\r
-  /*\r
-   * Compare strings in x4 and x5, return in w7\r
-   */\r
-  .align  3\r
-strcmp:\r
-  ldrb  w2, [x4], #1\r
-  ldrb  w3, [x5], #1\r
-  subs  w7, w2, w3\r
-  cbz  w2, 0f\r
-  cbz  w3, 0f\r
-  beq  strcmp\r
-0:  ret\r
-\r
-  .globl  find_memnode\r
-find_memnode:\r
-  // preserve link register\r
-  mov  xLR, x30\r
-  mov  xDTP, x0\r
-\r
-  /*\r
-   * Check the DTB magic at offset 0\r
-   */\r
-  movz  w4, #(FDT_MAGIC & 0xffff)\r
-  movk  w4, #(FDT_MAGIC >> 16), lsl #16\r
-  ldr  w5, [xDTP]\r
-  cmp  w4, w5\r
-  bne  err_invalid_magic\r
-\r
-  /*\r
-   * Read the string offset and store it for later use\r
-   */\r
-  ldr  w4, [xDTP, #12]\r
-  rev  w4, w4\r
-  add  xSTRTAB, xDTP, x4\r
-\r
-  /*\r
-   * Read the struct offset and add it to the DT pointer\r
-   */\r
-  ldr  w5, [xDTP, #8]\r
-  rev  w5, w5\r
-  add  xDTP, xDTP, x5\r
-\r
-  /*\r
-   * Check current tag for FDT_BEGIN_NODE\r
-   */\r
-  ldr  w5, [xDTP]\r
-  rev  w5, w5\r
-  cmp  w5, #FDT_BEGIN_NODE\r
-  bne  err_unexpected_begin_tag\r
-\r
-begin_node:\r
-  mov  xMEMNODE, #0\r
-  add  xDTP, xDTP, #4\r
-\r
-  /*\r
-   * Advance xDTP past NULL terminated string\r
-   */\r
-0:  ldrb  w4, [xDTP], #1\r
-  cbnz  w4, 0b\r
-\r
-next_tag:\r
-  /*\r
-   * Align the DT pointer xDTP to the next 32-bit boundary\r
-   */\r
-  add  xDTP, xDTP, #3\r
-  and  xDTP, xDTP, #~3\r
-\r
-  /*\r
-   * Read the next tag, could be BEGIN_NODE, END_NODE, PROP, END\r
-   */\r
-  ldr  w5, [xDTP]\r
-  rev  w5, w5\r
-  cmp  w5, #FDT_BEGIN_NODE\r
-  beq  begin_node\r
-  cmp  w5, #FDT_END_NODE\r
-  beq  end_node\r
-  cmp  w5, #FDT_PROP\r
-  beq  prop_node\r
-  cmp  w5, #FDT_END\r
-  beq  err_end_of_fdt\r
-  b  err_unexpected_tag\r
-\r
-prop_node:\r
-  /*\r
-   * If propname == 'reg', record as membase and memsize\r
-   * If propname == 'device_type' and value == 'memory',\r
-   * set the 'is_memnode' flag for this node\r
-   */\r
-  ldr  w6, [xDTP, #4]\r
-  add  xDTP, xDTP, #12\r
-  rev  w6, w6\r
-  mov  x5, xDTP\r
-  adr  x4, _memory\r
-  bl  strcmp\r
-\r
-  /*\r
-   * Get handle to property name\r
-   */\r
-  ldr  w5, [xDTP, #-4]\r
-  rev  w5, w5\r
-  add  x5, xSTRTAB, x5\r
-\r
-  cbz  w7, check_device_type\r
-\r
-  /*\r
-   * Check for 'reg' property\r
-   */\r
-  adr  x4, _reg\r
-  bl  strcmp\r
-  cbnz  w7, inc_and_next_tag\r
-\r
-  /*\r
-   * Extract two 64-bit quantities from the 'reg' property. These values\r
-   * will only be used if the node also turns out to have a device_type\r
-   * property with a value of 'memory'.\r
-   *\r
-   * NOTE: xDTP is only guaranteed to be 32 bit aligned, and we are most\r
-   *       likely executing with the MMU off, so we cannot use 64 bit\r
-   *       wide accesses here.\r
-   */\r
-  ldp  w4, w5, [xDTP]\r
-  orr  xMEMBASE, x4, x5, lsl #32\r
-  ldp  w4, w5, [xDTP, #8]\r
-  orr  xMEMSIZE, x4, x5, lsl #32\r
-  rev  xMEMBASE, xMEMBASE\r
-  rev  xMEMSIZE, xMEMSIZE\r
-  orr  xMEMNODE, xMEMNODE, #HAVE_REG\r
-  b  inc_and_next_tag\r
-\r
-check_device_type:\r
-  /*\r
-   * Check whether the current property's name is 'device_type'\r
-   */\r
-  adr  x4, _device_type\r
-  bl  strcmp\r
-  cbnz  w7, inc_and_next_tag\r
-  orr  xMEMNODE, xMEMNODE, #HAVE_DEVICE_TYPE\r
-\r
-inc_and_next_tag:\r
-  add  xDTP, xDTP, x6\r
-  b  next_tag\r
-\r
-end_node:\r
-  /*\r
-   * Check for device_type = memory and reg = xxxx\r
-   * If we have both, we are done\r
-   */\r
-  add  xDTP, xDTP, #4\r
-  cmp  xMEMNODE, #(HAVE_REG | HAVE_DEVICE_TYPE)\r
-  bne  next_tag\r
-\r
-  ret  xLR\r
-\r
-err_invalid_magic:\r
-err_unexpected_begin_tag:\r
-err_unexpected_tag:\r
-err_end_of_fdt:\r
-  wfi\r
index d6edc62efc0dcb08153d9c076cfbde8bccb92def..ae77492bf363253514703632abaf6a2cb7d7a286 100644 (file)
@@ -30,9 +30,6 @@ GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdArmPrimaryCore)
 GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdArmPrimaryCoreMask)\r
 GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdCoreCount)\r
 \r
-.LFdtMagic:\r
-  .byte   0xd0, 0x0d, 0xfe, 0xed\r
-\r
 .LArm64LinuxMagic:\r
   .byte   0x41, 0x52, 0x4d, 0x64\r
 \r
@@ -43,17 +40,15 @@ GCC_ASM_IMPORT(_gPcd_FixedAtBuild_PcdCoreCount)
 //   );\r
 ASM_PFX(ArmPlatformPeiBootAction):\r
   mov   x29, x30            // preserve LR\r
+  mov   x28, x0             // preserve DTB pointer\r
+  mov   x27, x1             // preserve base of image pointer\r
 \r
   //\r
   // If we are booting from RAM using the Linux kernel boot protocol, x0 will\r
   // point to the DTB image in memory. Otherwise, we are just coming out of\r
-  // reset, and x0 will be 0. Check also the FDT magic.\r
+  // reset, and x0 will be 0.\r
   //\r
   cbz   x0, .Lout\r
-  ldr   w8, .LFdtMagic\r
-  ldr   w9, [x0]\r
-  cmp   w8, w9\r
-  bne   .Lout\r
 \r
   //\r
   // The base of the runtime image has been preserved in x1. Check whether\r
@@ -80,36 +75,30 @@ ASM_PFX(ArmPlatformPeiBootAction):
   str   x1, [x8]\r
   str   x7, [x9]\r
 \r
+  //\r
+  // Discover the memory size and offset from the DTB, and record in the\r
+  // respective PCDs. This will also return false if a corrupt DTB is\r
+  // encountered. Since we are calling a C function, use the window at the\r
+  // beginning of the FD image as a temp stack.\r
+  //\r
+  adr   x1, PcdGet64 (PcdSystemMemorySize)\r
+  adr   x2, PcdGet64 (PcdSystemMemoryBase)\r
+  mov   sp, x7\r
+  bl    FindMemnode\r
+  cbz   x0, .Lout\r
+\r
   //\r
   // Copy the DTB to the slack space right after the 64 byte arm64/Linux style\r
   // image header at the base of this image (defined in the FDF), and record the\r
   // pointer in PcdDeviceTreeInitialBaseAddress.\r
   //\r
   adr   x8, PcdGet64 (PcdDeviceTreeInitialBaseAddress)\r
-  add   x1, x1, #0x40\r
-  str   x1, [x8]\r
-\r
-  ldr   w8, [x0, #4]          // get DTB size (BE)\r
-  mov   x9, x1\r
-  rev   w8, w8\r
-  add   x8, x8, x0\r
-0:ldp   x6, x7, [x0], #16\r
-  stp   x6, x7, [x9], #16\r
-  cmp   x0, x8\r
-  blt   0b\r
-\r
-  //\r
-  // Discover the memory size and offset from the DTB, and record in the\r
-  // respective PCDs\r
-  //\r
-  mov   x0, x1\r
-  bl    find_memnode    // returns (size, base) size in (x0, x1)\r
-  cbz   x0, .Lout\r
+  add   x27, x27, #0x40\r
+  str   x27, [x8]\r
 \r
-  adr   x8, PcdGet64 (PcdSystemMemorySize)\r
-  adr   x9, PcdGet64 (PcdSystemMemoryBase)\r
-  str   x0, [x8]\r
-  str   x1, [x9]\r
+  mov   x0, x27\r
+  mov   x1, x28\r
+  bl    CopyFdt\r
 \r
 .Lout:\r
   ret    x29\r
index 1afab21576ac742e0ba9e2bc0968627d3fde2187..fce3e11922bcf9e83a52e2077227668ae635323f 100644 (file)
   IoLib\r
   ArmLib\r
   PrintLib\r
+  FdtLib\r
 \r
 [Sources.common]\r
   RelocatableVirt.c\r
   XenVirtMem.c\r
+  FdtParser.c\r
 \r
 [Sources.AARCH64]\r
   AARCH64/RelocatableVirtHelper.S\r
-  AARCH64/MemnodeParser.S\r
 \r
 [FeaturePcd]\r
   gEmbeddedTokenSpaceGuid.PcdCacheEnable\r
diff --git a/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/FdtParser.c b/ArmVirtPkg/Library/ArmXenRelocatablePlatformLib/FdtParser.c
new file mode 100644 (file)
index 0000000..992932e
--- /dev/null
@@ -0,0 +1,91 @@
+/*\r
+ * Copyright (c) 2015, Linaro Ltd. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials\r
+ * are licensed and made available under the terms and conditions of the BSD License\r
+ * which accompanies this distribution.  The full text of the license may be found at\r
+ * http://opensource.org/licenses/bsd-license.php\r
+ *\r
+ * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ */\r
+\r
+#include <Uefi.h>\r
+#include <Include/libfdt.h>\r
+\r
+BOOLEAN\r
+FindMemnode (\r
+  IN  VOID    *DeviceTreeBlob,\r
+  OUT UINT64  *SystemMemoryBase,\r
+  OUT UINT64  *SystemMemorySize\r
+  )\r
+{\r
+  INT32         MemoryNode;\r
+  INT32         AddressCells;\r
+  INT32         SizeCells;\r
+  INT32         Length;\r
+  CONST INT32   *Prop;\r
+\r
+  if (fdt_check_header (DeviceTreeBlob) != 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Look for a node called "memory" at the lowest level of the tree\r
+  //\r
+  MemoryNode = fdt_path_offset (DeviceTreeBlob, "/memory");\r
+  if (MemoryNode <= 0) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Retrieve the #address-cells and #size-cells properties\r
+  // from the root node, or use the default if not provided.\r
+  //\r
+  AddressCells = 1;\r
+  SizeCells = 1;\r
+\r
+  Prop = fdt_getprop (DeviceTreeBlob, 0, "#address-cells", &Length);\r
+  if (Length == 4) {\r
+    AddressCells = fdt32_to_cpu (*Prop);\r
+  }\r
+\r
+  Prop = fdt_getprop (DeviceTreeBlob, 0, "#size-cells", &Length);\r
+  if (Length == 4) {\r
+    SizeCells = fdt32_to_cpu (*Prop);\r
+  }\r
+\r
+  //\r
+  // Now find the 'reg' property of the /memory node, and read the first\r
+  // range listed.\r
+  //\r
+  Prop = fdt_getprop (DeviceTreeBlob, MemoryNode, "reg", &Length);\r
+\r
+  if (Length < (AddressCells + SizeCells) * sizeof (INT32)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (AddressCells == 1) {\r
+    *SystemMemoryBase = fdt32_to_cpu (*Prop);\r
+  } else {\r
+    *SystemMemoryBase = fdt64_to_cpu (*(UINT64 *)Prop);\r
+  }\r
+  Prop += AddressCells;\r
+\r
+  if (SizeCells == 1) {\r
+    *SystemMemorySize = fdt32_to_cpu (*Prop);\r
+  } else {\r
+    *SystemMemorySize = fdt64_to_cpu (*(UINT64 *)Prop);\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+VOID\r
+CopyFdt (\r
+  IN    VOID    *FdtDest,\r
+  IN    VOID    *FdtSource\r
+  )\r
+{\r
+  CopyMem (FdtDest, FdtSource, fdt_totalsize (FdtSource));\r
+}\r