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 const char *sep; 411 char *endptr; 412 int poffset, ret; 413 414 fixup_end = memchr(value, '\0', len); 415 if (!fixup_end) 416 return -FDT_ERR_BADOVERLAY; 417 fixup_len = fixup_end - fixup_str; 418 419 len -= fixup_len + 1; 420 value += fixup_len + 1; 421 422 path = fixup_str; 423 sep = memchr(fixup_str, ':', fixup_len); 424 if (!sep || *sep != ':') 425 return -FDT_ERR_BADOVERLAY; 426 427 path_len = sep - path; 428 if (path_len == (fixup_len - 1)) 429 return -FDT_ERR_BADOVERLAY; 430 431 fixup_len -= path_len + 1; 432 name = sep + 1; 433 sep = memchr(name, ':', fixup_len); 434 if (!sep || *sep != ':') 435 return -FDT_ERR_BADOVERLAY; 436 437 name_len = sep - name; 438 if (!name_len) 439 return -FDT_ERR_BADOVERLAY; 440 441 poffset = strtoul(sep + 1, &endptr, 10); 442 if ((*endptr != '\0') || (endptr <= (sep + 1))) 443 return -FDT_ERR_BADOVERLAY; 444 445 ret = overlay_fixup_one_phandle(fdto, symbols_off, 446 path, path_len, name, name_len, 447 poffset, phandle); 448 if (ret) 449 return ret; 450 } while (len > 0); 451 452 return 0; 453 } 454 455 /** 456 * overlay_fixup_phandles - Resolve the overlay phandles to the base 457 * device tree 458 * @fdt: Base Device Tree blob 459 * @fdto: Device tree overlay blob 460 * 461 * overlay_fixup_phandles() resolves all the overlay phandles pointing 462 * to nodes in the base device tree. 463 * 464 * This is one of the steps of the device tree overlay application 465 * process, when you want all the phandles in the overlay to point to 466 * the actual base dt nodes. 467 * 468 * returns: 469 * 0 on success 470 * Negative error code on failure 471 */ 472 static int overlay_fixup_phandles(void *fdt, void *fdto) 473 { 474 int fixups_off, symbols_off; 475 int property; 476 477 /* We can have overlays without any fixups */ 478 fixups_off = fdt_path_offset(fdto, "/__fixups__"); 479 if (fixups_off == -FDT_ERR_NOTFOUND) 480 return 0; /* nothing to do */ 481 if (fixups_off < 0) 482 return fixups_off; 483 484 /* And base DTs without symbols */ 485 symbols_off = fdt_path_offset(fdt, "/__symbols__"); 486 if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) 487 return symbols_off; 488 489 fdt_for_each_property_offset(property, fdto, fixups_off) { 490 int ret; 491 492 ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); 493 if (ret) 494 return ret; 495 } 496 497 return 0; 498 } 499 500 /** 501 * overlay_adjust_local_conflicting_phandle: Changes a phandle value 502 * @fdto: Device tree overlay 503 * @node: The node the phandle is set for 504 * @fdt_phandle: The new value for the phandle 505 * 506 * returns: 507 * 0 on success 508 * Negative error code on failure 509 */ 510 static int overlay_adjust_local_conflicting_phandle(void *fdto, int node, 511 uint32_t fdt_phandle) 512 { 513 const fdt32_t *php; 514 int len, ret; 515 516 php = fdt_getprop(fdto, node, "phandle", &len); 517 if (php && len == sizeof(*php)) { 518 ret = fdt_setprop_inplace_u32(fdto, node, "phandle", fdt_phandle); 519 if (ret) 520 return ret; 521 } 522 523 php = fdt_getprop(fdto, node, "linux,phandle", &len); 524 if (php && len == sizeof(*php)) { 525 ret = fdt_setprop_inplace_u32(fdto, node, "linux,phandle", fdt_phandle); 526 if (ret) 527 return ret; 528 } 529 530 return 0; 531 } 532 533 /** 534 * overlay_update_node_conflicting_references - Recursively replace phandle values 535 * @fdto: Device tree overlay blob 536 * @tree_node: Node to recurse into 537 * @fixup_node: Node offset of the matching local fixups node 538 * @fdt_phandle: Value to replace phandles with 539 * @fdto_phandle: Value to be replaced 540 * 541 * Replaces all phandles with value @fdto_phandle by @fdt_phandle. 542 * 543 * returns: 544 * 0 on success 545 * Negative error code on failure 546 */ 547 static int overlay_update_node_conflicting_references(void *fdto, int tree_node, 548 int fixup_node, 549 uint32_t fdt_phandle, 550 uint32_t fdto_phandle) 551 { 552 int fixup_prop; 553 int fixup_child; 554 int ret; 555 556 fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { 557 const fdt32_t *fixup_val; 558 const char *name; 559 char *tree_val; 560 int fixup_len; 561 int tree_len; 562 int i; 563 564 fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, 565 &name, &fixup_len); 566 if (!fixup_val) 567 return fixup_len; 568 569 if (fixup_len % sizeof(uint32_t)) 570 return -FDT_ERR_BADOVERLAY; 571 fixup_len /= sizeof(uint32_t); 572 573 tree_val = fdt_getprop_w(fdto, tree_node, name, &tree_len); 574 if (!tree_val) { 575 if (tree_len == -FDT_ERR_NOTFOUND) 576 return -FDT_ERR_BADOVERLAY; 577 578 return tree_len; 579 } 580 581 for (i = 0; i < fixup_len; i++) { 582 fdt32_t *refp; 583 uint32_t valp; 584 585 refp = (fdt32_t *)(tree_val + fdt32_ld_(fixup_val + i)); 586 valp = fdt32_ld(refp); 587 588 if (valp == fdto_phandle) 589 fdt32_st(refp, fdt_phandle); 590 } 591 } 592 593 fdt_for_each_subnode(fixup_child, fdto, fixup_node) { 594 const char *fixup_child_name = fdt_get_name(fdto, fixup_child, NULL); 595 int tree_child; 596 597 tree_child = fdt_subnode_offset(fdto, tree_node, fixup_child_name); 598 599 if (tree_child == -FDT_ERR_NOTFOUND) 600 return -FDT_ERR_BADOVERLAY; 601 if (tree_child < 0) 602 return tree_child; 603 604 ret = overlay_update_node_conflicting_references(fdto, tree_child, 605 fixup_child, 606 fdt_phandle, 607 fdto_phandle); 608 if (ret) 609 return ret; 610 } 611 612 return 0; 613 } 614 615 /** 616 * overlay_update_local_conflicting_references - Recursively replace phandle values 617 * @fdto: Device tree overlay blob 618 * @fdt_phandle: Value to replace phandles with 619 * @fdto_phandle: Value to be replaced 620 * 621 * Replaces all phandles with value @fdto_phandle by @fdt_phandle. 622 * 623 * returns: 624 * 0 on success 625 * Negative error code on failure 626 */ 627 static int overlay_update_local_conflicting_references(void *fdto, 628 uint32_t fdt_phandle, 629 uint32_t fdto_phandle) 630 { 631 int fixups; 632 633 fixups = fdt_path_offset(fdto, "/__local_fixups__"); 634 if (fixups == -FDT_ERR_NOTFOUND) 635 return 0; 636 if (fixups < 0) 637 return fixups; 638 639 return overlay_update_node_conflicting_references(fdto, 0, fixups, 640 fdt_phandle, 641 fdto_phandle); 642 } 643 644 /** 645 * overlay_prevent_phandle_overwrite_node - Helper function for overlay_prevent_phandle_overwrite 646 * @fdt: Base Device tree blob 647 * @fdtnode: Node in fdt that is checked for an overwrite 648 * @fdto: Device tree overlay blob 649 * @fdtonode: Node in fdto matching @fdtnode 650 * 651 * returns: 652 * 0 on success 653 * Negative error code on failure 654 */ 655 static int overlay_prevent_phandle_overwrite_node(void *fdt, int fdtnode, 656 void *fdto, int fdtonode) 657 { 658 uint32_t fdt_phandle, fdto_phandle; 659 int fdtochild; 660 661 fdt_phandle = fdt_get_phandle(fdt, fdtnode); 662 fdto_phandle = fdt_get_phandle(fdto, fdtonode); 663 664 if (fdt_phandle && fdto_phandle) { 665 int ret; 666 667 ret = overlay_adjust_local_conflicting_phandle(fdto, fdtonode, 668 fdt_phandle); 669 if (ret) 670 return ret; 671 672 ret = overlay_update_local_conflicting_references(fdto, 673 fdt_phandle, 674 fdto_phandle); 675 if (ret) 676 return ret; 677 } 678 679 fdt_for_each_subnode(fdtochild, fdto, fdtonode) { 680 const char *name = fdt_get_name(fdto, fdtochild, NULL); 681 int fdtchild; 682 int ret; 683 684 fdtchild = fdt_subnode_offset(fdt, fdtnode, name); 685 if (fdtchild == -FDT_ERR_NOTFOUND) 686 /* 687 * no further overwrites possible here as this node is 688 * new 689 */ 690 continue; 691 692 ret = overlay_prevent_phandle_overwrite_node(fdt, fdtchild, 693 fdto, fdtochild); 694 if (ret) 695 return ret; 696 } 697 698 return 0; 699 } 700 701 /** 702 * overlay_prevent_phandle_overwrite - Fixes overlay phandles to not overwrite base phandles 703 * @fdt: Base Device Tree blob 704 * @fdto: Device tree overlay blob 705 * 706 * Checks recursively if applying fdto overwrites phandle values in the base 707 * dtb. When such a phandle is found, the fdto is changed to use the fdt's 708 * phandle value to not break references in the base. 709 * 710 * returns: 711 * 0 on success 712 * Negative error code on failure 713 */ 714 static int overlay_prevent_phandle_overwrite(void *fdt, void *fdto) 715 { 716 int fragment; 717 718 fdt_for_each_subnode(fragment, fdto, 0) { 719 int overlay; 720 int target; 721 int ret; 722 723 overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); 724 if (overlay == -FDT_ERR_NOTFOUND) 725 continue; 726 727 if (overlay < 0) 728 return overlay; 729 730 target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL); 731 if (target == -FDT_ERR_NOTFOUND) 732 /* 733 * The subtree doesn't exist in the base, so nothing 734 * will be overwritten. 735 */ 736 continue; 737 else if (target < 0) 738 return target; 739 740 ret = overlay_prevent_phandle_overwrite_node(fdt, target, 741 fdto, overlay); 742 if (ret) 743 return ret; 744 } 745 746 return 0; 747 } 748 749 /** 750 * overlay_apply_node - Merges a node into the base device tree 751 * @fdt: Base Device Tree blob 752 * @target: Node offset in the base device tree to apply the fragment to 753 * @fdto: Device tree overlay blob 754 * @node: Node offset in the overlay holding the changes to merge 755 * 756 * overlay_apply_node() merges a node into a target base device tree 757 * node pointed. 758 * 759 * This is part of the final step in the device tree overlay 760 * application process, when all the phandles have been adjusted and 761 * resolved and you just have to merge overlay into the base device 762 * tree. 763 * 764 * returns: 765 * 0 on success 766 * Negative error code on failure 767 */ 768 static int overlay_apply_node(void *fdt, int target, 769 void *fdto, int node) 770 { 771 int property; 772 int subnode; 773 774 fdt_for_each_property_offset(property, fdto, node) { 775 const char *name; 776 const void *prop; 777 int prop_len; 778 int ret; 779 780 prop = fdt_getprop_by_offset(fdto, property, &name, 781 &prop_len); 782 if (prop_len == -FDT_ERR_NOTFOUND) 783 return -FDT_ERR_INTERNAL; 784 if (prop_len < 0) 785 return prop_len; 786 787 ret = fdt_setprop(fdt, target, name, prop, prop_len); 788 if (ret) 789 return ret; 790 } 791 792 fdt_for_each_subnode(subnode, fdto, node) { 793 const char *name = fdt_get_name(fdto, subnode, NULL); 794 int nnode; 795 int ret; 796 797 nnode = fdt_add_subnode(fdt, target, name); 798 if (nnode == -FDT_ERR_EXISTS) { 799 nnode = fdt_subnode_offset(fdt, target, name); 800 if (nnode == -FDT_ERR_NOTFOUND) 801 return -FDT_ERR_INTERNAL; 802 } 803 804 if (nnode < 0) 805 return nnode; 806 807 ret = overlay_apply_node(fdt, nnode, fdto, subnode); 808 if (ret) 809 return ret; 810 } 811 812 return 0; 813 } 814 815 /** 816 * overlay_merge - Merge an overlay into its base device tree 817 * @fdt: Base Device Tree blob 818 * @fdto: Device tree overlay blob 819 * 820 * overlay_merge() merges an overlay into its base device tree. 821 * 822 * This is the next to last step in the device tree overlay application 823 * process, when all the phandles have been adjusted and resolved and 824 * you just have to merge overlay into the base device tree. 825 * 826 * returns: 827 * 0 on success 828 * Negative error code on failure 829 */ 830 static int overlay_merge(void *fdt, void *fdto) 831 { 832 int fragment; 833 834 fdt_for_each_subnode(fragment, fdto, 0) { 835 int overlay; 836 int target; 837 int ret; 838 839 /* 840 * Each fragments will have an __overlay__ node. If 841 * they don't, it's not supposed to be merged 842 */ 843 overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); 844 if (overlay == -FDT_ERR_NOTFOUND) 845 continue; 846 847 if (overlay < 0) 848 return overlay; 849 850 target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL); 851 if (target < 0) 852 return target; 853 854 ret = overlay_apply_node(fdt, target, fdto, overlay); 855 if (ret) 856 return ret; 857 } 858 859 return 0; 860 } 861 862 static int get_path_len(const void *fdt, int nodeoffset) 863 { 864 int len = 0, namelen; 865 const char *name; 866 867 FDT_RO_PROBE(fdt); 868 869 for (;;) { 870 name = fdt_get_name(fdt, nodeoffset, &namelen); 871 if (!name) 872 return namelen; 873 874 /* root? we're done */ 875 if (namelen == 0) 876 break; 877 878 nodeoffset = fdt_parent_offset(fdt, nodeoffset); 879 if (nodeoffset < 0) 880 return nodeoffset; 881 len += namelen + 1; 882 } 883 884 /* in case of root pretend it's "/" */ 885 if (len == 0) 886 len++; 887 return len; 888 } 889 890 /** 891 * overlay_symbol_update - Update the symbols of base tree after a merge 892 * @fdt: Base Device Tree blob 893 * @fdto: Device tree overlay blob 894 * 895 * overlay_symbol_update() updates the symbols of the base tree with the 896 * symbols of the applied overlay 897 * 898 * This is the last step in the device tree overlay application 899 * process, allowing the reference of overlay symbols by subsequent 900 * overlay operations. 901 * 902 * returns: 903 * 0 on success 904 * Negative error code on failure 905 */ 906 static int overlay_symbol_update(void *fdt, void *fdto) 907 { 908 int root_sym, ov_sym, prop, path_len, fragment, target; 909 int len, frag_name_len, ret, rel_path_len; 910 const char *s, *e; 911 const char *path; 912 const char *name; 913 const char *frag_name; 914 const char *rel_path; 915 const char *target_path; 916 char *buf; 917 void *p; 918 919 ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); 920 921 /* if no overlay symbols exist no problem */ 922 if (ov_sym < 0) 923 return 0; 924 925 root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); 926 927 /* it no root symbols exist we should create them */ 928 if (root_sym == -FDT_ERR_NOTFOUND) 929 root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); 930 931 /* any error is fatal now */ 932 if (root_sym < 0) 933 return root_sym; 934 935 /* iterate over each overlay symbol */ 936 fdt_for_each_property_offset(prop, fdto, ov_sym) { 937 path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); 938 if (!path) 939 return path_len; 940 941 /* verify it's a string property (terminated by a single \0) */ 942 if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) 943 return -FDT_ERR_BADVALUE; 944 945 /* keep end marker to avoid strlen() */ 946 e = path + path_len; 947 948 if (*path != '/') 949 return -FDT_ERR_BADVALUE; 950 951 /* get fragment name first */ 952 s = strchr(path + 1, '/'); 953 if (!s) { 954 /* Symbol refers to something that won't end 955 * up in the target tree */ 956 continue; 957 } 958 959 frag_name = path + 1; 960 frag_name_len = s - path - 1; 961 962 /* verify format; safe since "s" lies in \0 terminated prop */ 963 len = sizeof("/__overlay__/") - 1; 964 if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) { 965 /* /<fragment-name>/__overlay__/<relative-subnode-path> */ 966 rel_path = s + len; 967 rel_path_len = e - rel_path - 1; 968 } else if ((e - s) == len 969 && (memcmp(s, "/__overlay__", len - 1) == 0)) { 970 /* /<fragment-name>/__overlay__ */ 971 rel_path = ""; 972 rel_path_len = 0; 973 } else { 974 /* Symbol refers to something that won't end 975 * up in the target tree */ 976 continue; 977 } 978 979 /* find the fragment index in which the symbol lies */ 980 ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, 981 frag_name_len); 982 /* not found? */ 983 if (ret < 0) 984 return -FDT_ERR_BADOVERLAY; 985 fragment = ret; 986 987 /* an __overlay__ subnode must exist */ 988 ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); 989 if (ret < 0) 990 return -FDT_ERR_BADOVERLAY; 991 992 /* get the target of the fragment */ 993 ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); 994 if (ret < 0) 995 return ret; 996 target = ret; 997 998 /* if we have a target path use */ 999 if (!target_path) { 1000 ret = get_path_len(fdt, target); 1001 if (ret < 0) 1002 return ret; 1003 len = ret; 1004 } else { 1005 len = strlen(target_path); 1006 } 1007 1008 ret = fdt_setprop_placeholder(fdt, root_sym, name, 1009 len + (len > 1) + rel_path_len + 1, &p); 1010 if (ret < 0) 1011 return ret; 1012 1013 if (!target_path) { 1014 /* again in case setprop_placeholder changed it */ 1015 ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); 1016 if (ret < 0) 1017 return ret; 1018 target = ret; 1019 } 1020 1021 buf = p; 1022 if (len > 1) { /* target is not root */ 1023 if (!target_path) { 1024 ret = fdt_get_path(fdt, target, buf, len + 1); 1025 if (ret < 0) 1026 return ret; 1027 } else 1028 memcpy(buf, target_path, len + 1); 1029 1030 } else 1031 len--; 1032 1033 buf[len] = '/'; 1034 memcpy(buf + len + 1, rel_path, rel_path_len); 1035 buf[len + 1 + rel_path_len] = '\0'; 1036 } 1037 1038 return 0; 1039 } 1040 1041 int fdt_overlay_apply(void *fdt, void *fdto) 1042 { 1043 uint32_t delta; 1044 int ret; 1045 1046 FDT_RO_PROBE(fdt); 1047 FDT_RO_PROBE(fdto); 1048 1049 ret = fdt_find_max_phandle(fdt, &delta); 1050 if (ret) 1051 goto err; 1052 1053 /* Increase all phandles in the fdto by delta */ 1054 ret = overlay_adjust_local_phandles(fdto, delta); 1055 if (ret) 1056 goto err; 1057 1058 /* Adapt the phandle values in fdto to the above increase */ 1059 ret = overlay_update_local_references(fdto, delta); 1060 if (ret) 1061 goto err; 1062 1063 /* Update fdto's phandles using symbols from fdt */ 1064 ret = overlay_fixup_phandles(fdt, fdto); 1065 if (ret) 1066 goto err; 1067 1068 /* Don't overwrite phandles in fdt */ 1069 ret = overlay_prevent_phandle_overwrite(fdt, fdto); 1070 if (ret) 1071 goto err; 1072 1073 ret = overlay_merge(fdt, fdto); 1074 if (ret) 1075 goto err; 1076 1077 ret = overlay_symbol_update(fdt, fdto); 1078 if (ret) 1079 goto err; 1080 1081 /* 1082 * The overlay has been damaged, erase its magic. 1083 */ 1084 fdt_set_magic(fdto, ~0); 1085 1086 return 0; 1087 1088 err: 1089 /* 1090 * The overlay might have been damaged, erase its magic. 1091 */ 1092 fdt_set_magic(fdto, ~0); 1093 1094 /* 1095 * The base device tree might have been damaged, erase its 1096 * magic. 1097 */ 1098 fdt_set_magic(fdt, ~0); 1099 1100 return ret; 1101 } 1102