1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) 2 /* 3 * libfdt - Flat Device Tree manipulation 4 * Copyright (C) 2016 Free Electrons 5 * Copyright (C) 2016 NextThing Co. 6 */ 7 #include "libfdt_env.h" 8 9 #include <fdt.h> 10 #include <libfdt.h> 11 12 #include "libfdt_internal.h" 13 14 /** 15 * overlay_get_target_phandle - retrieves the target phandle of a fragment 16 * @fdto: pointer to the device tree overlay blob 17 * @fragment: node offset of the fragment in the overlay 18 * 19 * overlay_get_target_phandle() retrieves the target phandle of an 20 * overlay fragment when that fragment uses a phandle (target 21 * property) instead of a path (target-path property). 22 * 23 * returns: 24 * the phandle pointed by the target property 25 * 0, if the phandle was not found 26 * -1, if the phandle was malformed 27 */ 28 static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) 29 { 30 const fdt32_t *val; 31 int len; 32 33 val = fdt_getprop(fdto, fragment, "target", &len); 34 if (!val) 35 return 0; 36 37 if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) 38 return (uint32_t)-1; 39 40 return fdt32_to_cpu(*val); 41 } 42 43 int fdt_overlay_target_offset(const void *fdt, const void *fdto, 44 int fragment_offset, char const **pathp) 45 { 46 uint32_t phandle; 47 const char *path = NULL; 48 int path_len = 0, ret; 49 50 /* Try first to do a phandle based lookup */ 51 phandle = overlay_get_target_phandle(fdto, fragment_offset); 52 if (phandle == (uint32_t)-1) 53 return -FDT_ERR_BADPHANDLE; 54 55 /* no phandle, try path */ 56 if (!phandle) { 57 /* And then a path based lookup */ 58 path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len); 59 if (path) 60 ret = fdt_path_offset(fdt, path); 61 else 62 ret = path_len; 63 } else 64 ret = fdt_node_offset_by_phandle(fdt, phandle); 65 66 /* 67 * If we haven't found either a target or a 68 * target-path property in a node that contains a 69 * __overlay__ subnode (we wouldn't be called 70 * otherwise), consider it a improperly written 71 * overlay 72 */ 73 if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) 74 ret = -FDT_ERR_BADOVERLAY; 75 76 /* return on error */ 77 if (ret < 0) 78 return ret; 79 80 /* return pointer to path (if available) */ 81 if (pathp) 82 *pathp = path ? path : NULL; 83 84 return ret; 85 } 86 87 /** 88 * overlay_phandle_add_offset - Increases a phandle by an offset 89 * @fdt: Base device tree blob 90 * @node: Device tree overlay blob 91 * @name: Name of the property to modify (phandle or linux,phandle) 92 * @delta: offset to apply 93 * 94 * overlay_phandle_add_offset() increments a node phandle by a given 95 * offset. 96 * 97 * returns: 98 * 0 on success. 99 * Negative error code on error 100 */ 101 static int overlay_phandle_add_offset(void *fdt, int node, 102 const char *name, uint32_t delta) 103 { 104 fdt32_t *valp, val; 105 int len; 106 107 valp = fdt_getprop_w(fdt, node, name, &len); 108 if (!valp) 109 return len; 110 111 if (len != sizeof(val)) 112 return -FDT_ERR_BADPHANDLE; 113 114 val = fdt32_ld(valp); 115 if (val + delta < val || val + delta == (uint32_t)-1) 116 return -FDT_ERR_NOPHANDLES; 117 118 fdt32_st(valp, val + delta); 119 return 0; 120 } 121 122 /** 123 * overlay_adjust_node_phandles - Offsets the phandles of a node 124 * @fdto: Device tree overlay blob 125 * @node: Offset of the node we want to adjust 126 * @delta: Offset to shift the phandles of 127 * 128 * overlay_adjust_node_phandles() adds a constant to all the phandles 129 * of a given node. This is mainly use as part of the overlay 130 * application process, when we want to update all the overlay 131 * phandles to not conflict with the overlays of the base device tree. 132 * 133 * returns: 134 * 0 on success 135 * Negative error code on failure 136 */ 137 static int overlay_adjust_node_phandles(void *fdto, int node, 138 uint32_t delta) 139 { 140 int child; 141 int ret; 142 143 ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); 144 if (ret && ret != -FDT_ERR_NOTFOUND) 145 return ret; 146 147 ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); 148 if (ret && ret != -FDT_ERR_NOTFOUND) 149 return ret; 150 151 fdt_for_each_subnode(child, fdto, node) { 152 ret = overlay_adjust_node_phandles(fdto, child, delta); 153 if (ret) 154 return ret; 155 } 156 157 return 0; 158 } 159 160 /** 161 * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay 162 * @fdto: Device tree overlay blob 163 * @delta: Offset to shift the phandles of 164 * 165 * overlay_adjust_local_phandles() adds a constant to all the 166 * phandles of an overlay. This is mainly use as part of the overlay 167 * application process, when we want to update all the overlay 168 * phandles to not conflict with the overlays of the base device tree. 169 * 170 * returns: 171 * 0 on success 172 * Negative error code on failure 173 */ 174 static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) 175 { 176 /* 177 * Start adjusting the phandles from the overlay root 178 */ 179 return overlay_adjust_node_phandles(fdto, 0, delta); 180 } 181 182 /** 183 * overlay_update_local_node_references - Adjust the overlay references 184 * @fdto: Device tree overlay blob 185 * @tree_node: Node offset of the node to operate on 186 * @fixup_node: Node offset of the matching local fixups node 187 * @delta: Offset to shift the phandles of 188 * 189 * overlay_update_local_nodes_references() update the phandles 190 * pointing to a node within the device tree overlay by adding a 191 * constant delta. 192 * 193 * This is mainly used as part of a device tree application process, 194 * where you want the device tree overlays phandles to not conflict 195 * with the ones from the base device tree before merging them. 196 * 197 * returns: 198 * 0 on success 199 * Negative error code on failure 200 */ 201 static int overlay_update_local_node_references(void *fdto, 202 int tree_node, 203 int fixup_node, 204 uint32_t delta) 205 { 206 int fixup_prop; 207 int fixup_child; 208 int ret; 209 210 fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { 211 const fdt32_t *fixup_val; 212 const char *name; 213 char *tree_val; 214 int fixup_len; 215 int tree_len; 216 int i; 217 218 fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, 219 &name, &fixup_len); 220 if (!fixup_val) 221 return fixup_len; 222 223 if (fixup_len % sizeof(uint32_t)) 224 return -FDT_ERR_BADOVERLAY; 225 fixup_len /= sizeof(uint32_t); 226 227 tree_val = fdt_getprop_w(fdto, tree_node, name, &tree_len); 228 if (!tree_val) { 229 if (tree_len == -FDT_ERR_NOTFOUND) 230 return -FDT_ERR_BADOVERLAY; 231 232 return tree_len; 233 } 234 235 for (i = 0; i < fixup_len; i++) { 236 fdt32_t *refp; 237 238 refp = (fdt32_t *)(tree_val + fdt32_ld_(fixup_val + i)); 239 240 /* 241 * phandles to fixup can be unaligned, so use 242 * fdt32_{ld,st}() to read/write them. 243 */ 244 fdt32_st(refp, fdt32_ld(refp) + delta); 245 } 246 } 247 248 fdt_for_each_subnode(fixup_child, fdto, fixup_node) { 249 const char *fixup_child_name = fdt_get_name(fdto, fixup_child, 250 NULL); 251 int tree_child; 252 253 tree_child = fdt_subnode_offset(fdto, tree_node, 254 fixup_child_name); 255 if (tree_child == -FDT_ERR_NOTFOUND) 256 return -FDT_ERR_BADOVERLAY; 257 if (tree_child < 0) 258 return tree_child; 259 260 ret = overlay_update_local_node_references(fdto, 261 tree_child, 262 fixup_child, 263 delta); 264 if (ret) 265 return ret; 266 } 267 268 return 0; 269 } 270 271 /** 272 * overlay_update_local_references - Adjust the overlay references 273 * @fdto: Device tree overlay blob 274 * @delta: Offset to shift the phandles of 275 * 276 * overlay_update_local_references() update all the phandles pointing 277 * to a node within the device tree overlay by adding a constant 278 * delta to not conflict with the base overlay. 279 * 280 * This is mainly used as part of a device tree application process, 281 * where you want the device tree overlays phandles to not conflict 282 * with the ones from the base device tree before merging them. 283 * 284 * returns: 285 * 0 on success 286 * Negative error code on failure 287 */ 288 static int overlay_update_local_references(void *fdto, uint32_t delta) 289 { 290 int fixups; 291 292 fixups = fdt_path_offset(fdto, "/__local_fixups__"); 293 if (fixups < 0) { 294 /* There's no local phandles to adjust, bail out */ 295 if (fixups == -FDT_ERR_NOTFOUND) 296 return 0; 297 298 return fixups; 299 } 300 301 /* 302 * Update our local references from the root of the tree 303 */ 304 return overlay_update_local_node_references(fdto, 0, fixups, 305 delta); 306 } 307 308 /** 309 * overlay_fixup_one_phandle - Set an overlay phandle to the base one 310 * @fdto: Device tree overlay blob 311 * @symbols_off: Node offset of the symbols node in the base device tree 312 * @path: Path to a node holding a phandle in the overlay 313 * @path_len: number of path characters to consider 314 * @name: Name of the property holding the phandle reference in the overlay 315 * @name_len: number of name characters to consider 316 * @poffset: Offset within the overlay property where the phandle is stored 317 * @phandle: Phandle referencing the node 318 * 319 * overlay_fixup_one_phandle() resolves an overlay phandle pointing to 320 * a node in the base device tree. 321 * 322 * This is part of the device tree overlay application process, when 323 * you want all the phandles in the overlay to point to the actual 324 * base dt nodes. 325 * 326 * returns: 327 * 0 on success 328 * Negative error code on failure 329 */ 330 static int overlay_fixup_one_phandle(void *fdto, int symbols_off, 331 const char *path, uint32_t path_len, 332 const char *name, uint32_t name_len, 333 int poffset, uint32_t phandle) 334 { 335 fdt32_t phandle_prop; 336 int fixup_off; 337 338 if (symbols_off < 0) 339 return symbols_off; 340 341 fixup_off = fdt_path_offset_namelen(fdto, path, path_len); 342 if (fixup_off == -FDT_ERR_NOTFOUND) 343 return -FDT_ERR_BADOVERLAY; 344 if (fixup_off < 0) 345 return fixup_off; 346 347 phandle_prop = cpu_to_fdt32(phandle); 348 return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, 349 name, name_len, poffset, 350 &phandle_prop, 351 sizeof(phandle_prop)); 352 } 353 354 /** 355 * overlay_fixup_phandle - Set an overlay phandle to the base one 356 * @fdt: Base Device Tree blob 357 * @fdto: Device tree overlay blob 358 * @symbols_off: Node offset of the symbols node in the base device tree 359 * @property: Property offset in the overlay holding the list of fixups 360 * 361 * overlay_fixup_phandle() resolves all the overlay phandles pointed 362 * to in a __fixups__ property, and updates them to match the phandles 363 * in use in the base device tree. 364 * 365 * This is part of the device tree overlay application process, when 366 * you want all the phandles in the overlay to point to the actual 367 * base dt nodes. 368 * 369 * returns: 370 * 0 on success 371 * Negative error code on failure 372 */ 373 static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, 374 int property) 375 { 376 const char *value; 377 const char *label; 378 int len; 379 const char *symbol_path; 380 int prop_len; 381 int symbol_off; 382 uint32_t phandle; 383 384 value = fdt_getprop_by_offset(fdto, property, 385 &label, &len); 386 if (!value) { 387 if (len == -FDT_ERR_NOTFOUND) 388 return -FDT_ERR_INTERNAL; 389 390 return len; 391 } 392 393 symbol_path = fdt_getprop(fdt, symbols_off, label, &prop_len); 394 if (!symbol_path) 395 return prop_len; 396 397 symbol_off = fdt_path_offset(fdt, symbol_path); 398 if (symbol_off < 0) 399 return symbol_off; 400 401 phandle = fdt_get_phandle(fdt, symbol_off); 402 if (!phandle) 403 return -FDT_ERR_NOTFOUND; 404 405 do { 406 const char *path, *name, *fixup_end; 407 const char *fixup_str = value; 408 uint32_t path_len, name_len; 409 uint32_t fixup_len; 410 char *sep, *endptr; 411 int poffset, ret; 412 413 fixup_end = memchr(value, '\0', len); 414 if (!fixup_end) 415 return -FDT_ERR_BADOVERLAY; 416 fixup_len = fixup_end - fixup_str; 417 418 len -= fixup_len + 1; 419 value += fixup_len + 1; 420 421 path = fixup_str; 422 sep = memchr(fixup_str, ':', fixup_len); 423 if (!sep || *sep != ':') 424 return -FDT_ERR_BADOVERLAY; 425 426 path_len = sep - path; 427 if (path_len == (fixup_len - 1)) 428 return -FDT_ERR_BADOVERLAY; 429 430 fixup_len -= path_len + 1; 431 name = sep + 1; 432 sep = memchr(name, ':', fixup_len); 433 if (!sep || *sep != ':') 434 return -FDT_ERR_BADOVERLAY; 435 436 name_len = sep - name; 437 if (!name_len) 438 return -FDT_ERR_BADOVERLAY; 439 440 poffset = strtoul(sep + 1, &endptr, 10); 441 if ((*endptr != '\0') || (endptr <= (sep + 1))) 442 return -FDT_ERR_BADOVERLAY; 443 444 ret = overlay_fixup_one_phandle(fdto, symbols_off, 445 path, path_len, name, name_len, 446 poffset, phandle); 447 if (ret) 448 return ret; 449 } while (len > 0); 450 451 return 0; 452 } 453 454 /** 455 * overlay_fixup_phandles - Resolve the overlay phandles to the base 456 * device tree 457 * @fdt: Base Device Tree blob 458 * @fdto: Device tree overlay blob 459 * 460 * overlay_fixup_phandles() resolves all the overlay phandles pointing 461 * to nodes in the base device tree. 462 * 463 * This is one of the steps of the device tree overlay application 464 * process, when you want all the phandles in the overlay to point to 465 * the actual base dt nodes. 466 * 467 * returns: 468 * 0 on success 469 * Negative error code on failure 470 */ 471 static int overlay_fixup_phandles(void *fdt, void *fdto) 472 { 473 int fixups_off, symbols_off; 474 int property; 475 476 /* We can have overlays without any fixups */ 477 fixups_off = fdt_path_offset(fdto, "/__fixups__"); 478 if (fixups_off == -FDT_ERR_NOTFOUND) 479 return 0; /* nothing to do */ 480 if (fixups_off < 0) 481 return fixups_off; 482 483 /* And base DTs without symbols */ 484 symbols_off = fdt_path_offset(fdt, "/__symbols__"); 485 if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) 486 return symbols_off; 487 488 fdt_for_each_property_offset(property, fdto, fixups_off) { 489 int ret; 490 491 ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); 492 if (ret) 493 return ret; 494 } 495 496 return 0; 497 } 498 499 /** 500 * overlay_adjust_local_conflicting_phandle: Changes a phandle value 501 * @fdto: Device tree overlay 502 * @node: The node the phandle is set for 503 * @fdt_phandle: The new value for the phandle 504 * 505 * returns: 506 * 0 on success 507 * Negative error code on failure 508 */ 509 static int overlay_adjust_local_conflicting_phandle(void *fdto, int node, 510 uint32_t fdt_phandle) 511 { 512 const fdt32_t *php; 513 int len, ret; 514 515 php = fdt_getprop(fdto, node, "phandle", &len); 516 if (php && len == sizeof(*php)) { 517 ret = fdt_setprop_inplace_u32(fdto, node, "phandle", fdt_phandle); 518 if (ret) 519 return ret; 520 } 521 522 php = fdt_getprop(fdto, node, "linux,phandle", &len); 523 if (php && len == sizeof(*php)) { 524 ret = fdt_setprop_inplace_u32(fdto, node, "linux,phandle", fdt_phandle); 525 if (ret) 526 return ret; 527 } 528 529 return 0; 530 } 531 532 /** 533 * overlay_update_node_conflicting_references - Recursively replace phandle values 534 * @fdto: Device tree overlay blob 535 * @tree_node: Node to recurse into 536 * @fixup_node: Node offset of the matching local fixups node 537 * @fdt_phandle: Value to replace phandles with 538 * @fdto_phandle: Value to be replaced 539 * 540 * Replaces all phandles with value @fdto_phandle by @fdt_phandle. 541 * 542 * returns: 543 * 0 on success 544 * Negative error code on failure 545 */ 546 static int overlay_update_node_conflicting_references(void *fdto, int tree_node, 547 int fixup_node, 548 uint32_t fdt_phandle, 549 uint32_t fdto_phandle) 550 { 551 int fixup_prop; 552 int fixup_child; 553 int ret; 554 555 fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { 556 const fdt32_t *fixup_val; 557 const char *name; 558 char *tree_val; 559 int fixup_len; 560 int tree_len; 561 int i; 562 563 fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, 564 &name, &fixup_len); 565 if (!fixup_val) 566 return fixup_len; 567 568 if (fixup_len % sizeof(uint32_t)) 569 return -FDT_ERR_BADOVERLAY; 570 fixup_len /= sizeof(uint32_t); 571 572 tree_val = fdt_getprop_w(fdto, tree_node, name, &tree_len); 573 if (!tree_val) { 574 if (tree_len == -FDT_ERR_NOTFOUND) 575 return -FDT_ERR_BADOVERLAY; 576 577 return tree_len; 578 } 579 580 for (i = 0; i < fixup_len; i++) { 581 fdt32_t *refp; 582 uint32_t valp; 583 584 refp = (fdt32_t *)(tree_val + fdt32_ld_(fixup_val + i)); 585 valp = fdt32_ld(refp); 586 587 if (valp == fdto_phandle) 588 fdt32_st(refp, fdt_phandle); 589 } 590 } 591 592 fdt_for_each_subnode(fixup_child, fdto, fixup_node) { 593 const char *fixup_child_name = fdt_get_name(fdto, fixup_child, NULL); 594 int tree_child; 595 596 tree_child = fdt_subnode_offset(fdto, tree_node, fixup_child_name); 597 598 if (tree_child == -FDT_ERR_NOTFOUND) 599 return -FDT_ERR_BADOVERLAY; 600 if (tree_child < 0) 601 return tree_child; 602 603 ret = overlay_update_node_conflicting_references(fdto, tree_child, 604 fixup_child, 605 fdt_phandle, 606 fdto_phandle); 607 if (ret) 608 return ret; 609 } 610 611 return 0; 612 } 613 614 /** 615 * overlay_update_local_conflicting_references - Recursively replace phandle values 616 * @fdto: Device tree overlay blob 617 * @fdt_phandle: Value to replace phandles with 618 * @fdto_phandle: Value to be replaced 619 * 620 * Replaces all phandles with value @fdto_phandle by @fdt_phandle. 621 * 622 * returns: 623 * 0 on success 624 * Negative error code on failure 625 */ 626 static int overlay_update_local_conflicting_references(void *fdto, 627 uint32_t fdt_phandle, 628 uint32_t fdto_phandle) 629 { 630 int fixups; 631 632 fixups = fdt_path_offset(fdto, "/__local_fixups__"); 633 if (fixups == -FDT_ERR_NOTFOUND) 634 return 0; 635 if (fixups < 0) 636 return fixups; 637 638 return overlay_update_node_conflicting_references(fdto, 0, fixups, 639 fdt_phandle, 640 fdto_phandle); 641 } 642 643 /** 644 * overlay_prevent_phandle_overwrite_node - Helper function for overlay_prevent_phandle_overwrite 645 * @fdt: Base Device tree blob 646 * @fdtnode: Node in fdt that is checked for an overwrite 647 * @fdto: Device tree overlay blob 648 * @fdtonode: Node in fdto matching @fdtnode 649 * 650 * returns: 651 * 0 on success 652 * Negative error code on failure 653 */ 654 static int overlay_prevent_phandle_overwrite_node(void *fdt, int fdtnode, 655 void *fdto, int fdtonode) 656 { 657 uint32_t fdt_phandle, fdto_phandle; 658 int fdtochild; 659 660 fdt_phandle = fdt_get_phandle(fdt, fdtnode); 661 fdto_phandle = fdt_get_phandle(fdto, fdtonode); 662 663 if (fdt_phandle && fdto_phandle) { 664 int ret; 665 666 ret = overlay_adjust_local_conflicting_phandle(fdto, fdtonode, 667 fdt_phandle); 668 if (ret) 669 return ret; 670 671 ret = overlay_update_local_conflicting_references(fdto, 672 fdt_phandle, 673 fdto_phandle); 674 if (ret) 675 return ret; 676 } 677 678 fdt_for_each_subnode(fdtochild, fdto, fdtonode) { 679 const char *name = fdt_get_name(fdto, fdtochild, NULL); 680 int fdtchild; 681 int ret; 682 683 fdtchild = fdt_subnode_offset(fdt, fdtnode, name); 684 if (fdtchild == -FDT_ERR_NOTFOUND) 685 /* 686 * no further overwrites possible here as this node is 687 * new 688 */ 689 continue; 690 691 ret = overlay_prevent_phandle_overwrite_node(fdt, fdtchild, 692 fdto, fdtochild); 693 if (ret) 694 return ret; 695 } 696 697 return 0; 698 } 699 700 /** 701 * overlay_prevent_phandle_overwrite - Fixes overlay phandles to not overwrite base phandles 702 * @fdt: Base Device Tree blob 703 * @fdto: Device tree overlay blob 704 * 705 * Checks recursively if applying fdto overwrites phandle values in the base 706 * dtb. When such a phandle is found, the fdto is changed to use the fdt's 707 * phandle value to not break references in the base. 708 * 709 * returns: 710 * 0 on success 711 * Negative error code on failure 712 */ 713 static int overlay_prevent_phandle_overwrite(void *fdt, void *fdto) 714 { 715 int fragment; 716 717 fdt_for_each_subnode(fragment, fdto, 0) { 718 int overlay; 719 int target; 720 int ret; 721 722 overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); 723 if (overlay == -FDT_ERR_NOTFOUND) 724 continue; 725 726 if (overlay < 0) 727 return overlay; 728 729 target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL); 730 if (target == -FDT_ERR_NOTFOUND) 731 /* 732 * The subtree doesn't exist in the base, so nothing 733 * will be overwritten. 734 */ 735 continue; 736 else if (target < 0) 737 return target; 738 739 ret = overlay_prevent_phandle_overwrite_node(fdt, target, 740 fdto, overlay); 741 if (ret) 742 return ret; 743 } 744 745 return 0; 746 } 747 748 /** 749 * overlay_apply_node - Merges a node into the base device tree 750 * @fdt: Base Device Tree blob 751 * @target: Node offset in the base device tree to apply the fragment to 752 * @fdto: Device tree overlay blob 753 * @node: Node offset in the overlay holding the changes to merge 754 * 755 * overlay_apply_node() merges a node into a target base device tree 756 * node pointed. 757 * 758 * This is part of the final step in the device tree overlay 759 * application process, when all the phandles have been adjusted and 760 * resolved and you just have to merge overlay into the base device 761 * tree. 762 * 763 * returns: 764 * 0 on success 765 * Negative error code on failure 766 */ 767 static int overlay_apply_node(void *fdt, int target, 768 void *fdto, int node) 769 { 770 int property; 771 int subnode; 772 773 fdt_for_each_property_offset(property, fdto, node) { 774 const char *name; 775 const void *prop; 776 int prop_len; 777 int ret; 778 779 prop = fdt_getprop_by_offset(fdto, property, &name, 780 &prop_len); 781 if (prop_len == -FDT_ERR_NOTFOUND) 782 return -FDT_ERR_INTERNAL; 783 if (prop_len < 0) 784 return prop_len; 785 786 ret = fdt_setprop(fdt, target, name, prop, prop_len); 787 if (ret) 788 return ret; 789 } 790 791 fdt_for_each_subnode(subnode, fdto, node) { 792 const char *name = fdt_get_name(fdto, subnode, NULL); 793 int nnode; 794 int ret; 795 796 nnode = fdt_add_subnode(fdt, target, name); 797 if (nnode == -FDT_ERR_EXISTS) { 798 nnode = fdt_subnode_offset(fdt, target, name); 799 if (nnode == -FDT_ERR_NOTFOUND) 800 return -FDT_ERR_INTERNAL; 801 } 802 803 if (nnode < 0) 804 return nnode; 805 806 ret = overlay_apply_node(fdt, nnode, fdto, subnode); 807 if (ret) 808 return ret; 809 } 810 811 return 0; 812 } 813 814 /** 815 * overlay_merge - Merge an overlay into its base device tree 816 * @fdt: Base Device Tree blob 817 * @fdto: Device tree overlay blob 818 * 819 * overlay_merge() merges an overlay into its base device tree. 820 * 821 * This is the next to last step in the device tree overlay application 822 * process, when all the phandles have been adjusted and resolved and 823 * you just have to merge overlay into the base device tree. 824 * 825 * returns: 826 * 0 on success 827 * Negative error code on failure 828 */ 829 static int overlay_merge(void *fdt, void *fdto) 830 { 831 int fragment; 832 833 fdt_for_each_subnode(fragment, fdto, 0) { 834 int overlay; 835 int target; 836 int ret; 837 838 /* 839 * Each fragments will have an __overlay__ node. If 840 * they don't, it's not supposed to be merged 841 */ 842 overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); 843 if (overlay == -FDT_ERR_NOTFOUND) 844 continue; 845 846 if (overlay < 0) 847 return overlay; 848 849 target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL); 850 if (target < 0) 851 return target; 852 853 ret = overlay_apply_node(fdt, target, fdto, overlay); 854 if (ret) 855 return ret; 856 } 857 858 return 0; 859 } 860 861 static int get_path_len(const void *fdt, int nodeoffset) 862 { 863 int len = 0, namelen; 864 const char *name; 865 866 FDT_RO_PROBE(fdt); 867 868 for (;;) { 869 name = fdt_get_name(fdt, nodeoffset, &namelen); 870 if (!name) 871 return namelen; 872 873 /* root? we're done */ 874 if (namelen == 0) 875 break; 876 877 nodeoffset = fdt_parent_offset(fdt, nodeoffset); 878 if (nodeoffset < 0) 879 return nodeoffset; 880 len += namelen + 1; 881 } 882 883 /* in case of root pretend it's "/" */ 884 if (len == 0) 885 len++; 886 return len; 887 } 888 889 /** 890 * overlay_symbol_update - Update the symbols of base tree after a merge 891 * @fdt: Base Device Tree blob 892 * @fdto: Device tree overlay blob 893 * 894 * overlay_symbol_update() updates the symbols of the base tree with the 895 * symbols of the applied overlay 896 * 897 * This is the last step in the device tree overlay application 898 * process, allowing the reference of overlay symbols by subsequent 899 * overlay operations. 900 * 901 * returns: 902 * 0 on success 903 * Negative error code on failure 904 */ 905 static int overlay_symbol_update(void *fdt, void *fdto) 906 { 907 int root_sym, ov_sym, prop, path_len, fragment, target; 908 int len, frag_name_len, ret, rel_path_len; 909 const char *s, *e; 910 const char *path; 911 const char *name; 912 const char *frag_name; 913 const char *rel_path; 914 const char *target_path; 915 char *buf; 916 void *p; 917 918 ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); 919 920 /* if no overlay symbols exist no problem */ 921 if (ov_sym < 0) 922 return 0; 923 924 root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); 925 926 /* it no root symbols exist we should create them */ 927 if (root_sym == -FDT_ERR_NOTFOUND) 928 root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); 929 930 /* any error is fatal now */ 931 if (root_sym < 0) 932 return root_sym; 933 934 /* iterate over each overlay symbol */ 935 fdt_for_each_property_offset(prop, fdto, ov_sym) { 936 path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); 937 if (!path) 938 return path_len; 939 940 /* verify it's a string property (terminated by a single \0) */ 941 if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) 942 return -FDT_ERR_BADVALUE; 943 944 /* keep end marker to avoid strlen() */ 945 e = path + path_len; 946 947 if (*path != '/') 948 return -FDT_ERR_BADVALUE; 949 950 /* get fragment name first */ 951 s = strchr(path + 1, '/'); 952 if (!s) { 953 /* Symbol refers to something that won't end 954 * up in the target tree */ 955 continue; 956 } 957 958 frag_name = path + 1; 959 frag_name_len = s - path - 1; 960 961 /* verify format; safe since "s" lies in \0 terminated prop */ 962 len = sizeof("/__overlay__/") - 1; 963 if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) { 964 /* /<fragment-name>/__overlay__/<relative-subnode-path> */ 965 rel_path = s + len; 966 rel_path_len = e - rel_path - 1; 967 } else if ((e - s) == len 968 && (memcmp(s, "/__overlay__", len - 1) == 0)) { 969 /* /<fragment-name>/__overlay__ */ 970 rel_path = ""; 971 rel_path_len = 0; 972 } else { 973 /* Symbol refers to something that won't end 974 * up in the target tree */ 975 continue; 976 } 977 978 /* find the fragment index in which the symbol lies */ 979 ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, 980 frag_name_len); 981 /* not found? */ 982 if (ret < 0) 983 return -FDT_ERR_BADOVERLAY; 984 fragment = ret; 985 986 /* an __overlay__ subnode must exist */ 987 ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); 988 if (ret < 0) 989 return -FDT_ERR_BADOVERLAY; 990 991 /* get the target of the fragment */ 992 ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); 993 if (ret < 0) 994 return ret; 995 target = ret; 996 997 /* if we have a target path use */ 998 if (!target_path) { 999 ret = get_path_len(fdt, target); 1000 if (ret < 0) 1001 return ret; 1002 len = ret; 1003 } else { 1004 len = strlen(target_path); 1005 } 1006 1007 ret = fdt_setprop_placeholder(fdt, root_sym, name, 1008 len + (len > 1) + rel_path_len + 1, &p); 1009 if (ret < 0) 1010 return ret; 1011 1012 if (!target_path) { 1013 /* again in case setprop_placeholder changed it */ 1014 ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); 1015 if (ret < 0) 1016 return ret; 1017 target = ret; 1018 } 1019 1020 buf = p; 1021 if (len > 1) { /* target is not root */ 1022 if (!target_path) { 1023 ret = fdt_get_path(fdt, target, buf, len + 1); 1024 if (ret < 0) 1025 return ret; 1026 } else 1027 memcpy(buf, target_path, len + 1); 1028 1029 } else 1030 len--; 1031 1032 buf[len] = '/'; 1033 memcpy(buf + len + 1, rel_path, rel_path_len); 1034 buf[len + 1 + rel_path_len] = '\0'; 1035 } 1036 1037 return 0; 1038 } 1039 1040 int fdt_overlay_apply(void *fdt, void *fdto) 1041 { 1042 uint32_t delta; 1043 int ret; 1044 1045 FDT_RO_PROBE(fdt); 1046 FDT_RO_PROBE(fdto); 1047 1048 ret = fdt_find_max_phandle(fdt, &delta); 1049 if (ret) 1050 goto err; 1051 1052 /* Increase all phandles in the fdto by delta */ 1053 ret = overlay_adjust_local_phandles(fdto, delta); 1054 if (ret) 1055 goto err; 1056 1057 /* Adapt the phandle values in fdto to the above increase */ 1058 ret = overlay_update_local_references(fdto, delta); 1059 if (ret) 1060 goto err; 1061 1062 /* Update fdto's phandles using symbols from fdt */ 1063 ret = overlay_fixup_phandles(fdt, fdto); 1064 if (ret) 1065 goto err; 1066 1067 /* Don't overwrite phandles in fdt */ 1068 ret = overlay_prevent_phandle_overwrite(fdt, fdto); 1069 if (ret) 1070 goto err; 1071 1072 ret = overlay_merge(fdt, fdto); 1073 if (ret) 1074 goto err; 1075 1076 ret = overlay_symbol_update(fdt, fdto); 1077 if (ret) 1078 goto err; 1079 1080 /* 1081 * The overlay has been damaged, erase its magic. 1082 */ 1083 fdt_set_magic(fdto, ~0); 1084 1085 return 0; 1086 1087 err: 1088 /* 1089 * The overlay might have been damaged, erase its magic. 1090 */ 1091 fdt_set_magic(fdto, ~0); 1092 1093 /* 1094 * The base device tree might have been damaged, erase its 1095 * magic. 1096 */ 1097 fdt_set_magic(fdt, ~0); 1098 1099 return ret; 1100 } 1101