1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2016 NextThing Co
3*4882a593Smuzhiyun * Copyright (c) 2016 Free Electrons
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <command.h>
10*4882a593Smuzhiyun #include <errno.h>
11*4882a593Smuzhiyun #include <malloc.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/sizes.h>
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <test/ut.h>
16*4882a593Smuzhiyun #include <test/overlay.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun /* 4k ought to be enough for anybody */
19*4882a593Smuzhiyun #define FDT_COPY_SIZE (4 * SZ_1K)
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun extern u32 __dtb_test_fdt_base_begin;
22*4882a593Smuzhiyun extern u32 __dtb_test_fdt_overlay_begin;
23*4882a593Smuzhiyun extern u32 __dtb_test_fdt_overlay_stacked_begin;
24*4882a593Smuzhiyun
ut_fdt_getprop_u32_by_index(void * fdt,const char * path,const char * name,int index,u32 * out)25*4882a593Smuzhiyun static int ut_fdt_getprop_u32_by_index(void *fdt, const char *path,
26*4882a593Smuzhiyun const char *name, int index,
27*4882a593Smuzhiyun u32 *out)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun const fdt32_t *val;
30*4882a593Smuzhiyun int node_off;
31*4882a593Smuzhiyun int len;
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun node_off = fdt_path_offset(fdt, path);
34*4882a593Smuzhiyun if (node_off < 0)
35*4882a593Smuzhiyun return node_off;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun val = fdt_getprop(fdt, node_off, name, &len);
38*4882a593Smuzhiyun if (!val || (len < (sizeof(uint32_t) * (index + 1))))
39*4882a593Smuzhiyun return -FDT_ERR_NOTFOUND;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun *out = fdt32_to_cpu(*(val + index));
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun return 0;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
ut_fdt_getprop_u32(void * fdt,const char * path,const char * name,u32 * out)46*4882a593Smuzhiyun static int ut_fdt_getprop_u32(void *fdt, const char *path, const char *name,
47*4882a593Smuzhiyun u32 *out)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun return ut_fdt_getprop_u32_by_index(fdt, path, name, 0, out);
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
fdt_getprop_str(void * fdt,const char * path,const char * name,const char ** out)52*4882a593Smuzhiyun static int fdt_getprop_str(void *fdt, const char *path, const char *name,
53*4882a593Smuzhiyun const char **out)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun int node_off;
56*4882a593Smuzhiyun int len;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun node_off = fdt_path_offset(fdt, path);
59*4882a593Smuzhiyun if (node_off < 0)
60*4882a593Smuzhiyun return node_off;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun *out = fdt_stringlist_get(fdt, node_off, name, 0, &len);
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun return len < 0 ? len : 0;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
fdt_overlay_change_int_property(struct unit_test_state * uts)67*4882a593Smuzhiyun static int fdt_overlay_change_int_property(struct unit_test_state *uts)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun void *fdt = uts->priv;
70*4882a593Smuzhiyun u32 val = 0;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun ut_assertok(ut_fdt_getprop_u32(fdt, "/test-node", "test-int-property",
73*4882a593Smuzhiyun &val));
74*4882a593Smuzhiyun ut_asserteq(43, val);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun return CMD_RET_SUCCESS;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun OVERLAY_TEST(fdt_overlay_change_int_property, 0);
79*4882a593Smuzhiyun
fdt_overlay_change_str_property(struct unit_test_state * uts)80*4882a593Smuzhiyun static int fdt_overlay_change_str_property(struct unit_test_state *uts)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun void *fdt = uts->priv;
83*4882a593Smuzhiyun const char *val = NULL;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property",
86*4882a593Smuzhiyun &val));
87*4882a593Smuzhiyun ut_asserteq_str("foobar", val);
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun return CMD_RET_SUCCESS;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun OVERLAY_TEST(fdt_overlay_change_str_property, 0);
92*4882a593Smuzhiyun
fdt_overlay_add_str_property(struct unit_test_state * uts)93*4882a593Smuzhiyun static int fdt_overlay_add_str_property(struct unit_test_state *uts)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun void *fdt = uts->priv;
96*4882a593Smuzhiyun const char *val = NULL;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun ut_assertok(fdt_getprop_str(fdt, "/test-node", "test-str-property-2",
99*4882a593Smuzhiyun &val));
100*4882a593Smuzhiyun ut_asserteq_str("foobar2", val);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun return CMD_RET_SUCCESS;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun OVERLAY_TEST(fdt_overlay_add_str_property, 0);
105*4882a593Smuzhiyun
fdt_overlay_add_node_by_phandle(struct unit_test_state * uts)106*4882a593Smuzhiyun static int fdt_overlay_add_node_by_phandle(struct unit_test_state *uts)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun void *fdt = uts->priv;
109*4882a593Smuzhiyun int off;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun off = fdt_path_offset(fdt, "/test-node/new-node");
112*4882a593Smuzhiyun ut_assert(off >= 0);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL));
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun return CMD_RET_SUCCESS;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun OVERLAY_TEST(fdt_overlay_add_node_by_phandle, 0);
119*4882a593Smuzhiyun
fdt_overlay_add_node_by_path(struct unit_test_state * uts)120*4882a593Smuzhiyun static int fdt_overlay_add_node_by_path(struct unit_test_state *uts)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun void *fdt = uts->priv;
123*4882a593Smuzhiyun int off;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun off = fdt_path_offset(fdt, "/new-node");
126*4882a593Smuzhiyun ut_assert(off >= 0);
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun ut_assertnonnull(fdt_getprop(fdt, off, "new-property", NULL));
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun return CMD_RET_SUCCESS;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun OVERLAY_TEST(fdt_overlay_add_node_by_path, 0);
133*4882a593Smuzhiyun
fdt_overlay_add_subnode_property(struct unit_test_state * uts)134*4882a593Smuzhiyun static int fdt_overlay_add_subnode_property(struct unit_test_state *uts)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun void *fdt = uts->priv;
137*4882a593Smuzhiyun int off;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun off = fdt_path_offset(fdt, "/test-node/sub-test-node");
140*4882a593Smuzhiyun ut_assert(off >= 0);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun ut_assertnonnull(fdt_getprop(fdt, off, "sub-test-property", NULL));
143*4882a593Smuzhiyun ut_assertnonnull(fdt_getprop(fdt, off, "new-sub-test-property", NULL));
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun return CMD_RET_SUCCESS;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun OVERLAY_TEST(fdt_overlay_add_subnode_property, 0);
148*4882a593Smuzhiyun
fdt_overlay_local_phandle(struct unit_test_state * uts)149*4882a593Smuzhiyun static int fdt_overlay_local_phandle(struct unit_test_state *uts)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun uint32_t local_phandle;
152*4882a593Smuzhiyun void *fdt = uts->priv;
153*4882a593Smuzhiyun u32 val = 0;
154*4882a593Smuzhiyun int off;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun off = fdt_path_offset(fdt, "/new-local-node");
157*4882a593Smuzhiyun ut_assert(off >= 0);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun local_phandle = fdt_get_phandle(fdt, off);
160*4882a593Smuzhiyun ut_assert(local_phandle);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
163*4882a593Smuzhiyun 0, &val));
164*4882a593Smuzhiyun ut_asserteq(local_phandle, val);
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-several-phandle",
167*4882a593Smuzhiyun 1, &val));
168*4882a593Smuzhiyun ut_asserteq(local_phandle, val);
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun return CMD_RET_SUCCESS;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun OVERLAY_TEST(fdt_overlay_local_phandle, 0);
173*4882a593Smuzhiyun
fdt_overlay_local_phandles(struct unit_test_state * uts)174*4882a593Smuzhiyun static int fdt_overlay_local_phandles(struct unit_test_state *uts)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun uint32_t local_phandle, test_phandle;
177*4882a593Smuzhiyun void *fdt = uts->priv;
178*4882a593Smuzhiyun u32 val = 0;
179*4882a593Smuzhiyun int off;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun off = fdt_path_offset(fdt, "/new-local-node");
182*4882a593Smuzhiyun ut_assert(off >= 0);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun local_phandle = fdt_get_phandle(fdt, off);
185*4882a593Smuzhiyun ut_assert(local_phandle);
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun off = fdt_path_offset(fdt, "/test-node");
188*4882a593Smuzhiyun ut_assert(off >= 0);
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun test_phandle = fdt_get_phandle(fdt, off);
191*4882a593Smuzhiyun ut_assert(test_phandle);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 0,
194*4882a593Smuzhiyun &val));
195*4882a593Smuzhiyun ut_asserteq(test_phandle, val);
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun ut_assertok(ut_fdt_getprop_u32_by_index(fdt, "/", "test-phandle", 1,
198*4882a593Smuzhiyun &val));
199*4882a593Smuzhiyun ut_asserteq(local_phandle, val);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun return CMD_RET_SUCCESS;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun OVERLAY_TEST(fdt_overlay_local_phandles, 0);
204*4882a593Smuzhiyun
fdt_overlay_stacked(struct unit_test_state * uts)205*4882a593Smuzhiyun static int fdt_overlay_stacked(struct unit_test_state *uts)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun void *fdt = uts->priv;
208*4882a593Smuzhiyun u32 val = 0;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun ut_assertok(ut_fdt_getprop_u32(fdt, "/new-local-node",
211*4882a593Smuzhiyun "stacked-test-int-property", &val));
212*4882a593Smuzhiyun ut_asserteq(43, val);
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun return CMD_RET_SUCCESS;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun OVERLAY_TEST(fdt_overlay_stacked, 0);
217*4882a593Smuzhiyun
do_ut_overlay(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])218*4882a593Smuzhiyun int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun struct unit_test *tests = ll_entry_start(struct unit_test,
221*4882a593Smuzhiyun overlay_test);
222*4882a593Smuzhiyun const int n_ents = ll_entry_count(struct unit_test, overlay_test);
223*4882a593Smuzhiyun struct unit_test_state *uts;
224*4882a593Smuzhiyun struct unit_test *test;
225*4882a593Smuzhiyun void *fdt_base = &__dtb_test_fdt_base_begin;
226*4882a593Smuzhiyun void *fdt_overlay = &__dtb_test_fdt_overlay_begin;
227*4882a593Smuzhiyun void *fdt_overlay_stacked = &__dtb_test_fdt_overlay_stacked_begin;
228*4882a593Smuzhiyun void *fdt_base_copy, *fdt_overlay_copy, *fdt_overlay_stacked_copy;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun uts = calloc(1, sizeof(*uts));
231*4882a593Smuzhiyun if (!uts)
232*4882a593Smuzhiyun return -ENOMEM;
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun ut_assertok(fdt_check_header(fdt_base));
235*4882a593Smuzhiyun ut_assertok(fdt_check_header(fdt_overlay));
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun fdt_base_copy = malloc(FDT_COPY_SIZE);
238*4882a593Smuzhiyun if (!fdt_base_copy)
239*4882a593Smuzhiyun return -ENOMEM;
240*4882a593Smuzhiyun uts->priv = fdt_base_copy;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun fdt_overlay_copy = malloc(FDT_COPY_SIZE);
243*4882a593Smuzhiyun if (!fdt_overlay_copy)
244*4882a593Smuzhiyun return -ENOMEM;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun fdt_overlay_stacked_copy = malloc(FDT_COPY_SIZE);
247*4882a593Smuzhiyun if (!fdt_overlay_stacked_copy)
248*4882a593Smuzhiyun return -ENOMEM;
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun /*
251*4882a593Smuzhiyun * Resize the FDT to 4k so that we have room to operate on
252*4882a593Smuzhiyun *
253*4882a593Smuzhiyun * (and relocate it since the memory might be mapped
254*4882a593Smuzhiyun * read-only)
255*4882a593Smuzhiyun */
256*4882a593Smuzhiyun ut_assertok(fdt_open_into(fdt_base, fdt_base_copy, FDT_COPY_SIZE));
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun /*
259*4882a593Smuzhiyun * Resize the overlay to 4k so that we have room to operate on
260*4882a593Smuzhiyun *
261*4882a593Smuzhiyun * (and relocate it since the memory might be mapped
262*4882a593Smuzhiyun * read-only)
263*4882a593Smuzhiyun */
264*4882a593Smuzhiyun ut_assertok(fdt_open_into(fdt_overlay, fdt_overlay_copy,
265*4882a593Smuzhiyun FDT_COPY_SIZE));
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun /*
268*4882a593Smuzhiyun * Resize the stacked overlay to 4k so that we have room to operate on
269*4882a593Smuzhiyun *
270*4882a593Smuzhiyun * (and relocate it since the memory might be mapped
271*4882a593Smuzhiyun * read-only)
272*4882a593Smuzhiyun */
273*4882a593Smuzhiyun ut_assertok(fdt_open_into(fdt_overlay_stacked, fdt_overlay_stacked_copy,
274*4882a593Smuzhiyun FDT_COPY_SIZE));
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun /* Apply the overlay */
277*4882a593Smuzhiyun ut_assertok(fdt_overlay_apply(fdt_base_copy, fdt_overlay_copy));
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /* Apply the stacked overlay */
280*4882a593Smuzhiyun ut_assertok(fdt_overlay_apply(fdt_base_copy, fdt_overlay_stacked_copy));
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun if (argc == 1)
283*4882a593Smuzhiyun printf("Running %d environment tests\n", n_ents);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun for (test = tests; test < tests + n_ents; test++) {
286*4882a593Smuzhiyun if (argc > 1 && strcmp(argv[1], test->name))
287*4882a593Smuzhiyun continue;
288*4882a593Smuzhiyun printf("Test: %s\n", test->name);
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun uts->start = mallinfo();
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun test->func(uts);
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun printf("Failures: %d\n", uts->fail_count);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun free(fdt_overlay_stacked_copy);
298*4882a593Smuzhiyun free(fdt_overlay_copy);
299*4882a593Smuzhiyun free(fdt_base_copy);
300*4882a593Smuzhiyun free(uts);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun return uts->fail_count ? CMD_RET_FAILURE : 0;
303*4882a593Smuzhiyun }
304