1 /*
2 * libfdt - Flat Device Tree manipulation
3 * Testcase for DT overlays()
4 * Copyright (C) 2016 Free Electrons
5 * Copyright (C) 2016 NextThing Co.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * as published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <stdio.h>
23
24 #include <libfdt.h>
25
26 #include "tests.h"
27
28 #define CHECK(code) \
29 { \
30 int err = (code); \
31 if (err) \
32 FAIL(#code ": %s", fdt_strerror(err)); \
33 }
34
35 /* 4k ought to be enough for anybody */
36 #define FDT_COPY_SIZE (4 * 1024)
37
fdt_getprop_u32_by_poffset(void * fdt,const char * path,const char * name,int poffset,unsigned long * out)38 static int fdt_getprop_u32_by_poffset(void *fdt, const char *path,
39 const char *name, int poffset,
40 unsigned long *out)
41 {
42 const fdt32_t *val;
43 int node_off;
44 int len;
45
46 node_off = fdt_path_offset(fdt, path);
47 if (node_off < 0)
48 return node_off;
49
50 val = fdt_getprop(fdt, node_off, name, &len);
51 if (!val || (len < (sizeof(uint32_t) * (poffset + 1))))
52 return -FDT_ERR_NOTFOUND;
53
54 *out = fdt32_to_cpu(*(val + poffset));
55
56 return 0;
57 }
58
check_getprop_string_by_name(void * fdt,const char * path,const char * name,const char * val)59 static int check_getprop_string_by_name(void *fdt, const char *path,
60 const char *name, const char *val)
61 {
62 int node_off;
63
64 node_off = fdt_path_offset(fdt, path);
65 if (node_off < 0)
66 return node_off;
67
68 check_getprop_string(fdt, node_off, name, val);
69
70 return 0;
71 }
72
check_getprop_u32_by_name(void * fdt,const char * path,const char * name,uint32_t val)73 static int check_getprop_u32_by_name(void *fdt, const char *path,
74 const char *name, uint32_t val)
75 {
76 int node_off;
77
78 node_off = fdt_path_offset(fdt, path);
79 CHECK(node_off < 0);
80
81 check_getprop_cell(fdt, node_off, name, val);
82
83 return 0;
84 }
85
check_getprop_null_by_name(void * fdt,const char * path,const char * name)86 static int check_getprop_null_by_name(void *fdt, const char *path,
87 const char *name)
88 {
89 int node_off;
90
91 node_off = fdt_path_offset(fdt, path);
92 CHECK(node_off < 0);
93
94 check_property(fdt, node_off, name, 0, NULL);
95
96 return 0;
97 }
98
fdt_overlay_change_int_property(void * fdt)99 static int fdt_overlay_change_int_property(void *fdt)
100 {
101 return check_getprop_u32_by_name(fdt, "/test-node", "test-int-property",
102 43);
103 }
104
fdt_overlay_change_str_property(void * fdt)105 static int fdt_overlay_change_str_property(void *fdt)
106 {
107 return check_getprop_string_by_name(fdt, "/test-node",
108 "test-str-property", "foobar");
109 }
110
fdt_overlay_add_str_property(void * fdt)111 static int fdt_overlay_add_str_property(void *fdt)
112 {
113 return check_getprop_string_by_name(fdt, "/test-node",
114 "test-str-property-2", "foobar2");
115 }
116
fdt_overlay_add_node(void * fdt)117 static int fdt_overlay_add_node(void *fdt)
118 {
119 return check_getprop_null_by_name(fdt, "/test-node/new-node",
120 "new-property");
121 }
122
fdt_overlay_add_subnode_property(void * fdt)123 static int fdt_overlay_add_subnode_property(void *fdt)
124 {
125 check_getprop_null_by_name(fdt, "/test-node/sub-test-node",
126 "sub-test-property");
127 check_getprop_null_by_name(fdt, "/test-node/sub-test-node",
128 "new-sub-test-property");
129
130 return 0;
131 }
132
fdt_overlay_local_phandle(void * fdt)133 static int fdt_overlay_local_phandle(void *fdt)
134 {
135 uint32_t local_phandle;
136 unsigned long val = 0;
137 int off;
138
139 off = fdt_path_offset(fdt, "/test-node/new-local-node");
140 CHECK(off < 0);
141
142 local_phandle = fdt_get_phandle(fdt, off);
143 CHECK(!local_phandle);
144
145 CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node",
146 "test-several-phandle",
147 0, &val));
148 CHECK(val != local_phandle);
149
150 CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node",
151 "test-several-phandle",
152 1, &val));
153 CHECK(val != local_phandle);
154
155 return 0;
156 }
157
fdt_overlay_local_phandles(void * fdt)158 static int fdt_overlay_local_phandles(void *fdt)
159 {
160 uint32_t local_phandle, test_phandle;
161 unsigned long val = 0;
162 int off;
163
164 off = fdt_path_offset(fdt, "/test-node/new-local-node");
165 CHECK(off < 0);
166
167 local_phandle = fdt_get_phandle(fdt, off);
168 CHECK(!local_phandle);
169
170 off = fdt_path_offset(fdt, "/test-node");
171 CHECK(off < 0);
172
173 test_phandle = fdt_get_phandle(fdt, off);
174 CHECK(!test_phandle);
175
176 CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node",
177 "test-phandle", 0, &val));
178 CHECK(test_phandle != val);
179
180 CHECK(fdt_getprop_u32_by_poffset(fdt, "/test-node",
181 "test-phandle", 1, &val));
182 CHECK(local_phandle != val);
183
184 return 0;
185 }
186
open_dt(char * path)187 static void *open_dt(char *path)
188 {
189 void *dt, *copy;
190
191 dt = load_blob(path);
192 copy = xmalloc(FDT_COPY_SIZE);
193
194 /*
195 * Resize our DTs to 4k so that we have room to operate on
196 */
197 CHECK(fdt_open_into(dt, copy, FDT_COPY_SIZE));
198
199 return copy;
200 }
201
main(int argc,char * argv[])202 int main(int argc, char *argv[])
203 {
204 void *fdt_base, *fdt_overlay;
205
206 test_init(argc, argv);
207 if (argc != 3)
208 CONFIG("Usage: %s <base dtb> <overlay dtb>", argv[0]);
209
210 fdt_base = open_dt(argv[1]);
211 fdt_overlay = open_dt(argv[2]);
212
213 /* Apply the overlay */
214 CHECK(fdt_overlay_apply(fdt_base, fdt_overlay));
215
216 fdt_overlay_change_int_property(fdt_base);
217 fdt_overlay_change_str_property(fdt_base);
218 fdt_overlay_add_str_property(fdt_base);
219 fdt_overlay_add_node(fdt_base);
220 fdt_overlay_add_subnode_property(fdt_base);
221
222 /*
223 * If the base tree has a __symbols__ node, do the tests that
224 * are only successful with a proper phandle support, and thus
225 * dtc -@
226 */
227 if (fdt_path_offset(fdt_base, "/__symbols__") >= 0) {
228 fdt_overlay_local_phandle(fdt_base);
229 fdt_overlay_local_phandles(fdt_base);
230 }
231
232 PASS();
233 }
234