root/scripts/dtc/libfdt/fdt_overlay.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. overlay_get_target_phandle
  2. overlay_get_target
  3. overlay_phandle_add_offset
  4. overlay_adjust_node_phandles
  5. overlay_adjust_local_phandles
  6. overlay_update_local_node_references
  7. overlay_update_local_references
  8. overlay_fixup_one_phandle
  9. overlay_fixup_phandle
  10. overlay_fixup_phandles
  11. overlay_apply_node
  12. overlay_merge
  13. get_path_len
  14. overlay_symbol_update
  15. fdt_overlay_apply

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

/* [<][>][^][v][top][bottom][index][help] */