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