]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPlatformPkg/ArmVirtualizationPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S
ArmVirtualizationPkg: Xen/PV relocatable platformlib instance
[mirror_edk2.git] / ArmPlatformPkg / ArmVirtualizationPkg / Library / ArmXenRelocatablePlatformLib / AARCH64 / MemnodeParser.S
diff --git a/ArmPlatformPkg/ArmVirtualizationPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S b/ArmPlatformPkg/ArmVirtualizationPkg/Library/ArmXenRelocatablePlatformLib/AARCH64/MemnodeParser.S
new file mode 100644 (file)
index 0000000..f919b63
--- /dev/null
@@ -0,0 +1,237 @@
+/*\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, #:abs_g0_nc:FDT_MAGIC\r
+       movk    w4, #:abs_g1:FDT_MAGIC\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