~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/scripts/dtc/libfdt/fdt_overlay.c

Version: ~ [ linux-5.6-rc7 ] ~ [ linux-5.5.11 ] ~ [ linux-5.4.27 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.112 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.174 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.217 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.217 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.82 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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_RO_PROBE(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_RO_PROBE(fdt);
870         FDT_RO_PROBE(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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp