blob: 99f02b7951b892b2a9a79c5c2e55573f495ac40a [file] [log] [blame]
Simon Glassaac25692024-08-07 16:47:29 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * UPL handoff testing
4 *
5 * Copyright 2024 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
9#include <abuf.h>
10#include <mapmem.h>
11#include <upl.h>
12#include <dm/ofnode.h>
13#include <test/suites.h>
14#include <test/test.h>
15#include <test/ut.h>
16#include "bootstd_common.h"
17
18/* Declare a new upl test */
19#define UPL_TEST(_name, _flags) UNIT_TEST(_name, _flags, upl_test)
20
21static int add_region(struct unit_test_state *uts, struct alist *lst,
22 ulong base, ulong size)
23{
24 struct memregion region;
25
26 region.base = base;
27 region.size = size;
28 ut_assertnonnull(alist_add(lst, region));
29
30 return 0;
31}
32
33int upl_get_test_data(struct unit_test_state *uts, struct upl *upl)
34{
35 struct upl_memmap memmap;
36 struct upl_memres memres;
37 struct upl_image img;
38 struct upl_mem mem;
39
40 upl_init(upl);
41
42 upl->addr_cells = 1;
43 upl->size_cells = 1;
44 upl->smbios = 0x123;
45 upl->acpi = 0x456;
46 upl->bootmode = BIT(UPLBM_DEFAULT) | BIT(UPLBM_S3);
47 upl->fit = 0x789;
48 upl->conf_offset = 0x234;
49 upl->addr_width = 46;
50 upl->acpi_nvs_size = 0x100;
51
52 /* image[0] */
53 img.load = 0x1;
54 img.size = 0x2;
55 img.offset = 0x3;
56 img.description = "U-Boot";
57 ut_assertnonnull(alist_add(&upl->image, img));
58
59 /* image[1] */
60 img.load = 0x4;
61 img.size = 0x5;
62 img.offset = 0x6;
63 img.description = "ATF";
64 ut_assertnonnull(alist_add(&upl->image, img));
65
66 /* mem[0] : 3 regions */
67 memset(&mem, '\0', sizeof(mem));
68 alist_init_struct(&mem.region, struct memregion);
69 ut_assertok(add_region(uts, &mem.region, 0x10, 0x20));
70 ut_assertok(add_region(uts, &mem.region, 0x30, 0x40));
71 ut_assertok(add_region(uts, &mem.region, 0x40, 0x50));
72 ut_assertnonnull(alist_add(&upl->mem, mem));
73
74 /* mem[0] : 1 region */
75 alist_init_struct(&mem.region, struct memregion);
76 ut_assertok(add_region(uts, &mem.region, 0x70, 0x80));
77 mem.hotpluggable = true;
78 ut_assertnonnull(alist_add(&upl->mem, mem));
79 mem.hotpluggable = false;
80
81 /* memmap[0] : 5 regions */
82 alist_init_struct(&memmap.region, struct memregion);
83 memmap.name = "acpi";
84 memmap.usage = BIT(UPLUS_ACPI_RECLAIM);
85 ut_assertok(add_region(uts, &memmap.region, 0x11, 0x12));
86 ut_assertok(add_region(uts, &memmap.region, 0x13, 0x14));
87 ut_assertok(add_region(uts, &memmap.region, 0x15, 0x16));
88 ut_assertok(add_region(uts, &memmap.region, 0x17, 0x18));
89 ut_assertok(add_region(uts, &memmap.region, 0x19, 0x1a));
90 ut_assertnonnull(alist_add(&upl->memmap, memmap));
91
92 /* memmap[1] : 1 region */
93 memmap.name = "u-boot";
94 memmap.usage = BIT(UPLUS_BOOT_DATA);
95 alist_init_struct(&memmap.region, struct memregion);
96 ut_assertok(add_region(uts, &memmap.region, 0x21, 0x22));
97 ut_assertnonnull(alist_add(&upl->memmap, memmap));
98
99 /* memmap[2] : 1 region */
100 alist_init_struct(&memmap.region, struct memregion);
101 memmap.name = "efi";
102 memmap.usage = BIT(UPLUS_RUNTIME_CODE);
103 ut_assertok(add_region(uts, &memmap.region, 0x23, 0x24));
104 ut_assertnonnull(alist_add(&upl->memmap, memmap));
105
106 /* memmap[3]: 2 regions */
107 alist_init_struct(&memmap.region, struct memregion);
108 memmap.name = "empty";
109 memmap.usage = 0;
110 ut_assertok(add_region(uts, &memmap.region, 0x25, 0x26));
111 ut_assertok(add_region(uts, &memmap.region, 0x27, 0x28));
112 ut_assertnonnull(alist_add(&upl->memmap, memmap));
113
114 /* memmap[4]: 1 region */
115 alist_init_struct(&memmap.region, struct memregion);
116 memmap.name = "acpi-things";
117 memmap.usage = BIT(UPLUS_RUNTIME_CODE) | BIT(UPLUS_ACPI_NVS);
118 ut_assertok(add_region(uts, &memmap.region, 0x29, 0x2a));
119 ut_assertnonnull(alist_add(&upl->memmap, memmap));
120
121 /* memres[0]: 1 region */
122 alist_init_struct(&memres.region, struct memregion);
123 memset(&memres, '\0', sizeof(memres));
124 memres.name = "mmio";
125 ut_assertok(add_region(uts, &memres.region, 0x2b, 0x2c));
126 ut_assertnonnull(alist_add(&upl->memres, memres));
127
128 /* memres[1]: 2 regions */
129 alist_init_struct(&memres.region, struct memregion);
130 memres.name = "memory";
131 ut_assertok(add_region(uts, &memres.region, 0x2d, 0x2e));
132 ut_assertok(add_region(uts, &memres.region, 0x2f, 0x30));
133 memres.no_map = true;
134 ut_assertnonnull(alist_add(&upl->memres, memres));
135
136 upl->serial.compatible = "ns16550a";
137 upl->serial.clock_frequency = 1843200;
138 upl->serial.current_speed = 115200;
139 alist_init_struct(&upl->serial.reg, struct memregion);
140 ut_assertok(add_region(uts, &upl->serial.reg, 0xf1de0000, 0x100));
141 upl->serial.reg_io_shift = 2;
142 upl->serial.reg_offset = 0x40;
143 upl->serial.reg_io_width = 1;
144 upl->serial.virtual_reg = 0x20000000;
145 upl->serial.access_type = UPLSAT_MMIO;
146
147 alist_init_struct(&upl->graphics.reg, struct memregion);
148 ut_assertok(add_region(uts, &upl->graphics.reg, 0xd0000000, 0x10000000));
149 upl->graphics.width = 1280;
150 upl->graphics.height = 1280;
151 upl->graphics.stride = upl->graphics.width * 4;
152 upl->graphics.format = UPLGF_ARGB32;
153
154 return 0;
155}
156
157static int compare_upl_image(struct unit_test_state *uts,
158 const struct upl_image *base,
159 const struct upl_image *cmp)
160{
161 ut_asserteq(base->load, cmp->load);
162 ut_asserteq(base->size, cmp->size);
163 ut_asserteq(base->offset, cmp->offset);
164 ut_asserteq_str(base->description, cmp->description);
165
166 return 0;
167}
168
169static int compare_upl_memregion(struct unit_test_state *uts,
170 const struct memregion *base,
171 const struct memregion *cmp)
172{
173 ut_asserteq(base->base, cmp->base);
174 ut_asserteq(base->size, cmp->size);
175
176 return 0;
177}
178
179static int compare_upl_mem(struct unit_test_state *uts,
180 const struct upl_mem *base,
181 const struct upl_mem *cmp)
182{
183 int i;
184
185 ut_asserteq(base->region.count, cmp->region.count);
186 ut_asserteq(base->hotpluggable, cmp->hotpluggable);
187 for (i = 0; i < base->region.count; i++) {
188 ut_assertok(compare_upl_memregion(uts,
189 alist_get(&base->region, i, struct memregion),
190 alist_get(&cmp->region, i, struct memregion)));
191 }
192
193 return 0;
194}
195
196static int check_device_name(struct unit_test_state *uts, const char *base,
197 const char *cmp)
198{
199 const char *p;
200
201 p = strchr(cmp, '@');
202 if (p) {
203 ut_assertnonnull(p);
204 ut_asserteq_strn(base, cmp);
205 ut_asserteq(p - cmp, strlen(base));
206 } else {
207 ut_asserteq_str(base, cmp);
208 }
209
210 return 0;
211}
212
213static int compare_upl_memmap(struct unit_test_state *uts,
214 const struct upl_memmap *base,
215 const struct upl_memmap *cmp)
216{
217 int i;
218
219 ut_assertok(check_device_name(uts, base->name, cmp->name));
220 ut_asserteq(base->region.count, cmp->region.count);
221 ut_asserteq(base->usage, cmp->usage);
222 for (i = 0; i < base->region.count; i++)
223 ut_assertok(compare_upl_memregion(uts,
224 alist_get(&base->region, i, struct memregion),
225 alist_get(&cmp->region, i, struct memregion)));
226
227 return 0;
228}
229
230static int compare_upl_memres(struct unit_test_state *uts,
231 const struct upl_memres *base,
232 const struct upl_memres *cmp)
233{
234 int i;
235
236 ut_assertok(check_device_name(uts, base->name, cmp->name));
237 ut_asserteq(base->region.count, cmp->region.count);
238 ut_asserteq(base->no_map, cmp->no_map);
239 for (i = 0; i < base->region.count; i++)
240 ut_assertok(compare_upl_memregion(uts,
241 alist_get(&base->region, i, struct memregion),
242 alist_get(&cmp->region, i, struct memregion)));
243
244 return 0;
245}
246
247static int compare_upl_serial(struct unit_test_state *uts,
248 struct upl_serial *base, struct upl_serial *cmp)
249{
250 int i;
251
252 ut_asserteq_str(base->compatible, cmp->compatible);
253 ut_asserteq(base->clock_frequency, cmp->clock_frequency);
254 ut_asserteq(base->current_speed, cmp->current_speed);
255 for (i = 0; i < base->reg.count; i++)
256 ut_assertok(compare_upl_memregion(uts,
257 alist_get(&base->reg, i, struct memregion),
258 alist_get(&cmp->reg, i, struct memregion)));
259 ut_asserteq(base->reg_io_shift, cmp->reg_io_shift);
260 ut_asserteq(base->reg_offset, cmp->reg_offset);
261 ut_asserteq(base->reg_io_width, cmp->reg_io_width);
262 ut_asserteq(base->virtual_reg, cmp->virtual_reg);
263 ut_asserteq(base->access_type, cmp->access_type);
264
265 return 0;
266}
267
268static int compare_upl_graphics(struct unit_test_state *uts,
269 struct upl_graphics *base,
270 struct upl_graphics *cmp)
271{
272 int i;
273
274 for (i = 0; i < base->reg.count; i++)
275 ut_assertok(compare_upl_memregion(uts,
276 alist_get(&base->reg, i, struct memregion),
277 alist_get(&cmp->reg, i, struct memregion)));
278 ut_asserteq(base->width, cmp->width);
279 ut_asserteq(base->height, cmp->height);
280 ut_asserteq(base->stride, cmp->stride);
281 ut_asserteq(base->format, cmp->format);
282
283 return 0;
284}
285
286static int compare_upl(struct unit_test_state *uts, struct upl *base,
287 struct upl *cmp)
288{
289 int i;
290
291 ut_asserteq(base->addr_cells, cmp->addr_cells);
292 ut_asserteq(base->size_cells, cmp->size_cells);
293
294 ut_asserteq(base->smbios, cmp->smbios);
295 ut_asserteq(base->acpi, cmp->acpi);
296 ut_asserteq(base->bootmode, cmp->bootmode);
297 ut_asserteq(base->fit, cmp->fit);
298 ut_asserteq(base->conf_offset, cmp->conf_offset);
299 ut_asserteq(base->addr_width, cmp->addr_width);
300 ut_asserteq(base->acpi_nvs_size, cmp->acpi_nvs_size);
301
302 ut_asserteq(base->image.count, cmp->image.count);
303 for (i = 0; i < base->image.count; i++)
304 ut_assertok(compare_upl_image(uts,
305 alist_get(&base->image, i, struct upl_image),
306 alist_get(&cmp->image, i, struct upl_image)));
307
308 ut_asserteq(base->mem.count, cmp->mem.count);
309 for (i = 0; i < base->mem.count; i++)
310 ut_assertok(compare_upl_mem(uts,
311 alist_get(&base->mem, i, struct upl_mem),
312 alist_get(&cmp->mem, i, struct upl_mem)));
313
314 ut_asserteq(base->memmap.count, cmp->memmap.count);
315 for (i = 0; i < base->memmap.count; i++)
316 ut_assertok(compare_upl_memmap(uts,
317 alist_get(&base->memmap, i, struct upl_memmap),
318 alist_get(&cmp->memmap, i, struct upl_memmap)));
319
320 ut_asserteq(base->memres.count, cmp->memres.count);
321 for (i = 0; i < base->memres.count; i++)
322 ut_assertok(compare_upl_memres(uts,
323 alist_get(&base->memres, i, struct upl_memres),
324 alist_get(&cmp->memres, i, struct upl_memres)));
325
326 ut_assertok(compare_upl_serial(uts, &base->serial, &cmp->serial));
327 ut_assertok(compare_upl_graphics(uts, &base->graphics, &cmp->graphics));
328
329 return 0;
330}
331
332/* Basic test of writing and reading UPL handoff */
333static int upl_test_base(struct unit_test_state *uts)
334{
335 oftree tree, check_tree;
336 struct upl upl, check;
337 struct abuf buf;
338
339 if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
340 return -EAGAIN; /* skip test */
341 ut_assertok(upl_get_test_data(uts, &upl));
342
343 ut_assertok(upl_create_handoff_tree(&upl, &tree));
344 ut_assertok(oftree_to_fdt(tree, &buf));
345
346 /*
347 * strings in check_tree and therefore check are only valid so long as
348 * buf stays around. As soon as we call abuf_uninit they go away
349 */
350 check_tree = oftree_from_fdt(abuf_data(&buf));
351 ut_assert(ofnode_valid(oftree_path(check_tree, "/")));
352
353 ut_assertok(upl_read_handoff(&check, check_tree));
354 ut_assertok(compare_upl(uts, &upl, &check));
355 abuf_uninit(&buf);
356
357 return 0;
358}
359UPL_TEST(upl_test_base, 0);
360
Simon Glass3a028c22024-08-07 16:47:30 -0600361/* Test 'upl info' command */
362static int upl_test_info(struct unit_test_state *uts)
363{
364 gd_set_upl(NULL);
365 ut_assertok(run_command("upl info", 0));
366 ut_assert_nextline("UPL state: inactive");
367 ut_assert_console_end();
368
369 gd_set_upl((struct upl *)uts); /* set it to any non-zero value */
370 ut_assertok(run_command("upl info", 0));
371 ut_assert_nextline("UPL state: active");
372 ut_assert_console_end();
373 gd_set_upl(NULL);
374
375 return 0;
376}
Simon Glass11fcfa32024-08-22 07:57:50 -0600377UPL_TEST(upl_test_info, UTF_CONSOLE);
Simon Glass3a028c22024-08-07 16:47:30 -0600378
379/* Test 'upl read' and 'upl_write' commands */
380static int upl_test_read_write(struct unit_test_state *uts)
381{
382 ulong addr;
383
384 if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE))
385 return -EAGAIN; /* skip test */
386 ut_assertok(run_command("upl write", 0));
387
388 addr = env_get_hex("upladdr", 0);
389 ut_assert_nextline("UPL handoff written to %lx size %lx", addr,
390 env_get_hex("uplsize", 0));
391 ut_assert_console_end();
392
393 ut_assertok(run_command("upl read ${upladdr}", 0));
394 ut_assert_nextline("Reading UPL at %lx", addr);
395 ut_assert_console_end();
396
397 return 0;
398}
Simon Glass11fcfa32024-08-22 07:57:50 -0600399UPL_TEST(upl_test_read_write, UTF_CONSOLE);
Simon Glass3a028c22024-08-07 16:47:30 -0600400
Simon Glassbb5541a2024-08-07 16:47:39 -0600401/* Test UPL passthrough */
402static int upl_test_info_norun(struct unit_test_state *uts)
403{
404 const struct upl_image *img;
405 struct upl *upl = gd_upl();
406 const void *fit;
407
408 ut_assertok(run_command("upl info -v", 0));
409 ut_assert_nextline("UPL state: active");
410 ut_assert_nextline("fit %lx", upl->fit);
411 ut_assert_nextline("conf_offset %x", upl->conf_offset);
412 ut_assert_nextlinen("image 0");
413 ut_assert_nextlinen("image 1");
414 ut_assert_console_end();
415
416 /* check the offsets */
417 fit = map_sysmem(upl->fit, 0);
418 ut_asserteq_str("conf-1", fdt_get_name(fit, upl->conf_offset, NULL));
419
420 ut_asserteq(2, upl->image.count);
421
422 img = alist_get(&upl->image, 1, struct upl_image);
423 ut_asserteq_str("firmware-1", fdt_get_name(fit, img->offset, NULL));
424 ut_asserteq(CONFIG_TEXT_BASE, img->load);
425
426 return 0;
427}
Simon Glass11fcfa32024-08-22 07:57:50 -0600428UPL_TEST(upl_test_info_norun, UTF_CONSOLE | UTF_MANUAL);
Simon Glassbb5541a2024-08-07 16:47:39 -0600429
Simon Glassaac25692024-08-07 16:47:29 -0600430int do_ut_upl(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
431{
432 struct unit_test *tests = UNIT_TEST_SUITE_START(upl_test);
433 const int n_ents = UNIT_TEST_SUITE_COUNT(upl_test);
434
435 return cmd_ut_category("cmd_upl", "cmd_upl_", tests, n_ents, argc,
436 argv);
437}