1 /* 2 * libfdt - Flat Device Tree manipulation 3 * Copyright (C) 2016 Free Electrons 4 * Copyright (C) 2016 NextThing Co. 5 * 6 * libfdt is dual licensed: you can use it either under the terms of 7 * the GPL, or the BSD license, at your option. 8 * 9 * a) This library is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation; either version 2 of the 12 * License, or (at your option) any later version. 13 * 14 * This library is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public 20 * License along with this library; if not, write to the Free 21 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 22 * MA 02110-1301 USA 23 * 24 * Alternatively, 25 * 26 * b) Redistribution and use in source and binary forms, with or 27 * without modification, are permitted provided that the following 28 * conditions are met: 29 * 30 * 1. Redistributions of source code must retain the above 31 * copyright notice, this list of conditions and the following 32 * disclaimer. 33 * 2. Redistributions in binary form must reproduce the above 34 * copyright notice, this list of conditions and the following 35 * disclaimer in the documentation and/or other materials 36 * provided with the distribution. 37 * 38 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 39 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 40 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 41 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 42 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 43 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 48 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 49 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 50 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 */ 52 #include "libfdt_env.h" 53 54 #include <fdt.h> 55 #include <libfdt.h> 56 57 #include "libfdt_internal.h" 58 59 /** 60 * overlay_get_target_phandle - retrieves the target phandle of a fragment 61 * @fdto: pointer to the device tree overlay blob 62 * @fragment: node offset of the fragment in the overlay 63 * 64 * overlay_get_target_phandle() retrieves the target phandle of an 65 * overlay fragment when that fragment uses a phandle (target 66 * property) instead of a path (target-path property). 67 * 68 * returns: 69 * the phandle pointed by the target property 70 * 0, if the phandle was not found 71 * -1, if the phandle was malformed 72 */ 73 static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) 74 { 75 const fdt32_t *val; 76 int len; 77 78 val = fdt_getprop(fdto, fragment, "target", &len); 79 if (!val) 80 return 0; 81 82 if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) 83 return (uint32_t)-1; 84 85 return fdt32_to_cpu(*val); 86 } 87 88 /** 89 * overlay_get_target - retrieves the offset of a fragment's target 90 * @fdt: Base device tree blob 91 * @fdto: Device tree overlay blob 92 * @fragment: node offset of the fragment in the overlay 93 * @pathp: pointer which receives the path of the target (or NULL) 94 * 95 * overlay_get_target() retrieves the target offset in the base 96 * device tree of a fragment, no matter how the actual targetting is 97 * done (through a phandle or a path) 98 * 99 * returns: 100 * the targetted node offset in the base device tree 101 * Negative error code on error 102 */ 103 static int overlay_get_target(const void *fdt, const void *fdto, 104 int fragment, char const **pathp) 105 { 106 uint32_t phandle; 107 const char *path = NULL; 108 int path_len = 0, ret; 109 110 /* Try first to do a phandle based lookup */ 111 phandle = overlay_get_target_phandle(fdto, fragment); 112 if (phandle == (uint32_t)-1) 113 return -FDT_ERR_BADPHANDLE; 114 115 /* no phandle, try path */ 116 if (!phandle) { 117 /* And then a path based lookup */ 118 path = fdt_getprop(fdto, fragment, "target-path", &path_len); 119 if (path) 120 ret = fdt_path_offset(fdt, path); 121 else 122 ret = path_len; 123 } else 124 ret = fdt_node_offset_by_phandle(fdt, phandle); 125 126 /* 127 * If we haven't found either a target or a 128 * target-path property in a node that contains a 129 * __overlay__ subnode (we wouldn't be called 130 * otherwise), consider it a improperly written 131 * overlay 132 */ 133 if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) 134 ret = -FDT_ERR_BADOVERLAY; 135 136 /* return on error */ 137 if (ret < 0) 138 return ret; 139 140 /* return pointer to path (if available) */ 141 if (pathp) 142 *pathp = path ? path : NULL; 143 144 return ret; 145 } 146 147 /** 148 * overlay_phandle_add_offset - Increases a phandle by an offset 149 * @fdt: Base device tree blob 150 * @node: Device tree overlay blob 151 * @name: Name of the property to modify (phandle or linux,phandle) 152 * @delta: offset to apply 153 * 154 * overlay_phandle_add_offset() increments a node phandle by a given 155 * offset. 156 * 157 * returns: 158 * 0 on success. 159 * Negative error code on error 160 */ 161 static int overlay_phandle_add_offset(void *fdt, int node, 162 const char *name, uint32_t delta) 163 { 164 const fdt32_t *val; 165 uint32_t adj_val; 166 int len; 167 168 val = fdt_getprop(fdt, node, name, &len); 169 if (!val) 170 return len; 171 172 if (len != sizeof(*val)) 173 return -FDT_ERR_BADPHANDLE; 174 175 adj_val = fdt32_to_cpu(*val); 176 if ((adj_val + delta) < adj_val) 177 return -FDT_ERR_NOPHANDLES; 178 179 adj_val += delta; 180 if (adj_val == (uint32_t)-1) 181 return -FDT_ERR_NOPHANDLES; 182 183 return fdt_setprop_inplace_u32(fdt, node, name, adj_val); 184 } 185 186 /** 187 * overlay_adjust_node_phandles - Offsets the phandles of a node 188 * @fdto: Device tree overlay blob 189 * @node: Offset of the node we want to adjust 190 * @delta: Offset to shift the phandles of 191 * 192 * overlay_adjust_node_phandles() adds a constant to all the phandles 193 * of a given node. This is mainly use as part of the overlay 194 * application process, when we want to update all the overlay 195 * phandles to not conflict with the overlays of the base device tree. 196 * 197 * returns: 198 * 0 on success 199 * Negative error code on failure 200 */ 201 static int overlay_adjust_node_phandles(void *fdto, int node, 202 uint32_t delta) 203 { 204 int child; 205 int ret; 206 207 ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); 208 if (ret && ret != -FDT_ERR_NOTFOUND) 209 return ret; 210 211 ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); 212 if (ret && ret != -FDT_ERR_NOTFOUND) 213 return ret; 214 215 fdt_for_each_subnode(child, fdto, node) { 216 ret = overlay_adjust_node_phandles(fdto, child, delta); 217 if (ret) 218 return ret; 219 } 220 221 return 0; 222 } 223 224 /** 225 * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay 226 * @fdto: Device tree overlay blob 227 * @delta: Offset to shift the phandles of 228 * 229 * overlay_adjust_local_phandles() adds a constant to all the 230 * phandles of an overlay. This is mainly use as part of the overlay 231 * application process, when we want to update all the overlay 232 * phandles to not conflict with the overlays of the base device tree. 233 * 234 * returns: 235 * 0 on success 236 * Negative error code on failure 237 */ 238 static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) 239 { 240 /* 241 * Start adjusting the phandles from the overlay root 242 */ 243 return overlay_adjust_node_phandles(fdto, 0, delta); 244 } 245 246 /** 247 * overlay_update_local_node_references - Adjust the overlay references 248 * @fdto: Device tree overlay blob 249 * @tree_node: Node offset of the node to operate on 250 * @fixup_node: Node offset of the matching local fixups node 251 * @delta: Offset to shift the phandles of 252 * 253 * overlay_update_local_nodes_references() update the phandles 254 * pointing to a node within the device tree overlay by adding a 255 * constant delta. 256 * 257 * This is mainly used as part of a device tree application process, 258 * where you want the device tree overlays phandles to not conflict 259 * with the ones from the base device tree before merging them. 260 * 261 * returns: 262 * 0 on success 263 * Negative error code on failure 264 */ 265 static int overlay_update_local_node_references(void *fdto, 266 int tree_node, 267 int fixup_node, 268 uint32_t delta) 269 { 270 int fixup_prop; 271 int fixup_child; 272 int ret; 273 274 fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { 275 const fdt32_t *fixup_val; 276 const char *tree_val; 277 const char *name; 278 int fixup_len; 279 int tree_len; 280 int i; 281 282 fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, 283 &name, &fixup_len); 284 if (!fixup_val) 285 return fixup_len; 286 287 if (fixup_len % sizeof(uint32_t)) 288 return -FDT_ERR_BADOVERLAY; 289 290 tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); 291 if (!tree_val) { 292 if (tree_len == -FDT_ERR_NOTFOUND) 293 return -FDT_ERR_BADOVERLAY; 294 295 return tree_len; 296 } 297 298 for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { 299 fdt32_t adj_val; 300 uint32_t poffset; 301 302 poffset = fdt32_to_cpu(fixup_val[i]); 303 304 /* 305 * phandles to fixup can be unaligned. 306 * 307 * Use a memcpy for the architectures that do 308 * not support unaligned accesses. 309 */ 310 memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); 311 312 adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); 313 314 ret = fdt_setprop_inplace_namelen_partial(fdto, 315 tree_node, 316 name, 317 strlen(name), 318 poffset, 319 &adj_val, 320 sizeof(adj_val)); 321 if (ret == -FDT_ERR_NOSPACE) 322 return -FDT_ERR_BADOVERLAY; 323 324 if (ret) 325 return ret; 326 } 327 } 328 329 fdt_for_each_subnode(fixup_child, fdto, fixup_node) { 330 const char *fixup_child_name = fdt_get_name(fdto, fixup_child, 331 NULL); 332 int tree_child; 333 334 tree_child = fdt_subnode_offset(fdto, tree_node, 335 fixup_child_name); 336 if (tree_child == -FDT_ERR_NOTFOUND) 337 return -FDT_ERR_BADOVERLAY; 338 if (tree_child < 0) 339 return tree_child; 340 341 ret = overlay_update_local_node_references(fdto, 342 tree_child, 343 fixup_child, 344 delta); 345 if (ret) 346 return ret; 347 } 348 349 return 0; 350 } 351 352 /** 353 * overlay_update_local_references - Adjust the overlay references 354 * @fdto: Device tree overlay blob 355 * @delta: Offset to shift the phandles of 356 * 357 * overlay_update_local_references() update all the phandles pointing 358 * to a node within the device tree overlay by adding a constant 359 * delta to not conflict with the base overlay. 360 * 361 * This is mainly used as part of a device tree application process, 362 * where you want the device tree overlays phandles to not conflict 363 * with the ones from the base device tree before merging them. 364 * 365 * returns: 366 * 0 on success 367 * Negative error code on failure 368 */ 369 static int overlay_update_local_references(void *fdto, uint32_t delta) 370 { 371 int fixups; 372 373 fixups = fdt_path_offset(fdto, "/__local_fixups__"); 374 if (fixups < 0) { 375 /* There's no local phandles to adjust, bail out */ 376 if (fixups == -FDT_ERR_NOTFOUND) 377 return 0; 378 379 return fixups; 380 } 381 382 /* 383 * Update our local references from the root of the tree 384 */ 385 return overlay_update_local_node_references(fdto, 0, fixups, 386 delta); 387 } 388 389 /** 390 * overlay_fixup_one_phandle - Set an overlay phandle to the base one 391 * @fdt: Base Device Tree blob 392 * @fdto: Device tree overlay blob 393 * @symbols_off: Node offset of the symbols node in the base device tree 394 * @path: Path to a node holding a phandle in the overlay 395 * @path_len: number of path characters to consider 396 * @name: Name of the property holding the phandle reference in the overlay 397 * @name_len: number of name characters to consider 398 * @poffset: Offset within the overlay property where the phandle is stored 399 * @label: Label of the node referenced by the phandle 400 * 401 * overlay_fixup_one_phandle() resolves an overlay phandle pointing to 402 * a node in the base device tree. 403 * 404 * This is part of the device tree overlay application process, when 405 * you want all the phandles in the overlay to point to the actual 406 * base dt nodes. 407 * 408 * returns: 409 * 0 on success 410 * Negative error code on failure 411 */ 412 static int overlay_fixup_one_phandle(void *fdt, void *fdto, 413 int symbols_off, 414 const char *path, uint32_t path_len, 415 const char *name, uint32_t name_len, 416 int poffset, const char *label) 417 { 418 const char *symbol_path; 419 uint32_t phandle; 420 fdt32_t phandle_prop; 421 int symbol_off, fixup_off; 422 int prop_len; 423 424 if (symbols_off < 0) 425 return symbols_off; 426 427 symbol_path = fdt_getprop(fdt, symbols_off, label, 428 &prop_len); 429 if (!symbol_path) 430 return prop_len; 431 432 symbol_off = fdt_path_offset(fdt, symbol_path); 433 if (symbol_off < 0) 434 return symbol_off; 435 436 phandle = fdt_get_phandle(fdt, symbol_off); 437 if (!phandle) 438 return -FDT_ERR_NOTFOUND; 439 440 fixup_off = fdt_path_offset_namelen(fdto, path, path_len); 441 if (fixup_off == -FDT_ERR_NOTFOUND) 442 return -FDT_ERR_BADOVERLAY; 443 if (fixup_off < 0) 444 return fixup_off; 445 446 phandle_prop = cpu_to_fdt32(phandle); 447 return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, 448 name, name_len, poffset, 449 &phandle_prop, 450 sizeof(phandle_prop)); 451 }; 452 453 /** 454 * overlay_fixup_phandle - Set an overlay phandle to the base one 455 * @fdt: Base Device Tree blob 456 * @fdto: Device tree overlay blob 457 * @symbols_off: Node offset of the symbols node in the base device tree 458 * @property: Property offset in the overlay holding the list of fixups 459 * 460 * overlay_fixup_phandle() resolves all the overlay phandles pointed 461 * to in a __fixups__ property, and updates them to match the phandles 462 * in use in the base device tree. 463 * 464 * This is part of the device tree overlay application process, when 465 * you want all the phandles in the overlay to point to the actual 466 * base dt nodes. 467 * 468 * returns: 469 * 0 on success 470 * Negative error code on failure 471 */ 472 static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, 473 int property) 474 { 475 const char *value; 476 const char *label; 477 int len; 478 479 value = fdt_getprop_by_offset(fdto, property, 480 &label, &len); 481 if (!value) { 482 if (len == -FDT_ERR_NOTFOUND) 483 return -FDT_ERR_INTERNAL; 484 485 return len; 486 } 487 488 do { 489 const char *path, *name, *fixup_end; 490 const char *fixup_str = value; 491 uint32_t path_len, name_len; 492 uint32_t fixup_len; 493 char *sep, *endptr; 494 int poffset, ret; 495 496 fixup_end = memchr(value, '\0', len); 497 if (!fixup_end) 498 return -FDT_ERR_BADOVERLAY; 499 fixup_len = fixup_end - fixup_str; 500 501 len -= fixup_len + 1; 502 value += fixup_len + 1; 503 504 path = fixup_str; 505 sep = memchr(fixup_str, ':', fixup_len); 506 if (!sep || *sep != ':') 507 return -FDT_ERR_BADOVERLAY; 508 509 path_len = sep - path; 510 if (path_len == (fixup_len - 1)) 511 return -FDT_ERR_BADOVERLAY; 512 513 fixup_len -= path_len + 1; 514 name = sep + 1; 515 sep = memchr(name, ':', fixup_len); 516 if (!sep || *sep != ':') 517 return -FDT_ERR_BADOVERLAY; 518 519 name_len = sep - name; 520 if (!name_len) 521 return -FDT_ERR_BADOVERLAY; 522 523 poffset = strtoul(sep + 1, &endptr, 10); 524 if ((*endptr != '\0') || (endptr <= (sep + 1))) 525 return -FDT_ERR_BADOVERLAY; 526 527 ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, 528 path, path_len, name, name_len, 529 poffset, label); 530 if (ret) 531 return ret; 532 } while (len > 0); 533 534 return 0; 535 } 536 537 /** 538 * overlay_fixup_phandles - Resolve the overlay phandles to the base 539 * device tree 540 * @fdt: Base Device Tree blob 541 * @fdto: Device tree overlay blob 542 * 543 * overlay_fixup_phandles() resolves all the overlay phandles pointing 544 * to nodes in the base device tree. 545 * 546 * This is one of the steps of the device tree overlay application 547 * process, when you want all the phandles in the overlay to point to 548 * the actual base dt nodes. 549 * 550 * returns: 551 * 0 on success 552 * Negative error code on failure 553 */ 554 static int overlay_fixup_phandles(void *fdt, void *fdto) 555 { 556 int fixups_off, symbols_off; 557 int property; 558 559 /* We can have overlays without any fixups */ 560 fixups_off = fdt_path_offset(fdto, "/__fixups__"); 561 if (fixups_off == -FDT_ERR_NOTFOUND) 562 return 0; /* nothing to do */ 563 if (fixups_off < 0) 564 return fixups_off; 565 566 /* And base DTs without symbols */ 567 symbols_off = fdt_path_offset(fdt, "/__symbols__"); 568 if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) 569 return symbols_off; 570 571 fdt_for_each_property_offset(property, fdto, fixups_off) { 572 int ret; 573 574 ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); 575 if (ret) 576 return ret; 577 } 578 579 return 0; 580 } 581 582 /** 583 * overlay_apply_node - Merges a node into the base device tree 584 * @fdt: Base Device Tree blob 585 * @target: Node offset in the base device tree to apply the fragment to 586 * @fdto: Device tree overlay blob 587 * @node: Node offset in the overlay holding the changes to merge 588 * 589 * overlay_apply_node() merges a node into a target base device tree 590 * node pointed. 591 * 592 * This is part of the final step in the device tree overlay 593 * application process, when all the phandles have been adjusted and 594 * resolved and you just have to merge overlay into the base device 595 * tree. 596 * 597 * returns: 598 * 0 on success 599 * Negative error code on failure 600 */ 601 static int overlay_apply_node(void *fdt, int target, 602 void *fdto, int node) 603 { 604 int property; 605 int subnode; 606 607 fdt_for_each_property_offset(property, fdto, node) { 608 const char *name; 609 const void *prop; 610 int prop_len; 611 int ret; 612 613 prop = fdt_getprop_by_offset(fdto, property, &name, 614 &prop_len); 615 if (prop_len == -FDT_ERR_NOTFOUND) 616 return -FDT_ERR_INTERNAL; 617 if (prop_len < 0) 618 return prop_len; 619 620 ret = fdt_setprop(fdt, target, name, prop, prop_len); 621 if (ret) 622 return ret; 623 } 624 625 fdt_for_each_subnode(subnode, fdto, node) { 626 const char *name = fdt_get_name(fdto, subnode, NULL); 627 int nnode; 628 int ret; 629 630 nnode = fdt_add_subnode(fdt, target, name); 631 if (nnode == -FDT_ERR_EXISTS) { 632 nnode = fdt_subnode_offset(fdt, target, name); 633 if (nnode == -FDT_ERR_NOTFOUND) 634 return -FDT_ERR_INTERNAL; 635 } 636 637 if (nnode < 0) 638 return nnode; 639 640 ret = overlay_apply_node(fdt, nnode, fdto, subnode); 641 if (ret) 642 return ret; 643 } 644 645 return 0; 646 } 647 648 /** 649 * overlay_merge - Merge an overlay into its base device tree 650 * @fdt: Base Device Tree blob 651 * @fdto: Device tree overlay blob 652 * 653 * overlay_merge() merges an overlay into its base device tree. 654 * 655 * This is the next to last step in the device tree overlay application 656 * process, when all the phandles have been adjusted and resolved and 657 * you just have to merge overlay into the base device tree. 658 * 659 * returns: 660 * 0 on success 661 * Negative error code on failure 662 */ 663 static int overlay_merge(void *fdt, void *fdto) 664 { 665 int fragment; 666 667 fdt_for_each_subnode(fragment, fdto, 0) { 668 int overlay; 669 int target; 670 int ret; 671 672 /* 673 * Each fragments will have an __overlay__ node. If 674 * they don't, it's not supposed to be merged 675 */ 676 overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); 677 if (overlay == -FDT_ERR_NOTFOUND) 678 continue; 679 680 if (overlay < 0) 681 return overlay; 682 683 target = overlay_get_target(fdt, fdto, fragment, NULL); 684 if (target < 0) 685 return target; 686 687 ret = overlay_apply_node(fdt, target, fdto, overlay); 688 if (ret) 689 return ret; 690 } 691 692 return 0; 693 } 694 695 static int get_path_len(const void *fdt, int nodeoffset) 696 { 697 int len = 0, namelen; 698 const char *name; 699 700 FDT_CHECK_HEADER(fdt); 701 702 for (;;) { 703 name = fdt_get_name(fdt, nodeoffset, &namelen); 704 if (!name) 705 return namelen; 706 707 /* root? we're done */ 708 if (namelen == 0) 709 break; 710 711 nodeoffset = fdt_parent_offset(fdt, nodeoffset); 712 if (nodeoffset < 0) 713 return nodeoffset; 714 len += namelen + 1; 715 } 716 717 /* in case of root pretend it's "/" */ 718 if (len == 0) 719 len++; 720 return len; 721 } 722 723 /** 724 * overlay_symbol_update - Update the symbols of base tree after a merge 725 * @fdt: Base Device Tree blob 726 * @fdto: Device tree overlay blob 727 * 728 * overlay_symbol_update() updates the symbols of the base tree with the 729 * symbols of the applied overlay 730 * 731 * This is the last step in the device tree overlay application 732 * process, allowing the reference of overlay symbols by subsequent 733 * overlay operations. 734 * 735 * returns: 736 * 0 on success 737 * Negative error code on failure 738 */ 739 static int overlay_symbol_update(void *fdt, void *fdto) 740 { 741 int root_sym, ov_sym, prop, path_len, fragment, target; 742 int len, frag_name_len, ret, rel_path_len; 743 const char *s, *e; 744 const char *path; 745 const char *name; 746 const char *frag_name; 747 const char *rel_path; 748 const char *target_path; 749 char *buf; 750 void *p; 751 752 ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); 753 754 /* if no overlay symbols exist no problem */ 755 if (ov_sym < 0) 756 return 0; 757 758 root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); 759 760 /* it no root symbols exist we should create them */ 761 if (root_sym == -FDT_ERR_NOTFOUND) 762 root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); 763 764 /* any error is fatal now */ 765 if (root_sym < 0) 766 return root_sym; 767 768 /* iterate over each overlay symbol */ 769 fdt_for_each_property_offset(prop, fdto, ov_sym) { 770 path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); 771 if (!path) 772 return path_len; 773 774 /* verify it's a string property (terminated by a single \0) */ 775 if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) 776 return -FDT_ERR_BADVALUE; 777 778 /* keep end marker to avoid strlen() */ 779 e = path + path_len; 780 781 /* format: /<fragment-name>/__overlay__/<relative-subnode-path> */ 782 783 if (*path != '/') 784 return -FDT_ERR_BADVALUE; 785 786 /* get fragment name first */ 787 s = strchr(path + 1, '/'); 788 if (!s) 789 return -FDT_ERR_BADOVERLAY; 790 791 frag_name = path + 1; 792 frag_name_len = s - path - 1; 793 794 /* verify format; safe since "s" lies in \0 terminated prop */ 795 len = sizeof("/__overlay__/") - 1; 796 if ((e - s) < len || memcmp(s, "/__overlay__/", len)) 797 return -FDT_ERR_BADOVERLAY; 798 799 rel_path = s + len; 800 rel_path_len = e - rel_path; 801 802 /* find the fragment index in which the symbol lies */ 803 ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, 804 frag_name_len); 805 /* not found? */ 806 if (ret < 0) 807 return -FDT_ERR_BADOVERLAY; 808 fragment = ret; 809 810 /* an __overlay__ subnode must exist */ 811 ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); 812 if (ret < 0) 813 return -FDT_ERR_BADOVERLAY; 814 815 /* get the target of the fragment */ 816 ret = overlay_get_target(fdt, fdto, fragment, &target_path); 817 if (ret < 0) 818 return ret; 819 target = ret; 820 821 /* if we have a target path use */ 822 if (!target_path) { 823 ret = get_path_len(fdt, target); 824 if (ret < 0) 825 return ret; 826 len = ret; 827 } else { 828 len = strlen(target_path); 829 } 830 831 ret = fdt_setprop_placeholder(fdt, root_sym, name, 832 len + (len > 1) + rel_path_len + 1, &p); 833 if (ret < 0) 834 return ret; 835 836 if (!target_path) { 837 /* again in case setprop_placeholder changed it */ 838 ret = overlay_get_target(fdt, fdto, fragment, &target_path); 839 if (ret < 0) 840 return ret; 841 target = ret; 842 } 843 844 buf = p; 845 if (len > 1) { /* target is not root */ 846 if (!target_path) { 847 ret = fdt_get_path(fdt, target, buf, len + 1); 848 if (ret < 0) 849 return ret; 850 } else 851 memcpy(buf, target_path, len + 1); 852 853 } else 854 len--; 855 856 buf[len] = '/'; 857 memcpy(buf + len + 1, rel_path, rel_path_len); 858 buf[len + 1 + rel_path_len] = '\0'; 859 } 860 861 return 0; 862 } 863 864 int fdt_overlay_apply(void *fdt, void *fdto) 865 { 866 uint32_t delta = fdt_get_max_phandle(fdt); 867 int ret; 868 869 FDT_CHECK_HEADER(fdt); 870 FDT_CHECK_HEADER(fdto); 871 872 ret = overlay_adjust_local_phandles(fdto, delta); 873 if (ret) 874 goto err; 875 876 ret = overlay_update_local_references(fdto, delta); 877 if (ret) 878 goto err; 879 880 ret = overlay_fixup_phandles(fdt, fdto); 881 if (ret) 882 goto err; 883 884 ret = overlay_merge(fdt, fdto); 885 if (ret) 886 goto err; 887 888 ret = overlay_symbol_update(fdt, fdto); 889 if (ret) 890 goto err; 891 892 /* 893 * The overlay has been damaged, erase its magic. 894 */ 895 fdt_set_magic(fdto, ~0); 896 897 return 0; 898 899 err: 900 /* 901 * The overlay might have been damaged, erase its magic. 902 */ 903 fdt_set_magic(fdto, ~0); 904 905 /* 906 * The base device tree might have been damaged, erase its 907 * magic. 908 */ 909 fdt_set_magic(fdt, ~0); 910 911 return ret; 912 } 913