1 #include "libfdt_env.h" 2 3 #include <fdt.h> 4 #include <libfdt.h> 5 6 #include "libfdt_internal.h" 7 8 /** 9 * overlay_get_target_phandle - retrieves the target phandle of a fragment 10 * @fdto: pointer to the device tree overlay blob 11 * @fragment: node offset of the fragment in the overlay 12 * 13 * overlay_get_target_phandle() retrieves the target phandle of an 14 * overlay fragment when that fragment uses a phandle (target 15 * property) instead of a path (target-path property). 16 * 17 * returns: 18 * the phandle pointed by the target property 19 * 0, if the phandle was not found 20 * -1, if the phandle was malformed 21 */ 22 static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) 23 { 24 const uint32_t *val; 25 int len; 26 27 val = fdt_getprop(fdto, fragment, "target", &len); 28 if (!val) 29 return 0; 30 31 if ((*val == (uint32_t)-1) || (len != sizeof(*val))) 32 return (uint32_t)-1; 33 34 return fdt32_to_cpu(*val); 35 } 36 37 /** 38 * overlay_get_target - retrieves the target phandle of a fragment 39 * @fdt: Base device tree blob 40 * @fdto: Device tree overlay blob 41 * @fragment: node offset of the fragment in the overlay 42 * 43 * overlay_get_target() retrieves the target phandle in the base 44 * device tree of a fragment, no matter how the actual targetting is 45 * done (through a phandle or a path) 46 * 47 * returns: 48 * the targetted node offset in the base device tree 49 * Negative error code on error 50 */ 51 static int overlay_get_target(const void *fdt, const void *fdto, 52 int fragment) 53 { 54 uint32_t phandle; 55 const char *path; 56 57 /* Try first to do a phandle based lookup */ 58 phandle = overlay_get_target_phandle(fdto, fragment); 59 if (phandle == (uint32_t)-1) 60 return -FDT_ERR_BADPHANDLE; 61 62 if (phandle) 63 return fdt_node_offset_by_phandle(fdt, phandle); 64 65 /* And then a path based lookup */ 66 path = fdt_getprop(fdto, fragment, "target-path", NULL); 67 if (!path) 68 return -FDT_ERR_NOTFOUND; 69 70 return fdt_path_offset(fdt, path); 71 } 72 73 /** 74 * overlay_phandle_add_offset - Increases a phandle by an offset 75 * @fdt: Base device tree blob 76 * @node: Device tree overlay blob 77 * @name: Name of the property to modify (phandle or linux,phandle) 78 * @delta: offset to apply 79 * 80 * overlay_phandle_add_offset() increments a node phandle by a given 81 * offset. 82 * 83 * returns: 84 * 0 on success. 85 * Negative error code on error 86 */ 87 static int overlay_phandle_add_offset(void *fdt, int node, 88 const char *name, uint32_t delta) 89 { 90 const uint32_t *val; 91 uint32_t adj_val; 92 int len; 93 94 val = fdt_getprop(fdt, node, name, &len); 95 if (!val) 96 return len; 97 98 if (len != sizeof(*val)) 99 return -FDT_ERR_BADSTRUCTURE; 100 101 adj_val = fdt32_to_cpu(*val); 102 if ((adj_val + delta) < adj_val) 103 return -FDT_ERR_BADPHANDLE; 104 105 adj_val += delta; 106 return fdt_setprop_inplace_u32(fdt, node, name, adj_val); 107 } 108 109 /** 110 * overlay_adjust_node_phandles - Offsets the phandles of a node 111 * @fdto: Device tree overlay blob 112 * @node: Offset of the node we want to adjust 113 * @delta: Offset to shift the phandles of 114 * 115 * overlay_adjust_node_phandles() adds a constant to all the phandles 116 * of a given node. This is mainly use as part of the overlay 117 * application process, when we want to update all the overlay 118 * phandles to not conflict with the overlays of the base device tree. 119 * 120 * returns: 121 * 0 on success 122 * Negative error code on failure 123 */ 124 static int overlay_adjust_node_phandles(void *fdto, int node, 125 uint32_t delta) 126 { 127 bool found = false; 128 int child; 129 int ret; 130 131 ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); 132 if (ret && ret != -FDT_ERR_NOTFOUND) 133 return ret; 134 135 if (!ret) 136 found = true; 137 138 ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); 139 if (ret && ret != -FDT_ERR_NOTFOUND) 140 return ret; 141 142 /* 143 * If neither phandle nor linux,phandle have been found return 144 * an error. 145 */ 146 if (!found && !ret) 147 return ret; 148 149 fdt_for_each_subnode(fdto, child, node) 150 overlay_adjust_node_phandles(fdto, child, delta); 151 152 return 0; 153 } 154 155 /** 156 * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay 157 * @fdto: Device tree overlay blob 158 * @delta: Offset to shift the phandles of 159 * 160 * overlay_adjust_local_phandles() adds a constant to all the 161 * phandles of an overlay. This is mainly use as part of the overlay 162 * application process, when we want to update all the overlay 163 * phandles to not conflict with the overlays of the base device tree. 164 * 165 * returns: 166 * 0 on success 167 * Negative error code on failure 168 */ 169 static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) 170 { 171 /* 172 * Start adjusting the phandles from the overlay root 173 */ 174 return overlay_adjust_node_phandles(fdto, 0, delta); 175 } 176 177 /** 178 * overlay_update_local_node_references - Adjust the overlay references 179 * @fdto: Device tree overlay blob 180 * @tree_node: Node offset of the node to operate on 181 * @fixup_node: Node offset of the matching local fixups node 182 * @delta: Offset to shift the phandles of 183 * 184 * overlay_update_local_nodes_references() update the phandles 185 * pointing to a node within the device tree overlay by adding a 186 * constant delta. 187 * 188 * This is mainly used as part of a device tree application process, 189 * where you want the device tree overlays phandles to not conflict 190 * with the ones from the base device tree before merging them. 191 * 192 * returns: 193 * 0 on success 194 * Negative error code on failure 195 */ 196 static int overlay_update_local_node_references(void *fdto, 197 int tree_node, 198 int fixup_node, 199 uint32_t delta) 200 { 201 int fixup_prop; 202 int fixup_child; 203 int ret; 204 205 fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { 206 const unsigned char *fixup_val, *tree_val; 207 const char *name; 208 int fixup_len; 209 int tree_len; 210 int i; 211 212 fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, 213 &name, &fixup_len); 214 if (!fixup_val) 215 return fixup_len; 216 217 tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); 218 if (!tree_val) 219 return tree_len; 220 221 for (i = 0; i < fixup_len; i += sizeof(uint32_t)) { 222 uint32_t adj_val, index; 223 224 index = *(uint32_t *)(fixup_val + i); 225 index = fdt32_to_cpu(index); 226 227 /* 228 * phandles to fixup can be unaligned. 229 * 230 * Use a memcpy for the architectures that do 231 * not support unaligned accesses. 232 */ 233 memcpy(&adj_val, tree_val + index, sizeof(uint32_t)); 234 235 adj_val = fdt32_to_cpu(adj_val); 236 adj_val += delta; 237 adj_val = cpu_to_fdt32(adj_val); 238 239 ret = fdt_setprop_inplace_namelen_partial(fdto, 240 tree_node, 241 name, 242 strlen(name), 243 index, 244 &adj_val, 245 sizeof(adj_val)); 246 if (ret) 247 return ret; 248 } 249 } 250 251 fdt_for_each_subnode(fdto, fixup_child, fixup_node) { 252 const char *fixup_child_name = fdt_get_name(fdto, fixup_child, 253 NULL); 254 int tree_child; 255 256 tree_child = fdt_subnode_offset(fdto, tree_node, 257 fixup_child_name); 258 if (tree_child < 0) 259 return tree_child; 260 261 ret = overlay_update_local_node_references(fdto, 262 tree_child, 263 fixup_child, 264 delta); 265 if (ret) 266 return ret; 267 } 268 269 return 0; 270 } 271 272 /** 273 * overlay_update_local_references - Adjust the overlay references 274 * @fdto: Device tree overlay blob 275 * @delta: Offset to shift the phandles of 276 * 277 * overlay_update_local_references() update all the phandles pointing 278 * to a node within the device tree overlay by adding a constant 279 * delta to not conflict with the base overlay. 280 * 281 * This is mainly used as part of a device tree application process, 282 * where you want the device tree overlays phandles to not conflict 283 * with the ones from the base device tree before merging them. 284 * 285 * returns: 286 * 0 on success 287 * Negative error code on failure 288 */ 289 static int overlay_update_local_references(void *fdto, uint32_t delta) 290 { 291 int fixups; 292 293 fixups = fdt_path_offset(fdto, "/__local_fixups__"); 294 if (fixups < 0) { 295 /* There's no local phandles to adjust, bail out */ 296 if (fixups == -FDT_ERR_NOTFOUND) 297 return 0; 298 299 return fixups; 300 } 301 302 /* 303 * Update our local references from the root of the tree 304 */ 305 return overlay_update_local_node_references(fdto, 0, fixups, 306 delta); 307 } 308 309 /** 310 * overlay_fixup_one_phandle - Set an overlay phandle to the base one 311 * @fdt: Base Device Tree blob 312 * @fdto: Device tree overlay blob 313 * @symbols_off: Node offset of the symbols node in the base device tree 314 * @path: Path to a node holding a phandle in the overlay 315 * @path_len: number of path characters to consider 316 * @name: Name of the property holding the phandle reference in the overlay 317 * @name_len: number of name characters to consider 318 * @index: Index in the overlay property where the phandle is stored 319 * @label: Label of the node referenced by the phandle 320 * 321 * overlay_fixup_one_phandle() resolves an overlay phandle pointing to 322 * a node in the base device tree. 323 * 324 * This is part of the device tree overlay application process, when 325 * you want all the phandles in the overlay to point to the actual 326 * base dt nodes. 327 * 328 * returns: 329 * 0 on success 330 * Negative error code on failure 331 */ 332 static int overlay_fixup_one_phandle(void *fdt, void *fdto, 333 int symbols_off, 334 const char *path, uint32_t path_len, 335 const char *name, uint32_t name_len, 336 int index, const char *label) 337 { 338 const char *symbol_path; 339 uint32_t phandle; 340 int symbol_off, fixup_off; 341 int prop_len; 342 343 symbol_path = fdt_getprop(fdt, symbols_off, label, 344 &prop_len); 345 if (!symbol_path) 346 return -FDT_ERR_NOTFOUND; 347 348 symbol_off = fdt_path_offset(fdt, symbol_path); 349 if (symbol_off < 0) 350 return symbol_off; 351 352 phandle = fdt_get_phandle(fdt, symbol_off); 353 if (!phandle) 354 return -FDT_ERR_NOTFOUND; 355 356 fixup_off = fdt_path_offset_namelen(fdto, path, path_len); 357 if (fixup_off < 0) 358 return fixup_off; 359 360 phandle = cpu_to_fdt32(phandle); 361 return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, 362 name, name_len, index, 363 &phandle, sizeof(phandle)); 364 }; 365 366 /** 367 * overlay_fixup_phandle - Set an overlay phandle to the base one 368 * @fdt: Base Device Tree blob 369 * @fdto: Device tree overlay blob 370 * @symbols_off: Node offset of the symbols node in the base device tree 371 * @property: Property offset in the overlay holding the list of fixups 372 * 373 * overlay_fixup_phandle() resolves all the overlay phandles pointed 374 * to in a __local_fixup__ property, and updates them to match the 375 * phandles in use in the base device tree. 376 * 377 * This is part of the device tree overlay application process, when 378 * you want all the phandles in the overlay to point to the actual 379 * base dt nodes. 380 * 381 * returns: 382 * 0 on success 383 * Negative error code on failure 384 */ 385 static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, 386 int property) 387 { 388 const char *value; 389 const char *label; 390 int len; 391 392 value = fdt_getprop_by_offset(fdto, property, 393 &label, &len); 394 if (!value) 395 return len; 396 397 do { 398 const char *prop_string = value; 399 const char *path, *name; 400 uint32_t prop_len = strlen(value); 401 uint32_t path_len, name_len; 402 char *sep, *endptr; 403 int index; 404 int ret; 405 406 path = prop_string; 407 sep = memchr(prop_string, ':', prop_len); 408 if (*sep != ':') 409 return -FDT_ERR_BADSTRUCTURE; 410 path_len = sep - path; 411 412 name = sep + 1; 413 sep = memchr(name, ':', prop_len); 414 if (*sep != ':') 415 return -FDT_ERR_BADSTRUCTURE; 416 name_len = sep - name; 417 418 index = strtoul(sep + 1, &endptr, 10); 419 if ((*endptr != '\0') || (endptr <= (sep + 1))) 420 return -FDT_ERR_BADSTRUCTURE; 421 422 len -= prop_len + 1; 423 value += prop_len + 1; 424 425 ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, 426 path, path_len, name, name_len, 427 index, label); 428 if (ret) 429 return ret; 430 } while (len > 0); 431 432 return 0; 433 } 434 435 /** 436 * overlay_fixup_phandles - Resolve the overlay phandles to the base 437 * device tree 438 * @fdt: Base Device Tree blob 439 * @fdto: Device tree overlay blob 440 * 441 * overlay_fixup_phandles() resolves all the overlay phandles pointing 442 * to nodes in the base device tree. 443 * 444 * This is one of the steps of the device tree overlay application 445 * process, when you want all the phandles in the overlay to point to 446 * the actual base dt nodes. 447 * 448 * returns: 449 * 0 on success 450 * Negative error code on failure 451 */ 452 static int overlay_fixup_phandles(void *fdt, void *fdto) 453 { 454 int fixups_off, symbols_off; 455 int property; 456 457 symbols_off = fdt_path_offset(fdt, "/__symbols__"); 458 fixups_off = fdt_path_offset(fdto, "/__fixups__"); 459 460 fdt_for_each_property_offset(property, fdto, fixups_off) { 461 int ret; 462 463 ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); 464 if (ret) 465 return ret; 466 } 467 468 return 0; 469 } 470 471 /** 472 * overlay_apply_node - Merge an overlay fragment into the base device tree 473 * @fdt: Base Device Tree blob 474 * @target: Node offset in the base device tree to apply the fragment to 475 * @fdto: Device tree overlay blob 476 * @fragment: Node offset in the overlay holding the changes to merge 477 * 478 * overlay_apply_node() merges an overlay fragment into a target base 479 * device tree node pointed. 480 * 481 * This is part of the final step in the device tree overlay 482 * application process, when all the phandles have been adjusted and 483 * resolved and you just have to merge overlay into the base device 484 * tree. 485 * 486 * returns: 487 * 0 on success 488 * Negative error code on failure 489 */ 490 static int overlay_apply_node(void *fdt, int target, 491 void *fdto, int fragment) 492 { 493 int property; 494 int node; 495 496 fdt_for_each_property_offset(property, fdto, fragment) { 497 const char *name; 498 const void *prop; 499 int prop_len; 500 int ret; 501 502 prop = fdt_getprop_by_offset(fdto, property, &name, 503 &prop_len); 504 if (prop_len == -FDT_ERR_NOTFOUND) 505 return -FDT_ERR_INTERNAL; 506 if (prop_len < 0) 507 return prop_len; 508 509 ret = fdt_setprop(fdt, target, name, prop, prop_len); 510 if (ret) 511 return ret; 512 } 513 514 fdt_for_each_subnode(fdto, node, fragment) { 515 const char *name = fdt_get_name(fdto, node, NULL); 516 int nnode; 517 int ret; 518 519 nnode = fdt_add_subnode(fdt, target, name); 520 if (nnode == -FDT_ERR_EXISTS) 521 nnode = fdt_subnode_offset(fdt, target, name); 522 523 if (nnode < 0) 524 return nnode; 525 526 ret = overlay_apply_node(fdt, nnode, fdto, node); 527 if (ret) 528 return ret; 529 } 530 531 return 0; 532 } 533 534 /** 535 * overlay_merge - Merge an overlay into its base device tree 536 * @fdt: Base Device Tree blob 537 * @fdto: Device tree overlay blob 538 * 539 * overlay_merge() merges an overlay into its base device tree. 540 * 541 * This is the final step in the device tree overlay application 542 * process, when all the phandles have been adjusted and resolved and 543 * you just have to merge overlay into the base device tree. 544 * 545 * returns: 546 * 0 on success 547 * Negative error code on failure 548 */ 549 static int overlay_merge(void *dt, void *dto) 550 { 551 int fragment; 552 553 fdt_for_each_subnode(dto, fragment, 0) { 554 int overlay; 555 int target; 556 int ret; 557 558 target = overlay_get_target(dt, dto, fragment); 559 if (target < 0) 560 continue; 561 562 overlay = fdt_subnode_offset(dto, fragment, "__overlay__"); 563 if (overlay < 0) 564 return overlay; 565 566 ret = overlay_apply_node(dt, target, dto, overlay); 567 if (ret) 568 return ret; 569 } 570 571 return 0; 572 } 573 574 int fdt_overlay_apply(void *fdt, void *fdto) 575 { 576 uint32_t delta = fdt_get_max_phandle(fdt) + 1; 577 int ret; 578 579 FDT_CHECK_HEADER(fdt); 580 FDT_CHECK_HEADER(fdto); 581 582 ret = overlay_adjust_local_phandles(fdto, delta); 583 if (ret) 584 goto err; 585 586 ret = overlay_update_local_references(fdto, delta); 587 if (ret) 588 goto err; 589 590 ret = overlay_fixup_phandles(fdt, fdto); 591 if (ret) 592 goto err; 593 594 ret = overlay_merge(fdt, fdto); 595 if (ret) 596 goto err; 597 598 /* 599 * The overlay has been damaged, erase its magic. 600 */ 601 fdt_set_magic(fdto, ~0); 602 603 return 0; 604 605 err: 606 /* 607 * The overlay might have been damaged, erase its magic. 608 */ 609 fdt_set_magic(fdto, ~0); 610 611 /* 612 * The base device tree might have been damaged, erase its 613 * magic. 614 */ 615 fdt_set_magic(fdt, ~0); 616 617 return ret; 618 } 619