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/boot/fdt/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  * Copyright (c) 2015 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/11.0/sys/boot/fdt/fdt_overlay.c 298821 2016-04-29 22:42:59Z gonzo $");
   29 
   30 #include <stand.h>
   31 #include <libfdt.h>
   32 
   33 #include "fdt_overlay.h"
   34 
   35 /*
   36  * Get max phandle
   37  */
   38 static uint32_t
   39 fdt_max_phandle(void *fdtp)
   40 {
   41         int o, depth;
   42         uint32_t max_phandle, phandle;
   43 
   44         depth = 1;
   45         o = fdt_path_offset(fdtp, "/");
   46         max_phandle = fdt_get_phandle(fdtp, o);
   47         for (depth = 0; (o >= 0) && (depth >= 0); o = fdt_next_node(fdtp, o, &depth)) {
   48                 phandle = fdt_get_phandle(fdtp, o);
   49                 if (max_phandle < phandle)
   50                         max_phandle = phandle;
   51         }
   52 
   53         return max_phandle;
   54 }
   55 
   56 /*
   57  * Returns exact memory location specified by fixup in format
   58  * /path/to/node:property:offset
   59  */
   60 static void *
   61 fdt_get_fixup_location(void *fdtp, const char *fixup)
   62 {
   63         char *path, *prop, *offsetp, *endp;
   64         int prop_offset, o, proplen;
   65         void  *result;
   66 
   67         result = 0;
   68 
   69         path = strdup(fixup);
   70         prop = strchr(path, ':');
   71         if (prop == NULL) {
   72                 printf("missing property part in \"%s\"\n", fixup);
   73                 result = NULL;
   74                 goto out;
   75         }
   76 
   77         *prop = 0;
   78         prop++;
   79 
   80         offsetp = strchr(prop, ':');
   81         if (offsetp == NULL) {
   82                 printf("missing offset part in \"%s\"\n", fixup);
   83                 result = NULL;
   84                 goto out;
   85         }
   86 
   87         *offsetp = 0;
   88         offsetp++;
   89 
   90         prop_offset = strtoul(offsetp, &endp, 10);
   91         if (*endp != '\0') {
   92                 printf("\"%s\" is not valid number\n", offsetp);
   93                 result = NULL;
   94                 goto out;
   95         }
   96 
   97         o = fdt_path_offset(fdtp, path);
   98         if (o < 0) {
   99                 printf("path \"%s\" not found\n", path);
  100                 result = NULL;
  101                 goto out;
  102         }
  103 
  104         result = fdt_getprop_w(fdtp, o, prop, &proplen);
  105         if (result == NULL){
  106                 printf("property \"%s\" not found in  \"%s\" node\n", prop, path);
  107                 result = NULL;
  108                 goto out;
  109         }
  110 
  111         if (proplen < prop_offset + sizeof(uint32_t)) {
  112                 printf("%s: property length is too small for fixup\n", fixup);
  113                 result = NULL;
  114                 goto out;
  115         }
  116 
  117         result = (char*)result + prop_offset;
  118 
  119 out:
  120         free(path);
  121         return (result);
  122 }
  123 
  124 /*
  125  * Process one entry in __fixups__ { } node
  126  * @fixups is property value, array of NUL-terminated strings
  127  *   with fixup locations
  128  * @fixups_len length of the fixups array in bytes
  129  * @phandle is value for these locations
  130  */
  131 static int
  132 fdt_do_one_fixup(void *fdtp, const char *fixups, int fixups_len, int phandle)
  133 {
  134         void *fixup_pos;
  135         uint32_t val;
  136 
  137         val = cpu_to_fdt32(phandle);
  138 
  139         while (fixups_len > 0) {
  140                 fixup_pos = fdt_get_fixup_location(fdtp, fixups);
  141                 if (fixup_pos != NULL)
  142                         memcpy(fixup_pos, &val, sizeof(val));
  143 
  144                 fixups_len -= strlen(fixups) + 1;
  145                 fixups += strlen(fixups) + 1;
  146         }
  147 
  148         return (0);
  149 }
  150 
  151 /*
  152  * Increase u32 value at pos by offset
  153  */
  154 static void
  155 fdt_increase_u32(void *pos, uint32_t offset)
  156 {
  157         uint32_t val;
  158 
  159         memcpy(&val, pos,  sizeof(val));
  160         val = cpu_to_fdt32(fdt32_to_cpu(val) + offset);
  161         memcpy(pos, &val, sizeof(val));
  162 }
  163 
  164 /*
  165  * Process local fixups
  166  * @fixups is property value, array of NUL-terminated strings
  167  *   with fixup locations
  168  * @fixups_len length of the fixups array in bytes
  169  * @offset value these locations should be increased by
  170  */
  171 static int
  172 fdt_do_local_fixup(void *fdtp, const char *fixups, int fixups_len, int offset)
  173 {
  174         void *fixup_pos;
  175 
  176         while (fixups_len > 0) {
  177                 fixup_pos = fdt_get_fixup_location(fdtp, fixups);
  178                 if (fixup_pos != NULL)
  179                         fdt_increase_u32(fixup_pos, offset);
  180 
  181                 fixups_len -= strlen(fixups) + 1;
  182                 fixups += strlen(fixups) + 1;
  183         }
  184 
  185         return (0);
  186 }
  187 
  188 /*
  189  * Increase node phandle by phandle_offset
  190  */
  191 static void
  192 fdt_increase_phandle(void *fdtp, int node_offset, uint32_t phandle_offset)
  193 {
  194         int proplen;
  195         void *phandle_pos, *node_pos;
  196 
  197         node_pos = (char*)fdtp + node_offset;
  198 
  199         phandle_pos = fdt_getprop_w(fdtp, node_offset, "phandle", &proplen);
  200         if (phandle_pos)
  201                 fdt_increase_u32(phandle_pos, phandle_offset);
  202         phandle_pos = fdt_getprop_w(fdtp, node_offset, "linux,phandle", &proplen);
  203         if (phandle_pos)
  204                 fdt_increase_u32(phandle_pos, phandle_offset);
  205 }
  206 
  207 /*
  208  * Increase all phandles by offset
  209  */
  210 static void
  211 fdt_increase_phandles(void *fdtp, uint32_t offset)
  212 {
  213         int o, depth;
  214 
  215         o = fdt_path_offset(fdtp, "/");
  216         for (depth = 0; (o >= 0) && (depth >= 0); o = fdt_next_node(fdtp, o, &depth)) {
  217                 fdt_increase_phandle(fdtp, o, offset);
  218         }
  219 }
  220 
  221 /*
  222  * Overlay one node defined by <overlay_fdtp, overlay_o> over <main_fdtp, target_o>
  223  */
  224 static void
  225 fdt_overlay_node(void *main_fdtp, int target_o, void *overlay_fdtp, int overlay_o)
  226 {
  227         int len, o, depth;
  228         const char *name;
  229         const void *val;
  230         int target_subnode_o;
  231 
  232         /* Overlay properties */
  233         for (o = fdt_first_property_offset(overlay_fdtp, overlay_o);
  234             o >= 0; o = fdt_next_property_offset(overlay_fdtp, o)) {
  235                 val = fdt_getprop_by_offset(overlay_fdtp, o, &name, &len);
  236                 if (val)
  237                         fdt_setprop(main_fdtp, target_o, name, val, len);
  238         }
  239 
  240         /* Now overlay nodes */
  241         o = overlay_o;
  242         for (depth = 0; (o >= 0) && (depth >= 0);
  243             o = fdt_next_node(overlay_fdtp, o, &depth)) {
  244                 if (depth != 1)
  245                         continue;
  246                 /* Check if there is node with the same name */
  247                 name = fdt_get_name(overlay_fdtp, o, NULL);
  248                 target_subnode_o = fdt_subnode_offset(main_fdtp, target_o, name);
  249                 if (target_subnode_o < 0) {
  250                         /* create new subnode and run merge recursively */
  251                         target_subnode_o = fdt_add_subnode(main_fdtp, target_o, name);
  252                         if (target_subnode_o < 0) {
  253                                 printf("failed to create subnode \"%s\": %d\n",
  254                                     name, target_subnode_o);
  255                                 return;
  256                         }
  257                 }
  258 
  259                 fdt_overlay_node(main_fdtp, target_subnode_o,
  260                     overlay_fdtp, o);
  261         }
  262 }
  263 
  264 /*
  265  * Apply one overlay fragment
  266  */
  267 static void
  268 fdt_apply_fragment(void *main_fdtp, void *overlay_fdtp, int fragment_o)
  269 {
  270         uint32_t target;
  271         const char *target_path;
  272         const void *val;
  273         int target_node_o, overlay_node_o;
  274 
  275         target_node_o = -1;
  276         val = fdt_getprop(overlay_fdtp, fragment_o, "target", NULL);
  277         if (val) {
  278                 memcpy(&target, val, sizeof(target));
  279                 target = fdt32_to_cpu(target);
  280                 target_node_o = fdt_node_offset_by_phandle(main_fdtp, target);
  281                 if (target_node_o < 0) {
  282                         printf("failed to find target %04x\n", target);
  283                         return;
  284                 }
  285         }
  286 
  287         if (target_node_o < 0) {
  288                 target_path = fdt_getprop(overlay_fdtp, fragment_o, "target-path", NULL);
  289                 if (target_path == NULL)
  290                         return;
  291 
  292                 target_node_o = fdt_path_offset(main_fdtp, target_path);
  293                 if (target_node_o < 0) {
  294                         printf("failed to find target-path %s\n", target_path);
  295                         return;
  296                 }
  297         }
  298 
  299         if (target_node_o < 0)
  300                 return;
  301 
  302         overlay_node_o = fdt_subnode_offset(overlay_fdtp, fragment_o, "__overlay__");
  303         if (overlay_node_o < 0) {
  304                 printf("missing __overlay__ sub-node\n");
  305                 return;
  306         }
  307 
  308         fdt_overlay_node(main_fdtp, target_node_o, overlay_fdtp, overlay_node_o);
  309 }
  310 
  311 /*
  312  * Handle __fixups__ node in overlay DTB
  313  */
  314 static int
  315 fdt_overlay_do_fixups(void *main_fdtp, void *overlay_fdtp)
  316 {
  317         int main_symbols_o, symbol_o, overlay_fixups_o;
  318         int fixup_prop_o;
  319         int len;
  320         const char *fixups, *name;
  321         const char *symbol_path;
  322         uint32_t phandle;
  323 
  324         main_symbols_o = fdt_path_offset(main_fdtp, "/__symbols__");
  325         overlay_fixups_o = fdt_path_offset(overlay_fdtp, "/__fixups__");
  326 
  327         if (main_symbols_o < 0)
  328                 return (-1);
  329         if (overlay_fixups_o < 0)
  330                 return (-1);
  331 
  332         for (fixup_prop_o = fdt_first_property_offset(overlay_fdtp, overlay_fixups_o);
  333             fixup_prop_o >= 0;
  334             fixup_prop_o = fdt_next_property_offset(overlay_fdtp, fixup_prop_o)) {
  335                 fixups = fdt_getprop_by_offset(overlay_fdtp, fixup_prop_o, &name, &len);
  336                 symbol_path = fdt_getprop(main_fdtp, main_symbols_o, name, NULL);
  337                 if (symbol_path == NULL) {
  338                         printf("couldn't find \"%s\" symbol in main dtb\n", name);
  339                         return (-1);
  340                 }
  341                 symbol_o = fdt_path_offset(main_fdtp, symbol_path);
  342                 if (symbol_o < 0) {
  343                         printf("couldn't find \"%s\" path in main dtb\n", symbol_path);
  344                         return (-1);
  345                 }
  346                 phandle = fdt_get_phandle(main_fdtp, symbol_o);
  347                 if (fdt_do_one_fixup(overlay_fdtp, fixups, len, phandle) < 0)
  348                         return (-1);
  349         }
  350 
  351         return (0);
  352 }
  353 
  354 /*
  355  * Handle __local_fixups__ node in overlay DTB
  356  */
  357 static int
  358 fdt_overlay_do_local_fixups(void *main_fdtp, void *overlay_fdtp)
  359 {
  360         int overlay_local_fixups_o;
  361         int len;
  362         const char *fixups;
  363         uint32_t phandle_offset;
  364 
  365         overlay_local_fixups_o = fdt_path_offset(overlay_fdtp, "/__local_fixups__");
  366 
  367         if (overlay_local_fixups_o < 0)
  368                 return (-1);
  369 
  370         phandle_offset = fdt_max_phandle(main_fdtp);
  371         fdt_increase_phandles(overlay_fdtp, phandle_offset);
  372         fixups = fdt_getprop_w(overlay_fdtp, overlay_local_fixups_o, "fixup", &len);
  373         if (fixups) {
  374                 if (fdt_do_local_fixup(overlay_fdtp, fixups, len, phandle_offset) < 0)
  375                         return (-1);
  376         }
  377 
  378         return (0);
  379 }
  380 
  381 /*
  382  * Apply all fragments to main DTB
  383  */
  384 static int
  385 fdt_overlay_apply_fragments(void *main_fdtp, void *overlay_fdtp)
  386 {
  387         int o, depth;
  388 
  389         o = fdt_path_offset(overlay_fdtp, "/");
  390         for (depth = 0; (o >= 0) && (depth >= 0); o = fdt_next_node(overlay_fdtp, o, &depth)) {
  391                 if (depth != 1)
  392                         continue;
  393 
  394                 fdt_apply_fragment(main_fdtp, overlay_fdtp, o);
  395         }
  396 
  397         return (0);
  398 }
  399 
  400 int
  401 fdt_overlay_apply(void *main_fdtp, void *overlay_fdtp, size_t overlay_length)
  402 {
  403         void *overlay_copy;
  404         int rv;
  405 
  406         rv = 0;
  407 
  408         /* We modify overlay in-place, so we need writable copy */
  409         overlay_copy = malloc(overlay_length);
  410         if (overlay_copy == NULL) {
  411                 printf("failed to allocate memory for overlay copy\n");
  412                 return (-1);
  413         }
  414 
  415         memcpy(overlay_copy, overlay_fdtp, overlay_length);
  416 
  417         if (fdt_overlay_do_fixups(main_fdtp, overlay_copy) < 0) {
  418                 printf("failed to perform fixups in overlay\n");
  419                 rv = -1;
  420                 goto out;
  421         }
  422 
  423         if (fdt_overlay_do_local_fixups(main_fdtp, overlay_copy) < 0) {
  424                 printf("failed to perform local fixups in overlay\n");
  425                 rv = -1;
  426                 goto out;
  427         }
  428 
  429         if (fdt_overlay_apply_fragments(main_fdtp, overlay_copy) < 0) {
  430                 printf("failed to apply fragments\n");
  431                 rv = -1;
  432         }
  433 
  434 out:
  435         free(overlay_copy);
  436 
  437         return (rv);
  438 }

Cache object: 4ed74d1f05d1ba1738aebcd60602fd74


[ 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.