blob: dabd35fbb5d010012d37928742360d7bbd01a815 [file] [log] [blame]
Simon Glass74724482022-07-13 06:06:59 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Tests for fdt command
4 *
5 * Copyright 2022 Google LLCmap_to_sysmem(fdt));
6 */
7
8#include <common.h>
9#include <console.h>
10#include <fdt_support.h>
11#include <mapmem.h>
12#include <asm/global_data.h>
13#include <linux/libfdt.h>
14#include <test/suites.h>
15#include <test/ut.h>
16
17DECLARE_GLOBAL_DATA_PTR;
18
19/* Declare a new fdt test */
20#define FDT_TEST(_name, _flags) UNIT_TEST(_name, _flags, fdt_test)
21
22/**
23 * make_test_fdt() - Create an FDT with just a root node
24 *
25 * The size is set to the minimum needed
26 *
27 * @uts: Test state
28 * @fdt: Place to write FDT
29 * @size: Maximum size of space for fdt
30 */
31static int make_test_fdt(struct unit_test_state *uts, void *fdt, int size)
32{
33 ut_assertok(fdt_create(fdt, size));
34 ut_assertok(fdt_finish_reservemap(fdt));
35 ut_assert(fdt_begin_node(fdt, "") >= 0);
36 ut_assertok(fdt_end_node(fdt));
37 ut_assertok(fdt_finish(fdt));
38
39 return 0;
40}
41
Marek Vasut21e1d93b2023-03-02 04:08:27 +010042/**
43 * make_fuller_fdt() - Create an FDT with root node and properties
44 *
45 * The size is set to the minimum needed
46 *
47 * @uts: Test state
48 * @fdt: Place to write FDT
49 * @size: Maximum size of space for fdt
50 */
51static int make_fuller_fdt(struct unit_test_state *uts, void *fdt, int size)
52{
53 fdt32_t regs[2] = { cpu_to_fdt32(0x1234), cpu_to_fdt32(0x1000) };
54
55 /*
56 * Assemble the following DT for test purposes:
57 *
58 * / {
59 * #address-cells = <0x00000001>;
60 * #size-cells = <0x00000001>;
61 * compatible = "u-boot,fdt-test";
62 * model = "U-Boot FDT test";
63 *
64 * aliases {
65 * badalias = "/bad/alias";
66 * subnodealias = "/test-node@1234/subnode";
67 * testnodealias = "/test-node@1234";
68 * };
69 *
70 * test-node@1234 {
71 * #address-cells = <0x00000000>;
72 * #size-cells = <0x00000000>;
73 * compatible = "u-boot,fdt-test-device1";
74 * clock-names = "fixed", "i2c", "spi", "uart2", "uart1";
75 * u-boot,empty-property;
76 * clock-frequency = <0x00fde800>;
77 * regs = <0x00001234 0x00001000>;
78 *
79 * subnode {
80 * #address-cells = <0x00000000>;
81 * #size-cells = <0x00000000>;
82 * compatible = "u-boot,fdt-subnode-test-device";
83 * };
84 * };
85 * };
86 */
87
88 ut_assertok(fdt_create(fdt, size));
89 ut_assertok(fdt_finish_reservemap(fdt));
90 ut_assert(fdt_begin_node(fdt, "") >= 0);
91
92 ut_assertok(fdt_property_u32(fdt, "#address-cells", 1));
93 ut_assertok(fdt_property_u32(fdt, "#size-cells", 1));
94 /* <string> */
95 ut_assertok(fdt_property_string(fdt, "compatible", "u-boot,fdt-test"));
96 /* <string> */
97 ut_assertok(fdt_property_string(fdt, "model", "U-Boot FDT test"));
98
99 ut_assert(fdt_begin_node(fdt, "aliases") >= 0);
100 /* <string> */
101 ut_assertok(fdt_property_string(fdt, "badalias", "/bad/alias"));
102 /* <string> */
103 ut_assertok(fdt_property_string(fdt, "subnodealias", "/test-node@1234/subnode"));
104 /* <string> */
105 ut_assertok(fdt_property_string(fdt, "testnodealias", "/test-node@1234"));
106 ut_assertok(fdt_end_node(fdt));
107
108 ut_assert(fdt_begin_node(fdt, "test-node@1234") >= 0);
109 ut_assertok(fdt_property_cell(fdt, "#address-cells", 0));
110 ut_assertok(fdt_property_cell(fdt, "#size-cells", 0));
111 /* <string> */
112 ut_assertok(fdt_property_string(fdt, "compatible", "u-boot,fdt-test-device1"));
113 /* <stringlist> */
114 ut_assertok(fdt_property(fdt, "clock-names", "fixed\0i2c\0spi\0uart2\0uart1\0", 26));
115 /* <empty> */
116 ut_assertok(fdt_property(fdt, "u-boot,empty-property", NULL, 0));
117 /*
118 * <u32>
119 * This value is deliberate as it used to break cmd/fdt.c
120 * is_printable_string() implementation.
121 */
122 ut_assertok(fdt_property_u32(fdt, "clock-frequency", 16640000));
123 /* <prop-encoded-array> */
124 ut_assertok(fdt_property(fdt, "regs", &regs, sizeof(regs)));
125 ut_assert(fdt_begin_node(fdt, "subnode") >= 0);
126 ut_assertok(fdt_property_cell(fdt, "#address-cells", 0));
127 ut_assertok(fdt_property_cell(fdt, "#size-cells", 0));
128 ut_assertok(fdt_property_string(fdt, "compatible", "u-boot,fdt-subnode-test-device"));
129 ut_assertok(fdt_end_node(fdt));
130 ut_assertok(fdt_end_node(fdt));
131
132 ut_assertok(fdt_end_node(fdt));
133 ut_assertok(fdt_finish(fdt));
134
135 return 0;
136}
137
Simon Glass74724482022-07-13 06:06:59 -0600138/* Test 'fdt addr' getting/setting address */
139static int fdt_test_addr(struct unit_test_state *uts)
140{
141 const void *fdt_blob, *new_fdt;
142 char fdt[256];
143 ulong addr;
144 int ret;
145
146 ut_assertok(console_record_reset_enable());
147 ut_assertok(run_command("fdt addr -c", 0));
148 ut_assert_nextline("Control fdt: %08lx",
149 (ulong)map_to_sysmem(gd->fdt_blob));
150 ut_assertok(ut_check_console_end(uts));
151
152 /* The working fdt is not set, so this should fail */
153 set_working_fdt_addr(0);
Simon Glassbaf41412022-10-11 09:47:12 -0600154 ut_assert_nextline("Working FDT set to 0");
Simon Glass74724482022-07-13 06:06:59 -0600155 ut_asserteq(CMD_RET_FAILURE, run_command("fdt addr", 0));
156 ut_assert_nextline("libfdt fdt_check_header(): FDT_ERR_BADMAGIC");
157 ut_assertok(ut_check_console_end(uts));
158
159 /* Set up a working FDT and try again */
160 ut_assertok(make_test_fdt(uts, fdt, sizeof(fdt)));
161 addr = map_to_sysmem(fdt);
162 set_working_fdt_addr(addr);
Simon Glassbaf41412022-10-11 09:47:12 -0600163 ut_assert_nextline("Working FDT set to %lx", addr);
Simon Glass74724482022-07-13 06:06:59 -0600164 ut_assertok(run_command("fdt addr", 0));
165 ut_assert_nextline("Working fdt: %08lx", (ulong)map_to_sysmem(fdt));
166 ut_assertok(ut_check_console_end(uts));
167
168 /* Set the working FDT */
169 set_working_fdt_addr(0);
Simon Glassbaf41412022-10-11 09:47:12 -0600170 ut_assert_nextline("Working FDT set to 0");
Simon Glass74724482022-07-13 06:06:59 -0600171 ut_assertok(run_commandf("fdt addr %08x", addr));
Simon Glassbaf41412022-10-11 09:47:12 -0600172 ut_assert_nextline("Working FDT set to %lx", addr);
Simon Glass74724482022-07-13 06:06:59 -0600173 ut_asserteq(addr, map_to_sysmem(working_fdt));
174 ut_assertok(ut_check_console_end(uts));
175 set_working_fdt_addr(0);
Simon Glassbaf41412022-10-11 09:47:12 -0600176 ut_assert_nextline("Working FDT set to 0");
Simon Glass74724482022-07-13 06:06:59 -0600177
Simon Glassbaf41412022-10-11 09:47:12 -0600178 /* Set the control FDT */
Simon Glass74724482022-07-13 06:06:59 -0600179 fdt_blob = gd->fdt_blob;
180 gd->fdt_blob = NULL;
181 ret = run_commandf("fdt addr -c %08x", addr);
182 new_fdt = gd->fdt_blob;
183 gd->fdt_blob = fdt_blob;
184 ut_assertok(ret);
185 ut_asserteq(addr, map_to_sysmem(new_fdt));
186 ut_assertok(ut_check_console_end(uts));
187
188 /* Test setting an invalid FDT */
189 fdt[0] = 123;
190 ut_asserteq(1, run_commandf("fdt addr %08x", addr));
191 ut_assert_nextline("libfdt fdt_check_header(): FDT_ERR_BADMAGIC");
192 ut_assertok(ut_check_console_end(uts));
193
194 /* Test detecting an invalid FDT */
195 fdt[0] = 123;
196 set_working_fdt_addr(addr);
Simon Glassbaf41412022-10-11 09:47:12 -0600197 ut_assert_nextline("Working FDT set to %lx", addr);
Simon Glass74724482022-07-13 06:06:59 -0600198 ut_asserteq(1, run_commandf("fdt addr"));
199 ut_assert_nextline("libfdt fdt_check_header(): FDT_ERR_BADMAGIC");
200 ut_assertok(ut_check_console_end(uts));
201
202 return 0;
203}
204FDT_TEST(fdt_test_addr, UT_TESTF_CONSOLE_REC);
205
206/* Test 'fdt addr' resizing an fdt */
Marek Vasut4a9fe8c2023-03-02 04:08:25 +0100207static int fdt_test_addr_resize(struct unit_test_state *uts)
Simon Glass74724482022-07-13 06:06:59 -0600208{
209 char fdt[256];
210 const int newsize = sizeof(fdt) / 2;
211 ulong addr;
212
213 ut_assertok(make_test_fdt(uts, fdt, sizeof(fdt)));
214 addr = map_to_sysmem(fdt);
215 set_working_fdt_addr(addr);
216
217 /* Test setting and resizing the working FDT to a larger size */
218 ut_assertok(console_record_reset_enable());
219 ut_assertok(run_commandf("fdt addr %08x %x", addr, newsize));
Simon Glassbaf41412022-10-11 09:47:12 -0600220 ut_assert_nextline("Working FDT set to %lx", addr);
Simon Glass74724482022-07-13 06:06:59 -0600221 ut_assertok(ut_check_console_end(uts));
222
223 /* Try shrinking it */
224 ut_assertok(run_commandf("fdt addr %08x %x", addr, sizeof(fdt) / 4));
Simon Glassbaf41412022-10-11 09:47:12 -0600225 ut_assert_nextline("Working FDT set to %lx", addr);
Simon Glass74724482022-07-13 06:06:59 -0600226 ut_assert_nextline("New length %d < existing length %d, ignoring",
227 (int)sizeof(fdt) / 4, newsize);
228 ut_assertok(ut_check_console_end(uts));
229
230 /* ...quietly */
231 ut_assertok(run_commandf("fdt addr -q %08x %x", addr, sizeof(fdt) / 4));
Simon Glassbaf41412022-10-11 09:47:12 -0600232 ut_assert_nextline("Working FDT set to %lx", addr);
Simon Glass74724482022-07-13 06:06:59 -0600233 ut_assertok(ut_check_console_end(uts));
234
235 /* We cannot easily provoke errors in fdt_open_into(), so ignore that */
236
237 return 0;
238}
Marek Vasut4a9fe8c2023-03-02 04:08:25 +0100239FDT_TEST(fdt_test_addr_resize, UT_TESTF_CONSOLE_REC);
Simon Glass74724482022-07-13 06:06:59 -0600240
Marek Vasut79bcd802023-03-02 04:08:30 +0100241static int fdt_test_move(struct unit_test_state *uts)
242{
243 char fdt[256];
244 ulong addr, newaddr = 0x10000;
245 const int size = sizeof(fdt);
246 uint32_t ts;
247 void *buf;
248
249 /* Original source DT */
250 ut_assertok(make_test_fdt(uts, fdt, size));
251 ts = fdt_totalsize(fdt);
252 addr = map_to_sysmem(fdt);
253 set_working_fdt_addr(addr);
254
255 /* Moved target DT location */
256 buf = map_sysmem(newaddr, size);
257 memset(buf, 0, size);
258
259 /* Test moving the working FDT to a new location */
260 ut_assertok(console_record_reset_enable());
261 ut_assertok(run_commandf("fdt move %08x %08x %x", addr, newaddr, ts));
262 ut_assert_nextline("Working FDT set to %lx", newaddr);
263 ut_assertok(ut_check_console_end(uts));
264
265 /* Compare the source and destination DTs */
266 ut_assertok(console_record_reset_enable());
267 ut_assertok(run_commandf("cmp.b %08x %08x %x", addr, newaddr, ts));
268 ut_assert_nextline("Total of %d byte(s) were the same", ts);
269 ut_assertok(ut_check_console_end(uts));
270
271 return 0;
272}
273FDT_TEST(fdt_test_move, UT_TESTF_CONSOLE_REC);
274
Marek Vasut4efea812023-03-02 04:08:31 +0100275static int fdt_test_resize(struct unit_test_state *uts)
276{
277 char fdt[256];
278 const unsigned int newsize = 0x2000;
279 uint32_t ts;
280 ulong addr;
281
282 /* Original source DT */
283 ut_assertok(make_test_fdt(uts, fdt, sizeof(fdt)));
284 fdt_shrink_to_minimum(fdt, 0); /* Resize with 0 extra bytes */
285 ts = fdt_totalsize(fdt);
286 addr = map_to_sysmem(fdt);
287 set_working_fdt_addr(addr);
288
289 /* Test resizing the working FDT and verify the new space was added */
290 ut_assertok(console_record_reset_enable());
291 ut_assertok(run_commandf("fdt resize %x", newsize));
292 ut_asserteq(ts + newsize, fdt_totalsize(fdt));
293 ut_assertok(ut_check_console_end(uts));
294
295 return 0;
296}
297FDT_TEST(fdt_test_resize, UT_TESTF_CONSOLE_REC);
298
Marek Vasut38805e02023-03-02 04:08:26 +0100299/* Test 'fdt get value' reading an fdt */
Marek Vasute2d7daa2023-03-02 04:08:29 +0100300static int fdt_test_get_value_string(struct unit_test_state *uts,
301 const char *node, const char *prop,
302 const char *idx, const char *strres,
303 const int intres)
304{
305 ut_assertok(console_record_reset_enable());
306 ut_assertok(run_commandf("fdt get value var %s %s %s",
307 node, prop, idx ? : ""));
308 if (strres) {
309 ut_asserteq_str(strres, env_get("var"));
310 } else {
311 ut_asserteq(intres, env_get_hex("var", 0x1234));
312 }
313 ut_assertok(ut_check_console_end(uts));
314
315 return 0;
316}
317
Marek Vasuted145762023-03-02 04:08:28 +0100318static int fdt_test_get_value_common(struct unit_test_state *uts,
319 const char *node)
320{
321 /* Test getting default element of $node node clock-names property */
Marek Vasute2d7daa2023-03-02 04:08:29 +0100322 fdt_test_get_value_string(uts, node, "clock-names", NULL, "fixed", 0);
Marek Vasuted145762023-03-02 04:08:28 +0100323
324 /* Test getting 0th element of $node node clock-names property */
Marek Vasute2d7daa2023-03-02 04:08:29 +0100325 fdt_test_get_value_string(uts, node, "clock-names", "0", "fixed", 0);
Marek Vasuted145762023-03-02 04:08:28 +0100326
327 /* Test getting 1st element of $node node clock-names property */
Marek Vasute2d7daa2023-03-02 04:08:29 +0100328 fdt_test_get_value_string(uts, node, "clock-names", "1", "i2c", 0);
Marek Vasuted145762023-03-02 04:08:28 +0100329
330 /* Test getting 2nd element of $node node clock-names property */
Marek Vasute2d7daa2023-03-02 04:08:29 +0100331 fdt_test_get_value_string(uts, node, "clock-names", "2", "spi", 0);
332
333 /*
334 * Test getting default element of $node node regs property.
335 * The result here is highly unusual, the non-index value read from
336 * integer array is a string of concatenated values from the array,
337 * but only if the array is shorter than 40 characters. Anything
338 * longer is an error. This is a special case for handling hashes.
339 */
340 fdt_test_get_value_string(uts, node, "regs", NULL, "3412000000100000", 0);
341
342 /* Test getting 0th element of $node node regs property */
343 fdt_test_get_value_string(uts, node, "regs", "0", NULL, 0x1234);
344
345 /* Test getting 1st element of $node node regs property */
346 fdt_test_get_value_string(uts, node, "regs", "1", NULL, 0x1000);
Marek Vasuted145762023-03-02 04:08:28 +0100347
348 /* Test missing 10th element of $node node clock-names property */
349 ut_assertok(console_record_reset_enable());
350 ut_asserteq(1, run_commandf("fdt get value ften %s clock-names 10", node));
351 ut_assertok(ut_check_console_end(uts));
352
Marek Vasute2d7daa2023-03-02 04:08:29 +0100353 /* Test missing 10th element of $node node regs property */
354 ut_assertok(console_record_reset_enable());
355 ut_asserteq(1, run_commandf("fdt get value ften %s regs 10", node));
356 ut_assertok(ut_check_console_end(uts));
357
Marek Vasuted145762023-03-02 04:08:28 +0100358 /* Test getting default element of $node node nonexistent property */
359 ut_assertok(console_record_reset_enable());
360 ut_asserteq(1, run_commandf("fdt get value fnone %s nonexistent", node));
361 ut_assert_nextline("libfdt fdt_getprop(): FDT_ERR_NOTFOUND");
362 ut_assertok(ut_check_console_end(uts));
363
364 return 0;
365}
366
Marek Vasut38805e02023-03-02 04:08:26 +0100367static int fdt_test_get_value(struct unit_test_state *uts)
Marek Vasutd83615b2022-11-14 22:50:00 +0100368{
Marek Vasut21e1d93b2023-03-02 04:08:27 +0100369 char fdt[4096];
Marek Vasutd83615b2022-11-14 22:50:00 +0100370 ulong addr;
Marek Vasuted145762023-03-02 04:08:28 +0100371 int ret;
Marek Vasutd83615b2022-11-14 22:50:00 +0100372
Marek Vasut21e1d93b2023-03-02 04:08:27 +0100373 ut_assertok(make_fuller_fdt(uts, fdt, sizeof(fdt)));
374 addr = map_to_sysmem(fdt);
Marek Vasutd83615b2022-11-14 22:50:00 +0100375 set_working_fdt_addr(addr);
376
Marek Vasuted145762023-03-02 04:08:28 +0100377 ret = fdt_test_get_value_common(uts, "/test-node@1234");
378 if (!ret)
379 ret = fdt_test_get_value_common(uts, "testnodealias");
380 if (ret)
381 return ret;
Marek Vasutd83615b2022-11-14 22:50:00 +0100382
383 /* Test getting default element of /nonexistent node */
384 ut_assertok(console_record_reset_enable());
385 ut_asserteq(1, run_command("fdt get value fnode /nonexistent nonexistent", 1));
386 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND");
387 ut_assertok(ut_check_console_end(uts));
388
Marek Vasuted145762023-03-02 04:08:28 +0100389 /* Test getting default element of bad alias */
390 ut_assertok(console_record_reset_enable());
391 ut_asserteq(1, run_command("fdt get value vbadalias badalias nonexistent", 1));
392 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND");
393 ut_assertok(ut_check_console_end(uts));
394
395 /* Test getting default element of nonexistent alias */
396 ut_assertok(console_record_reset_enable());
397 ut_asserteq(1, run_command("fdt get value vnoalias noalias nonexistent", 1));
398 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_BADPATH");
399 ut_assertok(ut_check_console_end(uts));
400
Marek Vasutd83615b2022-11-14 22:50:00 +0100401 return 0;
402}
Marek Vasut38805e02023-03-02 04:08:26 +0100403FDT_TEST(fdt_test_get_value, UT_TESTF_CONSOLE_REC);
Marek Vasutd83615b2022-11-14 22:50:00 +0100404
Marek Vasut4e22e122023-03-02 04:08:33 +0100405static int fdt_test_get_name(struct unit_test_state *uts)
406{
407 char fdt[4096];
408 ulong addr;
409
410 ut_assertok(make_fuller_fdt(uts, fdt, sizeof(fdt)));
411 addr = map_to_sysmem(fdt);
412 set_working_fdt_addr(addr);
413
414 /* Test getting name of node 0 in /, which is /aliases node */
415 ut_assertok(console_record_reset_enable());
416 ut_assertok(run_command("fdt get name nzero / 0", 0));
417 ut_asserteq_str("aliases", env_get("nzero"));
418 ut_assertok(ut_check_console_end(uts));
419
420 /* Test getting name of node 1 in /, which is /test-node@1234 node */
421 ut_assertok(console_record_reset_enable());
422 ut_assertok(run_command("fdt get name none / 1", 0));
423 ut_asserteq_str("test-node@1234", env_get("none"));
424 ut_assertok(ut_check_console_end(uts));
425
426 /* Test getting name of node -1 in /, which is /aliases node, same as 0 */
427 ut_assertok(console_record_reset_enable());
428 ut_assertok(run_command("fdt get name nmone / -1", 0));
429 ut_asserteq_str("aliases", env_get("nmone"));
430 ut_assertok(ut_check_console_end(uts));
431
432 /* Test getting name of node 2 in /, which does not exist */
433 ut_assertok(console_record_reset_enable());
434 ut_asserteq(1, run_command("fdt get name ntwo / 2", 1));
435 ut_assert_nextline("libfdt node not found");
436 ut_assertok(ut_check_console_end(uts));
437
438 /* Test getting name of node 0 in /test-node@1234, which is /subnode node */
439 ut_assertok(console_record_reset_enable());
440 ut_assertok(run_command("fdt get name snzero /test-node@1234 0", 0));
441 ut_asserteq_str("subnode", env_get("snzero"));
442 ut_assertok(run_command("fdt get name asnzero testnodealias 0", 0));
443 ut_asserteq_str("subnode", env_get("asnzero"));
444 ut_assertok(ut_check_console_end(uts));
445
446 /* Test getting name of node 1 in /test-node@1234, which does not exist */
447 ut_assertok(console_record_reset_enable());
448 ut_asserteq(1, run_command("fdt get name snone /test-node@1234 1", 1));
449 ut_assert_nextline("libfdt node not found");
450 ut_asserteq(1, run_command("fdt get name asnone testnodealias 1", 1));
451 ut_assert_nextline("libfdt node not found");
452 ut_assertok(ut_check_console_end(uts));
453
454 /* Test getting name of node -1 in /test-node@1234, which is /subnode node, same as 0 */
455 ut_assertok(console_record_reset_enable());
456 ut_assertok(run_command("fdt get name snmone /test-node@1234 -1", 0));
457 ut_asserteq_str("subnode", env_get("snmone"));
458 ut_assertok(run_command("fdt get name asnmone testnodealias -1", 0));
459 ut_asserteq_str("subnode", env_get("asnmone"));
460 ut_assertok(ut_check_console_end(uts));
461
462 /* Test getting name of nonexistent node */
463 ut_assertok(console_record_reset_enable());
464 ut_asserteq(1, run_command("fdt get name nonode /nonexistent 0", 1));
465 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND");
466 ut_assertok(ut_check_console_end(uts));
467
468 /* Test getting name of bad alias */
469 ut_assertok(console_record_reset_enable());
470 ut_asserteq(1, run_command("fdt get name vbadalias badalias 0", 1));
471 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND");
472 ut_assertok(ut_check_console_end(uts));
473
474 /* Test getting name of nonexistent alias */
475 ut_assertok(console_record_reset_enable());
476 ut_asserteq(1, run_command("fdt get name vnoalias noalias 0", 1));
477 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_BADPATH");
478 ut_assertok(ut_check_console_end(uts));
479
480 return 0;
481}
482FDT_TEST(fdt_test_get_name, UT_TESTF_CONSOLE_REC);
483
Marek Vasut1b025af2023-03-02 04:08:34 +0100484static int fdt_test_get_addr_common(struct unit_test_state *uts, char *fdt,
485 const char *path, const char *prop)
486{
487 unsigned int offset;
488 int path_offset;
489 void *prop_ptr;
490 int len = 0;
491
492 path_offset = fdt_path_offset(fdt, path);
493 ut_assert(path_offset >= 0);
494 prop_ptr = (void *)fdt_getprop(fdt, path_offset, prop, &len);
495 ut_assertnonnull(prop_ptr);
496 offset = (char *)prop_ptr - fdt;
497
498 ut_assertok(console_record_reset_enable());
499 ut_assertok(run_commandf("fdt get addr pstr %s %s", path, prop));
500 ut_asserteq((ulong)map_sysmem(env_get_hex("fdtaddr", 0x1234), 0),
501 (ulong)(map_sysmem(env_get_hex("pstr", 0x1234), 0) - offset));
502 ut_assertok(ut_check_console_end(uts));
503
504 return 0;
505}
506
507static int fdt_test_get_addr(struct unit_test_state *uts)
508{
509 char fdt[4096];
510 ulong addr;
511
512 ut_assertok(make_fuller_fdt(uts, fdt, sizeof(fdt)));
513 addr = map_to_sysmem(fdt);
514 set_working_fdt_addr(addr);
515
516 /* Test getting address of root node / string property "compatible" */
517 fdt_test_get_addr_common(uts, fdt, "/", "compatible");
518
519 /* Test getting address of node /test-node@1234 stringlist property "clock-names" */
520 fdt_test_get_addr_common(uts, fdt, "/test-node@1234", "clock-names");
521 fdt_test_get_addr_common(uts, fdt, "testnodealias", "clock-names");
522
523 /* Test getting address of node /test-node@1234 u32 property "clock-frequency" */
524 fdt_test_get_addr_common(uts, fdt, "/test-node@1234", "clock-frequency");
525 fdt_test_get_addr_common(uts, fdt, "testnodealias", "clock-frequency");
526
527 /* Test getting address of node /test-node@1234 empty property "u-boot,empty-property" */
528 fdt_test_get_addr_common(uts, fdt, "/test-node@1234", "u-boot,empty-property");
529 fdt_test_get_addr_common(uts, fdt, "testnodealias", "u-boot,empty-property");
530
531 /* Test getting address of node /test-node@1234 array property "regs" */
532 fdt_test_get_addr_common(uts, fdt, "/test-node@1234", "regs");
533 fdt_test_get_addr_common(uts, fdt, "testnodealias", "regs");
534
535 /* Test getting address of node /test-node@1234/subnode non-existent property "noprop" */
536 ut_assertok(console_record_reset_enable());
537 ut_asserteq(1, run_command("fdt get addr pnoprop /test-node@1234/subnode noprop", 1));
538 ut_assert_nextline("libfdt fdt_getprop(): FDT_ERR_NOTFOUND");
539 ut_assertok(ut_check_console_end(uts));
540
541 /* Test getting address of non-existent node /test-node@1234/nonode@1 property "noprop" */
542 ut_assertok(console_record_reset_enable());
543 ut_asserteq(1, run_command("fdt get addr pnonode /test-node@1234/nonode@1 noprop", 1));
544 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND");
545 ut_assertok(ut_check_console_end(uts));
546
547 return 0;
548}
549FDT_TEST(fdt_test_get_addr, UT_TESTF_CONSOLE_REC);
550
Marek Vasut55d0f982023-03-02 04:08:35 +0100551static int fdt_test_get_size_common(struct unit_test_state *uts,
552 const char *path, const char *prop,
553 const unsigned int val)
554{
555 ut_assertok(console_record_reset_enable());
556 if (prop) {
557 ut_assertok(run_commandf("fdt get size sstr %s %s", path, prop));
558 } else {
559 ut_assertok(run_commandf("fdt get size sstr %s", path));
560 }
561 ut_asserteq(val, env_get_hex("sstr", 0x1234));
562 ut_assertok(ut_check_console_end(uts));
563
564 return 0;
565}
566
567static int fdt_test_get_size(struct unit_test_state *uts)
568{
569 char fdt[4096];
570 ulong addr;
571
572 ut_assertok(make_fuller_fdt(uts, fdt, sizeof(fdt)));
573 addr = map_to_sysmem(fdt);
574 set_working_fdt_addr(addr);
575
576 /* Test getting size of root node / string property "compatible" */
577 fdt_test_get_size_common(uts, "/", "compatible", 16);
578
579 /* Test getting size of node /test-node@1234 stringlist property "clock-names" */
580 fdt_test_get_size_common(uts, "/test-node@1234", "clock-names", 26);
581 fdt_test_get_size_common(uts, "testnodealias", "clock-names", 26);
582
583 /* Test getting size of node /test-node@1234 u32 property "clock-frequency" */
584 fdt_test_get_size_common(uts, "/test-node@1234", "clock-frequency", 4);
585 fdt_test_get_size_common(uts, "testnodealias", "clock-frequency", 4);
586
587 /* Test getting size of node /test-node@1234 empty property "u-boot,empty-property" */
588 fdt_test_get_size_common(uts, "/test-node@1234", "u-boot,empty-property", 0);
589 fdt_test_get_size_common(uts, "testnodealias", "u-boot,empty-property", 0);
590
591 /* Test getting size of node /test-node@1234 array property "regs" */
592 fdt_test_get_size_common(uts, "/test-node@1234", "regs", 8);
593 fdt_test_get_size_common(uts, "testnodealias", "regs", 8);
594
595 /* Test getting node count of node / */
596 fdt_test_get_size_common(uts, "/", NULL, 2);
597
598 /* Test getting node count of node /test-node@1234/subnode */
599 fdt_test_get_size_common(uts, "/test-node@1234/subnode", NULL, 0);
600 fdt_test_get_size_common(uts, "subnodealias", NULL, 0);
601
602 /* Test getting size of node /test-node@1234/subnode non-existent property "noprop" */
603 ut_assertok(console_record_reset_enable());
604 ut_asserteq(1, run_command("fdt get size pnoprop /test-node@1234/subnode noprop", 1));
605 ut_assert_nextline("libfdt fdt_getprop(): FDT_ERR_NOTFOUND");
606 ut_asserteq(1, run_command("fdt get size pnoprop subnodealias noprop", 1));
607 ut_assert_nextline("libfdt fdt_getprop(): FDT_ERR_NOTFOUND");
608 ut_assertok(ut_check_console_end(uts));
609
610 /* Test getting size of non-existent node /test-node@1234/nonode@1 property "noprop" */
611 ut_assertok(console_record_reset_enable());
612 ut_asserteq(1, run_command("fdt get size pnonode /test-node@1234/nonode@1 noprop", 1));
613 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND");
614 ut_assertok(ut_check_console_end(uts));
615
616 /* Test getting node count of non-existent node /test-node@1234/nonode@1 */
617 ut_assertok(console_record_reset_enable());
618 ut_asserteq(1, run_command("fdt get size pnonode /test-node@1234/nonode@1", 1));
619 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND");
620 ut_assertok(ut_check_console_end(uts));
621
622 /* Test getting node count of bad alias badalias */
623 ut_assertok(console_record_reset_enable());
624 ut_asserteq(1, run_command("fdt get size pnonode badalias noprop", 1));
625 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND");
626 ut_assertok(ut_check_console_end(uts));
627
628 /* Test getting node count of non-existent alias noalias */
629 ut_assertok(console_record_reset_enable());
630 ut_asserteq(1, run_command("fdt get size pnonode noalias", 1));
631 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_BADPATH");
632 ut_assertok(ut_check_console_end(uts));
633
634 return 0;
635}
636FDT_TEST(fdt_test_get_size, UT_TESTF_CONSOLE_REC);
637
Marek Vasuta6bcd972023-03-02 04:08:36 +0100638static int fdt_test_set_single(struct unit_test_state *uts,
639 const char *path, const char *prop,
640 const char *sval, int ival, bool integer)
641{
642 /*
643 * Set single element string/integer/<empty> property into DT, that is:
644 * => fdt set /path property string
645 * => fdt set /path property integer
646 * => fdt set /path property
647 */
648 ut_assertok(console_record_reset_enable());
649 if (sval) {
650 ut_assertok(run_commandf("fdt set %s %s %s", path, prop, sval));
651 } else if (integer) {
652 ut_assertok(run_commandf("fdt set %s %s <%d>", path, prop, ival));
653 } else {
654 ut_assertok(run_commandf("fdt set %s %s", path, prop));
655 }
656
657 /* Validate the property is present and has correct value. */
658 ut_assertok(run_commandf("fdt get value svar %s %s", path, prop));
659 if (sval) {
660 ut_asserteq_str(sval, env_get("svar"));
661 } else if (integer) {
662 ut_asserteq(ival, env_get_hex("svar", 0x1234));
663 } else {
664 ut_assertnull(env_get("svar"));
665 }
666 ut_assertok(ut_check_console_end(uts));
667
668 return 0;
669}
670
671static int fdt_test_set_multi(struct unit_test_state *uts,
672 const char *path, const char *prop,
673 const char *sval1, const char *sval2,
674 int ival1, int ival2)
675{
676 /*
677 * Set multi element string/integer array property in DT, that is:
678 * => fdt set /path property <string1 string2>
679 * => fdt set /path property <integer1 integer2>
680 *
681 * The set is done twice in here deliberately, The first set adds
682 * the property with an extra trailing element in its array to make
683 * the array longer, the second set is the expected final content of
684 * the array property. The longer array is used to verify that the
685 * new array is correctly sized and read past the new array length
686 * triggers failure.
687 */
688 ut_assertok(console_record_reset_enable());
689 if (sval1 && sval2) {
690 ut_assertok(run_commandf("fdt set %s %s %s %s end", path, prop, sval1, sval2));
691 ut_assertok(run_commandf("fdt set %s %s %s %s", path, prop, sval1, sval2));
692 } else {
693 ut_assertok(run_commandf("fdt set %s %s <%d %d 10>", path, prop, ival1, ival2));
694 ut_assertok(run_commandf("fdt set %s %s <%d %d>", path, prop, ival1, ival2));
695 }
696
697 /*
698 * Validate the property is present and has correct value.
699 *
700 * The "end/10" above and "svarn" below is used to validate that
701 * previous 'fdt set' to longer array does not polute newly set
702 * shorter array.
703 */
704 ut_assertok(run_commandf("fdt get value svar1 %s %s 0", path, prop));
705 ut_assertok(run_commandf("fdt get value svar2 %s %s 1", path, prop));
706 ut_asserteq(1, run_commandf("fdt get value svarn %s %s 2", path, prop));
707 if (sval1 && sval2) {
708 ut_asserteq_str(sval1, env_get("svar1"));
709 ut_asserteq_str(sval2, env_get("svar2"));
710 ut_assertnull(env_get("svarn"));
711 } else {
712 ut_asserteq(ival1, env_get_hex("svar1", 0x1234));
713 ut_asserteq(ival2, env_get_hex("svar2", 0x1234));
714 ut_assertnull(env_get("svarn"));
715 }
716 ut_assertok(ut_check_console_end(uts));
717
718 return 0;
719}
720
721static int fdt_test_set_node(struct unit_test_state *uts,
722 const char *path, const char *prop)
723{
724 fdt_test_set_single(uts, path, prop, "new", 0, false);
725 fdt_test_set_single(uts, path, prop, "rewrite", 0, false);
726 fdt_test_set_single(uts, path, prop, NULL, 42, true);
727 fdt_test_set_single(uts, path, prop, NULL, 0, false);
728 fdt_test_set_multi(uts, path, prop, NULL, NULL, 42, 1701);
729 fdt_test_set_multi(uts, path, prop, NULL, NULL, 74656, 9);
730 fdt_test_set_multi(uts, path, prop, "42", "1701", 0, 0);
731 fdt_test_set_multi(uts, path, prop, "74656", "9", 0, 0);
732
733 return 0;
734}
735
736static int fdt_test_set(struct unit_test_state *uts)
737{
738 char fdt[8192];
739 ulong addr;
740
741 ut_assertok(make_fuller_fdt(uts, fdt, sizeof(fdt)));
742 fdt_shrink_to_minimum(fdt, 4096); /* Resize with 4096 extra bytes */
743 addr = map_to_sysmem(fdt);
744 set_working_fdt_addr(addr);
745
746 /* Test setting of root node / existing property "compatible" */
747 fdt_test_set_node(uts, "/", "compatible");
748
749 /* Test setting of root node / new property "newproperty" */
750 fdt_test_set_node(uts, "/", "newproperty");
751
752 /* Test setting of subnode existing property "compatible" */
753 fdt_test_set_node(uts, "/test-node@1234/subnode", "compatible");
754 fdt_test_set_node(uts, "subnodealias", "compatible");
755
756 /* Test setting of subnode new property "newproperty" */
757 fdt_test_set_node(uts, "/test-node@1234/subnode", "newproperty");
758 fdt_test_set_node(uts, "subnodealias", "newproperty");
759
760 /* Test setting property of non-existent node */
761 ut_assertok(console_record_reset_enable());
762 ut_asserteq(1, run_command("fdt set /no-node noprop", 1));
763 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND");
764 ut_assertok(ut_check_console_end(uts));
765
766 /* Test setting property of non-existent alias */
767 ut_assertok(console_record_reset_enable());
768 ut_asserteq(1, run_command("fdt set noalias noprop", 1));
769 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_BADPATH");
770 ut_assertok(ut_check_console_end(uts));
771
772 /* Test setting property of bad alias */
773 ut_assertok(console_record_reset_enable());
774 ut_asserteq(1, run_command("fdt set badalias noprop", 1));
775 ut_assert_nextline("libfdt fdt_path_offset() returned FDT_ERR_NOTFOUND");
776 ut_assertok(ut_check_console_end(uts));
777
778 return 0;
779}
780FDT_TEST(fdt_test_set, UT_TESTF_CONSOLE_REC);
781
Simon Glass74724482022-07-13 06:06:59 -0600782int do_ut_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
783{
784 struct unit_test *tests = UNIT_TEST_SUITE_START(fdt_test);
785 const int n_ents = UNIT_TEST_SUITE_COUNT(fdt_test);
786
787 return cmd_ut_category("fdt", "fdt_test_", tests, n_ents, argc, argv);
788}