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