TianoCore EDK2 master
Loading...
Searching...
No Matches
fdt_overlay.c
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
73static uint32_t
74overlay_get_target_phandle (
75 const void *fdto,
76 int fragment
77 )
78{
79 const fdt32_t *val;
80 int len;
81
82 val = fdt_getprop (fdto, fragment, "target", &len);
83 if (!val) {
84 return 0;
85 }
86
87 if ((len != sizeof (*val)) || (fdt32_to_cpu (*val) == (uint32_t)-1)) {
88 return (uint32_t)-1;
89 }
90
91 return fdt32_to_cpu (*val);
92}
93
109static int
110overlay_get_target (
111 const void *fdt,
112 const void *fdto,
113 int fragment,
114 char const **pathp
115 )
116{
117 uint32_t phandle;
118 const char *path = NULL;
119 int path_len = 0, ret;
120
121 /* Try first to do a phandle based lookup */
122 phandle = overlay_get_target_phandle (fdto, fragment);
123 if (phandle == (uint32_t)-1) {
124 return -FDT_ERR_BADPHANDLE;
125 }
126
127 /* no phandle, try path */
128 if (!phandle) {
129 /* And then a path based lookup */
130 path = fdt_getprop (fdto, fragment, "target-path", &path_len);
131 if (path) {
132 ret = fdt_path_offset (fdt, path);
133 } else {
134 ret = path_len;
135 }
136 } else {
137 ret = fdt_node_offset_by_phandle (fdt, phandle);
138 }
139
140 /*
141 * If we haven't found either a target or a
142 * target-path property in a node that contains a
143 * __overlay__ subnode (we wouldn't be called
144 * otherwise), consider it a improperly written
145 * overlay
146 */
147 if ((ret < 0) && (path_len == -FDT_ERR_NOTFOUND)) {
148 ret = -FDT_ERR_BADOVERLAY;
149 }
150
151 /* return on error */
152 if (ret < 0) {
153 return ret;
154 }
155
156 /* return pointer to path (if available) */
157 if (pathp) {
158 *pathp = path ? path : NULL;
159 }
160
161 return ret;
162}
163
178static int
179overlay_phandle_add_offset (
180 void *fdt,
181 int node,
182 const char *name,
183 uint32_t delta
184 )
185{
186 const fdt32_t *val;
187 uint32_t adj_val;
188 int len;
189
190 val = fdt_getprop (fdt, node, name, &len);
191 if (!val) {
192 return len;
193 }
194
195 if (len != sizeof (*val)) {
196 return -FDT_ERR_BADPHANDLE;
197 }
198
199 adj_val = fdt32_to_cpu (*val);
200 if ((adj_val + delta) < adj_val) {
201 return -FDT_ERR_NOPHANDLES;
202 }
203
204 adj_val += delta;
205 if (adj_val == (uint32_t)-1) {
206 return -FDT_ERR_NOPHANDLES;
207 }
208
209 return fdt_setprop_inplace_u32 (fdt, node, name, adj_val);
210}
211
227static int
228overlay_adjust_node_phandles (
229 void *fdto,
230 int node,
231 uint32_t delta
232 )
233{
234 int child;
235 int ret;
236
237 ret = overlay_phandle_add_offset (fdto, node, "phandle", delta);
238 if (ret && (ret != -FDT_ERR_NOTFOUND)) {
239 return ret;
240 }
241
242 ret = overlay_phandle_add_offset (fdto, node, "linux,phandle", delta);
243 if (ret && (ret != -FDT_ERR_NOTFOUND)) {
244 return ret;
245 }
246
247 fdt_for_each_subnode (child, fdto, node) {
248 ret = overlay_adjust_node_phandles (fdto, child, delta);
249 if (ret) {
250 return ret;
251 }
252 }
253
254 return 0;
255}
256
271static int
272overlay_adjust_local_phandles (
273 void *fdto,
274 uint32_t delta
275 )
276{
277 /*
278 * Start adjusting the phandles from the overlay root
279 */
280 return overlay_adjust_node_phandles (fdto, 0, delta);
281}
282
302static int
303overlay_update_local_node_references (
304 void *fdto,
305 int tree_node,
306 int fixup_node,
307 uint32_t delta
308 )
309{
310 int fixup_prop;
311 int fixup_child;
312 int ret;
313
314 fdt_for_each_property_offset (fixup_prop, fdto, fixup_node) {
315 const fdt32_t *fixup_val;
316 const char *tree_val;
317 const char *name;
318 int fixup_len;
319 int tree_len;
320 int i;
321
322 fixup_val = fdt_getprop_by_offset (
323 fdto,
324 fixup_prop,
325 &name,
326 &fixup_len
327 );
328 if (!fixup_val) {
329 return fixup_len;
330 }
331
332 if (fixup_len % sizeof (uint32_t)) {
333 return -FDT_ERR_BADOVERLAY;
334 }
335
336 tree_val = fdt_getprop (fdto, tree_node, name, &tree_len);
337 if (!tree_val) {
338 if (tree_len == -FDT_ERR_NOTFOUND) {
339 return -FDT_ERR_BADOVERLAY;
340 }
341
342 return tree_len;
343 }
344
345 for (i = 0; i < (fixup_len / sizeof (uint32_t)); i++) {
346 fdt32_t adj_val;
347 uint32_t poffset;
348
349 poffset = fdt32_to_cpu (fixup_val[i]);
350
351 /*
352 * phandles to fixup can be unaligned.
353 *
354 * Use a memcpy for the architectures that do
355 * not support unaligned accesses.
356 */
357 memcpy (&adj_val, tree_val + poffset, sizeof (adj_val));
358
359 adj_val = cpu_to_fdt32 (fdt32_to_cpu (adj_val) + delta);
360
361 ret = fdt_setprop_inplace_namelen_partial (
362 fdto,
363 tree_node,
364 name,
365 strlen (name),
366 poffset,
367 &adj_val,
368 sizeof (adj_val)
369 );
370 if (ret == -FDT_ERR_NOSPACE) {
371 return -FDT_ERR_BADOVERLAY;
372 }
373
374 if (ret) {
375 return ret;
376 }
377 }
378 }
379
380 fdt_for_each_subnode (fixup_child, fdto, fixup_node) {
381 const char *fixup_child_name = fdt_get_name (
382 fdto,
383 fixup_child,
384 NULL
385 );
386 int tree_child;
387
388 tree_child = fdt_subnode_offset (
389 fdto,
390 tree_node,
391 fixup_child_name
392 );
393 if (tree_child == -FDT_ERR_NOTFOUND) {
394 return -FDT_ERR_BADOVERLAY;
395 }
396
397 if (tree_child < 0) {
398 return tree_child;
399 }
400
401 ret = overlay_update_local_node_references (
402 fdto,
403 tree_child,
404 fixup_child,
405 delta
406 );
407 if (ret) {
408 return ret;
409 }
410 }
411
412 return 0;
413}
414
432static int
433overlay_update_local_references (
434 void *fdto,
435 uint32_t delta
436 )
437{
438 int fixups;
439
440 fixups = fdt_path_offset (fdto, "/__local_fixups__");
441 if (fixups < 0) {
442 /* There's no local phandles to adjust, bail out */
443 if (fixups == -FDT_ERR_NOTFOUND) {
444 return 0;
445 }
446
447 return fixups;
448 }
449
450 /*
451 * Update our local references from the root of the tree
452 */
453 return overlay_update_local_node_references (
454 fdto,
455 0,
456 fixups,
457 delta
458 );
459}
460
484static int
485overlay_fixup_one_phandle (
486 void *fdt,
487 void *fdto,
488 int symbols_off,
489 const char *path,
490 uint32_t path_len,
491 const char *name,
492 uint32_t name_len,
493 int poffset,
494 const char *label
495 )
496{
497 const char *symbol_path;
498 uint32_t phandle;
499 fdt32_t phandle_prop;
500 int symbol_off, fixup_off;
501 int prop_len;
502
503 if (symbols_off < 0) {
504 return symbols_off;
505 }
506
507 symbol_path = fdt_getprop (
508 fdt,
509 symbols_off,
510 label,
511 &prop_len
512 );
513 if (!symbol_path) {
514 return prop_len;
515 }
516
517 symbol_off = fdt_path_offset (fdt, symbol_path);
518 if (symbol_off < 0) {
519 return symbol_off;
520 }
521
522 phandle = fdt_get_phandle (fdt, symbol_off);
523 if (!phandle) {
524 return -FDT_ERR_NOTFOUND;
525 }
526
527 fixup_off = fdt_path_offset_namelen (fdto, path, path_len);
528 if (fixup_off == -FDT_ERR_NOTFOUND) {
529 return -FDT_ERR_BADOVERLAY;
530 }
531
532 if (fixup_off < 0) {
533 return fixup_off;
534 }
535
536 phandle_prop = cpu_to_fdt32 (phandle);
537 return fdt_setprop_inplace_namelen_partial (
538 fdto,
539 fixup_off,
540 name,
541 name_len,
542 poffset,
543 &phandle_prop,
544 sizeof (phandle_prop)
545 );
546}
547
548unsigned long
549strtoul (
550 const char *nptr,
551 char **endptr,
552 int base
553 );
554
574static int
575overlay_fixup_phandle (
576 void *fdt,
577 void *fdto,
578 int symbols_off,
579 int property
580 )
581{
582 const char *value;
583 const char *label;
584 int len;
585
586 value = fdt_getprop_by_offset (
587 fdto,
588 property,
589 &label,
590 &len
591 );
592 if (!value) {
593 if (len == -FDT_ERR_NOTFOUND) {
594 return -FDT_ERR_INTERNAL;
595 }
596
597 return len;
598 }
599
600 do {
601 const char *path, *name, *fixup_end;
602 const char *fixup_str = value;
603 uint32_t path_len, name_len;
604 uint32_t fixup_len;
605 char *sep, *endptr;
606 int poffset, ret;
607
608 fixup_end = memchr (value, '\0', len);
609 if (!fixup_end) {
610 return -FDT_ERR_BADOVERLAY;
611 }
612
613 fixup_len = fixup_end - fixup_str;
614
615 len -= fixup_len + 1;
616 value += fixup_len + 1;
617
618 path = fixup_str;
619 sep = memchr (fixup_str, ':', fixup_len);
620 if (!sep || (*sep != ':')) {
621 return -FDT_ERR_BADOVERLAY;
622 }
623
624 path_len = sep - path;
625 if (path_len == (fixup_len - 1)) {
626 return -FDT_ERR_BADOVERLAY;
627 }
628
629 fixup_len -= path_len + 1;
630 name = sep + 1;
631 sep = memchr (name, ':', fixup_len);
632 if (!sep || (*sep != ':')) {
633 return -FDT_ERR_BADOVERLAY;
634 }
635
636 name_len = sep - name;
637 if (!name_len) {
638 return -FDT_ERR_BADOVERLAY;
639 }
640
641 poffset = strtoul (sep + 1, &endptr, 10);
642 if ((*endptr != '\0') || (endptr <= (sep + 1))) {
643 return -FDT_ERR_BADOVERLAY;
644 }
645
646 ret = overlay_fixup_one_phandle (
647 fdt,
648 fdto,
649 symbols_off,
650 path,
651 path_len,
652 name,
653 name_len,
654 poffset,
655 label
656 );
657 if (ret) {
658 return ret;
659 }
660 } while (len > 0);
661
662 return 0;
663}
664
682static int
683overlay_fixup_phandles (
684 void *fdt,
685 void *fdto
686 )
687{
688 int fixups_off, symbols_off;
689 int property;
690
691 /* We can have overlays without any fixups */
692 fixups_off = fdt_path_offset (fdto, "/__fixups__");
693 if (fixups_off == -FDT_ERR_NOTFOUND) {
694 return 0; /* nothing to do */
695 }
696
697 if (fixups_off < 0) {
698 return fixups_off;
699 }
700
701 /* And base DTs without symbols */
702 symbols_off = fdt_path_offset (fdt, "/__symbols__");
703 if (((symbols_off < 0) && (symbols_off != -FDT_ERR_NOTFOUND))) {
704 return symbols_off;
705 }
706
707 fdt_for_each_property_offset (property, fdto, fixups_off) {
708 int ret;
709
710 ret = overlay_fixup_phandle (fdt, fdto, symbols_off, property);
711 if (ret) {
712 return ret;
713 }
714 }
715
716 return 0;
717}
718
738static int
739overlay_apply_node (
740 void *fdt,
741 int target,
742 void *fdto,
743 int node
744 )
745{
746 int property;
747 int subnode;
748
749 fdt_for_each_property_offset (property, fdto, node) {
750 const char *name;
751 const void *prop;
752 int prop_len;
753 int ret;
754
755 prop = fdt_getprop_by_offset (
756 fdto,
757 property,
758 &name,
759 &prop_len
760 );
761 if (prop_len == -FDT_ERR_NOTFOUND) {
762 return -FDT_ERR_INTERNAL;
763 }
764
765 if (prop_len < 0) {
766 return prop_len;
767 }
768
769 ret = fdt_setprop (fdt, target, name, prop, prop_len);
770 if (ret) {
771 return ret;
772 }
773 }
774
775 fdt_for_each_subnode (subnode, fdto, node) {
776 const char *name = fdt_get_name (fdto, subnode, NULL);
777 int nnode;
778 int ret;
779
780 nnode = fdt_add_subnode (fdt, target, name);
781 if (nnode == -FDT_ERR_EXISTS) {
782 nnode = fdt_subnode_offset (fdt, target, name);
783 if (nnode == -FDT_ERR_NOTFOUND) {
784 return -FDT_ERR_INTERNAL;
785 }
786 }
787
788 if (nnode < 0) {
789 return nnode;
790 }
791
792 ret = overlay_apply_node (fdt, nnode, fdto, subnode);
793 if (ret) {
794 return ret;
795 }
796 }
797
798 return 0;
799}
800
816static int
817overlay_merge (
818 void *fdt,
819 void *fdto
820 )
821{
822 int fragment;
823
824 fdt_for_each_subnode (fragment, fdto, 0) {
825 int overlay;
826 int target;
827 int ret;
828
829 /*
830 * Each fragments will have an __overlay__ node. If
831 * they don't, it's not supposed to be merged
832 */
833 overlay = fdt_subnode_offset (fdto, fragment, "__overlay__");
834 if (overlay == -FDT_ERR_NOTFOUND) {
835 continue;
836 }
837
838 if (overlay < 0) {
839 return overlay;
840 }
841
842 target = overlay_get_target (fdt, fdto, fragment, NULL);
843 if (target < 0) {
844 return target;
845 }
846
847 ret = overlay_apply_node (fdt, target, fdto, overlay);
848 if (ret) {
849 return ret;
850 }
851 }
852
853 return 0;
854}
855
856static int
857get_path_len (
858 const void *fdt,
859 int nodeoffset
860 )
861{
862 int len = 0, namelen;
863 const char *name;
864
865 FDT_CHECK_HEADER (fdt);
866
867 for ( ; ;) {
868 name = fdt_get_name (fdt, nodeoffset, &namelen);
869 if (!name) {
870 return namelen;
871 }
872
873 /* root? we're done */
874 if (namelen == 0) {
875 break;
876 }
877
878 nodeoffset = fdt_parent_offset (fdt, nodeoffset);
879 if (nodeoffset < 0) {
880 return nodeoffset;
881 }
882
883 len += namelen + 1;
884 }
885
886 /* in case of root pretend it's "/" */
887 if (len == 0) {
888 len++;
889 }
890
891 return len;
892}
893
910static int
911overlay_symbol_update (
912 void *fdt,
913 void *fdto
914 )
915{
916 int root_sym, ov_sym, prop, path_len, fragment, target;
917 int len, frag_name_len, ret, rel_path_len;
918 const char *s, *e;
919 const char *path;
920 const char *name;
921 const char *frag_name;
922 const char *rel_path;
923 const char *target_path;
924 char *buf;
925 void *p;
926
927 ov_sym = fdt_subnode_offset (fdto, 0, "__symbols__");
928
929 /* if no overlay symbols exist no problem */
930 if (ov_sym < 0) {
931 return 0;
932 }
933
934 root_sym = fdt_subnode_offset (fdt, 0, "__symbols__");
935
936 /* it no root symbols exist we should create them */
937 if (root_sym == -FDT_ERR_NOTFOUND) {
938 root_sym = fdt_add_subnode (fdt, 0, "__symbols__");
939 }
940
941 /* any error is fatal now */
942 if (root_sym < 0) {
943 return root_sym;
944 }
945
946 /* iterate over each overlay symbol */
947 fdt_for_each_property_offset (prop, fdto, ov_sym) {
948 path = fdt_getprop_by_offset (fdto, prop, &name, &path_len);
949 if (!path) {
950 return path_len;
951 }
952
953 /* verify it's a string property (terminated by a single \0) */
954 if ((path_len < 1) || (memchr (path, '\0', path_len) != &path[path_len - 1])) {
955 return -FDT_ERR_BADVALUE;
956 }
957
958 /* keep end marker to avoid strlen() */
959 e = path + path_len;
960
961 /* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
962
963 if (*path != '/') {
964 return -FDT_ERR_BADVALUE;
965 }
966
967 /* get fragment name first */
968 s = strchr (path + 1, '/');
969 if (!s) {
970 return -FDT_ERR_BADOVERLAY;
971 }
972
973 frag_name = path + 1;
974 frag_name_len = s - path - 1;
975
976 /* verify format; safe since "s" lies in \0 terminated prop */
977 len = sizeof ("/__overlay__/") - 1;
978 if (((e - s) < len) || memcmp (s, "/__overlay__/", len)) {
979 return -FDT_ERR_BADOVERLAY;
980 }
981
982 rel_path = s + len;
983 rel_path_len = e - rel_path;
984
985 /* find the fragment index in which the symbol lies */
986 ret = fdt_subnode_offset_namelen (
987 fdto,
988 0,
989 frag_name,
990 frag_name_len
991 );
992 /* not found? */
993 if (ret < 0) {
994 return -FDT_ERR_BADOVERLAY;
995 }
996
997 fragment = ret;
998
999 /* an __overlay__ subnode must exist */
1000 ret = fdt_subnode_offset (fdto, fragment, "__overlay__");
1001 if (ret < 0) {
1002 return -FDT_ERR_BADOVERLAY;
1003 }
1004
1005 /* get the target of the fragment */
1006 ret = overlay_get_target (fdt, fdto, fragment, &target_path);
1007 if (ret < 0) {
1008 return ret;
1009 }
1010
1011 target = ret;
1012
1013 /* if we have a target path use */
1014 if (!target_path) {
1015 ret = get_path_len (fdt, target);
1016 if (ret < 0) {
1017 return ret;
1018 }
1019
1020 len = ret;
1021 } else {
1022 len = strlen (target_path);
1023 }
1024
1025 ret = fdt_setprop_placeholder (
1026 fdt,
1027 root_sym,
1028 name,
1029 len + (len > 1) + rel_path_len + 1,
1030 &p
1031 );
1032 if (ret < 0) {
1033 return ret;
1034 }
1035
1036 if (!target_path) {
1037 /* again in case setprop_placeholder changed it */
1038 ret = overlay_get_target (fdt, fdto, fragment, &target_path);
1039 if (ret < 0) {
1040 return ret;
1041 }
1042
1043 target = ret;
1044 }
1045
1046 buf = p;
1047 if (len > 1) {
1048 /* target is not root */
1049 if (!target_path) {
1050 ret = fdt_get_path (fdt, target, buf, len + 1);
1051 if (ret < 0) {
1052 return ret;
1053 }
1054 } else {
1055 memcpy (buf, target_path, len + 1);
1056 }
1057 } else {
1058 len--;
1059 }
1060
1061 buf[len] = '/';
1062 memcpy (buf + len + 1, rel_path, rel_path_len);
1063 buf[len + 1 + rel_path_len] = '\0';
1064 }
1065
1066 return 0;
1067}
1068
1069int
1070fdt_overlay_apply (
1071 void *fdt,
1072 void *fdto
1073 )
1074{
1075 uint32_t delta = fdt_get_max_phandle (fdt);
1076 int ret;
1077
1078 FDT_CHECK_HEADER (fdt);
1079 FDT_CHECK_HEADER (fdto);
1080
1081 ret = overlay_adjust_local_phandles (fdto, delta);
1082 if (ret) {
1083 goto err;
1084 }
1085
1086 ret = overlay_update_local_references (fdto, delta);
1087 if (ret) {
1088 goto err;
1089 }
1090
1091 ret = overlay_fixup_phandles (fdt, fdto);
1092 if (ret) {
1093 goto err;
1094 }
1095
1096 ret = overlay_merge (fdt, fdto);
1097 if (ret) {
1098 goto err;
1099 }
1100
1101 ret = overlay_symbol_update (fdt, fdto);
1102 if (ret) {
1103 goto err;
1104 }
1105
1106 /*
1107 * The overlay has been damaged, erase its magic.
1108 */
1109 fdt_set_magic (fdto, ~0);
1110
1111 return 0;
1112
1113err:
1114
1115 /*
1116 * The overlay might have been damaged, erase its magic.
1117 */
1118 fdt_set_magic (fdto, ~0);
1119
1120 /*
1121 * The base device tree might have been damaged, erase its
1122 * magic.
1123 */
1124 fdt_set_magic (fdt, ~0);
1125
1126 return ret;
1127}
#define NULL
Definition: Base.h:319