1 /* 2 * Copyright 2009 Benjamin Herrenschmidt, IBM Corp 3 * benh@kernel.crashing.org 4 * 5 * Based on parts of drivers/of/fdt.c from Linux v4.9 6 * Modifications for U-Boot 7 * Copyright (c) 2017 Google, Inc 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include <common.h> 13 #include <linux/libfdt.h> 14 #include <of_live.h> 15 #include <malloc.h> 16 #include <dm/of_access.h> 17 #include <linux/err.h> 18 19 static void *unflatten_dt_alloc(void **mem, unsigned long size, 20 unsigned long align) 21 { 22 void *res; 23 24 *mem = PTR_ALIGN(*mem, align); 25 res = *mem; 26 *mem += size; 27 28 return res; 29 } 30 31 /** 32 * unflatten_dt_node() - Alloc and populate a device_node from the flat tree 33 * @blob: The parent device tree blob 34 * @mem: Memory chunk to use for allocating device nodes and properties 35 * @poffset: pointer to node in flat tree 36 * @dad: Parent struct device_node 37 * @nodepp: The device_node tree created by the call 38 * @fpsize: Size of the node path up at t05he current depth. 39 * @dryrun: If true, do not allocate device nodes but still calculate needed 40 * memory size 41 */ 42 static void *unflatten_dt_node(const void *blob, void *mem, int *poffset, 43 struct device_node *dad, 44 struct device_node **nodepp, 45 unsigned long fpsize, bool dryrun) 46 { 47 const __be32 *p; 48 struct device_node *np; 49 struct property *pp, **prev_pp = NULL; 50 const char *pathp; 51 int l; 52 unsigned int allocl; 53 static int depth; 54 int old_depth; 55 int offset; 56 int has_name = 0; 57 int new_format = 0; 58 59 pathp = fdt_get_name(blob, *poffset, &l); 60 if (!pathp) 61 return mem; 62 63 allocl = ++l; 64 65 /* 66 * version 0x10 has a more compact unit name here instead of the full 67 * path. we accumulate the full path size using "fpsize", we'll rebuild 68 * it later. We detect this because the first character of the name is 69 * not '/'. 70 */ 71 if ((*pathp) != '/') { 72 new_format = 1; 73 if (fpsize == 0) { 74 /* 75 * root node: special case. fpsize accounts for path 76 * plus terminating zero. root node only has '/', so 77 * fpsize should be 2, but we want to avoid the first 78 * level nodes to have two '/' so we use fpsize 1 here 79 */ 80 fpsize = 1; 81 allocl = 2; 82 l = 1; 83 pathp = ""; 84 } else { 85 /* 86 * account for '/' and path size minus terminal 0 87 * already in 'l' 88 */ 89 fpsize += l; 90 allocl = fpsize; 91 } 92 } 93 94 np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, 95 __alignof__(struct device_node)); 96 if (!dryrun) { 97 char *fn; 98 99 fn = (char *)np + sizeof(*np); 100 np->full_name = fn; 101 if (new_format) { 102 /* rebuild full path for new format */ 103 if (dad && dad->parent) { 104 strcpy(fn, dad->full_name); 105 #ifdef DEBUG 106 if ((strlen(fn) + l + 1) != allocl) { 107 debug("%s: p: %d, l: %d, a: %d\n", 108 pathp, (int)strlen(fn), l, 109 allocl); 110 } 111 #endif 112 fn += strlen(fn); 113 } 114 *(fn++) = '/'; 115 } 116 memcpy(fn, pathp, l); 117 118 prev_pp = &np->properties; 119 if (dad != NULL) { 120 np->parent = dad; 121 np->sibling = dad->child; 122 dad->child = np; 123 } 124 } 125 /* process properties */ 126 for (offset = fdt_first_property_offset(blob, *poffset); 127 (offset >= 0); 128 (offset = fdt_next_property_offset(blob, offset))) { 129 const char *pname; 130 int sz; 131 132 p = fdt_getprop_by_offset(blob, offset, &pname, &sz); 133 if (!p) { 134 offset = -FDT_ERR_INTERNAL; 135 break; 136 } 137 138 if (pname == NULL) { 139 debug("Can't find property name in list !\n"); 140 break; 141 } 142 if (strcmp(pname, "name") == 0) 143 has_name = 1; 144 pp = unflatten_dt_alloc(&mem, sizeof(struct property), 145 __alignof__(struct property)); 146 if (!dryrun) { 147 /* 148 * We accept flattened tree phandles either in 149 * ePAPR-style "phandle" properties, or the 150 * legacy "linux,phandle" properties. If both 151 * appear and have different values, things 152 * will get weird. Don't do that. */ 153 if ((strcmp(pname, "phandle") == 0) || 154 (strcmp(pname, "linux,phandle") == 0)) { 155 if (np->phandle == 0) 156 np->phandle = be32_to_cpup(p); 157 } 158 /* 159 * And we process the "ibm,phandle" property 160 * used in pSeries dynamic device tree 161 * stuff */ 162 if (strcmp(pname, "ibm,phandle") == 0) 163 np->phandle = be32_to_cpup(p); 164 pp->name = (char *)pname; 165 pp->length = sz; 166 pp->value = (__be32 *)p; 167 *prev_pp = pp; 168 prev_pp = &pp->next; 169 } 170 } 171 /* 172 * with version 0x10 we may not have the name property, recreate 173 * it here from the unit name if absent 174 */ 175 if (!has_name) { 176 const char *p1 = pathp, *ps = pathp, *pa = NULL; 177 int sz; 178 179 while (*p1) { 180 if ((*p1) == '@') 181 pa = p1; 182 if ((*p1) == '/') 183 ps = p1 + 1; 184 p1++; 185 } 186 if (pa < ps) 187 pa = p1; 188 sz = (pa - ps) + 1; 189 pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, 190 __alignof__(struct property)); 191 if (!dryrun) { 192 pp->name = "name"; 193 pp->length = sz; 194 pp->value = pp + 1; 195 *prev_pp = pp; 196 prev_pp = &pp->next; 197 memcpy(pp->value, ps, sz - 1); 198 ((char *)pp->value)[sz - 1] = 0; 199 debug("fixed up name for %s -> %s\n", pathp, 200 (char *)pp->value); 201 } 202 } 203 if (!dryrun) { 204 *prev_pp = NULL; 205 np->name = of_get_property(np, "name", NULL); 206 np->type = of_get_property(np, "device_type", NULL); 207 208 if (!np->name) 209 np->name = "<NULL>"; 210 if (!np->type) 211 np->type = "<NULL>"; } 212 213 old_depth = depth; 214 *poffset = fdt_next_node(blob, *poffset, &depth); 215 if (depth < 0) 216 depth = 0; 217 while (*poffset > 0 && depth > old_depth) { 218 mem = unflatten_dt_node(blob, mem, poffset, np, NULL, 219 fpsize, dryrun); 220 if (!mem) 221 return NULL; 222 } 223 224 if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND) { 225 debug("unflatten: error %d processing FDT\n", *poffset); 226 return NULL; 227 } 228 229 /* 230 * Reverse the child list. Some drivers assumes node order matches .dts 231 * node order 232 */ 233 if (!dryrun && np->child) { 234 struct device_node *child = np->child; 235 np->child = NULL; 236 while (child) { 237 struct device_node *next = child->sibling; 238 239 child->sibling = np->child; 240 np->child = child; 241 child = next; 242 } 243 } 244 245 if (nodepp) 246 *nodepp = np; 247 248 return mem; 249 } 250 251 /** 252 * unflatten_device_tree() - create tree of device_nodes from flat blob 253 * 254 * unflattens a device-tree, creating the 255 * tree of struct device_node. It also fills the "name" and "type" 256 * pointers of the nodes so the normal device-tree walking functions 257 * can be used. 258 * @blob: The blob to expand 259 * @mynodes: The device_node tree created by the call 260 * @return 0 if OK, -ve on error 261 */ 262 static int unflatten_device_tree(const void *blob, 263 struct device_node **mynodes) 264 { 265 unsigned long size; 266 int start; 267 void *mem; 268 269 debug(" -> unflatten_device_tree()\n"); 270 271 if (!blob) { 272 debug("No device tree pointer\n"); 273 return -EINVAL; 274 } 275 276 debug("Unflattening device tree:\n"); 277 debug("magic: %08x\n", fdt_magic(blob)); 278 debug("size: %08x\n", fdt_totalsize(blob)); 279 debug("version: %08x\n", fdt_version(blob)); 280 281 if (fdt_check_header(blob)) { 282 debug("Invalid device tree blob header\n"); 283 return -EINVAL; 284 } 285 286 /* First pass, scan for size */ 287 start = 0; 288 size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 289 0, true); 290 if (!size) 291 return -EFAULT; 292 size = ALIGN(size, 4); 293 294 debug(" size is %lx, allocating...\n", size); 295 296 /* Allocate memory for the expanded device tree */ 297 mem = malloc(size + 4); 298 memset(mem, '\0', size); 299 300 *(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef); 301 302 debug(" unflattening %p...\n", mem); 303 304 /* Second pass, do actual unflattening */ 305 start = 0; 306 unflatten_dt_node(blob, mem, &start, NULL, mynodes, 0, false); 307 if (be32_to_cpup(mem + size) != 0xdeadbeef) { 308 debug("End of tree marker overwritten: %08x\n", 309 be32_to_cpup(mem + size)); 310 return -ENOSPC; 311 } 312 313 debug(" <- unflatten_device_tree()\n"); 314 315 return 0; 316 } 317 318 int of_live_build(const void *fdt_blob, struct device_node **rootp) 319 { 320 int ret; 321 322 debug("%s: start\n", __func__); 323 ret = unflatten_device_tree(fdt_blob, rootp); 324 if (ret) { 325 debug("Failed to create live tree: err=%d\n", ret); 326 return ret; 327 } 328 ret = of_alias_scan(); 329 if (ret) { 330 debug("Failed to scan live tree aliases: err=%d\n", ret); 331 return ret; 332 } 333 debug("%s: stop\n", __func__); 334 335 return ret; 336 } 337