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