+++ /dev/null
-/*\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
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
// );\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
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
--- /dev/null
+/*\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