From: Simon Glass Date: Wed, 7 Aug 2024 22:47:29 +0000 (-0600) Subject: upl: Add basic tests X-Git-Url: http://git.dujemihanovic.xyz/login.html?a=commitdiff_plain;h=637be2e53f66034ed7475d5981e4445a538a7639;p=u-boot.git upl: Add basic tests Add some unit tests to check that we can write a UPL handoff and read it back. Signed-off-by: Simon Glass --- diff --git a/MAINTAINERS b/MAINTAINERS index 04a6f23891..acb92bd3f8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1715,6 +1715,7 @@ S: Maintained T: git https://source.denx.de/u-boot/custodians/u-boot-dm.git F: boot/upl* F: include/upl.h +F: test/boot/upl.c USB M: Marek Vasut diff --git a/include/test/suites.h b/include/test/suites.h index 365d5f20df..2ceef577f7 100644 --- a/include/test/suites.h +++ b/include/test/suites.h @@ -63,5 +63,6 @@ int do_ut_str(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_time(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_unicode(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_ut_upl(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); #endif /* __TEST_SUITES_H__ */ diff --git a/include/upl.h b/include/upl.h index df644c4734..2ec5ef1b5c 100644 --- a/include/upl.h +++ b/include/upl.h @@ -309,6 +309,15 @@ int upl_create_handoff_tree(const struct upl *upl, oftree *treep); * Return: 0 on success, -ve on error */ int upl_read_handoff(struct upl *upl, oftree tree); + +/** + * upl_get_test_data() - Fill a UPL with some test data + * + * @uts: Test state (can be uninited) + * @upl: Returns test data + * Return: 0 on success, 1 on error + */ +int upl_get_test_data(struct unit_test_state *uts, struct upl *upl); #endif /* USE_HOSTCC */ #if CONFIG_IS_ENABLED(UPL) && defined(CONFIG_SPL_BUILD) diff --git a/test/boot/Makefile b/test/boot/Makefile index 068522cb9e..8ec5daa7bf 100644 --- a/test/boot/Makefile +++ b/test/boot/Makefile @@ -13,3 +13,5 @@ ifdef CONFIG_OF_LIVE obj-$(CONFIG_BOOTMETH_VBE_SIMPLE) += vbe_simple.o endif obj-$(CONFIG_BOOTMETH_VBE) += vbe_fixup.o + +obj-$(CONFIG_UPL) += upl.o diff --git a/test/boot/upl.c b/test/boot/upl.c new file mode 100644 index 0000000000..aa3fddcbb7 --- /dev/null +++ b/test/boot/upl.c @@ -0,0 +1,368 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * UPL handoff testing + * + * Copyright 2024 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include +#include +#include "bootstd_common.h" + +/* Declare a new upl test */ +#define UPL_TEST(_name, _flags) UNIT_TEST(_name, _flags, upl_test) + +static int add_region(struct unit_test_state *uts, struct alist *lst, + ulong base, ulong size) +{ + struct memregion region; + + region.base = base; + region.size = size; + ut_assertnonnull(alist_add(lst, region)); + + return 0; +} + +int upl_get_test_data(struct unit_test_state *uts, struct upl *upl) +{ + struct upl_memmap memmap; + struct upl_memres memres; + struct upl_image img; + struct upl_mem mem; + + upl_init(upl); + + upl->addr_cells = 1; + upl->size_cells = 1; + upl->smbios = 0x123; + upl->acpi = 0x456; + upl->bootmode = BIT(UPLBM_DEFAULT) | BIT(UPLBM_S3); + upl->fit = 0x789; + upl->conf_offset = 0x234; + upl->addr_width = 46; + upl->acpi_nvs_size = 0x100; + + /* image[0] */ + img.load = 0x1; + img.size = 0x2; + img.offset = 0x3; + img.description = "U-Boot"; + ut_assertnonnull(alist_add(&upl->image, img)); + + /* image[1] */ + img.load = 0x4; + img.size = 0x5; + img.offset = 0x6; + img.description = "ATF"; + ut_assertnonnull(alist_add(&upl->image, img)); + + /* mem[0] : 3 regions */ + memset(&mem, '\0', sizeof(mem)); + alist_init_struct(&mem.region, struct memregion); + ut_assertok(add_region(uts, &mem.region, 0x10, 0x20)); + ut_assertok(add_region(uts, &mem.region, 0x30, 0x40)); + ut_assertok(add_region(uts, &mem.region, 0x40, 0x50)); + ut_assertnonnull(alist_add(&upl->mem, mem)); + + /* mem[0] : 1 region */ + alist_init_struct(&mem.region, struct memregion); + ut_assertok(add_region(uts, &mem.region, 0x70, 0x80)); + mem.hotpluggable = true; + ut_assertnonnull(alist_add(&upl->mem, mem)); + mem.hotpluggable = false; + + /* memmap[0] : 5 regions */ + alist_init_struct(&memmap.region, struct memregion); + memmap.name = "acpi"; + memmap.usage = BIT(UPLUS_ACPI_RECLAIM); + ut_assertok(add_region(uts, &memmap.region, 0x11, 0x12)); + ut_assertok(add_region(uts, &memmap.region, 0x13, 0x14)); + ut_assertok(add_region(uts, &memmap.region, 0x15, 0x16)); + ut_assertok(add_region(uts, &memmap.region, 0x17, 0x18)); + ut_assertok(add_region(uts, &memmap.region, 0x19, 0x1a)); + ut_assertnonnull(alist_add(&upl->memmap, memmap)); + + /* memmap[1] : 1 region */ + memmap.name = "u-boot"; + memmap.usage = BIT(UPLUS_BOOT_DATA); + alist_init_struct(&memmap.region, struct memregion); + ut_assertok(add_region(uts, &memmap.region, 0x21, 0x22)); + ut_assertnonnull(alist_add(&upl->memmap, memmap)); + + /* memmap[2] : 1 region */ + alist_init_struct(&memmap.region, struct memregion); + memmap.name = "efi"; + memmap.usage = BIT(UPLUS_RUNTIME_CODE); + ut_assertok(add_region(uts, &memmap.region, 0x23, 0x24)); + ut_assertnonnull(alist_add(&upl->memmap, memmap)); + + /* memmap[3]: 2 regions */ + alist_init_struct(&memmap.region, struct memregion); + memmap.name = "empty"; + memmap.usage = 0; + ut_assertok(add_region(uts, &memmap.region, 0x25, 0x26)); + ut_assertok(add_region(uts, &memmap.region, 0x27, 0x28)); + ut_assertnonnull(alist_add(&upl->memmap, memmap)); + + /* memmap[4]: 1 region */ + alist_init_struct(&memmap.region, struct memregion); + memmap.name = "acpi-things"; + memmap.usage = BIT(UPLUS_RUNTIME_CODE) | BIT(UPLUS_ACPI_NVS); + ut_assertok(add_region(uts, &memmap.region, 0x29, 0x2a)); + ut_assertnonnull(alist_add(&upl->memmap, memmap)); + + /* memres[0]: 1 region */ + alist_init_struct(&memres.region, struct memregion); + memset(&memres, '\0', sizeof(memres)); + memres.name = "mmio"; + ut_assertok(add_region(uts, &memres.region, 0x2b, 0x2c)); + ut_assertnonnull(alist_add(&upl->memres, memres)); + + /* memres[1]: 2 regions */ + alist_init_struct(&memres.region, struct memregion); + memres.name = "memory"; + ut_assertok(add_region(uts, &memres.region, 0x2d, 0x2e)); + ut_assertok(add_region(uts, &memres.region, 0x2f, 0x30)); + memres.no_map = true; + ut_assertnonnull(alist_add(&upl->memres, memres)); + + upl->serial.compatible = "ns16550a"; + upl->serial.clock_frequency = 1843200; + upl->serial.current_speed = 115200; + alist_init_struct(&upl->serial.reg, struct memregion); + ut_assertok(add_region(uts, &upl->serial.reg, 0xf1de0000, 0x100)); + upl->serial.reg_io_shift = 2; + upl->serial.reg_offset = 0x40; + upl->serial.reg_io_width = 1; + upl->serial.virtual_reg = 0x20000000; + upl->serial.access_type = UPLSAT_MMIO; + + alist_init_struct(&upl->graphics.reg, struct memregion); + ut_assertok(add_region(uts, &upl->graphics.reg, 0xd0000000, 0x10000000)); + upl->graphics.width = 1280; + upl->graphics.height = 1280; + upl->graphics.stride = upl->graphics.width * 4; + upl->graphics.format = UPLGF_ARGB32; + + return 0; +} + +static int compare_upl_image(struct unit_test_state *uts, + const struct upl_image *base, + const struct upl_image *cmp) +{ + ut_asserteq(base->load, cmp->load); + ut_asserteq(base->size, cmp->size); + ut_asserteq(base->offset, cmp->offset); + ut_asserteq_str(base->description, cmp->description); + + return 0; +} + +static int compare_upl_memregion(struct unit_test_state *uts, + const struct memregion *base, + const struct memregion *cmp) +{ + ut_asserteq(base->base, cmp->base); + ut_asserteq(base->size, cmp->size); + + return 0; +} + +static int compare_upl_mem(struct unit_test_state *uts, + const struct upl_mem *base, + const struct upl_mem *cmp) +{ + int i; + + ut_asserteq(base->region.count, cmp->region.count); + ut_asserteq(base->hotpluggable, cmp->hotpluggable); + for (i = 0; i < base->region.count; i++) { + ut_assertok(compare_upl_memregion(uts, + alist_get(&base->region, i, struct memregion), + alist_get(&cmp->region, i, struct memregion))); + } + + return 0; +} + +static int check_device_name(struct unit_test_state *uts, const char *base, + const char *cmp) +{ + const char *p; + + p = strchr(cmp, '@'); + if (p) { + ut_assertnonnull(p); + ut_asserteq_strn(base, cmp); + ut_asserteq(p - cmp, strlen(base)); + } else { + ut_asserteq_str(base, cmp); + } + + return 0; +} + +static int compare_upl_memmap(struct unit_test_state *uts, + const struct upl_memmap *base, + const struct upl_memmap *cmp) +{ + int i; + + ut_assertok(check_device_name(uts, base->name, cmp->name)); + ut_asserteq(base->region.count, cmp->region.count); + ut_asserteq(base->usage, cmp->usage); + for (i = 0; i < base->region.count; i++) + ut_assertok(compare_upl_memregion(uts, + alist_get(&base->region, i, struct memregion), + alist_get(&cmp->region, i, struct memregion))); + + return 0; +} + +static int compare_upl_memres(struct unit_test_state *uts, + const struct upl_memres *base, + const struct upl_memres *cmp) +{ + int i; + + ut_assertok(check_device_name(uts, base->name, cmp->name)); + ut_asserteq(base->region.count, cmp->region.count); + ut_asserteq(base->no_map, cmp->no_map); + for (i = 0; i < base->region.count; i++) + ut_assertok(compare_upl_memregion(uts, + alist_get(&base->region, i, struct memregion), + alist_get(&cmp->region, i, struct memregion))); + + return 0; +} + +static int compare_upl_serial(struct unit_test_state *uts, + struct upl_serial *base, struct upl_serial *cmp) +{ + int i; + + ut_asserteq_str(base->compatible, cmp->compatible); + ut_asserteq(base->clock_frequency, cmp->clock_frequency); + ut_asserteq(base->current_speed, cmp->current_speed); + for (i = 0; i < base->reg.count; i++) + ut_assertok(compare_upl_memregion(uts, + alist_get(&base->reg, i, struct memregion), + alist_get(&cmp->reg, i, struct memregion))); + ut_asserteq(base->reg_io_shift, cmp->reg_io_shift); + ut_asserteq(base->reg_offset, cmp->reg_offset); + ut_asserteq(base->reg_io_width, cmp->reg_io_width); + ut_asserteq(base->virtual_reg, cmp->virtual_reg); + ut_asserteq(base->access_type, cmp->access_type); + + return 0; +} + +static int compare_upl_graphics(struct unit_test_state *uts, + struct upl_graphics *base, + struct upl_graphics *cmp) +{ + int i; + + for (i = 0; i < base->reg.count; i++) + ut_assertok(compare_upl_memregion(uts, + alist_get(&base->reg, i, struct memregion), + alist_get(&cmp->reg, i, struct memregion))); + ut_asserteq(base->width, cmp->width); + ut_asserteq(base->height, cmp->height); + ut_asserteq(base->stride, cmp->stride); + ut_asserteq(base->format, cmp->format); + + return 0; +} + +static int compare_upl(struct unit_test_state *uts, struct upl *base, + struct upl *cmp) +{ + int i; + + ut_asserteq(base->addr_cells, cmp->addr_cells); + ut_asserteq(base->size_cells, cmp->size_cells); + + ut_asserteq(base->smbios, cmp->smbios); + ut_asserteq(base->acpi, cmp->acpi); + ut_asserteq(base->bootmode, cmp->bootmode); + ut_asserteq(base->fit, cmp->fit); + ut_asserteq(base->conf_offset, cmp->conf_offset); + ut_asserteq(base->addr_width, cmp->addr_width); + ut_asserteq(base->acpi_nvs_size, cmp->acpi_nvs_size); + + ut_asserteq(base->image.count, cmp->image.count); + for (i = 0; i < base->image.count; i++) + ut_assertok(compare_upl_image(uts, + alist_get(&base->image, i, struct upl_image), + alist_get(&cmp->image, i, struct upl_image))); + + ut_asserteq(base->mem.count, cmp->mem.count); + for (i = 0; i < base->mem.count; i++) + ut_assertok(compare_upl_mem(uts, + alist_get(&base->mem, i, struct upl_mem), + alist_get(&cmp->mem, i, struct upl_mem))); + + ut_asserteq(base->memmap.count, cmp->memmap.count); + for (i = 0; i < base->memmap.count; i++) + ut_assertok(compare_upl_memmap(uts, + alist_get(&base->memmap, i, struct upl_memmap), + alist_get(&cmp->memmap, i, struct upl_memmap))); + + ut_asserteq(base->memres.count, cmp->memres.count); + for (i = 0; i < base->memres.count; i++) + ut_assertok(compare_upl_memres(uts, + alist_get(&base->memres, i, struct upl_memres), + alist_get(&cmp->memres, i, struct upl_memres))); + + ut_assertok(compare_upl_serial(uts, &base->serial, &cmp->serial)); + ut_assertok(compare_upl_graphics(uts, &base->graphics, &cmp->graphics)); + + return 0; +} + +/* Basic test of writing and reading UPL handoff */ +static int upl_test_base(struct unit_test_state *uts) +{ + oftree tree, check_tree; + struct upl upl, check; + struct abuf buf; + + if (!CONFIG_IS_ENABLED(OFNODE_MULTI_TREE)) + return -EAGAIN; /* skip test */ + ut_assertok(upl_get_test_data(uts, &upl)); + + ut_assertok(upl_create_handoff_tree(&upl, &tree)); + ut_assertok(oftree_to_fdt(tree, &buf)); + + /* + * strings in check_tree and therefore check are only valid so long as + * buf stays around. As soon as we call abuf_uninit they go away + */ + check_tree = oftree_from_fdt(abuf_data(&buf)); + ut_assert(ofnode_valid(oftree_path(check_tree, "/"))); + + ut_assertok(upl_read_handoff(&check, check_tree)); + ut_assertok(compare_upl(uts, &upl, &check)); + abuf_uninit(&buf); + + return 0; +} +UPL_TEST(upl_test_base, 0); + +int do_ut_upl(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + struct unit_test *tests = UNIT_TEST_SUITE_START(upl_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(upl_test); + + return cmd_ut_category("cmd_upl", "cmd_upl_", tests, n_ents, argc, + argv); +} diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 4e4aa8f1cb..38ba89ee33 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -133,6 +133,9 @@ static struct cmd_tbl cmd_ut_sub[] = { #ifdef CONFIG_CMD_SEAMA U_BOOT_CMD_MKENT(seama, CONFIG_SYS_MAXARGS, 1, do_ut_seama, "", ""), #endif +#ifdef CONFIG_CMD_UPL + U_BOOT_CMD_MKENT(upl, CONFIG_SYS_MAXARGS, 1, do_ut_upl, "", ""), +#endif }; static int do_ut_all(struct cmd_tbl *cmdtp, int flag, int argc,