]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/Library/FdtLib/fdt_overlay.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / EmbeddedPkg / Library / FdtLib / fdt_overlay.c
CommitLineData
e7108d0e
MK
1/*\r
2 * libfdt - Flat Device Tree manipulation\r
3 * Copyright (C) 2016 Free Electrons\r
4 * Copyright (C) 2016 NextThing Co.\r
5 *\r
6 * libfdt is dual licensed: you can use it either under the terms of\r
7 * the GPL, or the BSD license, at your option.\r
8 *\r
9 * a) This library is free software; you can redistribute it and/or\r
10 * modify it under the terms of the GNU General Public License as\r
11 * published by the Free Software Foundation; either version 2 of the\r
12 * License, or (at your option) any later version.\r
13 *\r
14 * This library is distributed in the hope that it will be useful,\r
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
17 * GNU General Public License for more details.\r
18 *\r
19 * You should have received a copy of the GNU General Public\r
20 * License along with this library; if not, write to the Free\r
21 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,\r
22 * MA 02110-1301 USA\r
23 *\r
24 * Alternatively,\r
25 *\r
26 * b) Redistribution and use in source and binary forms, with or\r
27 * without modification, are permitted provided that the following\r
28 * conditions are met:\r
29 *\r
30 * 1. Redistributions of source code must retain the above\r
31 * copyright notice, this list of conditions and the following\r
32 * disclaimer.\r
33 * 2. Redistributions in binary form must reproduce the above\r
34 * copyright notice, this list of conditions and the following\r
35 * disclaimer in the documentation and/or other materials\r
36 * provided with the distribution.\r
37 *\r
38 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\r
39 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,\r
40 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
41 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
42 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
43 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
48 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\r
49 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
50 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
51 */\r
52#include "libfdt_env.h"\r
53\r
54#include <fdt.h>\r
55#include <libfdt.h>\r
56\r
57#include "libfdt_internal.h"\r
58\r
59/**\r
60 * overlay_get_target_phandle - retrieves the target phandle of a fragment\r
61 * @fdto: pointer to the device tree overlay blob\r
62 * @fragment: node offset of the fragment in the overlay\r
63 *\r
64 * overlay_get_target_phandle() retrieves the target phandle of an\r
65 * overlay fragment when that fragment uses a phandle (target\r
66 * property) instead of a path (target-path property).\r
67 *\r
68 * returns:\r
69 * the phandle pointed by the target property\r
70 * 0, if the phandle was not found\r
71 * -1, if the phandle was malformed\r
72 */\r
73static uint32_t\r
74overlay_get_target_phandle (\r
75 const void *fdto,\r
76 int fragment\r
77 )\r
78{\r
79 const fdt32_t *val;\r
80 int len;\r
81\r
82 val = fdt_getprop (fdto, fragment, "target", &len);\r
83 if (!val) {\r
84 return 0;\r
85 }\r
86\r
87 if ((len != sizeof (*val)) || (fdt32_to_cpu (*val) == (uint32_t)-1)) {\r
88 return (uint32_t)-1;\r
89 }\r
90\r
91 return fdt32_to_cpu (*val);\r
92}\r
93\r
94/**\r
95 * overlay_get_target - retrieves the offset of a fragment's target\r
96 * @fdt: Base device tree blob\r
97 * @fdto: Device tree overlay blob\r
98 * @fragment: node offset of the fragment in the overlay\r
99 * @pathp: pointer which receives the path of the target (or NULL)\r
100 *\r
101 * overlay_get_target() retrieves the target offset in the base\r
102 * device tree of a fragment, no matter how the actual targetting is\r
103 * done (through a phandle or a path)\r
104 *\r
105 * returns:\r
106 * the targetted node offset in the base device tree\r
107 * Negative error code on error\r
108 */\r
109static int\r
110overlay_get_target (\r
111 const void *fdt,\r
112 const void *fdto,\r
113 int fragment,\r
114 char const **pathp\r
115 )\r
116{\r
117 uint32_t phandle;\r
118 const char *path = NULL;\r
119 int path_len = 0, ret;\r
120\r
121 /* Try first to do a phandle based lookup */\r
122 phandle = overlay_get_target_phandle (fdto, fragment);\r
123 if (phandle == (uint32_t)-1) {\r
124 return -FDT_ERR_BADPHANDLE;\r
125 }\r
126\r
127 /* no phandle, try path */\r
128 if (!phandle) {\r
129 /* And then a path based lookup */\r
130 path = fdt_getprop (fdto, fragment, "target-path", &path_len);\r
131 if (path) {\r
132 ret = fdt_path_offset (fdt, path);\r
133 } else {\r
134 ret = path_len;\r
135 }\r
136 } else {\r
137 ret = fdt_node_offset_by_phandle (fdt, phandle);\r
138 }\r
139\r
140 /*\r
141 * If we haven't found either a target or a\r
142 * target-path property in a node that contains a\r
143 * __overlay__ subnode (we wouldn't be called\r
144 * otherwise), consider it a improperly written\r
145 * overlay\r
146 */\r
147 if ((ret < 0) && (path_len == -FDT_ERR_NOTFOUND)) {\r
148 ret = -FDT_ERR_BADOVERLAY;\r
149 }\r
150\r
151 /* return on error */\r
152 if (ret < 0) {\r
153 return ret;\r
154 }\r
155\r
156 /* return pointer to path (if available) */\r
157 if (pathp) {\r
158 *pathp = path ? path : NULL;\r
159 }\r
160\r
161 return ret;\r
162}\r
163\r
164/**\r
165 * overlay_phandle_add_offset - Increases a phandle by an offset\r
166 * @fdt: Base device tree blob\r
167 * @node: Device tree overlay blob\r
168 * @name: Name of the property to modify (phandle or linux,phandle)\r
169 * @delta: offset to apply\r
170 *\r
171 * overlay_phandle_add_offset() increments a node phandle by a given\r
172 * offset.\r
173 *\r
174 * returns:\r
175 * 0 on success.\r
176 * Negative error code on error\r
177 */\r
178static int\r
179overlay_phandle_add_offset (\r
180 void *fdt,\r
181 int node,\r
182 const char *name,\r
183 uint32_t delta\r
184 )\r
185{\r
186 const fdt32_t *val;\r
187 uint32_t adj_val;\r
188 int len;\r
189\r
190 val = fdt_getprop (fdt, node, name, &len);\r
191 if (!val) {\r
192 return len;\r
193 }\r
194\r
195 if (len != sizeof (*val)) {\r
196 return -FDT_ERR_BADPHANDLE;\r
197 }\r
198\r
199 adj_val = fdt32_to_cpu (*val);\r
200 if ((adj_val + delta) < adj_val) {\r
201 return -FDT_ERR_NOPHANDLES;\r
202 }\r
203\r
204 adj_val += delta;\r
205 if (adj_val == (uint32_t)-1) {\r
206 return -FDT_ERR_NOPHANDLES;\r
207 }\r
208\r
209 return fdt_setprop_inplace_u32 (fdt, node, name, adj_val);\r
210}\r
211\r
212/**\r
213 * overlay_adjust_node_phandles - Offsets the phandles of a node\r
214 * @fdto: Device tree overlay blob\r
215 * @node: Offset of the node we want to adjust\r
216 * @delta: Offset to shift the phandles of\r
217 *\r
218 * overlay_adjust_node_phandles() adds a constant to all the phandles\r
219 * of a given node. This is mainly use as part of the overlay\r
220 * application process, when we want to update all the overlay\r
221 * phandles to not conflict with the overlays of the base device tree.\r
222 *\r
223 * returns:\r
224 * 0 on success\r
225 * Negative error code on failure\r
226 */\r
227static int\r
228overlay_adjust_node_phandles (\r
229 void *fdto,\r
230 int node,\r
231 uint32_t delta\r
232 )\r
233{\r
234 int child;\r
235 int ret;\r
236\r
237 ret = overlay_phandle_add_offset (fdto, node, "phandle", delta);\r
238 if (ret && (ret != -FDT_ERR_NOTFOUND)) {\r
239 return ret;\r
240 }\r
241\r
242 ret = overlay_phandle_add_offset (fdto, node, "linux,phandle", delta);\r
243 if (ret && (ret != -FDT_ERR_NOTFOUND)) {\r
244 return ret;\r
245 }\r
246\r
247 fdt_for_each_subnode (child, fdto, node) {\r
248 ret = overlay_adjust_node_phandles (fdto, child, delta);\r
249 if (ret) {\r
250 return ret;\r
251 }\r
252 }\r
253\r
254 return 0;\r
255}\r
256\r
257/**\r
258 * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay\r
259 * @fdto: Device tree overlay blob\r
260 * @delta: Offset to shift the phandles of\r
261 *\r
262 * overlay_adjust_local_phandles() adds a constant to all the\r
263 * phandles of an overlay. This is mainly use as part of the overlay\r
264 * application process, when we want to update all the overlay\r
265 * phandles to not conflict with the overlays of the base device tree.\r
266 *\r
267 * returns:\r
268 * 0 on success\r
269 * Negative error code on failure\r
270 */\r
271static int\r
272overlay_adjust_local_phandles (\r
273 void *fdto,\r
274 uint32_t delta\r
275 )\r
276{\r
277 /*\r
278 * Start adjusting the phandles from the overlay root\r
279 */\r
280 return overlay_adjust_node_phandles (fdto, 0, delta);\r
281}\r
282\r
283/**\r
284 * overlay_update_local_node_references - Adjust the overlay references\r
285 * @fdto: Device tree overlay blob\r
286 * @tree_node: Node offset of the node to operate on\r
287 * @fixup_node: Node offset of the matching local fixups node\r
288 * @delta: Offset to shift the phandles of\r
289 *\r
290 * overlay_update_local_nodes_references() update the phandles\r
291 * pointing to a node within the device tree overlay by adding a\r
292 * constant delta.\r
293 *\r
294 * This is mainly used as part of a device tree application process,\r
295 * where you want the device tree overlays phandles to not conflict\r
296 * with the ones from the base device tree before merging them.\r
297 *\r
298 * returns:\r
299 * 0 on success\r
300 * Negative error code on failure\r
301 */\r
302static int\r
303overlay_update_local_node_references (\r
304 void *fdto,\r
305 int tree_node,\r
306 int fixup_node,\r
307 uint32_t delta\r
308 )\r
309{\r
310 int fixup_prop;\r
311 int fixup_child;\r
312 int ret;\r
313\r
314 fdt_for_each_property_offset (fixup_prop, fdto, fixup_node) {\r
315 const fdt32_t *fixup_val;\r
316 const char *tree_val;\r
317 const char *name;\r
318 int fixup_len;\r
319 int tree_len;\r
320 int i;\r
321\r
322 fixup_val = fdt_getprop_by_offset (\r
323 fdto,\r
324 fixup_prop,\r
325 &name,\r
326 &fixup_len\r
327 );\r
328 if (!fixup_val) {\r
329 return fixup_len;\r
330 }\r
331\r
332 if (fixup_len % sizeof (uint32_t)) {\r
333 return -FDT_ERR_BADOVERLAY;\r
334 }\r
335\r
336 tree_val = fdt_getprop (fdto, tree_node, name, &tree_len);\r
337 if (!tree_val) {\r
338 if (tree_len == -FDT_ERR_NOTFOUND) {\r
339 return -FDT_ERR_BADOVERLAY;\r
340 }\r
341\r
342 return tree_len;\r
343 }\r
344\r
345 for (i = 0; i < (fixup_len / sizeof (uint32_t)); i++) {\r
346 fdt32_t adj_val;\r
347 uint32_t poffset;\r
348\r
349 poffset = fdt32_to_cpu (fixup_val[i]);\r
350\r
351 /*\r
352 * phandles to fixup can be unaligned.\r
353 *\r
354 * Use a memcpy for the architectures that do\r
355 * not support unaligned accesses.\r
356 */\r
357 memcpy (&adj_val, tree_val + poffset, sizeof (adj_val));\r
358\r
359 adj_val = cpu_to_fdt32 (fdt32_to_cpu (adj_val) + delta);\r
360\r
361 ret = fdt_setprop_inplace_namelen_partial (\r
362 fdto,\r
363 tree_node,\r
364 name,\r
365 strlen (name),\r
366 poffset,\r
367 &adj_val,\r
368 sizeof (adj_val)\r
369 );\r
370 if (ret == -FDT_ERR_NOSPACE) {\r
371 return -FDT_ERR_BADOVERLAY;\r
372 }\r
373\r
374 if (ret) {\r
375 return ret;\r
376 }\r
377 }\r
378 }\r
379\r
380 fdt_for_each_subnode (fixup_child, fdto, fixup_node) {\r
381 const char *fixup_child_name = fdt_get_name (\r
382 fdto,\r
383 fixup_child,\r
384 NULL\r
385 );\r
386 int tree_child;\r
387\r
388 tree_child = fdt_subnode_offset (\r
389 fdto,\r
390 tree_node,\r
391 fixup_child_name\r
392 );\r
393 if (tree_child == -FDT_ERR_NOTFOUND) {\r
394 return -FDT_ERR_BADOVERLAY;\r
395 }\r
396\r
397 if (tree_child < 0) {\r
398 return tree_child;\r
399 }\r
400\r
401 ret = overlay_update_local_node_references (\r
402 fdto,\r
403 tree_child,\r
404 fixup_child,\r
405 delta\r
406 );\r
407 if (ret) {\r
408 return ret;\r
409 }\r
410 }\r
411\r
412 return 0;\r
413}\r
414\r
415/**\r
416 * overlay_update_local_references - Adjust the overlay references\r
417 * @fdto: Device tree overlay blob\r
418 * @delta: Offset to shift the phandles of\r
419 *\r
420 * overlay_update_local_references() update all the phandles pointing\r
421 * to a node within the device tree overlay by adding a constant\r
422 * delta to not conflict with the base overlay.\r
423 *\r
424 * This is mainly used as part of a device tree application process,\r
425 * where you want the device tree overlays phandles to not conflict\r
426 * with the ones from the base device tree before merging them.\r
427 *\r
428 * returns:\r
429 * 0 on success\r
430 * Negative error code on failure\r
431 */\r
432static int\r
433overlay_update_local_references (\r
434 void *fdto,\r
435 uint32_t delta\r
436 )\r
437{\r
438 int fixups;\r
439\r
440 fixups = fdt_path_offset (fdto, "/__local_fixups__");\r
441 if (fixups < 0) {\r
442 /* There's no local phandles to adjust, bail out */\r
443 if (fixups == -FDT_ERR_NOTFOUND) {\r
444 return 0;\r
445 }\r
446\r
447 return fixups;\r
448 }\r
449\r
450 /*\r
451 * Update our local references from the root of the tree\r
452 */\r
453 return overlay_update_local_node_references (\r
454 fdto,\r
455 0,\r
456 fixups,\r
457 delta\r
458 );\r
459}\r
460\r
461/**\r
462 * overlay_fixup_one_phandle - Set an overlay phandle to the base one\r
463 * @fdt: Base Device Tree blob\r
464 * @fdto: Device tree overlay blob\r
465 * @symbols_off: Node offset of the symbols node in the base device tree\r
466 * @path: Path to a node holding a phandle in the overlay\r
467 * @path_len: number of path characters to consider\r
468 * @name: Name of the property holding the phandle reference in the overlay\r
469 * @name_len: number of name characters to consider\r
470 * @poffset: Offset within the overlay property where the phandle is stored\r
471 * @label: Label of the node referenced by the phandle\r
472 *\r
473 * overlay_fixup_one_phandle() resolves an overlay phandle pointing to\r
474 * a node in the base device tree.\r
475 *\r
476 * This is part of the device tree overlay application process, when\r
477 * you want all the phandles in the overlay to point to the actual\r
478 * base dt nodes.\r
479 *\r
480 * returns:\r
481 * 0 on success\r
482 * Negative error code on failure\r
483 */\r
484static int\r
485overlay_fixup_one_phandle (\r
486 void *fdt,\r
487 void *fdto,\r
488 int symbols_off,\r
489 const char *path,\r
490 uint32_t path_len,\r
491 const char *name,\r
492 uint32_t name_len,\r
493 int poffset,\r
494 const char *label\r
495 )\r
496{\r
497 const char *symbol_path;\r
498 uint32_t phandle;\r
499 fdt32_t phandle_prop;\r
500 int symbol_off, fixup_off;\r
501 int prop_len;\r
502\r
503 if (symbols_off < 0) {\r
504 return symbols_off;\r
505 }\r
506\r
507 symbol_path = fdt_getprop (\r
508 fdt,\r
509 symbols_off,\r
510 label,\r
511 &prop_len\r
512 );\r
513 if (!symbol_path) {\r
514 return prop_len;\r
515 }\r
516\r
517 symbol_off = fdt_path_offset (fdt, symbol_path);\r
518 if (symbol_off < 0) {\r
519 return symbol_off;\r
520 }\r
521\r
522 phandle = fdt_get_phandle (fdt, symbol_off);\r
523 if (!phandle) {\r
524 return -FDT_ERR_NOTFOUND;\r
525 }\r
526\r
527 fixup_off = fdt_path_offset_namelen (fdto, path, path_len);\r
528 if (fixup_off == -FDT_ERR_NOTFOUND) {\r
529 return -FDT_ERR_BADOVERLAY;\r
530 }\r
531\r
532 if (fixup_off < 0) {\r
533 return fixup_off;\r
534 }\r
535\r
536 phandle_prop = cpu_to_fdt32 (phandle);\r
537 return fdt_setprop_inplace_namelen_partial (\r
538 fdto,\r
539 fixup_off,\r
540 name,\r
541 name_len,\r
542 poffset,\r
543 &phandle_prop,\r
544 sizeof (phandle_prop)\r
545 );\r
546}\r
547\r
548unsigned long\r
549strtoul (\r
550 const char *nptr,\r
551 char **endptr,\r
552 int base\r
553 );\r
554\r
555/**\r
556 * overlay_fixup_phandle - Set an overlay phandle to the base one\r
557 * @fdt: Base Device Tree blob\r
558 * @fdto: Device tree overlay blob\r
559 * @symbols_off: Node offset of the symbols node in the base device tree\r
560 * @property: Property offset in the overlay holding the list of fixups\r
561 *\r
562 * overlay_fixup_phandle() resolves all the overlay phandles pointed\r
563 * to in a __fixups__ property, and updates them to match the phandles\r
564 * in use in the base device tree.\r
565 *\r
566 * This is part of the device tree overlay application process, when\r
567 * you want all the phandles in the overlay to point to the actual\r
568 * base dt nodes.\r
569 *\r
570 * returns:\r
571 * 0 on success\r
572 * Negative error code on failure\r
573 */\r
574static int\r
575overlay_fixup_phandle (\r
576 void *fdt,\r
577 void *fdto,\r
578 int symbols_off,\r
579 int property\r
580 )\r
581{\r
582 const char *value;\r
583 const char *label;\r
584 int len;\r
585\r
586 value = fdt_getprop_by_offset (\r
587 fdto,\r
588 property,\r
589 &label,\r
590 &len\r
591 );\r
592 if (!value) {\r
593 if (len == -FDT_ERR_NOTFOUND) {\r
594 return -FDT_ERR_INTERNAL;\r
595 }\r
596\r
597 return len;\r
598 }\r
599\r
600 do {\r
601 const char *path, *name, *fixup_end;\r
602 const char *fixup_str = value;\r
603 uint32_t path_len, name_len;\r
604 uint32_t fixup_len;\r
605 char *sep, *endptr;\r
606 int poffset, ret;\r
607\r
608 fixup_end = memchr (value, '\0', len);\r
609 if (!fixup_end) {\r
610 return -FDT_ERR_BADOVERLAY;\r
611 }\r
612\r
613 fixup_len = fixup_end - fixup_str;\r
614\r
615 len -= fixup_len + 1;\r
616 value += fixup_len + 1;\r
617\r
618 path = fixup_str;\r
619 sep = memchr (fixup_str, ':', fixup_len);\r
620 if (!sep || (*sep != ':')) {\r
621 return -FDT_ERR_BADOVERLAY;\r
622 }\r
623\r
624 path_len = sep - path;\r
625 if (path_len == (fixup_len - 1)) {\r
626 return -FDT_ERR_BADOVERLAY;\r
627 }\r
628\r
629 fixup_len -= path_len + 1;\r
630 name = sep + 1;\r
631 sep = memchr (name, ':', fixup_len);\r
632 if (!sep || (*sep != ':')) {\r
633 return -FDT_ERR_BADOVERLAY;\r
634 }\r
635\r
636 name_len = sep - name;\r
637 if (!name_len) {\r
638 return -FDT_ERR_BADOVERLAY;\r
639 }\r
640\r
641 poffset = strtoul (sep + 1, &endptr, 10);\r
642 if ((*endptr != '\0') || (endptr <= (sep + 1))) {\r
643 return -FDT_ERR_BADOVERLAY;\r
644 }\r
645\r
646 ret = overlay_fixup_one_phandle (\r
647 fdt,\r
648 fdto,\r
649 symbols_off,\r
650 path,\r
651 path_len,\r
652 name,\r
653 name_len,\r
654 poffset,\r
655 label\r
656 );\r
657 if (ret) {\r
658 return ret;\r
659 }\r
660 } while (len > 0);\r
661\r
662 return 0;\r
663}\r
664\r
665/**\r
666 * overlay_fixup_phandles - Resolve the overlay phandles to the base\r
667 * device tree\r
668 * @fdt: Base Device Tree blob\r
669 * @fdto: Device tree overlay blob\r
670 *\r
671 * overlay_fixup_phandles() resolves all the overlay phandles pointing\r
672 * to nodes in the base device tree.\r
673 *\r
674 * This is one of the steps of the device tree overlay application\r
675 * process, when you want all the phandles in the overlay to point to\r
676 * the actual base dt nodes.\r
677 *\r
678 * returns:\r
679 * 0 on success\r
680 * Negative error code on failure\r
681 */\r
682static int\r
683overlay_fixup_phandles (\r
684 void *fdt,\r
685 void *fdto\r
686 )\r
687{\r
688 int fixups_off, symbols_off;\r
689 int property;\r
690\r
691 /* We can have overlays without any fixups */\r
692 fixups_off = fdt_path_offset (fdto, "/__fixups__");\r
693 if (fixups_off == -FDT_ERR_NOTFOUND) {\r
694 return 0; /* nothing to do */\r
695 }\r
696\r
697 if (fixups_off < 0) {\r
698 return fixups_off;\r
699 }\r
700\r
701 /* And base DTs without symbols */\r
702 symbols_off = fdt_path_offset (fdt, "/__symbols__");\r
703 if (((symbols_off < 0) && (symbols_off != -FDT_ERR_NOTFOUND))) {\r
704 return symbols_off;\r
705 }\r
706\r
707 fdt_for_each_property_offset (property, fdto, fixups_off) {\r
708 int ret;\r
709\r
710 ret = overlay_fixup_phandle (fdt, fdto, symbols_off, property);\r
711 if (ret) {\r
712 return ret;\r
713 }\r
714 }\r
715\r
716 return 0;\r
717}\r
718\r
719/**\r
720 * overlay_apply_node - Merges a node into the base device tree\r
721 * @fdt: Base Device Tree blob\r
722 * @target: Node offset in the base device tree to apply the fragment to\r
723 * @fdto: Device tree overlay blob\r
724 * @node: Node offset in the overlay holding the changes to merge\r
725 *\r
726 * overlay_apply_node() merges a node into a target base device tree\r
727 * node pointed.\r
728 *\r
729 * This is part of the final step in the device tree overlay\r
730 * application process, when all the phandles have been adjusted and\r
731 * resolved and you just have to merge overlay into the base device\r
732 * tree.\r
733 *\r
734 * returns:\r
735 * 0 on success\r
736 * Negative error code on failure\r
737 */\r
738static int\r
739overlay_apply_node (\r
740 void *fdt,\r
741 int target,\r
742 void *fdto,\r
743 int node\r
744 )\r
745{\r
746 int property;\r
747 int subnode;\r
748\r
749 fdt_for_each_property_offset (property, fdto, node) {\r
750 const char *name;\r
751 const void *prop;\r
752 int prop_len;\r
753 int ret;\r
754\r
755 prop = fdt_getprop_by_offset (\r
756 fdto,\r
757 property,\r
758 &name,\r
759 &prop_len\r
760 );\r
761 if (prop_len == -FDT_ERR_NOTFOUND) {\r
762 return -FDT_ERR_INTERNAL;\r
763 }\r
764\r
765 if (prop_len < 0) {\r
766 return prop_len;\r
767 }\r
768\r
769 ret = fdt_setprop (fdt, target, name, prop, prop_len);\r
770 if (ret) {\r
771 return ret;\r
772 }\r
773 }\r
774\r
775 fdt_for_each_subnode (subnode, fdto, node) {\r
776 const char *name = fdt_get_name (fdto, subnode, NULL);\r
777 int nnode;\r
778 int ret;\r
779\r
780 nnode = fdt_add_subnode (fdt, target, name);\r
781 if (nnode == -FDT_ERR_EXISTS) {\r
782 nnode = fdt_subnode_offset (fdt, target, name);\r
783 if (nnode == -FDT_ERR_NOTFOUND) {\r
784 return -FDT_ERR_INTERNAL;\r
785 }\r
786 }\r
787\r
788 if (nnode < 0) {\r
789 return nnode;\r
790 }\r
791\r
792 ret = overlay_apply_node (fdt, nnode, fdto, subnode);\r
793 if (ret) {\r
794 return ret;\r
795 }\r
796 }\r
797\r
798 return 0;\r
799}\r
800\r
801/**\r
802 * overlay_merge - Merge an overlay into its base device tree\r
803 * @fdt: Base Device Tree blob\r
804 * @fdto: Device tree overlay blob\r
805 *\r
806 * overlay_merge() merges an overlay into its base device tree.\r
807 *\r
808 * This is the next to last step in the device tree overlay application\r
809 * process, when all the phandles have been adjusted and resolved and\r
810 * you just have to merge overlay into the base device tree.\r
811 *\r
812 * returns:\r
813 * 0 on success\r
814 * Negative error code on failure\r
815 */\r
816static int\r
817overlay_merge (\r
818 void *fdt,\r
819 void *fdto\r
820 )\r
821{\r
822 int fragment;\r
823\r
824 fdt_for_each_subnode (fragment, fdto, 0) {\r
825 int overlay;\r
826 int target;\r
827 int ret;\r
828\r
829 /*\r
830 * Each fragments will have an __overlay__ node. If\r
831 * they don't, it's not supposed to be merged\r
832 */\r
833 overlay = fdt_subnode_offset (fdto, fragment, "__overlay__");\r
834 if (overlay == -FDT_ERR_NOTFOUND) {\r
835 continue;\r
836 }\r
837\r
838 if (overlay < 0) {\r
839 return overlay;\r
840 }\r
841\r
842 target = overlay_get_target (fdt, fdto, fragment, NULL);\r
843 if (target < 0) {\r
844 return target;\r
845 }\r
846\r
847 ret = overlay_apply_node (fdt, target, fdto, overlay);\r
848 if (ret) {\r
849 return ret;\r
850 }\r
851 }\r
852\r
853 return 0;\r
854}\r
855\r
856static int\r
857get_path_len (\r
858 const void *fdt,\r
859 int nodeoffset\r
860 )\r
861{\r
862 int len = 0, namelen;\r
863 const char *name;\r
864\r
865 FDT_CHECK_HEADER (fdt);\r
866\r
867 for ( ; ;) {\r
868 name = fdt_get_name (fdt, nodeoffset, &namelen);\r
869 if (!name) {\r
870 return namelen;\r
871 }\r
872\r
873 /* root? we're done */\r
874 if (namelen == 0) {\r
875 break;\r
876 }\r
877\r
878 nodeoffset = fdt_parent_offset (fdt, nodeoffset);\r
879 if (nodeoffset < 0) {\r
880 return nodeoffset;\r
881 }\r
882\r
883 len += namelen + 1;\r
884 }\r
885\r
886 /* in case of root pretend it's "/" */\r
887 if (len == 0) {\r
888 len++;\r
889 }\r
890\r
891 return len;\r
892}\r
893\r
894/**\r
895 * overlay_symbol_update - Update the symbols of base tree after a merge\r
896 * @fdt: Base Device Tree blob\r
897 * @fdto: Device tree overlay blob\r
898 *\r
899 * overlay_symbol_update() updates the symbols of the base tree with the\r
900 * symbols of the applied overlay\r
901 *\r
902 * This is the last step in the device tree overlay application\r
903 * process, allowing the reference of overlay symbols by subsequent\r
904 * overlay operations.\r
905 *\r
906 * returns:\r
907 * 0 on success\r
908 * Negative error code on failure\r
909 */\r
910static int\r
911overlay_symbol_update (\r
912 void *fdt,\r
913 void *fdto\r
914 )\r
915{\r
916 int root_sym, ov_sym, prop, path_len, fragment, target;\r
917 int len, frag_name_len, ret, rel_path_len;\r
918 const char *s, *e;\r
919 const char *path;\r
920 const char *name;\r
921 const char *frag_name;\r
922 const char *rel_path;\r
923 const char *target_path;\r
924 char *buf;\r
925 void *p;\r
926\r
927 ov_sym = fdt_subnode_offset (fdto, 0, "__symbols__");\r
928\r
929 /* if no overlay symbols exist no problem */\r
930 if (ov_sym < 0) {\r
931 return 0;\r
932 }\r
933\r
934 root_sym = fdt_subnode_offset (fdt, 0, "__symbols__");\r
935\r
936 /* it no root symbols exist we should create them */\r
937 if (root_sym == -FDT_ERR_NOTFOUND) {\r
938 root_sym = fdt_add_subnode (fdt, 0, "__symbols__");\r
939 }\r
940\r
941 /* any error is fatal now */\r
942 if (root_sym < 0) {\r
943 return root_sym;\r
944 }\r
945\r
946 /* iterate over each overlay symbol */\r
947 fdt_for_each_property_offset (prop, fdto, ov_sym) {\r
948 path = fdt_getprop_by_offset (fdto, prop, &name, &path_len);\r
949 if (!path) {\r
950 return path_len;\r
951 }\r
952\r
953 /* verify it's a string property (terminated by a single \0) */\r
954 if ((path_len < 1) || (memchr (path, '\0', path_len) != &path[path_len - 1])) {\r
955 return -FDT_ERR_BADVALUE;\r
956 }\r
957\r
958 /* keep end marker to avoid strlen() */\r
959 e = path + path_len;\r
960\r
961 /* format: /<fragment-name>/__overlay__/<relative-subnode-path> */\r
962\r
963 if (*path != '/') {\r
964 return -FDT_ERR_BADVALUE;\r
965 }\r
966\r
967 /* get fragment name first */\r
968 s = strchr (path + 1, '/');\r
969 if (!s) {\r
970 return -FDT_ERR_BADOVERLAY;\r
971 }\r
972\r
973 frag_name = path + 1;\r
974 frag_name_len = s - path - 1;\r
975\r
976 /* verify format; safe since "s" lies in \0 terminated prop */\r
977 len = sizeof ("/__overlay__/") - 1;\r
978 if (((e - s) < len) || memcmp (s, "/__overlay__/", len)) {\r
979 return -FDT_ERR_BADOVERLAY;\r
980 }\r
981\r
982 rel_path = s + len;\r
983 rel_path_len = e - rel_path;\r
984\r
985 /* find the fragment index in which the symbol lies */\r
986 ret = fdt_subnode_offset_namelen (\r
987 fdto,\r
988 0,\r
989 frag_name,\r
990 frag_name_len\r
991 );\r
992 /* not found? */\r
993 if (ret < 0) {\r
994 return -FDT_ERR_BADOVERLAY;\r
995 }\r
996\r
997 fragment = ret;\r
998\r
999 /* an __overlay__ subnode must exist */\r
1000 ret = fdt_subnode_offset (fdto, fragment, "__overlay__");\r
1001 if (ret < 0) {\r
1002 return -FDT_ERR_BADOVERLAY;\r
1003 }\r
1004\r
1005 /* get the target of the fragment */\r
1006 ret = overlay_get_target (fdt, fdto, fragment, &target_path);\r
1007 if (ret < 0) {\r
1008 return ret;\r
1009 }\r
1010\r
1011 target = ret;\r
1012\r
1013 /* if we have a target path use */\r
1014 if (!target_path) {\r
1015 ret = get_path_len (fdt, target);\r
1016 if (ret < 0) {\r
1017 return ret;\r
1018 }\r
1019\r
1020 len = ret;\r
1021 } else {\r
1022 len = strlen (target_path);\r
1023 }\r
1024\r
1025 ret = fdt_setprop_placeholder (\r
1026 fdt,\r
1027 root_sym,\r
1028 name,\r
1029 len + (len > 1) + rel_path_len + 1,\r
1030 &p\r
1031 );\r
1032 if (ret < 0) {\r
1033 return ret;\r
1034 }\r
1035\r
1036 if (!target_path) {\r
1037 /* again in case setprop_placeholder changed it */\r
1038 ret = overlay_get_target (fdt, fdto, fragment, &target_path);\r
1039 if (ret < 0) {\r
1040 return ret;\r
1041 }\r
1042\r
1043 target = ret;\r
1044 }\r
1045\r
1046 buf = p;\r
1047 if (len > 1) {\r
1048 /* target is not root */\r
1049 if (!target_path) {\r
1050 ret = fdt_get_path (fdt, target, buf, len + 1);\r
1051 if (ret < 0) {\r
1052 return ret;\r
1053 }\r
1054 } else {\r
1055 memcpy (buf, target_path, len + 1);\r
1056 }\r
1057 } else {\r
1058 len--;\r
1059 }\r
1060\r
1061 buf[len] = '/';\r
1062 memcpy (buf + len + 1, rel_path, rel_path_len);\r
1063 buf[len + 1 + rel_path_len] = '\0';\r
1064 }\r
1065\r
1066 return 0;\r
1067}\r
1068\r
1069int\r
1070fdt_overlay_apply (\r
1071 void *fdt,\r
1072 void *fdto\r
1073 )\r
1074{\r
1075 uint32_t delta = fdt_get_max_phandle (fdt);\r
1076 int ret;\r
1077\r
1078 FDT_CHECK_HEADER (fdt);\r
1079 FDT_CHECK_HEADER (fdto);\r
1080\r
1081 ret = overlay_adjust_local_phandles (fdto, delta);\r
1082 if (ret) {\r
1083 goto err;\r
1084 }\r
1085\r
1086 ret = overlay_update_local_references (fdto, delta);\r
1087 if (ret) {\r
1088 goto err;\r
1089 }\r
1090\r
1091 ret = overlay_fixup_phandles (fdt, fdto);\r
1092 if (ret) {\r
1093 goto err;\r
1094 }\r
1095\r
1096 ret = overlay_merge (fdt, fdto);\r
1097 if (ret) {\r
1098 goto err;\r
1099 }\r
1100\r
1101 ret = overlay_symbol_update (fdt, fdto);\r
1102 if (ret) {\r
1103 goto err;\r
1104 }\r
1105\r
1106 /*\r
1107 * The overlay has been damaged, erase its magic.\r
1108 */\r
1109 fdt_set_magic (fdto, ~0);\r
1110\r
1111 return 0;\r
1112\r
1113err:\r
1114\r
1115 /*\r
1116 * The overlay might have been damaged, erase its magic.\r
1117 */\r
1118 fdt_set_magic (fdto, ~0);\r
1119\r
1120 /*\r
1121 * The base device tree might have been damaged, erase its\r
1122 * magic.\r
1123 */\r
1124 fdt_set_magic (fdt, ~0);\r
1125\r
1126 return ret;\r
1127}\r