The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/libfdt/fdt_overlay.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 }

Cache object: 9b0404b3615588ee32293b7d2312c269


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.