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