diff options
Diffstat (limited to 'test')
61 files changed, 3757 insertions, 243 deletions
diff --git a/test/Kconfig b/test/Kconfig index 830245b6f9a..c3db727c58e 100644 --- a/test/Kconfig +++ b/test/Kconfig @@ -2,6 +2,7 @@ menu "Testing" config UNIT_TEST bool "Unit tests" + depends on CMDLINE help Select this to compile in unit tests for various parts of U-Boot. Test suites will be subcommands of the "ut" command. @@ -101,6 +102,7 @@ config UT_UNICODE source "test/dm/Kconfig" source "test/env/Kconfig" +source "test/image/Kconfig" source "test/lib/Kconfig" source "test/optee/Kconfig" source "test/overlay/Kconfig" diff --git a/test/Makefile b/test/Makefile index 178773647a8..8e1fed2c28b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -3,9 +3,6 @@ # (C) Copyright 2012 The Chromium Authors obj-y += test-main.o -ifdef CONFIG_SPL_LOAD_FIT -obj-$(CONFIG_SANDBOX) += image/ -endif ifneq ($(CONFIG_$(SPL_)BLOBLIST),) obj-$(CONFIG_$(SPL_)CMDLINE) += bloblist.o @@ -30,4 +27,6 @@ obj-$(CONFIG_UNIT_TEST) += boot/ obj-$(CONFIG_UNIT_TEST) += common/ obj-y += log/ obj-$(CONFIG_$(SPL_)UT_UNICODE) += unicode_ut.o +else +obj-$(CONFIG_SPL_UT_LOAD) += image/ endif diff --git a/test/boot/Makefile b/test/boot/Makefile index 52947580ae6..068522cb9e0 100644 --- a/test/boot/Makefile +++ b/test/boot/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_BOOTSTD) += bootdev.o bootstd_common.o bootflow.o bootmeth.o obj-$(CONFIG_FIT) += image.o +obj-$(CONFIG_MEASURED_BOOT) += measurement.o obj-$(CONFIG_EXPO) += expo.o obj-$(CONFIG_CEDIT) += cedit.o diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 6b29213416d..0702fccdae6 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -190,12 +190,21 @@ static int bootdev_test_any(struct unit_test_state *uts) BOOTSTD_TEST(bootdev_test_any, UT_TESTF_DM | UT_TESTF_SCAN_FDT | UT_TESTF_ETH_BOOTDEV); -/* Check bootdev ordering with the bootdev-order property */ +/* + * Check bootdev ordering with the bootdev-order property and boot_targets + * environment variable + */ static int bootdev_test_order(struct unit_test_state *uts) { struct bootflow_iter iter; struct bootflow bflow; + test_set_skip_delays(true); + + /* Start up USB which gives us three additional bootdevs */ + usb_started = false; + ut_assertok(run_command("usb start", 0)); + /* * First try the order set by the bootdev-order property * Like all sandbox unit tests this relies on the devicetree setting up @@ -213,12 +222,55 @@ static int bootdev_test_order(struct unit_test_state *uts) bootflow_iter_uninit(&iter); /* Use the environment variable to override it */ - ut_assertok(env_set("boot_targets", "mmc1 mmc2")); + ut_assertok(env_set("boot_targets", "mmc1 mmc2 usb")); ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); - ut_asserteq(2, iter.num_devs); + ut_asserteq(5, iter.num_devs); ut_asserteq_str("mmc1.bootdev", iter.dev_used[0]->name); ut_asserteq_str("mmc2.bootdev", iter.dev_used[1]->name); + ut_asserteq_str("usb_mass_storage.lun0.bootdev", + iter.dev_used[2]->name); + bootflow_iter_uninit(&iter); + + /* Try a single uclass */ + ut_assertok(env_set("boot_targets", NULL)); + ut_assertok(bootflow_scan_first(NULL, "mmc", &iter, 0, &bflow)); + ut_asserteq(2, iter.num_devs); + + /* Now scan past mmc1 and make sure that only mmc0 shows up */ + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(3, iter.num_devs); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); + ut_asserteq_str("mmc1.bootdev", iter.dev_used[1]->name); + ut_asserteq_str("mmc0.bootdev", iter.dev_used[2]->name); + bootflow_iter_uninit(&iter); + + /* Try a single uclass with boot_targets */ + ut_assertok(env_set("boot_targets", "mmc")); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); + ut_asserteq(2, iter.num_devs); + + /* Now scan past mmc1 and make sure that only mmc0 shows up */ + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(3, iter.num_devs); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); + ut_asserteq_str("mmc1.bootdev", iter.dev_used[1]->name); + ut_asserteq_str("mmc0.bootdev", iter.dev_used[2]->name); + bootflow_iter_uninit(&iter); + + /* Try a single uclass with boot_targets */ + ut_assertok(env_set("boot_targets", "mmc usb")); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); + ut_asserteq(2, iter.num_devs); + + /* Now scan past mmc1 and make sure that the 3 USB devices show up */ + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(6, iter.num_devs); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); + ut_asserteq_str("mmc1.bootdev", iter.dev_used[1]->name); + ut_asserteq_str("mmc0.bootdev", iter.dev_used[2]->name); + ut_asserteq_str("usb_mass_storage.lun0.bootdev", + iter.dev_used[3]->name); bootflow_iter_uninit(&iter); return 0; diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index f5b2059140a..b97c566f000 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -511,19 +511,27 @@ BOOTSTD_TEST(bootflow_cmd_boot, UT_TESTF_DM | UT_TESTF_SCAN_FDT); /** * prep_mmc_bootdev() - Set up an mmc bootdev so we can access other distros * + * After calling this function, set std->bootdev_order to *@old_orderp to + * restore normal operation of bootstd (i.e. with the original bootdev order) + * * @uts: Unit test state - * @mmc_dev: MMC device to use, e.g. "mmc4" + * @mmc_dev: MMC device to use, e.g. "mmc4". Note that this must remain valid + * in the caller until + * @bind_cros: true to bind the ChromiumOS bootmeth + * @old_orderp: Returns the original bootdev order, which must be restored * Returns 0 on success, -ve on failure */ static int prep_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev, - bool bind_cros) + bool bind_cros, const char ***old_orderp) { - const char *order[] = {"mmc2", "mmc1", mmc_dev, NULL}; + static const char *order[] = {"mmc2", "mmc1", NULL, NULL}; struct udevice *dev, *bootstd; struct bootstd_priv *std; const char **old_order; ofnode root, node; + order[2] = mmc_dev; + /* Enable the mmc4 node since we need a second bootflow */ root = oftree_root(oftree_default()); node = ofnode_find_subnode(root, mmc_dev); @@ -546,26 +554,49 @@ static int prep_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev, std = dev_get_priv(bootstd); old_order = std->bootdev_order; std->bootdev_order = order; + *old_orderp = old_order; + + return 0; +} + +/** + * scan_mmc_bootdev() - Set up an mmc bootdev so we can access other distros + * + * @uts: Unit test state + * @mmc_dev: MMC device to use, e.g. "mmc4" + * @bind_cros: true to bind the ChromiumOS bootmeth + * Returns 0 on success, -ve on failure + */ +static int scan_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev, + bool bind_cros) +{ + struct bootstd_priv *std; + struct udevice *bootstd; + const char **old_order; + + ut_assertok(prep_mmc_bootdev(uts, mmc_dev, bind_cros, &old_order)); console_record_reset_enable(); ut_assertok(run_command("bootflow scan", 0)); ut_assert_console_end(); /* Restore the order used by the device tree */ + ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd)); + std = dev_get_priv(bootstd); std->bootdev_order = old_order; return 0; } /** - * prep_mmc4_bootdev() - Set up the mmc4 bootdev so we can access a fake Armbian + * scan_mmc4_bootdev() - Set up the mmc4 bootdev so we can access a fake Armbian * * @uts: Unit test state * Returns 0 on success, -ve on failure */ -static int prep_mmc4_bootdev(struct unit_test_state *uts) +static int scan_mmc4_bootdev(struct unit_test_state *uts) { - ut_assertok(prep_mmc_bootdev(uts, "mmc4", false)); + ut_assertok(scan_mmc_bootdev(uts, "mmc4", false)); return 0; } @@ -573,9 +604,13 @@ static int prep_mmc4_bootdev(struct unit_test_state *uts) /* Check 'bootflow menu' to select a bootflow */ static int bootflow_cmd_menu(struct unit_test_state *uts) { + struct bootstd_priv *std; char prev[3]; - ut_assertok(prep_mmc4_bootdev(uts)); + /* get access to the current bootflow */ + ut_assertok(bootstd_get_priv(&std)); + + ut_assertok(scan_mmc4_bootdev(uts)); /* Add keypresses to move to and select the second one in the list */ prev[0] = CTL_CH('n'); @@ -585,6 +620,17 @@ static int bootflow_cmd_menu(struct unit_test_state *uts) ut_assertok(run_command("bootflow menu", 0)); ut_assert_nextline("Selected: Armbian"); + ut_assertnonnull(std->cur_bootflow); + ut_assert_console_end(); + + /* Check not selecting anything */ + prev[0] = '\e'; + prev[1] = '\0'; + ut_asserteq(1, console_in_puts(prev)); + + ut_asserteq(1, run_command("bootflow menu", 0)); + ut_assertnull(std->cur_bootflow); + ut_assert_nextline("Nothing chosen"); ut_assert_console_end(); return 0; @@ -681,7 +727,7 @@ static int bootflow_menu_theme(struct unit_test_state *uts) ofnode node; int i; - ut_assertok(prep_mmc4_bootdev(uts)); + ut_assertok(scan_mmc4_bootdev(uts)); ut_assertok(bootflow_menu_new(&exp)); node = ofnode_path("/bootstd/theme"); @@ -973,10 +1019,30 @@ static int bootflow_cmdline(struct unit_test_state *uts) } BOOTSTD_TEST(bootflow_cmdline, 0); +/* test a few special changes to a long command line */ +static int bootflow_cmdline_special(struct unit_test_state *uts) +{ + char buf[500]; + int pos; + + /* + * check handling of an argument which has an embedded '=', as well as + * handling of a argument which partially matches ("ro" and "root") + */ + ut_asserteq(32, cmdline_set_arg( + buf, sizeof(buf), + "loglevel=7 root=PARTUUID=d68352e3 rootwait ro noinitrd", + "root", NULL, &pos)); + ut_asserteq_str("loglevel=7 rootwait ro noinitrd", buf); + + return 0; +} +BOOTSTD_TEST(bootflow_cmdline_special, 0); + /* Test ChromiumOS bootmeth */ static int bootflow_cros(struct unit_test_state *uts) { - ut_assertok(prep_mmc_bootdev(uts, "mmc5", true)); + ut_assertok(scan_mmc_bootdev(uts, "mmc5", true)); ut_assertok(run_command("bootflow list", 0)); ut_assert_nextlinen("Showing all"); diff --git a/test/boot/cedit.c b/test/boot/cedit.c index ab2b8a1f9ff..aa417190486 100644 --- a/test/boot/cedit.c +++ b/test/boot/cedit.c @@ -58,6 +58,7 @@ BOOTSTD_TEST(cedit_base, 0); /* Check the cedit write_fdt and read_fdt commands */ static int cedit_fdt(struct unit_test_state *uts) { + struct scene_obj_textline *tline; struct video_priv *vid_priv; extern struct expo *cur_exp; struct scene_obj_menu *menu; @@ -66,6 +67,7 @@ static int cedit_fdt(struct unit_test_state *uts) struct scene *scn; oftree tree; ofnode node; + char *str; void *fdt; int i; @@ -79,6 +81,12 @@ static int cedit_fdt(struct unit_test_state *uts) ut_assertnonnull(menu); menu->cur_item_id = ID_CPU_SPEED_2; + /* get a textline to fiddle with too */ + tline = scene_obj_find(scn, ID_MACHINE_NAME, SCENEOBJT_TEXTLINE); + ut_assertnonnull(tline); + str = abuf_data(&tline->buf); + strcpy(str, "my-machine"); + ut_assertok(run_command("cedit write_fdt hostfs - settings.dtb", 0)); ut_assertok(run_commandf("load hostfs - %lx settings.dtb", addr)); ut_assert_nextlinen("1024 bytes read"); @@ -86,26 +94,29 @@ static int cedit_fdt(struct unit_test_state *uts) fdt = map_sysmem(addr, 1024); tree = oftree_from_fdt(fdt); node = ofnode_find_subnode(oftree_root(tree), CEDIT_NODE_NAME); + ut_assert(ofnode_valid(node)); ut_asserteq(ID_CPU_SPEED_2, ofnode_read_u32_default(node, "cpu-speed", 0)); ut_asserteq_str("2.5 GHz", ofnode_read_string(node, "cpu-speed-str")); - ut_assert(ofnode_valid(node)); + ut_asserteq_str("my-machine", ofnode_read_string(node, "machine-name")); - /* There should only be 4 properties */ + /* There should only be 5 properties */ for (i = 0, ofnode_first_property(node, &prop); ofprop_valid(&prop); i++, ofnode_next_property(&prop)) ; - ut_asserteq(4, i); + ut_asserteq(5, i); ut_assert_console_end(); /* reset the expo */ menu->cur_item_id = ID_CPU_SPEED_1; + *str = '\0'; /* load in the settings and make sure they update */ ut_assertok(run_command("cedit read_fdt hostfs - settings.dtb", 0)); ut_asserteq(ID_CPU_SPEED_2, menu->cur_item_id); + ut_asserteq_str("my-machine", ofnode_read_string(node, "machine-name")); ut_assertnonnull(menu); ut_assert_console_end(); @@ -117,10 +128,12 @@ BOOTSTD_TEST(cedit_fdt, 0); /* Check the cedit write_env and read_env commands */ static int cedit_env(struct unit_test_state *uts) { + struct scene_obj_textline *tline; struct video_priv *vid_priv; extern struct expo *cur_exp; struct scene_obj_menu *menu; struct scene *scn; + char *str; console_record_reset_enable(); ut_assertok(run_command("cedit load hostfs - cedit.dtb", 0)); @@ -132,25 +145,36 @@ static int cedit_env(struct unit_test_state *uts) ut_assertnonnull(menu); menu->cur_item_id = ID_CPU_SPEED_2; + /* get a textline to fiddle with too */ + tline = scene_obj_find(scn, ID_MACHINE_NAME, SCENEOBJT_TEXTLINE); + ut_assertnonnull(tline); + str = abuf_data(&tline->buf); + strcpy(str, "my-machine"); + ut_assertok(run_command("cedit write_env -v", 0)); ut_assert_nextlinen("c.cpu-speed=7"); ut_assert_nextlinen("c.cpu-speed-str=2.5 GHz"); ut_assert_nextlinen("c.power-loss=10"); ut_assert_nextlinen("c.power-loss-str=Always Off"); + ut_assert_nextlinen("c.machine-name=my-machine"); ut_assert_console_end(); ut_asserteq(7, env_get_ulong("c.cpu-speed", 10, 0)); ut_asserteq_str("2.5 GHz", env_get("c.cpu-speed-str")); + ut_asserteq_str("my-machine", env_get("c.machine-name")); /* reset the expo */ menu->cur_item_id = ID_CPU_SPEED_1; + *str = '\0'; ut_assertok(run_command("cedit read_env -v", 0)); ut_assert_nextlinen("c.cpu-speed=7"); ut_assert_nextlinen("c.power-loss=10"); + ut_assert_nextlinen("c.machine-name=my-machine"); ut_assert_console_end(); ut_asserteq(ID_CPU_SPEED_2, menu->cur_item_id); + ut_asserteq_str("my-machine", env_get("c.machine-name")); return 0; } diff --git a/test/boot/expo.c b/test/boot/expo.c index 90027409c81..714fdfa415d 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -654,7 +654,7 @@ static int expo_test_build(struct unit_test_state *uts) ut_asserteq_str("name", exp->name); ut_asserteq(0, exp->scene_id); - ut_asserteq(ID_DYNAMIC_START + 20, exp->next_id); + ut_asserteq(ID_DYNAMIC_START + 24, exp->next_id); ut_asserteq(false, exp->popup); /* check the scene */ diff --git a/test/boot/files/expo_ids.h b/test/boot/files/expo_ids.h index 027d44bf38c..a86e0d06f6b 100644 --- a/test/boot/files/expo_ids.h +++ b/test/boot/files/expo_ids.h @@ -21,5 +21,8 @@ enum { ID_AC_ON, ID_AC_MEMORY, + ID_MACHINE_NAME, + ID_MACHINE_NAME_EDIT, + ID_DYNAMIC_START, }; diff --git a/test/boot/files/expo_layout.dts b/test/boot/files/expo_layout.dts index cb2a674d9d5..bed552288f4 100644 --- a/test/boot/files/expo_layout.dts +++ b/test/boot/files/expo_layout.dts @@ -55,6 +55,14 @@ start-bit = <0x422>; bit-length = <2>; }; + + machine-name { + id = <ID_MACHINE_NAME>; + type = "textline"; + max-chars = <20>; + title = "Machine name"; + edit-id = <ID_MACHINE_NAME_EDIT>; + }; }; }; diff --git a/test/boot/measurement.c b/test/boot/measurement.c new file mode 100644 index 00000000000..9db2ed324c2 --- /dev/null +++ b/test/boot/measurement.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for measured boot functions + * + * Copyright 2023 IBM Corp. + * Written by Eddie James <eajames@linux.ibm.com> + */ + +#include <common.h> +#include <bootm.h> +#include <malloc.h> +#include <test/suites.h> +#include <test/test.h> +#include <test/ut.h> +#include <asm/io.h> + +#define MEASUREMENT_TEST(_name, _flags) \ + UNIT_TEST(_name, _flags, measurement_test) + +static int measure(struct unit_test_state *uts) +{ + struct bootm_headers images; + const size_t size = 1024; + u8 *kernel; + u8 *initrd; + size_t i; + + kernel = malloc(size); + initrd = malloc(size); + + images.os.image_start = map_to_sysmem(kernel); + images.os.image_len = size; + + images.rd_start = map_to_sysmem(initrd); + images.rd_end = images.rd_start + size; + + images.ft_addr = malloc(size); + images.ft_len = size; + + env_set("bootargs", "measurement testing"); + + for (i = 0; i < size; ++i) { + kernel[i] = 0xf0 | (i & 0xf); + initrd[i] = (i & 0xf0) | 0xf; + images.ft_addr[i] = i & 0xff; + } + + ut_assertok(bootm_measure(&images)); + + free(images.ft_addr); + free(initrd); + free(kernel); + + return 0; +} +MEASUREMENT_TEST(measure, 0); + +int do_ut_measurement(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct unit_test *tests = UNIT_TEST_SUITE_START(measurement_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(measurement_test); + + return cmd_ut_category("measurement", "measurement_test_", tests, + n_ents, argc, argv); +} diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 6e3d7e919ef..e296ba1192b 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_CMD_ADDRMAP) += addrmap.o obj-$(CONFIG_CMD_BDI) += bdinfo.o obj-$(CONFIG_CMD_FDT) += fdt.o obj-$(CONFIG_CONSOLE_TRUETYPE) += font.o +obj-$(CONFIG_CMD_HISTORY) += history.o obj-$(CONFIG_CMD_LOADM) += loadm.o obj-$(CONFIG_CMD_MEM_SEARCH) += mem_search.o ifdef CONFIG_CMD_PCI @@ -23,6 +24,7 @@ obj-$(CONFIG_CMD_PINMUX) += pinmux.o obj-$(CONFIG_CMD_PWM) += pwm.o obj-$(CONFIG_CMD_SEAMA) += seama.o ifdef CONFIG_SANDBOX +obj-$(CONFIG_CMD_MBR) += mbr.o obj-$(CONFIG_CMD_READ) += rw.o obj-$(CONFIG_CMD_SETEXPR) += setexpr.o obj-$(CONFIG_ARM_FFA_TRANSPORT) += armffa.o diff --git a/test/cmd/history.c b/test/cmd/history.c new file mode 100644 index 00000000000..06517fcdbb5 --- /dev/null +++ b/test/cmd/history.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for history command + * + * Copyright 2023 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <cli.h> +#include <command.h> +#include <test/lib.h> +#include <test/test.h> +#include <test/ut.h> + +static int lib_test_history(struct unit_test_state *uts) +{ + static const char cmd1[] = "setenv fred hello"; + static const char cmd2[] = "print fred"; + + /* running commands directly does not add to history */ + ut_assertok(run_command(cmd1, 0)); + ut_assert_console_end(); + ut_assertok(run_command("history", 0)); + ut_assert_console_end(); + + /* enter commands via the console */ + console_in_puts(cmd1); + console_in_puts("\n"); + ut_asserteq(strlen(cmd1), cli_readline("")); + ut_assert_nextline(cmd1); + + console_in_puts(cmd2); + console_in_puts("\n"); + ut_asserteq(strlen(cmd2), cli_readline("")); + ut_assert_nextline(cmd2); + + ut_assertok(run_command("print fred", 0)); + ut_assert_nextline("fred=hello"); + ut_assert_console_end(); + + ut_assertok(run_command("history", 0)); + ut_assert_nextline(cmd1); + ut_assert_nextline(cmd2); + ut_assert_console_end(); + + return 0; +} +LIB_TEST(lib_test_history, UT_TESTF_CONSOLE_REC); diff --git a/test/cmd/mbr.c b/test/cmd/mbr.c new file mode 100644 index 00000000000..46b78e706ca --- /dev/null +++ b/test/cmd/mbr.c @@ -0,0 +1,479 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Tests for mbr command + * + * Copyright 2023 Matrox Video + * Written by Alex Gendin <agendin@matrox.com> + */ + +#include <dm.h> +#include <console.h> +#include <dm/test.h> +#include <mapmem.h> +#include <part.h> +#include <asm/global_data.h> +#include <dm/device-internal.h> +#include <dm/lists.h> +#include <test/suites.h> +#include <test/ut.h> + +DECLARE_GLOBAL_DATA_PTR; +/* + * Requirements for running test manually: + * mmc6.img - File size needs to be at least 12 MiB + * + * Command to create mmc6.img: + * $ dd if=/dev/zero of=mmc6.img bs=12M count=1 + * + * To run this test manually, place mmc6.img into the same directory as u-boot, + * then run: + * $ ./u-boot -Tc 'ut mbr' + * + * To run this test as part of U-Boot test: + * $ ./test/py/test.py --bd sandbox --build -k ut_dm -v + * Note: mmc6.img will be created by the test suit. + */ + +static char * mbr_parts_header = "setenv mbr_parts '"; +static char * mbr_parts_p1 = "uuid_disk=0x12345678;name=p1,start=8M,bootable,size=1M,id=0x0e"; +static char * mbr_parts_p2 = ";name=p2,size=1M,id=0x0e"; +static char * mbr_parts_p3 = ";name=p3,size=1M,id=0x0e"; +static char * mbr_parts_p4 = ";name=p4,size=1M,id=0x0e"; +static char * mbr_parts_p5 = ";name=[ext],size=2M,id=0x05;name=p5,size=1M,id=0x0e"; +static char * mbr_parts_tail = "'"; + +/* + * One MBR partition +000001b0 00 00 00 00 00 00 00 00 78 56 34 12 00 00 80 05 |........xV4.....| +000001c0 05 01 0e 25 24 01 00 40 00 00 00 08 00 00 00 00 |...%$..@........| +000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.| +*/ +static unsigned mbr_cmp_start = 0x1B8; +static unsigned mbr_cmp_size = 0x48; +static unsigned char mbr_parts_ref_p1[] = { + 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x80, 0x05, +0x05, 0x01, 0x0e, 0x25, 0x24, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa +}; + +/* + * Two MBR partitions +000001b0 00 00 00 00 00 00 00 00 78 56 34 12 00 00 80 05 |........xV4.....| +000001c0 05 01 0e 25 24 01 00 40 00 00 00 08 00 00 00 25 |...%$..@.......%| +000001d0 25 01 0e 46 05 01 00 48 00 00 00 08 00 00 00 00 |%..F...H........| +000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.| +*/ +static unsigned char mbr_parts_ref_p2[] = { + 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x80, 0x05, +0x05, 0x01, 0x0e, 0x25, 0x24, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x25, +0x25, 0x01, 0x0e, 0x46, 0x05, 0x01, 0x00, 0x48, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa +}; + +/* + * Three MBR partitions +000001b0 00 00 00 00 00 00 00 00 78 56 34 12 00 00 80 05 |........xV4.....| +000001c0 05 01 0e 25 24 01 00 40 00 00 00 08 00 00 00 25 |...%$..@.......%| +000001d0 25 01 0e 46 05 01 00 48 00 00 00 08 00 00 00 46 |%..F...H.......F| +000001e0 06 01 0e 66 25 01 00 50 00 00 00 08 00 00 00 00 |...f%..P........| +000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.| +*/ +static unsigned char mbr_parts_ref_p3[] = { + 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x80, 0x05, +0x05, 0x01, 0x0e, 0x25, 0x24, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x25, +0x25, 0x01, 0x0e, 0x46, 0x05, 0x01, 0x00, 0x48, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x46, +0x06, 0x01, 0x0e, 0x66, 0x25, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa +}; + +/* + * Four MBR partitions +000001b0 00 00 00 00 00 00 00 00 78 56 34 12 00 00 80 05 |........xV4.....| +000001c0 05 01 0e 25 24 01 00 40 00 00 00 08 00 00 00 25 |...%$..@.......%| +000001d0 25 01 0e 46 05 01 00 48 00 00 00 08 00 00 00 46 |%..F...H.......F| +000001e0 06 01 0e 66 25 01 00 50 00 00 00 08 00 00 00 66 |...f%..P.......f| +000001f0 26 01 0e 87 06 01 00 58 00 00 00 08 00 00 55 aa |&......X......U.| +*/ +static unsigned char mbr_parts_ref_p4[] = { + 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x80, 0x05, +0x05, 0x01, 0x0e, 0x25, 0x24, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x25, +0x25, 0x01, 0x0e, 0x46, 0x05, 0x01, 0x00, 0x48, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x46, +0x06, 0x01, 0x0e, 0x66, 0x25, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x66, +0x26, 0x01, 0x0e, 0x87, 0x06, 0x01, 0x00, 0x58, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x55, 0xaa +}; + +/* + * Five MBR partitions +000001b0 00 00 00 00 00 00 00 00 78 56 34 12 00 00 80 05 |........xV4.....| +000001c0 05 01 0e 25 24 01 00 40 00 00 00 08 00 00 00 25 |...%$..@.......%| +000001d0 25 01 0e 46 05 01 00 48 00 00 00 08 00 00 00 46 |%..F...H.......F| +000001e0 06 01 0e 66 25 01 00 50 00 00 00 08 00 00 00 66 |...f%..P.......f| +000001f0 26 01 05 a7 26 01 00 58 00 00 00 10 00 00 55 aa |&...&..X......U.| +*/ +static unsigned char mbr_parts_ref_p5[] = { + 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x80, 0x05, +0x05, 0x01, 0x0e, 0x25, 0x24, 0x01, 0x00, 0x40, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x25, +0x25, 0x01, 0x0e, 0x46, 0x05, 0x01, 0x00, 0x48, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x46, +0x06, 0x01, 0x0e, 0x66, 0x25, 0x01, 0x00, 0x50, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x66, +0x26, 0x01, 0x05, 0xa7, 0x26, 0x01, 0x00, 0x58, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x55, 0xaa +}; +static unsigned ebr_cmp_start = 0x1B8; +static unsigned ebr_cmp_size = 0x48; +/* + * EBR +00b001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 87 |................| +00b001c0 07 01 0e a7 26 01 00 08 00 00 00 08 00 00 00 00 |....&...........| +00b001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00b001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00b001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.| +*/ +static unsigned char ebr_parts_ref_p5[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, +0x07, 0x01, 0x0e, 0xa7, 0x26, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa +}; + +/* Fill write buffers with pseudo-random data */ +static void init_write_buffers(char *mbr_wb, size_t mbr_wb_size, + char *ebr_wb, size_t ebr_wb_size, unsigned seed) +{ + while (mbr_wb_size--) { + *mbr_wb++ = seed; + seed *= 43; + seed += 17 + mbr_wb_size/4; + } + while (ebr_wb_size--) { + *ebr_wb++ = seed; + seed *= 43; + seed += 17 + ebr_wb_size/4; + } +} + +/* Build string with MBR partition(s) layout */ +static unsigned build_mbr_parts(char *buf, size_t buf_size, unsigned num_parts) +{ + size_t bytes_remaining, cur_str_size; + char * cur_buf; + + if (!num_parts || num_parts > 5 || !buf) + return 1; + + cur_buf = buf; + *cur_buf = '\0'; + bytes_remaining = buf_size; + + cur_str_size = sizeof(mbr_parts_header); + if (cur_str_size + 1 > bytes_remaining) + return 1; + strcat(cur_buf, mbr_parts_header); + bytes_remaining -= cur_str_size; + + if (num_parts >= 1) { + cur_str_size = sizeof(mbr_parts_p1); + if (cur_str_size + 1 > bytes_remaining) + return 1; + strcat(cur_buf, mbr_parts_p1); + bytes_remaining -= cur_str_size; + + if (num_parts >= 2) { + cur_str_size = sizeof(mbr_parts_p2); + if (cur_str_size + 1 > bytes_remaining) + return 1; + strcat(cur_buf, mbr_parts_p2); + bytes_remaining -= cur_str_size; + + if (num_parts >= 3) { + cur_str_size = sizeof(mbr_parts_p3); + if (cur_str_size + 1 > bytes_remaining) + return 1; + strcat(cur_buf, mbr_parts_p3); + bytes_remaining -= cur_str_size; + + if (num_parts == 4) { + cur_str_size = sizeof(mbr_parts_p4); + if (cur_str_size + 1 > bytes_remaining) + return 1; + strcat(cur_buf, mbr_parts_p4); + bytes_remaining -= cur_str_size; + + } + else if (num_parts == 5) { + cur_str_size = sizeof(mbr_parts_p5); + if (cur_str_size + 1 > bytes_remaining) + return 1; + strcat(cur_buf, mbr_parts_p5); + bytes_remaining -= cur_str_size; + + } + } + } + } + + cur_str_size = sizeof(mbr_parts_tail); + if (cur_str_size + 1 > bytes_remaining) + return 1; + strcat(cur_buf, mbr_parts_tail); + + return 0; +} + +static int mbr_test_run(struct unit_test_state *uts) +{ + struct blk_desc *mmc_dev_desc; + unsigned char mbr_wbuf[512], ebr_wbuf[512], rbuf[512]; + char mbr_parts_buf[256]; + ulong mbr_wa, ebr_wa, ra, ebr_blk, mbr_parts_max; + struct udevice *dev; + ofnode root, node; + + /* Enable the mmc6 node for this test */ + root = oftree_root(oftree_default()); + node = ofnode_find_subnode(root, "mmc6"); + ut_assert(ofnode_valid(node)); + ut_assertok(lists_bind_fdt(gd->dm_root, node, &dev, NULL, false)); + + mbr_parts_max = sizeof('\0') + 2 + + strlen(mbr_parts_header) + + strlen(mbr_parts_p1) + + strlen(mbr_parts_p2) + + strlen(mbr_parts_p3) + + max(strlen(mbr_parts_p4), strlen(mbr_parts_p5)) + + strlen(mbr_parts_tail); + ut_assertf(sizeof(mbr_parts_buf) >= mbr_parts_max, "Buffer avail: %ld; buffer req: %ld\n", + sizeof(mbr_parts_buf), mbr_parts_max); + + mbr_wa = map_to_sysmem(mbr_wbuf); + ebr_wa = map_to_sysmem(ebr_wbuf); + ra = map_to_sysmem(rbuf); + ebr_blk = (ulong)0xB00000 / 0x200; + + /* Make sure mmc6 exists */ + ut_asserteq(6, blk_get_device_by_str("mmc", "6", &mmc_dev_desc)); + ut_assertok(console_record_reset_enable()); + ut_assertok(run_commandf("mmc dev 6")); + ut_assert_nextline("switch to partitions #0, OK"); + ut_assert_nextline("mmc6 is current device"); + ut_assertok(ut_check_console_end(uts)); + + /* Make sure mmc6 is 12+ MiB in size */ + ut_assertok(run_commandf("mmc read 0x%lx 0x%lx 1", ra, (ulong)0xBFFE00 / 0x200)); + + /* Test one MBR partition */ + init_write_buffers(mbr_wbuf, sizeof(mbr_wbuf), ebr_wbuf, sizeof(ebr_wbuf), __LINE__); + ut_assertok(build_mbr_parts(mbr_parts_buf, sizeof(mbr_parts_buf), 1)); + ut_assertok(run_commandf("write mmc 6:0 0x%lx 0 1", mbr_wa)); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0 1", ra)); + ut_assertok(memcmp(mbr_wbuf, rbuf, 512)); + ut_assertok(run_commandf("write mmc 6:0 0x%lx 0x%lx 1", ebr_wa, ebr_blk)); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0x%lx 1", ra, ebr_blk)); + ut_assertok(memcmp(ebr_wbuf, rbuf, 512)); + ut_assertok(console_record_reset_enable()); + ut_assertf(0 == run_commandf(mbr_parts_buf), "Invalid partitions string: %s\n", mbr_parts_buf); + ut_assertok(run_commandf("mbr write mmc 6")); + ut_assert_nextline("MBR: write success!"); + ut_assertok(run_commandf("mbr verify mmc 6")); + ut_assert_nextline("MBR: verify success!"); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0x%lx 1", ra, ebr_blk)); + ut_assertok(memcmp(ebr_wbuf, rbuf, 512)); + ut_assertok(ut_check_console_end(uts)); + /* + 000001b0 00 00 00 00 00 00 00 00 78 56 34 12 00 00 80 05 |........xV4.....| + 000001c0 05 01 0e 25 24 01 00 40 00 00 00 08 00 00 00 00 |...%$..@........| + 000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.| + */ + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0 1", ra)); + for (unsigned i = 0; i < mbr_cmp_size; i++) { + ut_assertf(rbuf[mbr_cmp_start + i] == mbr_parts_ref_p1[i], + "1P MBR+0x%04X: expected 0x%02X, actual: 0x%02X\n", + mbr_cmp_start + i, mbr_parts_ref_p1[i], rbuf[mbr_cmp_start + i]); + } + + /* Test two MBR partitions */ + init_write_buffers(mbr_wbuf, sizeof(mbr_wbuf), ebr_wbuf, sizeof(ebr_wbuf), __LINE__); + ut_assertok(build_mbr_parts(mbr_parts_buf, sizeof(mbr_parts_buf), 2)); + ut_assertok(run_commandf("write mmc 6:0 0x%lx 0 1", mbr_wa)); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0 1", ra)); + ut_assertok(memcmp(mbr_wbuf, rbuf, 512)); + ut_assertok(run_commandf("write mmc 6:0 0x%lx 0x%lx 1", ebr_wa, ebr_blk)); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0x%lx 1", ra, ebr_blk)); + ut_assertok(memcmp(ebr_wbuf, rbuf, 512)); + ut_assertok(console_record_reset_enable()); + ut_assertf(0 == run_commandf(mbr_parts_buf), "Invalid partitions string: %s\n", mbr_parts_buf); + ut_assertok(run_commandf("mbr write mmc 6")); + ut_assert_nextline("MBR: write success!"); + ut_assertok(run_commandf("mbr verify mmc 6")); + ut_assert_nextline("MBR: verify success!"); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0x%lx 1", ra, ebr_blk)); + ut_assertok(memcmp(ebr_wbuf, rbuf, 512)); + ut_assertok(ut_check_console_end(uts)); + /* + 000001b0 00 00 00 00 00 00 00 00 78 56 34 12 00 00 80 05 |........xV4.....| + 000001c0 05 01 0e 25 24 01 00 40 00 00 00 08 00 00 00 25 |...%$..@.......%| + 000001d0 25 01 0e 46 05 01 00 48 00 00 00 08 00 00 00 00 |%..F...H........| + 000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.| + */ + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0 1", ra)); + for (unsigned i = 0; i < mbr_cmp_size; i++) { + ut_assertf(rbuf[mbr_cmp_start + i] == mbr_parts_ref_p2[i], + "2P MBR+0x%04X: expected 0x%02X, actual: 0x%02X\n", + mbr_cmp_start + i, mbr_parts_ref_p2[i], rbuf[mbr_cmp_start + i]); + } + + /* Test three MBR partitions */ + init_write_buffers(mbr_wbuf, sizeof(mbr_wbuf), ebr_wbuf, sizeof(ebr_wbuf), __LINE__); + ut_assertok(build_mbr_parts(mbr_parts_buf, sizeof(mbr_parts_buf), 3)); + ut_assertok(run_commandf("write mmc 6:0 0x%lx 0 1", mbr_wa)); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0 1", ra)); + ut_assertok(memcmp(mbr_wbuf, rbuf, 512)); + ut_assertok(run_commandf("write mmc 6:0 0x%lx 0x%lx 1", ebr_wa, ebr_blk)); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0x%lx 1", ra, ebr_blk)); + ut_assertok(memcmp(ebr_wbuf, rbuf, 512)); + ut_assertok(console_record_reset_enable()); + ut_assertf(0 == run_commandf(mbr_parts_buf), "Invalid partitions string: %s\n", mbr_parts_buf); + ut_assertok(run_commandf("mbr write mmc 6")); + ut_assert_nextline("MBR: write success!"); + ut_assertok(run_commandf("mbr verify mmc 6")); + ut_assert_nextline("MBR: verify success!"); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0x%lx 1", ra, ebr_blk)); + ut_assertok(memcmp(ebr_wbuf, rbuf, 512)); + ut_assertok(ut_check_console_end(uts)); + /* + 000001b0 00 00 00 00 00 00 00 00 78 56 34 12 00 00 80 05 |........xV4.....| + 000001c0 05 01 0e 25 24 01 00 40 00 00 00 08 00 00 00 25 |...%$..@.......%| + 000001d0 25 01 0e 46 05 01 00 48 00 00 00 08 00 00 00 46 |%..F...H.......F| + 000001e0 06 01 0e 66 25 01 00 50 00 00 00 08 00 00 00 00 |...f%..P........| + 000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.| + */ + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0 1", ra)); + for (unsigned i = 0; i < mbr_cmp_size; i++) { + ut_assertf(rbuf[mbr_cmp_start + i] == mbr_parts_ref_p3[i], + "3P MBR+0x%04X: expected 0x%02X, actual: 0x%02X\n", + mbr_cmp_start + i, mbr_parts_ref_p3[i], rbuf[mbr_cmp_start + i]); + } + + /* Test four MBR partitions */ + init_write_buffers(mbr_wbuf, sizeof(mbr_wbuf), ebr_wbuf, sizeof(ebr_wbuf), __LINE__); + ut_assertok(build_mbr_parts(mbr_parts_buf, sizeof(mbr_parts_buf), 4)); + ut_assertok(run_commandf("write mmc 6:0 0x%lx 0 1", mbr_wa)); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0 1", ra)); + ut_assertok(memcmp(mbr_wbuf, rbuf, 512)); + ut_assertok(run_commandf("write mmc 6:0 0x%lx 0x%lx 1", ebr_wa, ebr_blk)); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0x%lx 1", ra, ebr_blk)); + ut_assertok(memcmp(ebr_wbuf, rbuf, 512)); + ut_assertok(console_record_reset_enable()); + ut_assertf(0 == run_commandf(mbr_parts_buf), "Invalid partitions string: %s\n", mbr_parts_buf); + ut_assertok(run_commandf("mbr write mmc 6")); + ut_assert_nextline("MBR: write success!"); + ut_assertok(run_commandf("mbr verify mmc 6")); + ut_assert_nextline("MBR: verify success!"); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0x%lx 1", ra, ebr_blk)); + ut_assertok(memcmp(ebr_wbuf, rbuf, 512)); + ut_assertok(ut_check_console_end(uts)); + /* + 000001b0 00 00 00 00 00 00 00 00 78 56 34 12 00 00 80 05 |........xV4.....| + 000001c0 05 01 0e 25 24 01 00 40 00 00 00 08 00 00 00 25 |...%$..@.......%| + 000001d0 25 01 0e 46 05 01 00 48 00 00 00 08 00 00 00 46 |%..F...H.......F| + 000001e0 06 01 0e 66 25 01 00 50 00 00 00 08 00 00 00 66 |...f%..P.......f| + 000001f0 26 01 0e 87 06 01 00 58 00 00 00 08 00 00 55 aa |&......X......U.| + */ + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0 1", ra)); + for (unsigned i = 0; i < mbr_cmp_size; i++) { + ut_assertf(rbuf[mbr_cmp_start + i] == mbr_parts_ref_p4[i], + "4P MBR+0x%04X: expected 0x%02X, actual: 0x%02X\n", + mbr_cmp_start + i, mbr_parts_ref_p4[i], rbuf[mbr_cmp_start + i]); + } + + /* Test five MBR partitions */ + init_write_buffers(mbr_wbuf, sizeof(mbr_wbuf), ebr_wbuf, sizeof(ebr_wbuf), __LINE__); + ut_assertok(build_mbr_parts(mbr_parts_buf, sizeof(mbr_parts_buf), 5)); + ut_assertok(run_commandf("write mmc 6:0 0x%lx 0 1", mbr_wa)); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0 1", ra)); + ut_assertok(memcmp(mbr_wbuf, rbuf, 512)); + ut_assertok(run_commandf("write mmc 6:0 0x%lx 0x%lx 1", ebr_wa, ebr_blk)); + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0x%lx 1", ra, ebr_blk)); + ut_assertok(memcmp(ebr_wbuf, rbuf, 512)); + ut_assertok(console_record_reset_enable()); + ut_assertf(0 == run_commandf(mbr_parts_buf), "Invalid partitions string: %s\n", mbr_parts_buf); + ut_assertf(0 == run_commandf("mbr write mmc 6"), "Invalid partitions string: %s\n", mbr_parts_buf); + ut_assert_nextline("MBR: write success!"); + ut_assertok(run_commandf("mbr verify mmc 6")); + ut_assert_nextline("MBR: verify success!"); + ut_assertok(ut_check_console_end(uts)); + /* + 000001b0 00 00 00 00 00 00 00 00 78 56 34 12 00 00 80 05 |........xV4.....| + 000001c0 05 01 0e 25 24 01 00 40 00 00 00 08 00 00 00 25 |...%$..@.......%| + 000001d0 25 01 0e 46 05 01 00 48 00 00 00 08 00 00 00 46 |%..F...H.......F| + 000001e0 06 01 0e 66 25 01 00 50 00 00 00 08 00 00 00 66 |...f%..P.......f| + 000001f0 26 01 05 a7 26 01 00 58 00 00 00 10 00 00 55 aa |&...&..X......U.| + */ + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0 1", ra)); + for (unsigned i = 0; i < mbr_cmp_size; i++) { + ut_assertf(rbuf[mbr_cmp_start + i] == mbr_parts_ref_p5[i], + "5P MBR+0x%04X: expected 0x%02X, actual: 0x%02X\n", + mbr_cmp_start + i, mbr_parts_ref_p5[i], rbuf[mbr_cmp_start + i]); + } + /* + 00b001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 87 |................| + 00b001c0 07 01 0e a7 26 01 00 08 00 00 00 08 00 00 00 00 |....&...........| + 00b001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 00b001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 00b001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.| + */ + memset(rbuf, 0, sizeof(rbuf)); + ut_assertok(run_commandf("read mmc 6:0 0x%lx 0x%lx 1", ra, ebr_blk)); + for (unsigned i = 0; i < ebr_cmp_size; i++) { + ut_assertf(rbuf[ebr_cmp_start + i] == ebr_parts_ref_p5[i], + "5P EBR+0x%04X: expected 0x%02X, actual: 0x%02X\n", + ebr_cmp_start + i, ebr_parts_ref_p5[i], rbuf[ebr_cmp_start + i]); + } + + return 0; +} + +/* Declare mbr test */ +UNIT_TEST(mbr_test_run, UT_TESTF_CONSOLE_REC, mbr_test); + +int do_ut_mbr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) +{ + struct unit_test *tests = UNIT_TEST_SUITE_START(mbr_test); + const int n_ents = UNIT_TEST_SUITE_COUNT(mbr_test); + + return cmd_ut_category("mbr", "mbr_test_", tests, n_ents, argc, argv); +} + +static int dm_test_cmd_mbr(struct unit_test_state *uts) +{ + return mbr_test_run(uts); +} + +DM_TEST(dm_test_cmd_mbr, UT_TESTF_SCAN_FDT | UT_TESTF_CONSOLE_REC); diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 0f56409e803..2d5b80f992e 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -87,6 +87,10 @@ static struct cmd_tbl cmd_ut_sub[] = { #ifdef CONFIG_UT_LOG U_BOOT_CMD_MKENT(log, CONFIG_SYS_MAXARGS, 1, do_ut_log, "", ""), #endif +#if defined(CONFIG_SANDBOX) && defined(CONFIG_CMD_MBR) && defined(CONFIG_CMD_MMC) \ + && defined(CONFIG_MMC_SANDBOX) && defined(CONFIG_MMC_WRITE) + U_BOOT_CMD_MKENT(mbr, CONFIG_SYS_MAXARGS, 1, do_ut_mbr, "", ""), +#endif U_BOOT_CMD_MKENT(mem, CONFIG_SYS_MAXARGS, 1, do_ut_mem, "", ""), #if defined(CONFIG_SANDBOX) && defined(CONFIG_CMD_SETEXPR) U_BOOT_CMD_MKENT(setexpr, CONFIG_SYS_MAXARGS, 1, do_ut_setexpr, "", @@ -99,6 +103,10 @@ static struct cmd_tbl cmd_ut_sub[] = { #if CONFIG_IS_ENABLED(UT_UNICODE) && !defined(API_BUILD) U_BOOT_CMD_MKENT(unicode, CONFIG_SYS_MAXARGS, 1, do_ut_unicode, "", ""), #endif +#ifdef CONFIG_MEASURED_BOOT + U_BOOT_CMD_MKENT(measurement, CONFIG_SYS_MAXARGS, 1, do_ut_measurement, + "", ""), +#endif #ifdef CONFIG_SANDBOX U_BOOT_CMD_MKENT(compression, CONFIG_SYS_MAXARGS, 1, do_ut_compression, "", ""), @@ -166,8 +174,7 @@ static int do_ut(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) return CMD_RET_USAGE; } -#ifdef CONFIG_SYS_LONGHELP -static char ut_help_text[] = +U_BOOT_LONGHELP(ut, "[-r] [-f] [<suite>] - run unit tests\n" " -r<runs> Number of times to run each test\n" " -f Force 'manual' tests to run as well\n" @@ -237,8 +244,7 @@ static char ut_help_text[] = !defined(CONFIG_SPL_BUILD) && !defined(API_BUILD) "\nunicode - Unicode functions" #endif - ; -#endif /* CONFIG_SYS_LONGHELP */ + ); U_BOOT_CMD( ut, CONFIG_SYS_MAXARGS, 1, do_ut, diff --git a/test/common/cread.c b/test/common/cread.c index 2fdd29a265f..4edc7739604 100644 --- a/test/common/cread.c +++ b/test/common/cread.c @@ -43,6 +43,12 @@ static int cli_ch_test(struct unit_test_state *uts) ut_asserteq('a', cli_ch_process(cch, 'a')); ut_asserteq(0, cli_ch_process(cch, 0)); + /* unexpected 'Esc' */ + ut_asserteq('a', cli_ch_process(cch, 'a')); + ut_asserteq(0, cli_ch_process(cch, '\e')); + ut_asserteq('b', cli_ch_process(cch, 'b')); + ut_asserteq(0, cli_ch_process(cch, 0)); + return 0; } COMMON_TEST(cli_ch_test, 0); @@ -80,6 +86,12 @@ static int cread_test(struct unit_test_state *uts) ut_asserteq(7, cli_readline_into_buffer("-> ", buf, 1)); ut_asserteq_str("abc\e[Xx", buf); + /* unexpected 'Esc' */ + *buf = '\0'; + ut_asserteq(7, console_in_puts("abc\eXx\n")); + ut_asserteq(5, cli_readline_into_buffer("-> ", buf, 1)); + ut_asserteq_str("abcXx", buf); + /* check timeout, should be between 1000 and 1050ms */ start = get_timer(0); *buf = '\0'; diff --git a/test/dm/Makefile b/test/dm/Makefile index 7ed00733c1a..a3ce7b3889f 100644 --- a/test/dm/Makefile +++ b/test/dm/Makefile @@ -73,6 +73,7 @@ obj-$(CONFIG_CMD_MUX) += mux-cmd.o obj-$(CONFIG_MULTIPLEXER) += mux-emul.o obj-$(CONFIG_MUX_MMIO) += mux-mmio.o obj-y += fdtdec.o +obj-$(CONFIG_MTD_RAW_NAND) += nand.o obj-$(CONFIG_UT_DM) += nop.o obj-y += ofnode.o obj-y += ofread.o @@ -100,6 +101,7 @@ obj-$(CONFIG_REMOTEPROC) += remoteproc.o obj-$(CONFIG_DM_RESET) += reset.o obj-$(CONFIG_SYSRESET) += sysreset.o obj-$(CONFIG_DM_REGULATOR) += regulator.o +obj-$(CONFIG_CMD_RKMTD) += rkmtd.o obj-$(CONFIG_DM_RNG) += rng.o obj-$(CONFIG_DM_RTC) += rtc.o obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o @@ -115,6 +117,7 @@ obj-$(CONFIG_DM_SPI) += spi.o obj-$(CONFIG_SPMI) += spmi.o obj-y += syscon.o obj-$(CONFIG_RESET_SYSCON) += syscon-reset.o +obj-$(CONFIG_SM) += sm.o obj-$(CONFIG_SYSINFO) += sysinfo.o obj-$(CONFIG_SYSINFO_GPIO) += sysinfo-gpio.o obj-$(CONFIG_UT_DM) += tag.o diff --git a/test/dm/blk.c b/test/dm/blk.c index 446c4423e6f..799f1e4dc75 100644 --- a/test/dm/blk.c +++ b/test/dm/blk.c @@ -4,6 +4,7 @@ */ #include <common.h> +#include <blk.h> #include <dm.h> #include <part.h> #include <sandbox_host.h> @@ -22,8 +23,8 @@ static int dm_test_blk_base(struct unit_test_state *uts) struct udevice *blk0, *blk1, *dev0, *dev1, *dev, *chk0, *chk1; /* Create two, one the parent of the other */ - ut_assertok(host_create_device("test0", false, &dev0)); - ut_assertok(host_create_device("test1", false, &dev1)); + ut_assertok(host_create_device("test0", false, DEFAULT_BLKSZ, &dev0)); + ut_assertok(host_create_device("test1", false, DEFAULT_BLKSZ, &dev1)); /* Check we can find them */ ut_assertok(blk_get_device(UCLASS_HOST, 0, &blk0)); @@ -99,7 +100,7 @@ static int dm_test_blk_find(struct unit_test_state *uts) { struct udevice *blk, *chk, *dev; - ut_assertok(host_create_device("test0", false, &dev)); + ut_assertok(host_create_device("test0", false, DEFAULT_BLKSZ, &dev)); ut_assertok(blk_find_device(UCLASS_HOST, 0, &chk)); ut_assertok(device_find_first_child_by_uclass(dev, UCLASS_BLK, &blk)); diff --git a/test/dm/eth.c b/test/dm/eth.c index d05d2a9abe1..bb3dcc6b954 100644 --- a/test/dm/eth.c +++ b/test/dm/eth.c @@ -263,12 +263,16 @@ static int dm_test_eth_act(struct unit_test_state *uts) /* Prepare the test scenario */ for (i = 0; i < DM_TEST_ETH_NUM; i++) { + char *addr; + ut_assertok(uclass_find_device_by_name(UCLASS_ETH, ethname[i], &dev[i])); ut_assertok(device_remove(dev[i], DM_REMOVE_NORMAL)); /* Invalidate MAC address */ - strncpy(ethaddr[i], env_get(addrname[i]), 17); + addr = env_get(addrname[i]); + ut_assertnonnull(addr); + strncpy(ethaddr[i], addr, 17); /* Must disable access protection for ethaddr before clearing */ env_set(".flags", addrname[i]); env_set(addrname[i], NULL); @@ -312,12 +316,16 @@ static int dm_test_ethaddr(struct unit_test_state *uts) for (i = 0; i < ARRAY_SIZE(addr); i++) { char addrname[10]; + char *env_addr; if (i) snprintf(addrname, sizeof(addrname), "eth%daddr", i + 1); else strcpy(addrname, "ethaddr"); - ut_asserteq_str(addr[i], env_get(addrname)); + + env_addr = env_get(addrname); + ut_assertnonnull(env_addr); + ut_asserteq_str(addr[i], env_addr); } return 0; diff --git a/test/dm/host.c b/test/dm/host.c index 85f21f9839e..ca05a36b313 100644 --- a/test/dm/host.c +++ b/test/dm/host.c @@ -31,7 +31,7 @@ static int dm_test_host(struct unit_test_state *uts) ut_asserteq(-ENODEV, uclass_first_device_err(UCLASS_PARTITION, &part)); mem_start = ut_check_delta(0); - ut_assertok(host_create_device(label, true, &dev)); + ut_assertok(host_create_device(label, true, DEFAULT_BLKSZ, &dev)); /* Check that the plat data has been allocated */ plat = dev_get_plat(dev); @@ -83,7 +83,7 @@ static int dm_test_host_dup(struct unit_test_state *uts) char fname[256]; ut_asserteq(0, uclass_id_count(UCLASS_HOST)); - ut_assertok(host_create_device(label, true, &dev)); + ut_assertok(host_create_device(label, true, DEFAULT_BLKSZ, &dev)); /* Attach a file created in test_ut_dm_init */ ut_assertok(os_persistent_file(fname, sizeof(fname), "2MB.ext2.img")); @@ -93,7 +93,7 @@ static int dm_test_host_dup(struct unit_test_state *uts) ut_asserteq(1, uclass_id_count(UCLASS_HOST)); /* Create another device with the same label (should remove old one) */ - ut_assertok(host_create_device(label, true, &dev)); + ut_assertok(host_create_device(label, true, DEFAULT_BLKSZ, &dev)); /* Attach a different file created in test_ut_dm_init */ ut_assertok(os_persistent_file(fname, sizeof(fname), "1MB.fat32.img")); @@ -120,7 +120,7 @@ static int dm_test_cmd_host(struct unit_test_state *uts) /* first check 'host info' with binding */ ut_assertok(run_command("host info", 0)); - ut_assert_nextline("dev blocks label path"); + ut_assert_nextline("dev blocks blksz label path"); ut_assert_console_end(); ut_assertok(os_persistent_file(fname, sizeof(fname), "2MB.ext2.img")); @@ -133,8 +133,8 @@ static int dm_test_cmd_host(struct unit_test_state *uts) ut_asserteq(true, desc->removable); ut_assertok(run_command("host info", 0)); - ut_assert_nextline("dev blocks label path"); - ut_assert_nextlinen(" 0 4096 test2"); + ut_assert_nextline("dev blocks blksz label path"); + ut_assert_nextlinen(" 0 4096 512 test2"); ut_assert_console_end(); ut_assertok(os_persistent_file(fname, sizeof(fname), "1MB.fat32.img")); @@ -147,9 +147,9 @@ static int dm_test_cmd_host(struct unit_test_state *uts) ut_asserteq(false, desc->removable); ut_assertok(run_command("host info", 0)); - ut_assert_nextline("dev blocks label path"); - ut_assert_nextlinen(" 0 4096 test2"); - ut_assert_nextlinen(" 1 2048 fat"); + ut_assert_nextline("dev blocks blksz label path"); + ut_assert_nextlinen(" 0 4096 512 test2"); + ut_assert_nextlinen(" 1 2048 512 fat"); ut_assert_console_end(); ut_asserteq(1, run_command("host info test", 0)); @@ -157,8 +157,8 @@ static int dm_test_cmd_host(struct unit_test_state *uts) ut_assert_console_end(); ut_assertok(run_command("host info fat", 0)); - ut_assert_nextline("dev blocks label path"); - ut_assert_nextlinen(" 1 2048 fat"); + ut_assert_nextline("dev blocks blksz label path"); + ut_assert_nextlinen(" 1 2048 512 fat"); ut_assert_console_end(); /* check 'host dev' */ @@ -194,8 +194,8 @@ static int dm_test_cmd_host(struct unit_test_state *uts) ut_assert_console_end(); ut_assertok(run_command("host info", 0)); - ut_assert_nextline("dev blocks label path"); - ut_assert_nextlinen(" 1 2048 fat"); + ut_assert_nextline("dev blocks blksz label path"); + ut_assert_nextlinen(" 1 2048 512 fat"); ut_assert_console_end(); return 0; diff --git a/test/dm/mux-emul.c b/test/dm/mux-emul.c index 58233edc9b2..c6aeeb7e1f1 100644 --- a/test/dm/mux-emul.c +++ b/test/dm/mux-emul.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2020 Texas Instruments Incorporated - https://www.ti.com/ * Pratyush Yadav <p.yadav@ti.com> */ #include <common.h> diff --git a/test/dm/mux-mmio.c b/test/dm/mux-mmio.c index fd353d8b155..27c881dabde 100644 --- a/test/dm/mux-mmio.c +++ b/test/dm/mux-mmio.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2017-2018 Texas Instruments Incorporated - https://www.ti.com/ * Jean-Jacques Hiblot <jjhiblot@ti.com> */ diff --git a/test/dm/nand.c b/test/dm/nand.c new file mode 100644 index 00000000000..0b992fdce1c --- /dev/null +++ b/test/dm/nand.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Sean Anderson <seanga2@gmail.com> + */ + +#include <nand.h> +#include <part.h> +#include <rand.h> +#include <dm/test.h> +#include <test/test.h> +#include <test/ut.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/rawnand.h> + +static int dm_test_nand(struct unit_test_state *uts, int dev, bool end) +{ + nand_erase_options_t opts = { }; + struct mtd_info *mtd; + size_t length; + loff_t size; + char *buf; + int *gold; + u8 oob[NAND_MAX_OOBSIZE]; + int i; + loff_t off = 0; + mtd_oob_ops_t ops = { }; + + /* Seed RNG for bit errors */ + srand((off >> 32) ^ off ^ ~dev); + + mtd = get_nand_dev_by_index(dev); + ut_assertnonnull(mtd); + size = mtd->erasesize * 4; + length = size; + + buf = malloc(size); + ut_assertnonnull(buf); + gold = malloc(size); + ut_assertnonnull(gold); + + /* Mark a block as bad */ + ut_assertok(mtd_block_markbad(mtd, off + mtd->erasesize)); + + /* Erase some stuff */ + if (end) + off = mtd->size - size - mtd->erasesize; + opts.offset = off; + opts.length = size; + opts.spread = 1; + opts.lim = U32_MAX; + ut_assertok(nand_erase_opts(mtd, &opts)); + + /* Make sure everything is erased */ + memset(gold, 0xff, size); + ut_assertok(nand_read_skip_bad(mtd, off, &length, NULL, U64_MAX, buf)); + ut_asserteq(size, length); + ut_asserteq_mem(gold, buf, size); + + /* ...but our bad block marker is still there */ + ops.oobbuf = oob; + ops.ooblen = mtd->oobsize; + ut_assertok(mtd_read_oob(mtd, mtd->erasesize, &ops)); + ut_asserteq(0, oob[mtd_to_nand(mtd)->badblockpos]); + + /* Generate some data and write it */ + for (i = 0; i < size / sizeof(int); i++) + gold[i] = rand(); + ut_assertok(nand_write_skip_bad(mtd, off, &length, NULL, U64_MAX, + (void *)gold, 0)); + ut_asserteq(size, length); + + /* Verify */ + ut_assertok(nand_read_skip_bad(mtd, off, &length, NULL, U64_MAX, buf)); + ut_asserteq(size, length); + ut_asserteq_mem(gold, buf, size); + + /* Erase some blocks */ + memset(((char *)gold) + mtd->erasesize, 0xff, mtd->erasesize * 2); + opts.offset = off + mtd->erasesize; + opts.length = mtd->erasesize * 2; + ut_assertok(nand_erase_opts(mtd, &opts)); + + /* Verify */ + ut_assertok(nand_read_skip_bad(mtd, off, &length, NULL, U64_MAX, buf)); + ut_asserteq(size, length); + ut_asserteq_mem(gold, buf, size); + + return 0; +} + +#define DM_NAND_TEST(dev) \ +static int dm_test_nand##dev##_start(struct unit_test_state *uts) \ +{ \ + return dm_test_nand(uts, dev, false); \ +} \ +DM_TEST(dm_test_nand##dev##_start, UT_TESTF_SCAN_FDT); \ +static int dm_test_nand##dev##_end(struct unit_test_state *uts) \ +{ \ + return dm_test_nand(uts, dev, true); \ +} \ +DM_TEST(dm_test_nand##dev##_end, UT_TESTF_SCAN_FDT) + +DM_NAND_TEST(0); +DM_NAND_TEST(1); diff --git a/test/dm/nop.c b/test/dm/nop.c index 75b9e7b6cc0..f7d9a0f3df3 100644 --- a/test/dm/nop.c +++ b/test/dm/nop.c @@ -2,7 +2,7 @@ /* * Test for the NOP uclass * - * (C) Copyright 2019 - Texas Instruments Incorporated - http://www.ti.com/ + * (C) Copyright 2019 - Texas Instruments Incorporated - https://www.ti.com/ * Jean-Jacques Hiblot <jjhiblot@ti.com> */ diff --git a/test/dm/ofnode.c b/test/dm/ofnode.c index d71faac0ee4..a5bc43aea4e 100644 --- a/test/dm/ofnode.c +++ b/test/dm/ofnode.c @@ -17,6 +17,7 @@ */ #include <common.h> +#include <abuf.h> #include <dm.h> #include <log.h> #include <of_live.h> @@ -26,6 +27,7 @@ #include <dm/root.h> #include <dm/test.h> #include <dm/uclass-internal.h> +#include <linux/sizes.h> #include <test/test.h> #include <test/ut.h> @@ -91,6 +93,7 @@ void free_oftree(oftree tree) free(tree.np); } +/* test ofnode_device_is_compatible() */ static int dm_test_ofnode_compatible(struct unit_test_state *uts) { ofnode root_node = ofnode_path("/"); @@ -114,7 +117,7 @@ static int dm_test_ofnode_compatible_ot(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_compatible_ot, UT_TESTF_OTHER_FDT); +DM_TEST(dm_test_ofnode_compatible_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); static int dm_test_ofnode_get_by_phandle(struct unit_test_state *uts) { @@ -134,6 +137,7 @@ static int dm_test_ofnode_get_by_phandle(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_get_by_phandle, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +/* test oftree_get_by_phandle() with a the 'other' oftree */ static int dm_test_ofnode_get_by_phandle_ot(struct unit_test_state *uts) { oftree otree = get_other_oftree(uts); @@ -146,7 +150,8 @@ static int dm_test_ofnode_get_by_phandle_ot(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_get_by_phandle_ot, UT_TESTF_OTHER_FDT); +DM_TEST(dm_test_ofnode_get_by_phandle_ot, + UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); static int check_prop_values(struct unit_test_state *uts, ofnode start, const char *propname, const char *propval, @@ -187,6 +192,7 @@ static int dm_test_ofnode_by_prop_value(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_by_prop_value, UT_TESTF_SCAN_FDT); +/* test ofnode_by_prop_value() with a the 'other' oftree */ static int dm_test_ofnode_by_prop_value_ot(struct unit_test_state *uts) { oftree otree = get_other_oftree(uts); @@ -196,8 +202,10 @@ static int dm_test_ofnode_by_prop_value_ot(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_by_prop_value_ot, UT_TESTF_OTHER_FDT); +DM_TEST(dm_test_ofnode_by_prop_value_ot, + UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); +/* test ofnode_read_fmap_entry() */ static int dm_test_ofnode_fmap(struct unit_test_state *uts) { struct fmap_entry entry; @@ -213,12 +221,16 @@ static int dm_test_ofnode_fmap(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_fmap, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +/* test ofnode_read_prop() */ static int dm_test_ofnode_read(struct unit_test_state *uts) { const u32 *val; ofnode node; int size; + node = oftree_path(oftree_default(), "/"); + ut_assert(ofnode_valid(node)); + node = ofnode_path("/a-test"); ut_assert(ofnode_valid(node)); @@ -237,8 +249,9 @@ static int dm_test_ofnode_read(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_read, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +DM_TEST(dm_test_ofnode_read, UT_TESTF_SCAN_FDT); +/* test ofnode_read_prop() with the 'other' tree */ static int dm_test_ofnode_read_ot(struct unit_test_state *uts) { oftree otree = get_other_oftree(uts); @@ -246,6 +259,9 @@ static int dm_test_ofnode_read_ot(struct unit_test_state *uts) ofnode node; int size; + node = oftree_path(otree, "/"); + ut_assert(ofnode_valid(node)); + node = oftree_path(otree, "/node/subnode"); ut_assert(ofnode_valid(node)); @@ -256,8 +272,9 @@ static int dm_test_ofnode_read_ot(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_read_ot, UT_TESTF_OTHER_FDT); +DM_TEST(dm_test_ofnode_read_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); +/* test ofnode_count_/parse_phandle_with_args() */ static int dm_test_ofnode_phandle(struct unit_test_state *uts) { struct ofnode_phandle_args args; @@ -333,6 +350,7 @@ static int dm_test_ofnode_phandle(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_phandle, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +/* test ofnode_count_/parse_phandle_with_args() with 'other' tree */ static int dm_test_ofnode_phandle_ot(struct unit_test_state *uts) { oftree otree = get_other_oftree(uts); @@ -361,6 +379,7 @@ static int dm_test_ofnode_phandle_ot(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_phandle_ot, UT_TESTF_OTHER_FDT); +/* test ofnode_read_chosen_string/node/prop() */ static int dm_test_ofnode_read_chosen(struct unit_test_state *uts) { const char *str; @@ -390,6 +409,7 @@ static int dm_test_ofnode_read_chosen(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_read_chosen, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +/* test ofnode_get_aliases_node/prop() */ static int dm_test_ofnode_read_aliases(struct unit_test_state *uts) { const void *val; @@ -433,6 +453,7 @@ static int dm_test_ofnode_get_child_count(struct unit_test_state *uts) DM_TEST(dm_test_ofnode_get_child_count, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +/* test ofnode_get_child_count() with 'other' tree */ static int dm_test_ofnode_get_child_count_ot(struct unit_test_state *uts) { oftree otree = get_other_oftree(uts); @@ -452,7 +473,8 @@ static int dm_test_ofnode_get_child_count_ot(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_get_child_count_ot, UT_TESTF_OTHER_FDT); +DM_TEST(dm_test_ofnode_get_child_count_ot, + UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); static int dm_test_ofnode_is_enabled(struct unit_test_state *uts) { @@ -466,6 +488,7 @@ static int dm_test_ofnode_is_enabled(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_is_enabled, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +/* test ofnode_is_enabled() with 'other' tree */ static int dm_test_ofnode_is_enabled_ot(struct unit_test_state *uts) { oftree otree = get_other_oftree(uts); @@ -479,6 +502,7 @@ static int dm_test_ofnode_is_enabled_ot(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_is_enabled_ot, UT_TESTF_OTHER_FDT); +/* test ofnode_get_addr/size() */ static int dm_test_ofnode_get_reg(struct unit_test_state *uts) { ofnode node; @@ -515,6 +539,7 @@ static int dm_test_ofnode_get_reg(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_get_reg, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +/* test ofnode_get_addr() with 'other' tree */ static int dm_test_ofnode_get_reg_ot(struct unit_test_state *uts) { oftree otree = get_other_oftree(uts); @@ -526,7 +551,7 @@ static int dm_test_ofnode_get_reg_ot(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_get_reg_ot, UT_TESTF_OTHER_FDT); +DM_TEST(dm_test_ofnode_get_reg_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); static int dm_test_ofnode_get_path(struct unit_test_state *uts) { @@ -549,6 +574,7 @@ static int dm_test_ofnode_get_path(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_get_path, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +/* test ofnode_get_path() with 'other' tree */ static int dm_test_ofnode_get_path_ot(struct unit_test_state *uts) { oftree otree = get_other_oftree(uts); @@ -566,8 +592,9 @@ static int dm_test_ofnode_get_path_ot(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_get_path_ot, UT_TESTF_OTHER_FDT); +DM_TEST(dm_test_ofnode_get_path_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); +/* test ofnode_conf_read_bool/int/str() */ static int dm_test_ofnode_conf(struct unit_test_state *uts) { ut_assert(!ofnode_conf_read_bool("missing")); @@ -581,7 +608,7 @@ static int dm_test_ofnode_conf(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_conf, 0); +DM_TEST(dm_test_ofnode_conf, UT_TESTF_SCAN_FDT); static int dm_test_ofnode_options(struct unit_test_state *uts) { @@ -620,6 +647,7 @@ static int dm_test_ofnode_for_each_compatible_node(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_for_each_compatible_node, UT_TESTF_SCAN_FDT); +/* test dm_test_ofnode_string_count/index/list() */ static int dm_test_ofnode_string(struct unit_test_state *uts) { const char **val; @@ -665,8 +693,9 @@ static int dm_test_ofnode_string(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_string, 0); +DM_TEST(dm_test_ofnode_string, UT_TESTF_SCAN_FDT); +/* test error returns from ofnode_read_string_count/index/list() */ static int dm_test_ofnode_string_err(struct unit_test_state *uts) { const char **val; @@ -716,7 +745,7 @@ static int dm_test_ofnode_string_err(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_string_err, UT_TESTF_LIVE_TREE); -static int dm_test_ofnode_get_phy(struct unit_test_state *uts) +static int dm_test_ofnode_read_phy_mode(struct unit_test_state *uts) { ofnode eth_node, phy_node; phy_interface_t mode; @@ -736,7 +765,7 @@ static int dm_test_ofnode_get_phy(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_get_phy, 0); +DM_TEST(dm_test_ofnode_read_phy_mode, UT_TESTF_SCAN_FDT); /** * make_ofnode_fdt() - Create an FDT for testing with ofnode @@ -770,11 +799,11 @@ static int make_ofnode_fdt(struct unit_test_state *uts, void *fdt, int size, return 0; } -static int dm_test_ofnode_root(struct unit_test_state *uts) +/* Check that aliases work on the control FDT */ +static int dm_test_ofnode_aliases(struct unit_test_state *uts) { ofnode node; - /* Check that aliases work on the control FDT */ node = ofnode_get_aliases_node("ethernet3"); ut_assert(ofnode_valid(node)); ut_asserteq_str("sbe5", ofnode_get_name(node)); @@ -783,8 +812,15 @@ static int dm_test_ofnode_root(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_root, UT_TESTF_SCAN_FDT); +DM_TEST(dm_test_ofnode_aliases, UT_TESTF_SCAN_FDT); +/** + * dm_test_ofnode_root_mult() - Check aliaes on control and 'other' tree + * + * Check that aliases work only with the control FDT, not with 'other' tree. + * This is not actually the desired behaviour. If aliases are implemented for + * any tree, then this test should be changed. + */ static int dm_test_ofnode_root_mult(struct unit_test_state *uts) { char fdt[256]; @@ -817,6 +853,7 @@ static int dm_test_ofnode_root_mult(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_root_mult, UT_TESTF_SCAN_FDT); +/* test ofnode_set_enabled(), ofnode_write_prop() on a livetree */ static int dm_test_ofnode_livetree_writing(struct unit_test_state *uts) { struct udevice *dev; @@ -906,6 +943,7 @@ static int dm_test_ofnode_write_copy(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_write_copy, UT_TESTF_SCAN_FDT); +/* test writing a property to the 'other' tree */ static int dm_test_ofnode_write_copy_ot(struct unit_test_state *uts) { oftree otree = get_other_oftree(uts); @@ -920,8 +958,9 @@ static int dm_test_ofnode_write_copy_ot(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_write_copy_ot, UT_TESTF_OTHER_FDT); +DM_TEST(dm_test_ofnode_write_copy_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); +/* test ofnode_read_u32_index/default() */ static int dm_test_ofnode_u32(struct unit_test_state *uts) { ofnode node; @@ -949,6 +988,7 @@ static int dm_test_ofnode_u32(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_u32, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +/* test ofnode_read_u32_array() */ static int dm_test_ofnode_u32_array(struct unit_test_state *uts) { ofnode node; @@ -975,6 +1015,7 @@ static int dm_test_ofnode_u32_array(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_u32_array, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +/* test ofnode_read_u64() and ofnode_write_u64() */ static int dm_test_ofnode_u64(struct unit_test_state *uts) { ofnode node; @@ -984,6 +1025,10 @@ static int dm_test_ofnode_u64(struct unit_test_state *uts) ut_assert(ofnode_valid(node)); ut_assertok(ofnode_read_u64(node, "int64-value", &val)); ut_asserteq_64(0x1111222233334444, val); + ut_assertok(ofnode_write_u64(node, "new-int64-value", 0x9876543210)); + ut_assertok(ofnode_read_u64(node, "new-int64-value", &val)); + ut_asserteq_64(0x9876543210, val); + ut_asserteq(-EINVAL, ofnode_read_u64(node, "missing", &val)); ut_assertok(ofnode_read_u64_index(node, "int64-array", 0, &val)); @@ -994,6 +1039,12 @@ static int dm_test_ofnode_u64(struct unit_test_state *uts) ofnode_read_u64_index(node, "int64-array", 2, &val)); ut_asserteq(-EINVAL, ofnode_read_u64_index(node, "missing", 0, &val)); + ut_assertok(ofnode_write_u64(node, "int64-array", 0x9876543210)); + ut_assertok(ofnode_read_u64_index(node, "int64-array", 0, &val)); + ut_asserteq_64(0x9876543210, val); + ut_asserteq(-EOVERFLOW, + ofnode_read_u64_index(node, "int64-array", 1, &val)); + return 0; } DM_TEST(dm_test_ofnode_u64, UT_TESTF_SCAN_FDT); @@ -1107,6 +1158,7 @@ static int dm_test_ofnode_by_compatible(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_by_compatible, UT_TESTF_SCAN_FDT); +/* check ofnode_by_compatible() on the 'other' tree */ static int dm_test_ofnode_by_compatible_ot(struct unit_test_state *uts) { const char *compat = "sandbox-other2"; @@ -1122,7 +1174,7 @@ static int dm_test_ofnode_by_compatible_ot(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_ofnode_by_compatible_ot, UT_TESTF_OTHER_FDT); +DM_TEST(dm_test_ofnode_by_compatible_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); static int dm_test_ofnode_find_subnode(struct unit_test_state *uts) { @@ -1141,6 +1193,7 @@ static int dm_test_ofnode_find_subnode(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_find_subnode, UT_TESTF_SCAN_FDT); +/* test ofnode_find_subnode() on the 'other' tree */ static int dm_test_ofnode_find_subnode_ot(struct unit_test_state *uts) { oftree otree = get_other_oftree(uts); @@ -1209,12 +1262,11 @@ static int dm_test_ofnode_too_many(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_too_many, UT_TESTF_SCAN_FDT); -static int check_copy_props(struct unit_test_state *uts, ofnode src, - ofnode dst) +static int check_copy_props(struct unit_test_state *uts, ofnode dst, ofnode src) { u32 reg[2], val; - ut_assertok(ofnode_copy_props(src, dst)); + ut_assertok(ofnode_copy_props(dst, src)); ut_assertok(ofnode_read_u32(dst, "ping-expect", &val)); ut_asserteq(3, val); @@ -1246,7 +1298,7 @@ static int dm_test_ofnode_copy_props(struct unit_test_state *uts) src = ofnode_path("/b-test"); dst = ofnode_path("/some-bus"); - ut_assertok(check_copy_props(uts, src, dst)); + ut_assertok(check_copy_props(uts, dst, src)); /* check a property that is in the destination already */ ut_asserteq_str("mux0", ofnode_read_string(dst, "mux-control-names")); @@ -1255,6 +1307,7 @@ static int dm_test_ofnode_copy_props(struct unit_test_state *uts) } DM_TEST(dm_test_ofnode_copy_props, UT_TESTF_SCAN_FDT); +/* test ofnode_copy_props() with the 'other' tree */ static int dm_test_ofnode_copy_props_ot(struct unit_test_state *uts) { ofnode src, dst; @@ -1262,7 +1315,7 @@ static int dm_test_ofnode_copy_props_ot(struct unit_test_state *uts) src = ofnode_path("/b-test"); dst = oftree_path(otree, "/node/subnode2"); - ut_assertok(check_copy_props(uts, src, dst)); + ut_assertok(check_copy_props(uts, dst, src)); return 0; } @@ -1292,7 +1345,7 @@ static int dm_test_livetree_align(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_livetree_align, UT_TESTF_LIVE_TREE); +DM_TEST(dm_test_livetree_align, UT_TESTF_SCAN_FDT | UT_TESTF_LIVE_TREE); /* check that it is possible to load an arbitrary livetree */ static int dm_test_livetree_ensure(struct unit_test_state *uts) @@ -1311,4 +1364,161 @@ static int dm_test_livetree_ensure(struct unit_test_state *uts) return 0; } -DM_TEST(dm_test_livetree_ensure, 0); +DM_TEST(dm_test_livetree_ensure, UT_TESTF_SCAN_FDT); + +static int dm_test_oftree_new(struct unit_test_state *uts) +{ + ofnode node, subnode, check; + oftree tree; + + ut_assertok(oftree_new(&tree)); + node = oftree_root(tree); + ut_assert(ofnode_valid(node)); + ut_assertok(ofnode_add_subnode(node, "edmund", &subnode)); + check = ofnode_find_subnode(node, "edmund"); + ut_asserteq(check.of_offset, subnode.of_offset); + + return 0; +} +DM_TEST(dm_test_oftree_new, UT_TESTF_SCAN_FDT); + +static int check_copy_node(struct unit_test_state *uts, ofnode dst, ofnode src, + ofnode *nodep) +{ + u32 reg[2], val; + ofnode node; + + ut_assertok(ofnode_copy_node(dst, "copy-test", src, &node)); + + ut_assertok(ofnode_read_u32(node, "ping-expect", &val)); + ut_asserteq(3, val); + + ut_asserteq_str("denx,u-boot-fdt-test", + ofnode_read_string(node, "compatible")); + + /* check that a property with the same name is overwritten */ + ut_assertok(ofnode_read_u32_array(node, "reg", reg, ARRAY_SIZE(reg))); + ut_asserteq(3, reg[0]); + ut_asserteq(1, reg[1]); + + /* reset the compatible so the live tree does not change */ + ut_assertok(ofnode_write_string(node, "compatible", "nothing")); + *nodep = node; + + return 0; +} + +static int dm_test_ofnode_copy_node(struct unit_test_state *uts) +{ + ofnode src, dst, node, try; + + /* + * These nodes are chosen so that the src node is before the destination + * node in the tree. This doesn't matter with livetree, but with + * flattree any attempt to insert a property earlier in the tree will + * mess up the offsets after it. + */ + src = ofnode_path("/b-test"); + dst = ofnode_path("/some-bus"); + + ut_assertok(check_copy_node(uts, dst, src, &node)); + + /* check trying to copy over an existing node */ + ut_asserteq(-EEXIST, ofnode_copy_node(dst, "copy-test", src, &try)); + ut_asserteq(try.of_offset, node.of_offset); + + return 0; +} +DM_TEST(dm_test_ofnode_copy_node, UT_TESTF_SCAN_FDT); + +/* test ofnode_copy_node() with the 'other' tree */ +static int dm_test_ofnode_copy_node_ot(struct unit_test_state *uts) +{ + oftree otree = get_other_oftree(uts); + ofnode src, dst, node; + + src = ofnode_path("/b-test"); + dst = oftree_path(otree, "/node/subnode2"); + ut_assertok(check_copy_node(uts, dst, src, &node)); + + return 0; +} +DM_TEST(dm_test_ofnode_copy_node_ot, UT_TESTF_SCAN_FDT | UT_TESTF_OTHER_FDT); + +static int dm_test_ofnode_delete(struct unit_test_state *uts) +{ + ofnode node; + + /* + * At present the livetree is not restored after changes made in tests. + * See test_pre_run() for how this is done with the other FDT and + * dm_test_pre_run() where it sets up the root-tree pointer. So use + * nodes which don't matter to other tests. + * + * We could fix this by detecting livetree changes and regenerating it + * before the next test if needed. + */ + node = ofnode_path("/leds/iracibble"); + ut_assert(ofnode_valid(node)); + ut_assertok(ofnode_delete(&node)); + ut_assert(!ofnode_valid(node)); + ut_assert(!ofnode_valid(ofnode_path("/leds/iracibble"))); + + node = ofnode_path("/leds/default_on"); + ut_assert(ofnode_valid(node)); + ut_assertok(ofnode_delete(&node)); + ut_assert(!ofnode_valid(node)); + ut_assert(!ofnode_valid(ofnode_path("/leds/default_on"))); + + ut_asserteq(2, ofnode_get_child_count(ofnode_path("/leds"))); + + return 0; +} +DM_TEST(dm_test_ofnode_delete, UT_TESTF_SCAN_FDT); + +static int dm_test_oftree_to_fdt(struct unit_test_state *uts) +{ + oftree tree, check; + struct abuf buf, buf2; + + tree = oftree_default(); + ut_assertok(oftree_to_fdt(tree, &buf)); + ut_assert(abuf_size(&buf) > SZ_16K); + + /* convert it back to a tree and see if it looks OK */ + check = oftree_from_fdt(abuf_data(&buf)); + ut_assert(oftree_valid(check)); + + ut_assertok(oftree_to_fdt(check, &buf2)); + ut_assert(abuf_size(&buf2) > SZ_16K); + ut_asserteq(abuf_size(&buf), abuf_size(&buf2)); + ut_asserteq_mem(abuf_data(&buf), abuf_data(&buf2), abuf_size(&buf)); + + return 0; +} +DM_TEST(dm_test_oftree_to_fdt, UT_TESTF_SCAN_FDT); + +/* test ofnode_read_bool() and ofnode_write_bool() */ +static int dm_test_bool(struct unit_test_state *uts) +{ + const char *propname = "missing-bool-value"; + ofnode node; + + node = ofnode_path("/a-test"); + ut_assert(ofnode_read_bool(node, "bool-value")); + ut_assert(!ofnode_read_bool(node, propname)); + ut_assert(!ofnode_has_property(node, propname)); + + ut_assertok(ofnode_write_bool(node, propname, true)); + ut_assert(ofnode_read_bool(node, propname)); + ut_assert(ofnode_has_property(node, propname)); + ut_assert(ofnode_read_bool(node, "bool-value")); + + ut_assertok(ofnode_write_bool(node, propname, false)); + ut_assert(!ofnode_read_bool(node, propname)); + ut_assert(!ofnode_has_property(node, propname)); + ut_assert(ofnode_read_bool(node, "bool-value")); + + return 0; +} +DM_TEST(dm_test_bool, UT_TESTF_SCAN_FDT); diff --git a/test/dm/pci.c b/test/dm/pci.c index 70a736cfdb8..8c5e7da9e62 100644 --- a/test/dm/pci.c +++ b/test/dm/pci.c @@ -301,10 +301,12 @@ static int dm_test_pci_addr_flat(struct unit_test_state *uts) { struct udevice *swap1f, *swap1; ulong io_addr, mem_addr; + fdt_addr_t size; ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f)); io_addr = dm_pci_read_bar32(swap1f, 0); - ut_asserteq(io_addr, dev_read_addr_pci(swap1f)); + ut_asserteq(io_addr, dev_read_addr_pci(swap1f, &size)); + ut_asserteq(0, size); /* * This device has both I/O and MEM spaces but the MEM space appears @@ -312,7 +314,8 @@ static int dm_test_pci_addr_flat(struct unit_test_state *uts) */ ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1)); mem_addr = dm_pci_read_bar32(swap1, 1); - ut_asserteq(mem_addr, dev_read_addr_pci(swap1)); + ut_asserteq(mem_addr, dev_read_addr_pci(swap1, &size)); + ut_asserteq(0, size); return 0; } @@ -329,12 +332,15 @@ DM_TEST(dm_test_pci_addr_flat, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT | static int dm_test_pci_addr_live(struct unit_test_state *uts) { struct udevice *swap1f, *swap1; + fdt_size_t size; ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1f, 0), &swap1f)); - ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f)); + ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1f, &size)); + ut_asserteq(0, size); ut_assertok(dm_pci_bus_find_bdf(PCI_BDF(0, 0x1, 0), &swap1)); - ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1)); + ut_asserteq_64(FDT_ADDR_T_NONE, dev_read_addr_pci(swap1, &size)); + ut_asserteq(0, size); return 0; } diff --git a/test/dm/phy.c b/test/dm/phy.c index 4f91abca3a0..0cf3689fdec 100644 --- a/test/dm/phy.c +++ b/test/dm/phy.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/ + * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com/ * Written by Jean-Jacques Hiblot <jjhiblot@ti.com> */ diff --git a/test/dm/remoteproc.c b/test/dm/remoteproc.c index 7a8ff47fa14..f6f9e509e27 100644 --- a/test/dm/remoteproc.c +++ b/test/dm/remoteproc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2015 - * Texas Instruments Incorporated - http://www.ti.com/ + * Texas Instruments Incorporated - https://www.ti.com/ */ #include <common.h> #include <dm.h> diff --git a/test/dm/rkmtd.c b/test/dm/rkmtd.c new file mode 100644 index 00000000000..3c3e8efa92f --- /dev/null +++ b/test/dm/rkmtd.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause +/* + * Test derived from: + * /test/dm/host.c + * Copyright 2022 Google LLC + * Written by Simon Glass <sjg@chromium.org> + * + * Copyright (C) 2023 Johan Jonker <jbx6244@gmail.com> + */ + +#include <common.h> +#include <blk.h> +#include <dm.h> +#include <fs.h> +#include <rkmtd.h> +#include <asm/test.h> +#include <dm/device-internal.h> +#include <dm/test.h> +#include <test/test.h> +#include <test/ut.h> + +#define RW_BUF_SIZE 12 * 512 + +/* Basic test of the RKMTD interface */ +static int dm_test_rkmtd(struct unit_test_state *uts) +{ + struct udevice *dev, *part, *chk, *blk; + char write[RW_BUF_SIZE], read[RW_BUF_SIZE]; + static const char label[] = "test"; + struct rkmtd_dev *plat; + struct blk_desc *desc; + struct sector0 *sec0; + int i; + + ut_asserteq(-ENODEV, uclass_first_device_err(UCLASS_RKMTD, &dev)); + ut_asserteq(-ENODEV, uclass_first_device_err(UCLASS_PARTITION, &part)); + + ut_assertok(rkmtd_create_device(label, &dev)); + + /* Check that the plat data has been allocated */ + plat = dev_get_plat(dev); + ut_asserteq_str("test", plat->label); + ut_assert(label != plat->label); + + /* Attach RKMTD driver */ + ut_assertok(rkmtd_attach(dev)); + ut_assertok(uclass_first_device_err(UCLASS_RKMTD, &chk)); + ut_asserteq_ptr(chk, dev); + + /* Get RKMTD block device */ + ut_assertok(blk_get_from_parent(dev, &blk)); + ut_assertok(device_probe(blk)); + + /* There should be a GPT partition table in this device */ + ut_asserteq(0, uclass_first_device_err(UCLASS_PARTITION, &part)); + + /* Write a boot block and verify that we get the same data back */ + desc = dev_get_uclass_plat(blk); + ut_asserteq(true, desc->removable); + ut_asserteq(LBA, desc->lba); + + memset(write, '\0', BLK_SIZE); + + for (i = BLK_SIZE; i < sizeof(write); i++) + write[i] = i; + + sec0 = (struct sector0 *)write; + sec0->magic = 0x0FF0AA55; + sec0->rc4_flag = 0; + sec0->boot_code1_offset = 4; + sec0->boot_code2_offset = 4; + sec0->flash_data_size = 4; + sec0->flash_boot_size = 8; + + rkmtd_rc4(write, 512); + ut_asserteq(RK_TAG, sec0->magic); + + ut_asserteq(12, blk_dwrite(desc, 64, 12, write)); + ut_asserteq(12, blk_dread(desc, 64, 12, read)); + ut_asserteq_mem(write, read, RW_BUF_SIZE); + + ut_assertok(rkmtd_detach(dev)); + + ut_asserteq(-ENODEV, blk_get_from_parent(dev, &blk)); + ut_assertok(device_unbind(dev)); + + return 0; +} +DM_TEST(dm_test_rkmtd, UT_TESTF_SCAN_FDT); + +/* Reusing the same label should work */ +static int dm_test_rkmtd_dup(struct unit_test_state *uts) +{ + static const char label[] = "test"; + struct udevice *dev, *chk; + + /* Create a RKMTD device with label "test" */ + ut_asserteq(0, uclass_id_count(UCLASS_RKMTD)); + ut_assertok(rkmtd_create_device(label, &dev)); + ut_assertok(rkmtd_attach(dev)); + ut_assertok(uclass_first_device_err(UCLASS_RKMTD, &chk)); + ut_asserteq_ptr(chk, dev); + ut_asserteq(1, uclass_id_count(UCLASS_RKMTD)); + + /* Create another device with the same label (should remove old one) */ + ut_assertok(rkmtd_create_device(label, &dev)); + ut_assertok(rkmtd_attach(dev)); + ut_assertok(uclass_first_device_err(UCLASS_RKMTD, &chk)); + ut_asserteq_ptr(chk, dev); + + /* Make sure there is still only one device */ + ut_asserteq(1, uclass_id_count(UCLASS_RKMTD)); + + return 0; +} +DM_TEST(dm_test_rkmtd_dup, UT_TESTF_SCAN_FDT); + +/* Basic test of the 'rkmtd' command */ +static int dm_test_rkmtd_cmd(struct unit_test_state *uts) +{ + struct udevice *dev, *blk; + struct blk_desc *desc; + + /* First check 'rkmtd info' with binding */ + ut_assertok(run_command("rkmtd info", 0)); + ut_assert_nextline("dev blocks label "); + ut_assert_console_end(); + + /* Bind device 1 */ + ut_assertok(run_commandf("rkmtd bind test1")); + ut_assertok(uclass_first_device_err(UCLASS_RKMTD, &dev)); + ut_assertok(blk_get_from_parent(dev, &blk)); + desc = dev_get_uclass_plat(blk); + + ut_assertok(run_command("rkmtd info", 0)); + ut_assert_nextline("dev blocks label "); + ut_assert_nextline(" 0 609 test1 "); + ut_assert_console_end(); + + /* Bind device 2 */ + ut_assertok(run_commandf("rkmtd bind test2")); + ut_assertok(uclass_next_device_err(&dev)); + ut_assertok(blk_get_from_parent(dev, &blk)); + desc = dev_get_uclass_plat(blk); + + ut_assertok(run_command("rkmtd info", 0)); + ut_assert_nextline("dev blocks label "); + ut_assert_nextline(" 0 609 test1 "); + ut_assert_nextline(" 1 609 test2 "); + ut_assert_console_end(); + + ut_asserteq(1, run_command("rkmtd info test", 0)); + ut_assert_nextline("No such device 'test'"); + ut_assert_console_end(); + + ut_assertok(run_command("rkmtd info test2", 0)); + ut_assert_nextline("dev blocks label "); + ut_assert_nextline(" 1 609 test2 "); + ut_assert_console_end(); + + /* Check 'rkmtd dev' */ + ut_asserteq(1, run_command("rkmtd dev", 0)); + ut_assert_nextline("No current rkmtd device"); + ut_assert_console_end(); + + ut_asserteq(1, run_command("rkmtd dev missing", 0)); + ut_assert_nextline("No such device 'missing'"); + ut_assert_console_end(); + + ut_assertok(run_command("rkmtd dev test2", 0)); + ut_assert_console_end(); + + ut_assertok(run_command("rkmtd dev", 0)); + ut_assert_nextline("Current rkmtd device: 1: test2"); + ut_assert_console_end(); + + /* Try a numerical label */ + ut_assertok(run_command("rkmtd dev 0", 0)); + ut_assert_console_end(); + + ut_assertok(run_command("rkmtd dev", 0)); + ut_assert_nextline("Current rkmtd device: 0: test1"); + ut_assert_console_end(); + + /* Remove one of the bindings */ + ut_assertok(run_commandf("rkmtd unbind test1")); + + /* There should now be no current device */ + ut_asserteq(1, run_command("rkmtd dev", 0)); + ut_assert_nextline("No current rkmtd device"); + ut_assert_console_end(); + + ut_assertok(run_command("rkmtd info", 0)); + ut_assert_nextline("dev blocks label "); + ut_assert_nextline(" 1 609 test2 "); + ut_assert_console_end(); + + return 0; +} +DM_TEST(dm_test_rkmtd_cmd, UT_TESTF_SCAN_FDT | UT_TESTF_CONSOLE_REC); diff --git a/test/dm/scmi.c b/test/dm/scmi.c index d87e2731ce4..e80667ef72a 100644 --- a/test/dm/scmi.c +++ b/test/dm/scmi.c @@ -16,6 +16,10 @@ #include <clk.h> #include <dm.h> #include <reset.h> +#include <scmi_agent.h> +#include <scmi_agent-uclass.h> +#include <scmi_protocols.h> +#include <vsprintf.h> #include <asm/scmi_test.h> #include <dm/device-internal.h> #include <dm/test.h> @@ -23,22 +27,11 @@ #include <power/regulator.h> #include <test/ut.h> -static int ut_assert_scmi_state_preprobe(struct unit_test_state *uts) -{ - struct sandbox_scmi_service *scmi_ctx = sandbox_scmi_service_ctx(); - - ut_assertnonnull(scmi_ctx); - ut_assertnull(scmi_ctx->agent); - - return 0; -} - static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, + struct sandbox_scmi_agent *agent, struct udevice *dev) { struct sandbox_scmi_devices *scmi_devices; - struct sandbox_scmi_service *scmi_ctx; - struct sandbox_scmi_agent *agent; /* Device references to check context against test sequence */ scmi_devices = sandbox_scmi_devices_ctx(dev); @@ -48,10 +41,6 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, ut_asserteq(2, scmi_devices->regul_count); /* State of the simulated SCMI server exposed */ - scmi_ctx = sandbox_scmi_service_ctx(); - ut_assertnonnull(scmi_ctx); - agent = scmi_ctx->agent; - ut_assertnonnull(agent); ut_asserteq(3, agent->clk_count); ut_assertnonnull(agent->clk); ut_asserteq(1, agent->reset_count); @@ -63,27 +52,32 @@ static int ut_assert_scmi_state_postprobe(struct unit_test_state *uts, } static int load_sandbox_scmi_test_devices(struct unit_test_state *uts, + struct sandbox_scmi_agent **ctx, struct udevice **dev) { - int ret; + struct udevice *agent_dev; - ret = ut_assert_scmi_state_preprobe(uts); - if (ret) - return ret; + ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi", + &agent_dev)); + ut_assertnonnull(agent_dev); + *ctx = sandbox_scmi_agent_ctx(agent_dev); + ut_assertnonnull(*ctx); + + /* probe */ ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "sandbox_scmi", dev)); ut_assertnonnull(*dev); - return ut_assert_scmi_state_postprobe(uts, *dev); + return ut_assert_scmi_state_postprobe(uts, *ctx, *dev); } static int release_sandbox_scmi_test_devices(struct unit_test_state *uts, struct udevice *dev) { + /* un-probe */ ut_assertok(device_remove(dev, DM_REMOVE_NORMAL)); - /* Not sure test devices are fully removed, agent may not be visible */ return 0; } @@ -93,10 +87,11 @@ static int release_sandbox_scmi_test_devices(struct unit_test_state *uts, */ static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts) { + struct sandbox_scmi_agent *ctx; struct udevice *dev = NULL; int ret; - ret = load_sandbox_scmi_test_devices(uts, &dev); + ret = load_sandbox_scmi_test_devices(uts, &ctx, &dev); if (!ret) ret = release_sandbox_scmi_test_devices(uts, dev); @@ -104,25 +99,325 @@ static int dm_test_scmi_sandbox_agent(struct unit_test_state *uts) } DM_TEST(dm_test_scmi_sandbox_agent, UT_TESTF_SCAN_FDT); -static int dm_test_scmi_clocks(struct unit_test_state *uts) +static int dm_test_scmi_base(struct unit_test_state *uts) +{ + struct udevice *agent_dev, *base; + struct scmi_agent_priv *priv; + u32 version, num_agents, num_protocols, impl_version; + u32 attributes, agent_id; + u8 *vendor, *agent_name, *protocols; + int ret; + + /* preparation */ + ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi", + &agent_dev)); + ut_assertnonnull(agent_dev); + ut_assertnonnull(priv = dev_get_uclass_plat(agent_dev)); + ut_assertnonnull(base = scmi_get_protocol(agent_dev, + SCMI_PROTOCOL_ID_BASE)); + + /* version */ + ret = scmi_base_protocol_version(base, &version); + ut_assertok(ret); + ut_asserteq(priv->version, version); + + /* protocol attributes */ + ret = scmi_base_protocol_attrs(base, &num_agents, &num_protocols); + ut_assertok(ret); + ut_asserteq(priv->num_agents, num_agents); + ut_asserteq(priv->num_protocols, num_protocols); + + /* discover vendor */ + ret = scmi_base_discover_vendor(base, &vendor); + ut_assertok(ret); + ut_asserteq_str(priv->vendor, vendor); + free(vendor); + + /* message attributes */ + ret = scmi_base_protocol_message_attrs(base, + SCMI_BASE_DISCOVER_SUB_VENDOR, + &attributes); + ut_assertok(ret); + ut_assertok(attributes); + + /* discover sub vendor */ + ret = scmi_base_discover_sub_vendor(base, &vendor); + ut_assertok(ret); + ut_asserteq_str(priv->sub_vendor, vendor); + free(vendor); + + /* impl version */ + ret = scmi_base_discover_impl_version(base, &impl_version); + ut_assertok(ret); + ut_asserteq(priv->impl_version, impl_version); + + /* discover agent (my self) */ + ret = scmi_base_discover_agent(base, 0xffffffff, &agent_id, + &agent_name); + ut_assertok(ret); + ut_asserteq(priv->agent_id, agent_id); + ut_asserteq_str(priv->agent_name, agent_name); + free(agent_name); + + /* discover protocols */ + ret = scmi_base_discover_list_protocols(base, &protocols); + ut_asserteq(num_protocols, ret); + ut_asserteq_mem(priv->protocols, protocols, sizeof(u8) * num_protocols); + free(protocols); + + /* + * NOTE: Sandbox SCMI driver handles device-0 only. It supports setting + * access and protocol permissions, but doesn't allow unsetting them nor + * resetting the configurations. + */ + /* set device permissions */ + ret = scmi_base_set_device_permissions(base, agent_id, 0, + SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS); + ut_assertok(ret); /* SCMI_SUCCESS */ + ret = scmi_base_set_device_permissions(base, agent_id, 1, + SCMI_BASE_SET_DEVICE_PERMISSIONS_ACCESS); + ut_asserteq(-ENOENT, ret); /* SCMI_NOT_FOUND */ + ret = scmi_base_set_device_permissions(base, agent_id, 0, 0); + ut_asserteq(-EACCES, ret); /* SCMI_DENIED */ + + /* set protocol permissions */ + ret = scmi_base_set_protocol_permissions(base, agent_id, 0, + SCMI_PROTOCOL_ID_CLOCK, + SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS); + ut_assertok(ret); /* SCMI_SUCCESS */ + ret = scmi_base_set_protocol_permissions(base, agent_id, 1, + SCMI_PROTOCOL_ID_CLOCK, + SCMI_BASE_SET_PROTOCOL_PERMISSIONS_ACCESS); + ut_asserteq(-ENOENT, ret); /* SCMI_NOT_FOUND */ + ret = scmi_base_set_protocol_permissions(base, agent_id, 0, + SCMI_PROTOCOL_ID_CLOCK, 0); + ut_asserteq(-EACCES, ret); /* SCMI_DENIED */ + + /* reset agent configuration */ + ret = scmi_base_reset_agent_configuration(base, agent_id, 0); + ut_asserteq(-EACCES, ret); /* SCMI_DENIED */ + ret = scmi_base_reset_agent_configuration(base, agent_id, + SCMI_BASE_RESET_ALL_ACCESS_PERMISSIONS); + ut_asserteq(-EACCES, ret); /* SCMI_DENIED */ + ret = scmi_base_reset_agent_configuration(base, agent_id, 0); + ut_asserteq(-EACCES, ret); /* SCMI_DENIED */ + + return 0; +} + +DM_TEST(dm_test_scmi_base, UT_TESTF_SCAN_FDT); + +static int dm_test_scmi_cmd(struct unit_test_state *uts) { + struct udevice *agent_dev; + int num_proto = 0; + char cmd_out[30]; + + if (!CONFIG_IS_ENABLED(CMD_SCMI)) + return -EAGAIN; + + /* preparation */ + ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi", + &agent_dev)); + ut_assertnonnull(agent_dev); + + /* + * Estimate the number of provided protocols. + * This estimation is correct as far as a corresponding + * protocol support is added to sandbox fake serer. + */ + if (CONFIG_IS_ENABLED(POWER_DOMAIN)) + num_proto++; + if (CONFIG_IS_ENABLED(CLK_SCMI)) + num_proto++; + if (CONFIG_IS_ENABLED(RESET_SCMI)) + num_proto++; + if (CONFIG_IS_ENABLED(DM_REGULATOR_SCMI)) + num_proto++; + + /* scmi info */ + ut_assertok(run_command("scmi info", 0)); + + ut_assert_nextline("SCMI device: scmi"); + snprintf(cmd_out, 30, " protocol version: 0x%x", + SCMI_BASE_PROTOCOL_VERSION); + ut_assert_nextline(cmd_out); + ut_assert_nextline(" # of agents: 2"); + ut_assert_nextline(" 0: platform"); + ut_assert_nextline(" > 1: OSPM"); + snprintf(cmd_out, 30, " # of protocols: %d", num_proto); + ut_assert_nextline(cmd_out); + if (CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN)) + ut_assert_nextline(" Power domain management"); + if (CONFIG_IS_ENABLED(CLK_SCMI)) + ut_assert_nextline(" Clock management"); + if (CONFIG_IS_ENABLED(RESET_SCMI)) + ut_assert_nextline(" Reset domain management"); + if (CONFIG_IS_ENABLED(DM_REGULATOR_SCMI)) + ut_assert_nextline(" Voltage domain management"); + ut_assert_nextline(" vendor: U-Boot"); + ut_assert_nextline(" sub vendor: Sandbox"); + ut_assert_nextline(" impl version: 0x1"); + + ut_assert_console_end(); + + /* scmi perm_dev */ + ut_assertok(run_command("scmi perm_dev 1 0 1", 0)); + ut_assert_console_end(); + + ut_assert(run_command("scmi perm_dev 1 0 0", 0)); + ut_assert_nextline("Denying access to device:0 failed (-13)"); + ut_assert_console_end(); + + /* scmi perm_proto */ + ut_assertok(run_command("scmi perm_proto 1 0 14 1", 0)); + ut_assert_console_end(); + + ut_assert(run_command("scmi perm_proto 1 0 14 0", 0)); + ut_assert_nextline("Denying access to protocol:0x14 on device:0 failed (-13)"); + ut_assert_console_end(); + + /* scmi reset */ + ut_assert(run_command("scmi reset 1 1", 0)); + ut_assert_nextline("Reset failed (-13)"); + ut_assert_console_end(); + + return 0; +} + +DM_TEST(dm_test_scmi_cmd, UT_TESTF_SCAN_FDT); + +static int dm_test_scmi_power_domains(struct unit_test_state *uts) +{ + struct sandbox_scmi_agent *agent; struct sandbox_scmi_devices *scmi_devices; - struct sandbox_scmi_service *scmi_ctx; + struct udevice *agent_dev, *pwd, *dev; + u32 version, count, attributes, pstate; + u64 stats_addr; + size_t stats_len; + u8 *name; + int ret; + + if (!CONFIG_IS_ENABLED(SCMI_POWER_DOMAIN)) + return -EAGAIN; + + /* preparation */ + ut_assertok(load_sandbox_scmi_test_devices(uts, &agent, &dev)); + ut_assertnonnull(agent); + scmi_devices = sandbox_scmi_devices_ctx(dev); + ut_assertnonnull(scmi_devices); + ut_asserteq(2, scmi_devices->pwdom->id); /* in test.dts */ + + ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi", + &agent_dev)); + ut_assertnonnull(agent_dev); + pwd = scmi_get_protocol(agent_dev, SCMI_PROTOCOL_ID_POWER_DOMAIN); + ut_assertnonnull(pwd); + + /* + * SCMI Power domain management protocol interfaces + */ + /* version */ + ret = scmi_generic_protocol_version(pwd, SCMI_PROTOCOL_ID_POWER_DOMAIN, + &version); + ut_assertok(ret); + ut_asserteq(agent->pwdom_version, version); + + /* protocol attributes */ + ret = scmi_pwd_protocol_attrs(pwd, &count, &stats_addr, &stats_len); + ut_assertok(ret); + ut_asserteq(agent->pwdom_count, count); + ut_asserteq(0, stats_len); + + /* protocol message attributes */ + ret = scmi_pwd_protocol_message_attrs(pwd, SCMI_PWD_STATE_SET, + &attributes); + ut_assertok(ret); + ret = scmi_pwd_protocol_message_attrs(pwd, SCMI_PWD_STATE_NOTIFY, + &attributes); + ut_asserteq(-ENOENT, ret); /* the protocol not supported */ + + /* power domain attributes */ + ret = scmi_pwd_attrs(pwd, 0, &attributes, &name); + ut_assertok(ret); + ut_asserteq_str("power-domain--0", name); + free(name); + + ret = scmi_pwd_attrs(pwd, 10, &attributes, &name); + ut_asserteq(-ENOENT, ret); /* domain-10 doesn't exist */ + + /* power domain state set/get */ + ret = scmi_pwd_state_set(pwd, 0, 0, 0); + ut_assertok(ret); + ret = scmi_pwd_state_get(pwd, 0, &pstate); + ut_assertok(ret); + ut_asserteq(0, pstate); /* ON */ + + ret = scmi_pwd_state_set(pwd, 0, 0, SCMI_PWD_PSTATE_TYPE_LOST); + ut_assertok(ret); + ret = scmi_pwd_state_get(pwd, 0, &pstate); + ut_assertok(ret); + ut_asserteq(SCMI_PWD_PSTATE_TYPE_LOST, pstate); /* OFF */ + + ret = scmi_pwd_state_set(pwd, 0, 10, 0); + ut_asserteq(-ENOENT, ret); + + /* power domain name get */ + ret = scmi_pwd_name_get(pwd, 0, &name); + ut_assertok(ret); + ut_asserteq_str("power-domain--0-extended", name); + free(name); + + ret = scmi_pwd_name_get(pwd, 10, &name); + ut_asserteq(-ENOENT, ret); /* domain-10 doesn't exist */ + + /* + * U-Boot driver model interfaces + */ + /* power_domain_on */ + ret = power_domain_on(scmi_devices->pwdom); + ut_assertok(ret); + ret = scmi_pwd_state_get(pwd, scmi_devices->pwdom->id, &pstate); + ut_assertok(ret); + ut_asserteq(0, pstate); /* ON */ + + /* power_domain_off */ + ret = power_domain_off(scmi_devices->pwdom); + ut_assertok(ret); + ret = scmi_pwd_state_get(pwd, scmi_devices->pwdom->id, &pstate); + ut_assertok(ret); + ut_asserteq(SCMI_PWD_PSTATE_TYPE_LOST, pstate); /* OFF */ + + return release_sandbox_scmi_test_devices(uts, dev); +} + +DM_TEST(dm_test_scmi_power_domains, UT_TESTF_SCAN_FDT); + +static int dm_test_scmi_clocks(struct unit_test_state *uts) +{ struct sandbox_scmi_agent *agent; - struct udevice *dev; + struct sandbox_scmi_devices *scmi_devices; + struct udevice *agent_dev, *clock_dev, *dev; int ret_dev; int ret; - ret = load_sandbox_scmi_test_devices(uts, &dev); + if (!CONFIG_IS_ENABLED(CLK_SCMI)) + return -EAGAIN; + + ret = load_sandbox_scmi_test_devices(uts, &agent, &dev); if (ret) return ret; scmi_devices = sandbox_scmi_devices_ctx(dev); ut_assertnonnull(scmi_devices); - scmi_ctx = sandbox_scmi_service_ctx(); - ut_assertnonnull(scmi_ctx); - agent = scmi_ctx->agent; - ut_assertnonnull(agent); + + /* Sandbox SCMI clock protocol has its own channel */ + ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi", + &agent_dev)); + ut_assertnonnull(agent_dev); + clock_dev = scmi_get_protocol(agent_dev, SCMI_PROTOCOL_ID_CLOCK); + ut_assertnonnull(clock_dev); + ut_asserteq(0x14, sandbox_scmi_channel_id(clock_dev)); /* Test SCMI clocks rate manipulation */ ut_asserteq(333, agent->clk[0].rate); @@ -169,22 +464,28 @@ DM_TEST(dm_test_scmi_clocks, UT_TESTF_SCAN_FDT); static int dm_test_scmi_resets(struct unit_test_state *uts) { - struct sandbox_scmi_devices *scmi_devices; - struct sandbox_scmi_service *scmi_ctx; struct sandbox_scmi_agent *agent; - struct udevice *dev = NULL; + struct sandbox_scmi_devices *scmi_devices; + struct udevice *agent_dev, *reset_dev, *dev = NULL; int ret; - ret = load_sandbox_scmi_test_devices(uts, &dev); + if (!CONFIG_IS_ENABLED(RESET_SCMI)) + return -EAGAIN; + + ret = load_sandbox_scmi_test_devices(uts, &agent, &dev); if (ret) return ret; scmi_devices = sandbox_scmi_devices_ctx(dev); ut_assertnonnull(scmi_devices); - scmi_ctx = sandbox_scmi_service_ctx(); - ut_assertnonnull(scmi_ctx); - agent = scmi_ctx->agent; - ut_assertnonnull(agent); + + /* Sandbox SCMI reset protocol doesn't have its own channel */ + ut_assertok(uclass_get_device_by_name(UCLASS_SCMI_AGENT, "scmi", + &agent_dev)); + ut_assertnonnull(agent_dev); + reset_dev = scmi_get_protocol(agent_dev, SCMI_PROTOCOL_ID_RESET_DOMAIN); + ut_assertnonnull(reset_dev); + ut_asserteq(0x0, sandbox_scmi_channel_id(reset_dev)); /* Test SCMI resect controller manipulation */ ut_assert(!agent->reset[0].asserted); @@ -201,21 +502,19 @@ DM_TEST(dm_test_scmi_resets, UT_TESTF_SCAN_FDT); static int dm_test_scmi_voltage_domains(struct unit_test_state *uts) { - struct sandbox_scmi_devices *scmi_devices; - struct sandbox_scmi_service *scmi_ctx; struct sandbox_scmi_agent *agent; + struct sandbox_scmi_devices *scmi_devices; struct dm_regulator_uclass_plat *uc_pdata; struct udevice *dev; struct udevice *regul0_dev; - ut_assertok(load_sandbox_scmi_test_devices(uts, &dev)); + if (!CONFIG_IS_ENABLED(DM_REGULATOR_SCMI)) + return -EAGAIN; + + ut_assertok(load_sandbox_scmi_test_devices(uts, &agent, &dev)); scmi_devices = sandbox_scmi_devices_ctx(dev); ut_assertnonnull(scmi_devices); - scmi_ctx = sandbox_scmi_service_ctx(); - ut_assertnonnull(scmi_ctx); - agent = scmi_ctx->agent; - ut_assertnonnull(agent); /* Set/Get an SCMI voltage domain level */ regul0_dev = scmi_devices->regul[0]; diff --git a/test/dm/serial.c b/test/dm/serial.c index 37d17a65f16..34b783e062e 100644 --- a/test/dm/serial.c +++ b/test/dm/serial.c @@ -29,6 +29,7 @@ static int dm_test_serial(struct unit_test_state *uts) &dev_serial)); ut_assertok(serial_tstc()); + ut_asserteq(115200, fetch_baud_from_dtb()); /* * test with default config which is the only one supported by * sandbox_serial driver diff --git a/test/dm/sm.c b/test/dm/sm.c new file mode 100644 index 00000000000..7ebb0c9c85e --- /dev/null +++ b/test/dm/sm.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2023 SberDevices, Inc. + * + * Author: Alexey Romanov <avromanov@salutedevices.com> + */ + +#include <common.h> +#include <dm.h> +#include <sm.h> +#include <sandbox-sm.h> +#include <asm/ptrace.h> +#include <dm/device-internal.h> +#include <dm/test.h> +#include <test/ut.h> +#include <linux/sizes.h> + +static int dm_test_sm(struct unit_test_state *uts) +{ + struct udevice *dev; + struct pt_regs regs; + char buffer[128] = { 0 }; + char test_string[] = "secure-monitor"; + int ret, val; + + ut_assertok(uclass_get_device_by_name(UCLASS_SM, + "secure-monitor", &dev)); + + ret = sm_call(dev, SANDBOX_SMC_CMD_COUNT, NULL, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call(dev, SANDBOX_SMC_CMD_COMMON, &val, ®s); + ut_asserteq(ret, 0); + ut_asserteq(val, 0); + + ret = sm_call_write(dev, buffer, sizeof(buffer), + SANDBOX_SMC_CMD_COUNT, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call_write(dev, buffer, SZ_4K + 1, + SANDBOX_SMC_CMD_WRITE_MEM, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call_write(dev, buffer, sizeof(buffer), + SANDBOX_SMC_CMD_COUNT, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call_write(dev, buffer, SZ_4K + 1, + SANDBOX_SMC_CMD_READ_MEM, ®s); + ut_asserteq(ret, -EINVAL); + + ret = sm_call_write(dev, test_string, sizeof(test_string), + SANDBOX_SMC_CMD_WRITE_MEM, ®s); + ut_asserteq(ret, sizeof(test_string)); + + ret = sm_call_read(dev, buffer, sizeof(buffer), + SANDBOX_SMC_CMD_READ_MEM, ®s); + ut_asserteq(ret, sizeof(buffer)); + + ut_asserteq_str(buffer, test_string); + + return 0; +} + +DM_TEST(dm_test_sm, UT_TESTF_SCAN_FDT); diff --git a/test/dm/soc.c b/test/dm/soc.c index 17e1b5ba012..8f6c97fa790 100644 --- a/test/dm/soc.c +++ b/test/dm/soc.c @@ -2,7 +2,7 @@ /* * Test for the SOC uclass * - * (C) Copyright 2020 - Texas Instruments Incorporated - http://www.ti.com/ + * (C) Copyright 2020 - Texas Instruments Incorporated - https://www.ti.com/ * Dave Gerlach <d-gerlach@ti.com> */ diff --git a/test/dm/sysreset.c b/test/dm/sysreset.c index 691683c5674..5aa69e04618 100644 --- a/test/dm/sysreset.c +++ b/test/dm/sysreset.c @@ -27,8 +27,8 @@ static int dm_test_sysreset_base(struct unit_test_state *uts) /* Device 1 is the warm sysreset device */ ut_assertok(uclass_get_device(UCLASS_SYSRESET, 1, &dev)); ut_asserteq(-EACCES, sysreset_request(dev, SYSRESET_WARM)); - ut_asserteq(-ENOSYS, sysreset_request(dev, SYSRESET_COLD)); - ut_asserteq(-ENOSYS, sysreset_request(dev, SYSRESET_POWER)); + ut_asserteq(-EPROTONOSUPPORT, sysreset_request(dev, SYSRESET_COLD)); + ut_asserteq(-EPROTONOSUPPORT, sysreset_request(dev, SYSRESET_POWER)); state->sysreset_allowed[SYSRESET_WARM] = true; ut_asserteq(-EINPROGRESS, sysreset_request(dev, SYSRESET_WARM)); @@ -36,7 +36,7 @@ static int dm_test_sysreset_base(struct unit_test_state *uts) /* Device 2 is the cold sysreset device */ ut_assertok(uclass_get_device(UCLASS_SYSRESET, 2, &dev)); - ut_asserteq(-ENOSYS, sysreset_request(dev, SYSRESET_WARM)); + ut_asserteq(-EPROTONOSUPPORT, sysreset_request(dev, SYSRESET_WARM)); state->sysreset_allowed[SYSRESET_COLD] = false; ut_asserteq(-EACCES, sysreset_request(dev, SYSRESET_COLD)); state->sysreset_allowed[SYSRESET_COLD] = true; diff --git a/test/dm/wdt.c b/test/dm/wdt.c index 653d7b1c8b3..2bbebcdbf28 100644 --- a/test/dm/wdt.c +++ b/test/dm/wdt.c @@ -54,7 +54,7 @@ static int dm_test_wdt_gpio_toggle(struct unit_test_state *uts) */ struct udevice *wdt, *gpio; const u64 timeout = 42; - const int offset = 7; + const int offset = 8; int val; ut_assertok(uclass_get_device_by_name(UCLASS_WDT, @@ -115,7 +115,7 @@ static int dm_test_wdt_watchdog_reset(struct unit_test_state *uts) struct udevice *gpio_wdt, *sandbox_wdt; struct udevice *gpio; const u64 timeout = 42; - const int offset = 7; + const int offset = 8; uint reset_count; int val; diff --git a/test/fuzz/cmd_fuzz.c b/test/fuzz/cmd_fuzz.c index e2f44f3ecb6..d0bc7b8d7b7 100644 --- a/test/fuzz/cmd_fuzz.c +++ b/test/fuzz/cmd_fuzz.c @@ -70,11 +70,8 @@ static int do_fuzz(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[] return 1; } -#ifdef CONFIG_SYS_LONGHELP -static char fuzz_help_text[] = - "[fuzz-test-name] - execute the named fuzz test\n" - ; -#endif /* CONFIG_SYS_LONGHELP */ +U_BOOT_LONGHELP(fuzz, + "[fuzz-test-name] - execute the named fuzz test\n"); U_BOOT_CMD( fuzz, CONFIG_SYS_MAXARGS, 1, do_fuzz, diff --git a/test/image/Kconfig b/test/image/Kconfig new file mode 100644 index 00000000000..45b6e8c52e6 --- /dev/null +++ b/test/image/Kconfig @@ -0,0 +1,60 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (C) 2023 Sean Anderson <seanga2@gmail.com> + +config SPL_UT_LOAD + bool "Unit tests for SPL load methods" + depends on SPL_UNIT_TEST + default y if SANDBOX + help + Test various SPL load methods. + +if SPL_UT_LOAD + +config SPL_UT_LOAD_FS + bool "Unit tests for filesystems" + depends on SANDBOX && SPL_OF_REAL + depends on FS_LOADER + depends on SPL_BLK_FS + depends on SPL_FS_FAT + depends on SPL_FS_EXT4 + depends on SPL_MMC_WRITE + depends on SYS_MMCSD_RAW_MODE_U_BOOT_USE_SECTOR + default y + help + Test filesystems and the various load methods which use them. + +config SPL_UT_LOAD_NAND + bool "Test loading from NAND flash" + depends on SANDBOX && SPL_OF_REAL + depends on SPL_NAND_SUPPORT + depends on SPL_MTD + default y + help + Test the NAND flash load method. + +config SPL_UT_LOAD_NET + bool "Test loading over TFTP" + depends on SANDBOX && SPL_OF_REAL + depends on SPL_ETH + depends on USE_BOOTFILE + default y + help + Test loading images over TFTP using the NET image load method. + +config SPL_UT_LOAD_SPI + bool "Test loading from SPI Flash" + depends on SANDBOX && SPL_OF_REAL + depends on SPL_SPI_LOAD + default y + help + Test the SPI flash image load metod. + +config SPL_UT_LOAD_OS + bool "Test loading from the host OS" + depends on SANDBOX && SPL_LOAD_FIT + select SPL_LOAD_BLOCK + default y + help + Smoke test to ensure that loading U-boot works in sandbox. + +endif diff --git a/test/image/Makefile b/test/image/Makefile index c4039df707f..11ed25734e8 100644 --- a/test/image/Makefile +++ b/test/image/Makefile @@ -2,4 +2,10 @@ # # Copyright 2021 Google LLC -obj-$(CONFIG_SPL_BUILD) += spl_load.o +obj-y += spl_load.o +obj-$(CONFIG_SPL_UT_LOAD_FS) += spl_load_fs.o +obj-$(CONFIG_SPL_UT_LOAD_NAND) += spl_load_nand.o +obj-$(CONFIG_SPL_UT_LOAD_NET) += spl_load_net.o +obj-$(CONFIG_SPL_NOR_SUPPORT) += spl_load_nor.o +obj-$(CONFIG_SPL_UT_LOAD_OS) += spl_load_os.o +obj-$(CONFIG_SPL_UT_LOAD_SPI) += spl_load_spi.o diff --git a/test/image/spl_load.c b/test/image/spl_load.c index 4e27ff460ab..e1036eff28c 100644 --- a/test/image/spl_load.c +++ b/test/image/spl_load.c @@ -1,91 +1,662 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * Copyright 2021 Google LLC - * Written by Simon Glass <sjg@chromium.org> + * Copyright (C) 2023 Sean Anderson <seanga2@gmail.com> */ #include <common.h> #include <image.h> +#include <imx_container.h> #include <mapmem.h> -#include <os.h> +#include <memalign.h> +#include <rand.h> +#include <spi_flash.h> #include <spl.h> +#include <test/spl.h> #include <test/ut.h> +#include <u-boot/crc.h> -/* Declare a new SPL test */ -#define SPL_TEST(_name, _flags) UNIT_TEST(_name, _flags, spl_test) +int board_fit_config_name_match(const char *name) +{ + return 0; +} -/* Context used for this test */ -struct text_ctx { - int fd; -}; +struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size) +{ + return map_sysmem(0x100000, 0); +} + +/* Try to reuse the load buffer to conserve memory */ +void *board_spl_fit_buffer_addr(ulong fit_size, int sectors, int bl_len) +{ + static void *buf; + static size_t size; + + if (size < sectors * bl_len) { + free(buf); + size = sectors * bl_len; + buf = malloc_cache_aligned(size); + } + return buf; +} + +/* Local flags for spl_image; start from the "top" to avoid conflicts */ +#define SPL_IMX_CONTAINER 0x80000000 +#define SPL_COMP_LZMA 0x40000000 + +void generate_data(char *data, size_t size, const char *test_name) +{ + int i; + unsigned int seed = 1; + + while (*test_name) { + seed += *test_name++; + rand_r(&seed); + } + + for (i = 0; i < size; i++) + data[i] = (i & 0xf) << 4 | (rand_r(&seed) & 0xf); +} + +static size_t create_legacy(void *dst, struct spl_image_info *spl_image, + size_t *data_offset) +{ + struct legacy_img_hdr *hdr = dst; + void *data = dst + sizeof(*hdr); + + if (data_offset) + *data_offset = data - dst; + + if (!dst) + goto out; + + image_set_magic(hdr, IH_MAGIC); + image_set_time(hdr, 0); + image_set_size(hdr, spl_image->size); + image_set_load(hdr, spl_image->load_addr); + image_set_ep(hdr, spl_image->entry_point); + image_set_dcrc(hdr, crc32(0, data, spl_image->size)); + image_set_os(hdr, spl_image->os); + image_set_arch(hdr, IH_ARCH_DEFAULT); + image_set_type(hdr, IH_TYPE_FIRMWARE); + image_set_comp(hdr, spl_image->flags & SPL_COMP_LZMA ? IH_COMP_LZMA : + IH_COMP_NONE); + image_set_name(hdr, spl_image->name); + image_set_hcrc(hdr, crc32(0, (void *)hdr, sizeof(*hdr))); + +out: + return sizeof(*hdr) + spl_image->size; +} + +static size_t create_imx8(void *dst, struct spl_image_info *spl_image, + size_t *data_offset) +{ + struct container_hdr *hdr = dst; + struct boot_img_t *img = dst + sizeof(*hdr); + size_t length = sizeof(*hdr) + sizeof(*img); + /* Align to MMC block size for now */ + void *data = dst + 512; + + if (data_offset) + *data_offset = data - dst; + + if (!dst) + goto out; + + hdr->version = CONTAINER_HDR_VERSION; + hdr->length_lsb = length & 0xff; + hdr->length_msb = length >> 8; + hdr->tag = CONTAINER_HDR_TAG; + hdr->num_images = 1; + + /* spl_load_imx_container doesn't handle endianness; whoops! */ + img->offset = data - dst; + img->size = spl_image->size; + img->dst = spl_image->load_addr; + img->entry = spl_image->entry_point; + +out: + return data - dst + spl_image->size; +} + +#define ADDRESS_CELLS (sizeof(uintptr_t) / sizeof(u32)) -static ulong read_fit_image(struct spl_load_info *load, ulong sector, - ulong count, void *buf) +static inline int fdt_property_addr(void *fdt, const char *name, uintptr_t val) { - struct text_ctx *text_ctx = load->priv; - off_t offset, ret; - ssize_t res; + if (sizeof(uintptr_t) == sizeof(u32)) + return fdt_property_u32(fdt, name, val); + return fdt_property_u64(fdt, name, val); +} + +static size_t start_fit(void *dst, size_t fit_size, size_t data_size, + bool external) +{ + void *data; - offset = sector * load->bl_len; - ret = os_lseek(text_ctx->fd, offset, OS_SEEK_SET); - if (ret != offset) { - printf("Failed to seek to %zx, got %zx (errno=%d)\n", offset, - ret, errno); + if (fdt_create(dst, fit_size)) + return 0; + if (fdt_finish_reservemap(dst)) + return 0; + if (fdt_begin_node(dst, "")) + return 0; + if (fdt_property_u32(dst, FIT_TIMESTAMP_PROP, 0)) + return 0; + if (fdt_property_u32(dst, "#address-cells", ADDRESS_CELLS)) return 0; + if (fdt_property_string(dst, FIT_DESC_PROP, "")) + return 0; + + if (fdt_begin_node(dst, "images")) + return 0; + if (fdt_begin_node(dst, "u-boot")) + return 0; + + if (external) { + if (fdt_property_u32(dst, FIT_DATA_OFFSET_PROP, 0)) + return 0; + return fit_size; } - res = os_read(text_ctx->fd, buf, count * load->bl_len); - if (res == -1) { - printf("Failed to read %lx bytes, got %ld (errno=%d)\n", - count * load->bl_len, res, errno); + if (fdt_property_placeholder(dst, FIT_DATA_PROP, data_size, &data)) return 0; + return data - dst; +} + +static size_t create_fit(void *dst, struct spl_image_info *spl_image, + size_t *data_offset, bool external) +{ + size_t prop_size = 596, total_size = prop_size + spl_image->size; + size_t off, size; + + if (external) { + size = prop_size; + off = size; + } else { + char tmp[256]; + + size = total_size; + off = start_fit(tmp, sizeof(tmp), 0, false); + if (!off) + return 0; } - return count; + if (data_offset) + *data_offset = off; + + if (!dst) + goto out; + + if (start_fit(dst, size, spl_image->size, external) != off) + return 0; + + if (fdt_property_string(dst, FIT_DESC_PROP, spl_image->name)) + return 0; + if (fdt_property_string(dst, FIT_TYPE_PROP, "firmware")) + return 0; + if (fdt_property_string(dst, FIT_COMP_PROP, "none")) + return 0; + if (fdt_property_u32(dst, FIT_DATA_SIZE_PROP, spl_image->size)) + return 0; + if (fdt_property_string(dst, FIT_OS_PROP, + genimg_get_os_short_name(spl_image->os))) + return 0; + if (fdt_property_string(dst, FIT_ARCH_PROP, + genimg_get_arch_short_name(IH_ARCH_DEFAULT))) + return 0; + if (fdt_property_addr(dst, FIT_ENTRY_PROP, spl_image->entry_point)) + return 0; + if (fdt_property_addr(dst, FIT_LOAD_PROP, spl_image->load_addr)) + return 0; + if (fdt_end_node(dst)) /* u-boot */ + return 0; + if (fdt_end_node(dst)) /* images */ + return 0; + + if (fdt_begin_node(dst, "configurations")) + return 0; + if (fdt_property_string(dst, FIT_DEFAULT_PROP, "config-1")) + return 0; + if (fdt_begin_node(dst, "config-1")) + return 0; + if (fdt_property_string(dst, FIT_DESC_PROP, spl_image->name)) + return 0; + if (fdt_property_string(dst, FIT_FIRMWARE_PROP, "u-boot")) + return 0; + if (fdt_end_node(dst)) /* configurations */ + return 0; + if (fdt_end_node(dst)) /* config-1 */ + return 0; + + if (fdt_end_node(dst)) /* root */ + return 0; + if (fdt_finish(dst)) + return 0; + + if (external) { + if (fdt_totalsize(dst) > size) + return 0; + fdt_set_totalsize(dst, size); + } + +out: + return total_size; } -int board_fit_config_name_match(const char *name) +size_t create_image(void *dst, enum spl_test_image type, + struct spl_image_info *info, size_t *data_offset) { + bool external = false; + + info->os = IH_OS_U_BOOT; + info->load_addr = CONFIG_TEXT_BASE; + info->entry_point = CONFIG_TEXT_BASE + 0x100; + info->flags = 0; + + switch (type) { + case LEGACY_LZMA: + info->flags = SPL_COMP_LZMA; + case LEGACY: + return create_legacy(dst, info, data_offset); + case IMX8: + info->flags = SPL_IMX_CONTAINER; + return create_imx8(dst, info, data_offset); + case FIT_EXTERNAL: + /* + * spl_fit_append_fdt will clobber external images with U-Boot's + * FDT if the image doesn't have one. Just set the OS to + * something which doesn't take a devicetree. + */ + if (!IS_ENABLED(CONFIG_LOAD_FIT_FULL)) + info->os = IH_OS_TEE; + external = true; + case FIT_INTERNAL: + info->flags = SPL_FIT_FOUND; + return create_fit(dst, info, data_offset, external); + } + return 0; } -struct legacy_img_hdr *spl_get_load_buffer(ssize_t offset, size_t size) +int check_image_info(struct unit_test_state *uts, struct spl_image_info *info1, + struct spl_image_info *info2) { - return map_sysmem(0x100000, 0); + if (info2->name) { + if (info1->flags & SPL_FIT_FOUND) + ut_asserteq_str(genimg_get_os_name(info1->os), + info2->name); + else + ut_asserteq_str(info1->name, info2->name); + } + + if (info1->flags & SPL_IMX_CONTAINER) + ut_asserteq(IH_OS_INVALID, info2->os); + else + ut_asserteq(info1->os, info2->os); + + ut_asserteq(info1->entry_point, info2->entry_point); + if (info1->flags & (SPL_FIT_FOUND | SPL_IMX_CONTAINER) || + info2->flags & SPL_COPY_PAYLOAD_ONLY) { + ut_asserteq(info1->load_addr, info2->load_addr); + if (info1->flags & SPL_IMX_CONTAINER) + ut_asserteq(0, info2->size); + else if (!(info1->flags & SPL_COMP_LZMA)) + ut_asserteq(info1->size, info2->size); + } else { + ut_asserteq(info1->load_addr - sizeof(struct legacy_img_hdr), + info2->load_addr); + ut_asserteq(info1->size + sizeof(struct legacy_img_hdr), + info2->size); + } + + return 0; } -static int spl_test_load(struct unit_test_state *uts) +static ulong spl_test_read(struct spl_load_info *load, ulong sector, + ulong count, void *buf) { - struct spl_image_info image; - struct legacy_img_hdr *header; - struct text_ctx text_ctx; - struct spl_load_info load; - char fname[256]; - int ret; - int fd; - - memset(&load, '\0', sizeof(load)); - load.bl_len = 512; - load.read = read_fit_image; - - ret = sandbox_find_next_phase(fname, sizeof(fname), true); - if (ret) { - printf("(%s not found, error %d)\n", fname, ret); - return ret; + memcpy(buf, load->priv + sector, count); + return count; +} + +static int spl_test_image(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + size_t img_size, img_data, data_size = SPL_TEST_DATA_SIZE; + struct spl_image_info info_write = { + .name = test_name, + .size = data_size, + }, info_read = { }; + char *data; + void *img; + + img_size = create_image(NULL, type, &info_write, &img_data); + ut_assert(img_size); + img = calloc(img_size, 1); + ut_assertnonnull(img); + + data = img + img_data; + generate_data(data, data_size, test_name); + ut_asserteq(img_size, create_image(img, type, &info_write, NULL)); + + if (type == LEGACY) { + ut_assertok(spl_parse_image_header(&info_read, NULL, img)); + if (check_image_info(uts, &info_write, &info_read)) + return CMD_RET_FAILURE; + } else { + struct spl_load_info load; + + spl_set_bl_len(&load, 1); + load.priv = img; + load.read = spl_test_read; + if (type == IMX8) + ut_assertok(spl_load_imx_container(&info_read, &load, + 0)); + else if (IS_ENABLED(CONFIG_SPL_FIT_FULL)) + ut_assertok(spl_parse_image_header(&info_read, NULL, + img)); + else + ut_assertok(spl_load_simple_fit(&info_read, &load, 0, + img)); + if (check_image_info(uts, &info_write, &info_read)) + return CMD_RET_FAILURE; + ut_asserteq_mem(data, phys_to_virt(info_write.load_addr), + data_size); } - load.filename = fname; - header = spl_get_load_buffer(-sizeof(*header), sizeof(*header)); + free(img); + return 0; +} +SPL_IMG_TEST(spl_test_image, LEGACY, 0); +SPL_IMG_TEST(spl_test_image, IMX8, 0); +SPL_IMG_TEST(spl_test_image, FIT_INTERNAL, 0); +SPL_IMG_TEST(spl_test_image, FIT_EXTERNAL, 0); + +/* + * LZMA is too complex to generate on the fly, so let's use some data I put in + * the oven^H^H^H^H compressed earlier + */ +const char lzma_compressed[] = { + 0x5d, 0x00, 0x00, 0x80, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x02, 0x05, 0x55, 0x4e, 0x82, 0xbc, 0xc2, 0x42, 0xf6, 0x88, + 0x6c, 0x99, 0xd6, 0x82, 0x48, 0xa6, 0x06, 0x67, 0xf8, 0x46, 0x7c, 0xe9, + 0x41, 0x79, 0xfe, 0x90, 0x0b, 0x31, 0x7b, 0x79, 0x91, 0xb8, 0x5f, 0x33, + 0x11, 0x04, 0xc3, 0x4f, 0xf5, 0x71, 0xd1, 0xfb, 0x94, 0x6b, 0x5f, 0x78, + 0xe2, 0xfa, 0x6a, 0x21, 0xb6, 0x1d, 0x11, 0x0e, 0x5b, 0x56, 0x6a, 0x5b, + 0xe9, 0x56, 0x5f, 0x8b, 0x87, 0x61, 0x96, 0x6d, 0xce, 0x66, 0xbb, 0xb6, + 0xe7, 0x13, 0x5a, 0xd8, 0x84, 0x29, 0x60, 0xa0, 0x80, 0x43, 0xdd, 0x0f, + 0x4b, 0x85, 0xb0, 0x04, 0x9d, 0x9f, 0x28, 0x97, 0x0a, 0x1e, 0x16, 0xb0, + 0x45, 0x33, 0x5e, 0x79, 0x4f, 0xaa, 0xee, 0x79, 0x6e, 0xc3, 0x4e, 0x3d, + 0xe8, 0x67, 0x7c, 0xe0, 0xd0, 0xcc, 0x05, 0x40, 0xae, 0x6b, 0x97, 0x82, + 0x97, 0x02, 0x01, 0xe2, 0xe3, 0xbc, 0xe4, 0x9b, 0xb3, 0x28, 0xed, 0x5e, + 0x0d, 0x68, 0x6e, 0xe5, 0x17, 0x0a, 0x86, 0x5a, 0xcd, 0x8d, 0x46, 0x2d, + 0x06, 0x10, 0xa6, 0x90, 0x44, 0xa1, 0xfc, 0x66, 0x6d, 0x7c, 0x57, 0x57, + 0x07, 0xbc, 0x95, 0xb2, 0x8d, 0xf0, 0x9f, 0x4d, 0x90, 0x04, 0xaf, 0x0c, + 0x23, 0x51, 0x1b, 0x34, 0xd5, 0x5c, 0x5d, 0x87, 0x5e, 0x10, 0x2b, 0x71, + 0xc2, 0xcf, 0xc5, 0x9d, 0x4b, 0x89, 0x01, 0xc4, 0x97, 0xf2, 0xea, 0x83, + 0x97, 0xfa, 0xe0, 0x51, 0x96, 0x78, 0x4f, 0x44, 0xb8, 0xa8, 0x9d, 0x03, + 0x1c, 0x6e, 0xb7, 0xc6, 0xd7, 0xc5, 0x3e, 0x32, 0x65, 0xa7, 0x06, 0xab, + 0x86, 0xfb, 0xd2, 0x9b, 0xd7, 0x86, 0xa8, 0xfe, 0x46, 0x41, 0x2e, 0xc2, + 0x4e, 0xed, 0xa2, 0x9b, 0x79, 0x36, 0x37, 0x49, 0x90, 0xfc, 0xa6, 0x14, + 0x93, 0x17, 0x82, 0x62, 0x3f, 0x79, 0x6b, 0x86, 0xc2, 0xeb, 0x82, 0xfe, + 0x87, 0x49, 0xa5, 0x7e, 0x41, 0xe3, 0x59, 0x60, 0x15, 0x61, 0x4e, 0x3b, + 0x16, 0xcf, 0xdb, 0x49, 0x2c, 0x84, 0x92, 0x26, 0x40, 0x04, 0x78, 0xd3, + 0xd6, 0xa6, 0xed, 0x6e, 0x63, 0x49, 0xcb, 0xea, 0xfe, 0x43, 0x85, 0x21, + 0x1a, 0x28, 0x36, 0x0a, 0x3e, 0x2a, 0xad, 0xba, 0xfc, 0x8a, 0x37, 0x18, + 0xb4, 0x80, 0xbe, 0x6a, 0x36, 0x14, 0x03, 0xdd, 0xa3, 0x37, 0xbd, 0xc1, + 0x8a, 0xbb, 0x2d, 0xd4, 0x08, 0xd7, 0x4b, 0xc4, 0xe9, 0xb8, 0xb4, 0x65, + 0xdd, 0xf6, 0xe8, 0x17, 0x2c, 0x2c, 0x9b, 0x1e, 0x92, 0x0b, 0xcb, 0x22, + 0x7c, 0x1b, 0x74, 0x8d, 0x65, 0x11, 0x5f, 0xfe, 0xf5, 0x2a, 0xc2, 0xbe, + 0xea, 0xa2, 0xf1, 0x7b, 0xe8, 0xaf, 0x32, 0x5a, 0x0a, 0x5b, 0xd2, 0x5a, + 0x11, 0x22, 0x79, 0xfa, 0xae, 0x2d, 0xe8, 0xc6, 0x17, 0xba, 0x17, 0x81, + 0x6a, 0x63, 0xb5, 0x26, 0xd7, 0x8d, 0xd0, 0x66, 0x0c, 0x4a, 0x0c, 0x22, + 0x1b, 0x20, 0x9f, 0x3d, 0x0b, 0x1b, 0x59, 0x53, 0x89, 0x9b, 0x5e, 0xbd, + 0x3d, 0xd1, 0xdd, 0xff, 0xca, 0xb2, 0xb7, 0x12, 0x8d, 0x03, 0xaa, 0xc3, + 0x1d, 0x56, 0x76, 0x14, 0xf8, 0xee, 0xb3, 0xeb, 0x80, 0x38, 0xc1, 0xc1, + 0x1a, 0xef, 0x4a, 0xd5, 0x16, 0x1f, 0x5e, 0x21, 0x5d, 0x46, 0x01, 0xb3, + 0xa4, 0xf7, 0x99, 0x94, 0x05, 0xc6, 0xc8, 0x06, 0xd8, 0x1c, 0xac, 0x47, + 0x13, 0x54, 0x13, 0x1b, 0x1f, 0xb6, 0x23, 0x9c, 0x73, 0x2b, 0x57, 0x32, + 0x94, 0x92, 0xf1, 0x71, 0x44, 0x40, 0x02, 0xc3, 0x21, 0x4a, 0x2f, 0x36, + 0x5e, 0x8a, 0xd0, 0x4b, 0x02, 0xc7, 0x6e, 0xcf, 0xed, 0xa2, 0xdb, 0xce, + 0x0a, 0x0f, 0x66, 0x4f, 0xb2, 0x3d, 0xb6, 0xcc, 0x75, 0x45, 0x80, 0x0a, + 0x49, 0x4a, 0xe7, 0xe7, 0x24, 0x62, 0x65, 0xc7, 0x02, 0x22, 0x13, 0xbe, + 0x6c, 0xa9, 0x9a, 0x8b, 0xa9, 0x1b, 0x2b, 0x3a, 0xde, 0x5e, 0x37, 0xbd, + 0x7f, 0x85, 0xd1, 0x32, 0x1d, 0xbf, 0x03, 0x8a, 0x3b, 0xe5, 0xb3, 0xfd, + 0x01, 0xca, 0xde, 0x0d, 0x7a, 0x5b, 0x01, 0x05, 0x1d, 0x3c, 0x23, 0x00, + 0x60, 0xb7, 0x50, 0xfd, 0x0d, 0xd7, 0x63, 0x92, 0xd6, 0xb0, 0x48, 0x3a, + 0x2d, 0xa3, 0xf8, 0xf6, 0x44, 0xe1, 0xda, 0x3b, 0xf4, 0x39, 0x47, 0xc4, + 0x4d, 0x8f, 0x54, 0x78, 0xec, 0x27, 0x7b, 0xc6, 0xe4, 0x81, 0x3a, 0x3f, + 0xa5, 0x61, 0x9d, 0xcb, 0x71, 0x0b, 0x0d, 0x55, 0xea, 0x5b, 0xeb, 0x58, + 0xa5, 0x49, 0xb5, 0x44, 0x1b, 0xb0, 0x0d, 0x1f, 0x58, 0xfb, 0x7a, 0xd4, + 0x09, 0x1e, 0x9a, 0x7e, 0x21, 0xba, 0xb3, 0x36, 0xa6, 0x04, 0x74, 0xe1, + 0xd0, 0xca, 0x02, 0x11, 0x84, 0x93, 0x8f, 0x86, 0x3d, 0x79, 0xbf, 0xa8, + 0xec, 0x0a, 0x23, 0x5e, 0xde, 0xc4, 0xc6, 0xda, 0x45, 0xbd, 0x95, 0x74, + 0x7b, 0xbf, 0xc1, 0x80, 0x48, 0x3f, 0x10, 0xb6, 0xb9, 0x5c, 0x31, 0x52, + 0x06, 0x5a, 0xac, 0xec, 0x94, 0x21, 0x80, 0x51, 0xba, 0x64, 0xed, 0x9d, + 0x27, 0x72, 0x8d, 0x17, 0x43, 0x5f, 0xf1, 0x60, 0xfa, 0xb5, 0x65, 0xd4, + 0xb9, 0xf8, 0xfc, 0x48, 0x7b, 0xe3, 0xfe, 0xae, 0xe4, 0x71, 0x4a, 0x3d, + 0x8c, 0xf5, 0x72, 0x8b, 0xbf, 0x60, 0xd8, 0x6a, 0x8f, 0x51, 0x82, 0xae, + 0x98, 0xd0, 0x56, 0xf9, 0xa8, 0x3a, 0xad, 0x86, 0x26, 0xa8, 0x5a, 0xf8, + 0x63, 0x87, 0x2c, 0x74, 0xbf, 0xf9, 0x7d, 0x00, 0xa0, 0x2f, 0x17, 0x23, + 0xb7, 0x62, 0x94, 0x19, 0x47, 0x57, 0xf9, 0xa8, 0xe7, 0x4b, 0xe9, 0x2b, + 0xe8, 0xb4, 0x03, 0xbf, 0x23, 0x75, 0xfe, 0xc3, 0x94, 0xc0, 0xa9, 0x5b, + 0x07, 0xb5, 0x75, 0x87, 0xcc, 0xa5, 0xb5, 0x9b, 0x35, 0x29, 0xe4, 0xb1, + 0xaa, 0x04, 0x57, 0xe9, 0xa3, 0xd0, 0xa3, 0xe4, 0x11, 0xe1, 0xaa, 0x3b, + 0x67, 0x09, 0x60, 0x83, 0x23, 0x72, 0xa6, 0x7b, 0x73, 0x22, 0x5b, 0x4a, + 0xe0, 0xf0, 0xa3, 0xeb, 0x9c, 0x91, 0xda, 0xba, 0x8b, 0xc1, 0x32, 0xa9, + 0x24, 0x13, 0x51, 0xe4, 0x67, 0x49, 0x4a, 0xd9, 0x3d, 0xae, 0x80, 0xfd, + 0x0a, 0x0d, 0x56, 0x98, 0x66, 0xa2, 0x6d, 0x92, 0x54, 0x7f, 0x82, 0xe5, + 0x17, 0x39, 0xd3, 0xaa, 0xc4, 0x4e, 0x6f, 0xe1, 0x2e, 0xfe, 0x03, 0x44, + 0x8a, 0xdd, 0xeb, 0xc0, 0x74, 0x79, 0x63, 0x33, 0x2b, 0x4b, 0xb5, 0x62, + 0xdd, 0x47, 0xba, 0x6e, 0xfc, 0x91, 0x08, 0xa9, 0x17, 0x8c, 0x47, 0x61, + 0xd9, 0x32, 0xe9, 0xa0, 0xb3, 0xa2, 0x82, 0xc9, 0xa6, 0x32, 0xa1, 0xca, + 0x7c, 0x41, 0xa6, 0x5a, 0xe2, 0x46, 0xb6, 0x45, 0x53, 0x72, 0x55, 0x9e, + 0xdf, 0xac, 0x96, 0x68, 0xe5, 0xdc, 0x4e, 0x2d, 0xa8, 0x1e, 0x7a, 0x8e, + 0xff, 0x54, 0xe4, 0x0a, 0x33, 0x5d, 0x97, 0xdf, 0x4e, 0x36, 0x96, 0xba, + 0x52, 0xd9, 0xa9, 0xec, 0x52, 0xe5, 0x1d, 0x94, 0xfe, 0x1c, 0x46, 0x54, + 0xa6, 0x8e, 0x85, 0x47, 0xba, 0xeb, 0x4b, 0x8d, 0x57, 0xe4, 0x34, 0x24, + 0x9e, 0x80, 0xb5, 0xc9, 0xa9, 0x94, 0x1d, 0xe4, 0x18, 0xb6, 0x07, 0x1e, + 0xfa, 0xe0, 0x1c, 0x88, 0x06, 0x84, 0xaa, 0xcb, 0x5e, 0xfa, 0x15, 0x5a, + 0xdd, 0x10, 0x43, 0x81, 0xf2, 0x50, 0x3e, 0x93, 0x26, 0x77, 0x1c, 0x77, + 0xe9, 0x0c, 0xfc, 0x5f, 0xdd, 0x67, 0x31, 0x02, 0xc6, 0xdd, 0xf4, 0x30, + 0x76, 0x51, 0xce, 0x56, 0xba, 0x7f, 0x44, 0xbd, 0x42, 0x9f, 0x10, 0x8c, + 0x56, 0x49, 0x48, 0xa2, 0xcb, 0xc4, 0xdd, 0x29, 0xae, 0xf0, 0x33, 0x35, + 0x46, 0x69, 0x1d, 0xae, 0xde, 0xde, 0x98, 0x82, 0x79, 0xa6, 0x50, 0x28, + 0xb3, 0x5f, 0x10, 0x24, 0x63, 0xee, 0x9a, 0x22, 0xbe, 0xf8, 0x3a, 0xf4, + 0xab, 0x98, 0xfe, 0xdf, 0x30, 0x03, 0xe8, 0x45, 0x8c, 0xf4, 0x85, 0xc6, + 0x98, 0x7b, 0x35, 0xb8, 0x30, 0x9c, 0x15, 0xa6, 0x45, 0xbd, 0x39, 0x84, + 0xe7, 0x43, 0x4b, 0x05, 0xa4, 0x8f, 0x52, 0x8e, 0x4a, 0xe4, 0x87, 0xc1, + 0xdc, 0xdf, 0x25, 0x9c, 0x5c, 0x37, 0xd0, 0x66, 0x12, 0x41, 0x66, 0x8c, + 0x28, 0xd0, 0x3f, 0x5c, 0x7f, 0x15, 0x9b, 0xcf, 0xa0, 0xae, 0x29, 0x33, + 0xb0, 0xe4, 0xb7, 0x36, 0x2a, 0x45, 0x83, 0xff, 0x86, 0x75, 0xcf, 0xa7, + 0x4d, 0x5c, 0xa8, 0xcf, 0x3f, 0xf2, 0xc8, 0xde, 0xdd, 0xad, 0x42, 0x8f, + 0x0e, 0xd0, 0x11, 0x24, 0x42, 0x86, 0x51, 0x52, 0x76, 0x21, 0x68, 0xf1, + 0xa7, 0x8f, 0xdb, 0x5b, 0x78, 0xfa, 0x44, 0x5f, 0xee, 0x31, 0xda, 0x62, + 0x5f, 0xfe, 0x69, 0xae, 0x97, 0xc9, 0xb5, 0x04, 0x76, 0x79, 0x2e, 0xb9, + 0xd9, 0x1b, 0xdd, 0xb7, 0xc4, 0x12, 0x78, 0xb2, 0x4d, 0xab, 0xd2, 0x29, + 0x25, 0x8c, 0xd5, 0x52, 0x4a, 0xd7, 0x2e, 0x18, 0x9d, 0xa2, 0xee, 0x7b, + 0xa5, 0xe5, 0x35, 0x3c, 0xb5, 0x54, 0x1c, 0x7f, 0x87, 0x4b, 0xc0, 0xbb, + 0x1a, 0x85, 0x19, 0xc0, 0xa9, 0x2b, 0x4d, 0xed, 0x71, 0xc0, 0x15, 0xb3, + 0x49, 0x2c, 0x46, 0xfc, 0x37, 0x40, 0xc0, 0x60, 0xd0, 0x00, 0x96, 0xfa, + 0x7f, 0xbb, 0x30, 0x94, 0x6b, 0x81, 0x61, 0xc5, 0x13, 0x93, 0x95, 0xaa, + 0xf3, 0x8d, 0x1d, 0xac, 0xdb, 0xbd, 0xc3, 0x90, 0xf3, 0xd2, 0x5f, 0x3a, + 0x08, 0xb1, 0xc9, 0x3a, 0xe8, 0x25, 0x4d, 0x20, 0x2a, 0xe9, 0x4c, 0xaf, + 0x9b, 0x54, 0x7b, 0xaf, 0x89, 0x44, 0x3a, 0x60, 0x23, 0xd3, 0x02, 0xb1, + 0xb3, 0x9a, 0x3a, 0xb0, 0xa0, 0xdb, 0x61, 0x0b, 0xac, 0x55, 0xa1, 0x36, + 0x55, 0x5b, 0xc4, 0xc5, 0xbd, 0x2a, 0x16, 0xe9, 0xe7, 0x86, 0x7f, 0xdb, + 0xee, 0x90, 0xfa, 0xfd, 0x08, 0x7f, 0x1a, 0x43, 0xe0, 0xb8, 0x21, 0xb3, + 0xe3, 0xdf, 0x27, 0x56, 0x61, 0xc4, 0xe8, 0xd5, 0x60, 0xe9, 0x6d, 0x49, + 0xd9, 0xa8, 0xf5, 0xd9, 0xfc, 0x66, 0x82, 0xe9, 0x80, 0x5b, 0x85, 0x16, + 0x55, 0x2b, 0xef, 0x50, 0x90, 0x6c, 0x5d, 0x81, 0x00, 0x00, 0x88, 0x9b, + 0xb4, 0x62, 0x49, 0x46, 0x2e, 0x5d, 0x71, 0x95, 0xff, 0x63, 0xfb, 0x93, + 0x23, 0xf8, 0x9f, 0xa2, 0x55, 0x56, 0xd4, 0xd5, 0xf7, 0xae, 0xaf, 0xd3, + 0xf6, 0x82, 0xc8, 0xdd, 0x89, 0x0f, 0x7e, 0x89, 0x0d, 0x0d, 0x7f, 0x4f, + 0x84, 0xa7, 0x16, 0xe8, 0xaf, 0xf2, 0x95, 0xd7, 0xc3, 0x66, 0xd6, 0x85, + 0x5b, 0xa1, 0xbb, 0xea, 0x31, 0x02, 0xac, 0xa2, 0x7b, 0x50, 0xf4, 0x78, + 0x29, 0x49, 0x59, 0xf6, 0x41, 0x42, 0x52, 0xa8, 0x19, 0xfb, 0x3d, 0xda, + 0xa9, 0x8d, 0xac, 0xe1, 0x25, 0xd4, 0x12, 0x1e, 0x2b, 0x48, 0x44, 0xb0, + 0xf6, 0x29, 0xd0, 0x55, 0x22, 0xb4, 0xe7, 0xbc, 0x22, 0x97, 0x1f, 0xe2, + 0xe1, 0x73, 0x16, 0x13, 0x7a, 0x00, 0x62, 0x14, 0xcb, 0x25, 0x9b, 0x21, + 0x98, 0x9d, 0xb8, 0xd8, 0xf4, 0x65, 0xf6, 0x8f, 0x39, 0xe4, 0x76, 0xf7, + 0x30, 0xaf, 0xbc, 0x3a, 0xfe, 0x0e, 0xf1, 0x81, 0xa7, 0xff, 0x4d, 0xa7, + 0xff, 0xbf, 0x15, 0x60, 0x0b, 0xcd, 0x69, 0xd5, 0x77, 0xba, 0xcb, 0x7b, + 0x5a, 0xfb, 0x34, 0xc7, 0x5d, 0x13, 0x33, 0xd7, 0x86, 0x02, 0x43, 0x57, + 0x52, 0x2c, 0x74, 0x61, 0x21, 0xa3, 0x34, 0xf5, 0x89, 0x51, 0x44, 0x89, + 0xfc, 0xbb, 0x57, 0x5c, 0x6d, 0xb0, 0x2e, 0x8c, 0xff, 0x73, 0xe5, 0x09, + 0x13, 0x3b, 0x45, 0x5b, 0x27, 0x88, 0xee, 0x9b, 0xab, 0x57, 0x7c, 0x9b, + 0xb9, 0x78, 0x73, 0xd2, 0x2d, 0x98, 0x6f, 0xd2, 0x78, 0xb3, 0xeb, 0xaa, + 0x18, 0x44, 0x87, 0x6d, 0x51, 0x1e, 0x9b, 0x73, 0xaa, 0x91, 0x1a, 0x4f, + 0x69, 0x78, 0xef, 0x3f, 0xb1, 0x2d, 0x39, 0x3e, 0xda, 0x31, 0xfc, 0x99, + 0xf6, 0xa2, 0x8c, 0xe5, 0xfd, 0x97, 0x95, 0x77, 0x37, 0xef, 0xf5, 0xd1, + 0xc8, 0x74, 0x2c, 0x9a, 0x1f, 0x23, 0x8f, 0x72, 0x96, 0x3d, 0xb5, 0xad, + 0x28, 0xa0, 0x6c, 0x66, 0xe8, 0xee, 0xaa, 0x9d, 0xc2, 0x8a, 0x56, 0x54, + 0x89, 0x74, 0x56, 0xdc, 0x57, 0x49, 0xc3, 0x8e, 0xb9, 0x3a, 0x91, 0x34, + 0xc4, 0x5e, 0x0b, 0x13, 0x63, 0x5e, 0xeb, 0xc5, 0xef, 0xc7, 0xe9, 0x7f, + 0x27, 0xe8, 0xe7, 0xe5, 0x0d, 0x83, 0x95, 0x5f, 0x8a, 0xf2, 0xb2, 0x22, + 0x03, 0x8d, 0x71, 0x4f, 0x62, 0xb7, 0xf1, 0x87, 0xf5, 0x3f, 0xc4, 0x23, + 0x21, 0x40, 0x35, 0xcf, 0x79, 0x7a, 0x5b, 0x9d, 0x76, 0xb2, 0xdc, 0x6a, + 0xb5, 0x1d, 0x8b, 0xb6, 0x9a, 0x19, 0xe4, 0x87, 0xf5, 0xce, 0x38, 0xf3, + 0x70, 0xbf, 0x9e, 0x86, 0xa6, 0x07, 0x53, 0xdd, 0x5d, 0xc7, 0x72, 0x84, + 0x47, 0x38, 0xd0, 0xe2, 0xeb, 0x64, 0x4c, 0x3a, 0x1e, 0xf6, 0x56, 0x79, + 0x75, 0x75, 0x14, 0x5d, 0xe4, 0x1d, 0x9d, 0xbb, 0xe1, 0x35, 0x03, 0x5e, + 0x4f, 0x8f, 0xea, 0x95, 0xde, 0x19, 0x57, 0x98, 0xe9, 0x2c, 0x42, 0x22, + 0xcb, 0x0f, 0x15, 0x7a, 0x6b, 0x53, 0xc3, 0xec, 0xdc, 0xa0, 0x66, 0x26, + 0x91, 0x04, 0x83, 0x75, 0x09, 0x0c, 0x22, 0x05, 0xec, 0x3a, 0x2d, 0x39, + 0xea, 0x19, 0xf2, 0x1d, 0xdb, 0xba, 0x5c, 0x46, 0x47, 0xd4, 0x94, 0x6d, + 0x51, 0xdb, 0x68, 0xde, 0x0c, 0xa0, 0x36, 0x8f, 0xbc, 0xfd, 0x9b, 0x8f, + 0xfe, 0x04, 0x1f, 0xde, 0x1e, 0x77, 0xb5, 0x80, 0xb9, 0x9c, 0x1b, 0x24, + 0x61, 0xfc, 0x2b, 0xc0, 0x42, 0x2b, 0xc5, 0x90, 0x58, 0xa2, 0xb1, 0x38, + 0x58, 0xf2, 0x8b, 0x65, 0xbf, 0xe8, 0xe6, 0x79, 0xcf, 0x65, 0x35, 0xa5, + 0xe1, 0xb7, 0x8b, 0x95, 0x54, 0xd7, 0x1d, 0xf0, 0x91, 0x18, 0xc0, 0x5d, + 0x2c, 0xb5, 0xca, 0x1a, 0x7f, 0x8d, 0xfb, 0x9e, 0x57, 0x1c, 0x5c, 0xf0, + 0x94, 0x36, 0x51, 0x95, 0x27, 0x62, 0xca, 0x92, 0x96, 0xe5, 0x00, 0x2e, + 0xa4, 0x41, 0x97, 0xbf, 0x28, 0x3c, 0x6d, 0xc1, 0xb7, 0xe9, 0x1c, 0x2e, + 0x3e, 0xe0, 0x5e, 0x89, 0x0c, 0x78, 0x88, 0x80, 0xb8, 0x30, 0xd2, 0x22, + 0xf9, 0x71, 0xb4, 0xc8, 0xee, 0xe6, 0x80, 0x04, 0x04, 0x9a, 0xfb, 0x0c, + 0x36, 0xcb, 0xea, 0x66, 0xf9, 0x52, 0x8c, 0x66, 0xbf, 0x4c, 0x0f, 0xf4, + 0xf8, 0x1e, 0x7e, 0x39, 0x80, 0xe8, 0x82, 0x4b, 0x0e, 0x66, 0x1d, 0x51, + 0x16, 0xa9, 0x8d, 0xd6, 0xea, 0x33, 0xb0, 0x2c, 0x36, 0x25, 0xf5, 0x01, + 0x30, 0x7e, 0x03, 0x7f, 0xae, 0x8e, 0xd6, 0x25, 0x62, 0x6d, 0x99, 0x8c, + 0x1f, 0xc1, 0x22, 0xf0, 0x94, 0x80, 0xbf, 0x82, 0x51, 0xea, 0xc2, 0x5a, + 0x3c, 0x85, 0x2a, 0x5d, 0xbe, 0xae, 0xe1, 0xe3, 0x07, 0x92, 0xd2, 0x40, + 0x47, 0xe8, 0x0f, 0x1a, 0xa5, 0x73, 0x64, 0x26, 0xc4, 0xac, 0xca, 0xc2, + 0x83, 0x5a, 0x56, 0xbc, 0x81, 0x21, 0xcb, 0x72, 0xf3, 0xe7, 0x82, 0x1e, + 0xc8, 0x54, 0x18, 0x42, 0xfe, 0xd6, 0xfc, 0x96, 0x0e, 0x03, 0x29, 0x98, + 0x4f, 0xd1, 0xd2, 0x98, 0x7c, 0x9e, 0x4e, 0x1a, 0x0f, 0xd6, 0x4e, 0xa4, + 0x52, 0x1b, 0xd1, 0xd8, 0x36, 0xf7, 0x47, 0x5f, 0xce, 0xcb, 0x87, 0x36, + 0xc8, 0x9b, 0x44, 0xc6, 0x7a, 0xf3, 0x45, 0x28, 0xae, 0x96, 0x5a, 0x85, + 0x62, 0x8b, 0x10, 0xc2, 0x7b, 0x39, 0x51, 0xdf, 0xf4, 0x21, 0xc2, 0x6b, + 0x6f, 0x93, 0x27, 0xed, 0xf6, 0xea, 0xff, 0x2a, 0x21, 0x70, 0x84, 0x4e, + 0x21, 0xac, 0xbc, 0x06, 0x41, 0xd3, 0x59, 0xa0, 0xa1, 0x50, 0xa6, 0x87, + 0xa2, 0x48, 0xad, 0x94, 0x44, 0x8d, 0x2f, 0xa8, 0xc6, 0x10, 0xb5, 0xeb, + 0x66, 0x82, 0x94, 0x5f, 0xae, 0x6a, 0x56, 0xb4, 0x8d, 0xf4, 0x62, 0x80, + 0xe4, 0x42, 0xc4, 0xbc, 0xe7, 0xee, 0xa6, 0x96, 0x3b, 0xfd, 0xc0, 0x92, + 0x7d, 0xcd, 0xe7, 0x0c, 0x99, 0x9a, 0xb6, 0x83, 0xcf, 0x45, 0xe5, 0x74, + 0xb3, 0xbc, 0xc0, 0x40, 0xad, 0x4d, 0xfc, 0xa7, 0x92, 0x35, 0x13, 0x81, + 0x5c, 0x9c, 0x21, 0x00, 0xa4, 0x37, 0x07, 0x1d, 0x19, 0xfc, 0x88, 0x4d, + 0x71, 0x43, 0x7d, 0x94, 0xf7, 0x32, 0xb8, 0x4b, 0x8a, 0x54, 0xd6, 0xe4, + 0x37, 0x4f, 0x27, 0x1f, 0xfd, 0x45, 0x83, 0xb9, 0x14, 0x5a, 0xf7, 0x36, + 0xdc, 0x98, 0xad, 0x99, 0xb9, 0x38, 0x69, 0xac, 0x18, 0x7e, 0x47, 0xd0, + 0x63, 0x27, 0xba, 0xe7, 0xd5, 0x1d, 0x7b, 0x6e, 0xde, 0x28, 0x7b, 0xf1, + 0x84, 0x4d, 0x2d, 0x7c, 0x16, 0x38, 0x4b, 0x16, 0xa9, 0x10, 0x83, 0xfb, + 0xe0, 0xe0, 0x6f, 0xdd, 0x03, 0x0a, 0xb8, 0x81, 0xf5, 0x8c, 0x98, 0xc3, + 0xf4, 0xc8, 0x31, 0x3a, 0xed, 0x14, 0x83, 0x89, 0xc3, 0x0e, 0xf7, 0xba, + 0x84, 0xb0, 0x49, 0xdf, 0xc6, 0x6b, 0xed, 0xbe, 0xd4, 0xa3, 0x83, 0x3a, + 0xe6, 0x6d, 0xa3, 0x83, 0x17, 0x43, 0x5e, 0x3a, 0x83, 0xda, 0x81, 0xe3, + 0x26, 0x95, 0x6b, 0xe5, 0x30, 0x28, 0x6d, 0xec, 0xd7, 0xd7, 0x35, 0xfa, + 0x1a, 0xad, 0x86, 0x04, 0x05, 0x2c, 0x76, 0x3f, 0xb2, 0x83, 0x92, 0x4e, + 0xef, 0x05, 0xde, 0x13, 0x26, 0x68, 0x80, 0x57, 0xee, 0x92, 0x80, 0xa3, + 0x99, 0xb4, 0xac, 0x98, 0x31, 0xd4, 0xf3, 0xe2, 0x60, 0xd9, 0xb9, 0x8d, + 0x20, 0xf7, 0x97, 0x70, 0x10, 0xd6, 0xba, 0x86, 0xb8, 0x9c, 0xb8, 0xf8, + 0x49, 0x71, 0x28, 0x9d, 0x05, 0x38, 0x1f, 0x63, 0xba, 0xf7, 0x15, 0x60, + 0x96, 0x61, 0x84, 0x68, 0xeb, 0x5d, 0x28, 0x51, 0xe3, 0x51, 0xdd, 0x69, + 0x8a, 0xdd, 0xba, 0xec, 0xbd, 0xd3, 0xa1, 0x42, 0x83, 0x59, 0x77, 0x11, + 0x12, 0x86, 0x5b, 0x8d, 0x30, 0xcf, 0xdf, 0x6f, 0xea, 0x9d, 0x31, 0xa2, + 0x65, 0xa5, 0x61, 0xc0, 0xde, 0x52, 0x6c, 0x72, 0x71, 0x0b, 0x4c, 0x7a, + 0x4c, 0x9f, 0x75, 0x74, 0x38, 0xc8, 0xdd, 0x12, 0xba, 0x21, 0x57, 0x1b, + 0x45, 0xb3, 0x02, 0x1d, 0x67, 0x22, 0x66, 0x53, 0x18, 0x48, 0xed, 0x60, + 0x40, 0x55, 0xd1, 0x25, 0x3b, 0xbc, 0x08, 0x7b, 0x19, 0x8a, 0x30, 0x5b, + 0x02, 0x4f, 0x65, 0x42, 0xff, 0xce, 0x87, 0xe8, 0x97, 0x2b, 0xbb, 0xfe, + 0x52, 0x52, 0x72, 0xe8, 0xb5, 0x77, 0xb7, 0x8e, 0x94, 0x34, 0xbc, 0x46, + 0xf1, 0xe1, 0x94, 0x98, 0x19, 0xbe, 0x7c, 0x3f, 0xf6, 0x0e, 0xe4, 0xbb, + 0x88, 0x32, 0x07, 0x83, 0x64, 0xad, 0xd7, 0xd1, 0xe8, 0x35, 0x8d, 0x5d, + 0x70, 0x16, 0xc8, 0x11, 0x94, 0x39, 0xc9, 0xac, 0xd6, 0xed, 0x6b, 0xdf, + 0xc8, 0xf3, 0x1d, 0x5e, 0x37, 0xd8, 0xb5, 0x86, 0x9b, 0xc2, 0xdc, 0x3c, + 0x5c, 0x04, 0x52, 0x5c, 0x11, 0x88, 0x0a, 0x2b, 0x78, 0x48, 0x9e, 0x5e, + 0x98, 0x57, 0x5a, 0xd1, 0x77, 0x1c, 0x7d, 0x5f, 0x60, 0xbb, 0x61, 0x7e, + 0x7e, 0x2a, 0xaf, 0x44, 0x14, 0x88, 0xfc, 0xa5, 0x31, 0xb7, 0xd4, 0x44, + 0x48, 0xda, 0xb5, 0x71, 0xa8, 0xd8, 0x4f, 0x79, 0xcd, 0xe4, 0xbe, 0xb6, + 0x1a, 0x61, 0x74, 0x4b, 0xd8, 0xec, 0xd7, 0xbf, 0xad, 0x57, 0x00, 0x42, + 0x04, 0xe8, 0xb3, 0xec, 0x47, 0x1d, 0x2a, 0x0a, 0xde, 0x7c, 0x6e, 0x5e, + 0xf8, 0xaa, 0x44, 0x05, 0x10, 0xab, 0xe9, 0x4e, 0xd7, 0x44, 0x0b, 0x97, + 0x6f, 0x1a, 0xc1, 0x59, 0x2b, 0xe4, 0xe1, 0x8a, 0x13, 0x82, 0x65, 0xd8, + 0xae, 0x5f, 0x2b, 0xbc, 0xa6, 0x14, 0x39, 0xaf, 0x38, 0x41, 0x26, 0x74, + 0xdb, 0x55, 0x6b, 0xe2, 0x21, 0x80, 0x5d, 0x20, 0xc3, 0xf5, 0x82, 0xee, + 0xcc, 0x3c, 0xc9, 0xb4, 0xeb, 0x52, 0xe9, 0x13, 0x8a, 0xea, 0xc6, 0x19, + 0x70, 0x37, 0x1b, 0xb8, 0x2e, 0x86, 0xa2, 0xe9, 0x9d, 0xb6, 0xd5, 0xd6, + 0xf3, 0xa8, 0x31, 0xf3, 0x02, 0xaa, 0x10, 0x33, 0x3f, 0xba, 0xf8, 0xf9, + 0x46, 0x5b, 0xe1, 0xd7, 0x34, 0x9f, 0x94, 0xcb, 0xfb, 0xb1, 0x3d, 0x60, + 0x77, 0x85, 0x14, 0xd4, 0xcf, 0x55, 0x60, 0x5d, 0x47, 0x6c, 0x07, 0xb4, + 0xc7, 0x73, 0xbd, 0x49, 0xbd, 0xa5, 0x31, 0xa1, 0xfa, 0x34, 0x3a, 0x8b, + 0x77, 0x1b, 0xaa, 0xaf, 0xa5, 0x87, 0x12, 0x4e, 0x36, 0x06, 0x14, 0xe7, + 0xb3, 0xb8, 0x87, 0x6c, 0x4b, 0x50, 0xc9, 0x52, 0x1b, 0x19, 0x48, 0x69, + 0x5b, 0x7f, 0xd8, 0xc9, 0x14, 0xb8, 0x11, 0xa0, 0x51, 0x09, 0xbd, 0x42, + 0x5a, 0x50, 0x32, 0x57, 0x69, 0x39, 0x30, 0xdb, 0xbf, 0x8b, 0x93, 0x54, + 0x43, 0x80, 0x4e, 0xd0, 0xc6, 0xf2, 0x81, 0x15, 0x6d, 0xef, 0x5a, 0xb6, + 0x4d, 0x70, 0x93, 0x88, 0x8d, 0xce, 0x0d, 0xb8, 0xe9, 0xac, 0xa2, 0xcd, + 0xc7, 0x18, 0xa5, 0x95, 0xb7, 0xf6, 0x0c, 0x6f, 0xe1, 0x10, 0x7b, 0x22, + 0xf8, 0x81, 0x18, 0x42, 0x6a, 0x09, 0x75, 0x20, 0xb4, 0x2f, 0x67, 0x7a, + 0xda, 0x55, 0x28, 0xc3, 0x81, 0xf7, 0xc1, 0xf0, 0xe6, 0x1b, 0x29, 0x9c, + 0x72, 0x87, 0xe5, 0x4c, 0xa9, 0x5b, 0x5b, 0x62, 0xb5, 0xb7, 0x1e, 0x82, + 0xc3, 0x7b, 0xaf, 0xe9, 0x6f, 0x37, 0x31, 0x9f, 0x79, 0xe7, 0x4f, 0x06, + 0x1e, 0xff, 0xff, 0x80, 0x8e, 0x00, 0x00 +}; + +const size_t lzma_compressed_size = sizeof(lzma_compressed); - fd = os_open(fname, OS_O_RDONLY); - ut_assert(fd >= 0); - ut_asserteq(512, os_read(fd, header, 512)); - text_ctx.fd = fd; +int do_spl_test_load(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type, struct spl_image_loader *loader, + int (*write_image)(struct unit_test_state *, void *, size_t)) +{ + size_t img_size, img_data, plain_size = SPL_TEST_DATA_SIZE; + struct spl_image_info info_write = { + .name = test_name, + .size = type == LEGACY_LZMA ? sizeof(lzma_compressed) : + plain_size, + }, info_read = { }; + struct spl_boot_device bootdev = { + .boot_device = loader->boot_device, + }; + char *data, *plain; + void *img; + + img_size = create_image(NULL, type, &info_write, &img_data); + ut_assert(img_size); + img = calloc(img_size, 1); + ut_assertnonnull(img); + + data = img + img_data; + if (type == LEGACY_LZMA) { + plain = malloc(plain_size); + ut_assertnonnull(plain); + generate_data(plain, plain_size, "lzma"); + memcpy(data, lzma_compressed, sizeof(lzma_compressed)); + } else { + plain = data; + generate_data(plain, plain_size, test_name); + } + ut_asserteq(img_size, create_image(img, type, &info_write, NULL)); - load.priv = &text_ctx; + if (write_image(uts, img, img_size)) + return CMD_RET_FAILURE; - ut_assertok(spl_load_simple_fit(&image, &load, 0, header)); + ut_assertok(loader->load_image(&info_read, &bootdev)); + if (check_image_info(uts, &info_write, &info_read)) + return CMD_RET_FAILURE; + if (type == LEGACY_LZMA) + ut_asserteq(plain_size, info_read.size); + ut_asserteq_mem(plain, phys_to_virt(info_write.load_addr), plain_size); + if (type == LEGACY_LZMA) + free(plain); + free(img); return 0; } -SPL_TEST(spl_test_load, 0); diff --git a/test/image/spl_load_fs.c b/test/image/spl_load_fs.c new file mode 100644 index 00000000000..a89189e1124 --- /dev/null +++ b/test/image/spl_load_fs.c @@ -0,0 +1,442 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Sean Anderson <seanga2@gmail.com> + */ + +#include <common.h> +#include <blk.h> +#include <ext_common.h> +#include <ext4fs.h> +#include <fat.h> +#include <fs.h> +#include <memalign.h> +#include <spl.h> +#include <asm/io.h> +#include <linux/stat.h> +#include <test/spl.h> +#include <test/ut.h> + +/** + * create_ext2() - Create an "ext2" filesystem with a single file + * @dst: The location of the new filesystem; MUST be zeroed + * @size: The size of the file + * @filename: The name of the file + * @data_offset: Filled with the offset of the file data from @dst + * + * Budget mke2fs. We use 1k blocks (to reduce overhead) with a single block + * group, which limits us to 8M of data. Almost every feature which increases + * complexity (checksums, hash tree directories, etc.) is disabled. We do cheat + * a little and use extents from ext4 to save having to deal with indirects, but + * U-Boot doesn't care. + * + * If @dst is %NULL, nothing is copied. + * + * Return: The size of the filesystem in bytes + */ +static size_t create_ext2(void *dst, size_t size, const char *filename, + size_t *data_offset) +{ + u32 super_block = 1; + u32 group_block = 2; + u32 block_bitmap_block = 3; + u32 inode_bitmap_block = 4; + u32 inode_table_block = 5; + u32 root_block = 6; + u32 file_block = 7; + + u32 root_ino = EXT2_ROOT_INO; + u32 file_ino = EXT2_BOOT_LOADER_INO; + + u32 block_size = EXT2_MIN_BLOCK_SIZE; + u32 inode_size = sizeof(struct ext2_inode); + + u32 file_blocks = (size + block_size - 1) / block_size; + u32 blocks = file_block + file_blocks; + u32 inodes = block_size / inode_size; + u32 filename_len = strlen(filename); + u32 dirent_len = ALIGN(filename_len, sizeof(struct ext2_dirent)) + + sizeof(struct ext2_dirent); + + struct ext2_sblock *sblock = dst + super_block * block_size; + struct ext2_block_group *bg = dst + group_block * block_size; + struct ext2_inode *inode_table = dst + inode_table_block * block_size; + struct ext2_inode *root_inode = &inode_table[root_ino - 1]; + struct ext2_inode *file_inode = &inode_table[file_ino - 1]; + struct ext4_extent_header *ext_block = (void *)&file_inode->b; + struct ext4_extent *extent = (void *)(ext_block + 1); + struct ext2_dirent *dot = dst + root_block * block_size; + struct ext2_dirent *dotdot = dot + 2; + struct ext2_dirent *dirent = dotdot + 2; + struct ext2_dirent *last = ((void *)dirent) + dirent_len; + + /* Make sure we fit in one block group */ + if (blocks > block_size * 8) + return 0; + + if (filename_len > EXT2_NAME_LEN) + return 0; + + if (data_offset) + *data_offset = file_block * block_size; + + if (!dst) + goto out; + + sblock->total_inodes = cpu_to_le32(inodes); + sblock->total_blocks = cpu_to_le32(blocks); + sblock->first_data_block = cpu_to_le32(super_block); + sblock->blocks_per_group = cpu_to_le32(blocks); + sblock->fragments_per_group = cpu_to_le32(blocks); + sblock->inodes_per_group = cpu_to_le32(inodes); + sblock->magic = cpu_to_le16(EXT2_MAGIC); + /* Done mostly so we can pretend to be (in)compatible */ + sblock->revision_level = cpu_to_le32(EXT2_DYNAMIC_REV); + /* Not really accurate but it doesn't matter */ + sblock->first_inode = cpu_to_le32(EXT2_GOOD_OLD_FIRST_INO); + sblock->inode_size = cpu_to_le32(inode_size); + sblock->feature_incompat = cpu_to_le32(EXT4_FEATURE_INCOMPAT_EXTENTS); + + bg->block_id = cpu_to_le32(block_bitmap_block); + bg->inode_id = cpu_to_le32(inode_bitmap_block); + bg->inode_table_id = cpu_to_le32(inode_table_block); + + /* + * All blocks/inodes are in-use. I don't want to have to deal with + * endianness, so just fill everything in. + */ + memset(dst + block_bitmap_block * block_size, 0xff, block_size * 2); + + root_inode->mode = cpu_to_le16(S_IFDIR | 0755); + root_inode->size = cpu_to_le32(block_size); + root_inode->nlinks = cpu_to_le16(3); + root_inode->blockcnt = cpu_to_le32(1); + root_inode->flags = cpu_to_le32(EXT4_TOPDIR_FL); + root_inode->b.blocks.dir_blocks[0] = root_block; + + file_inode->mode = cpu_to_le16(S_IFREG | 0644); + file_inode->size = cpu_to_le32(size); + file_inode->nlinks = cpu_to_le16(1); + file_inode->blockcnt = cpu_to_le32(file_blocks); + file_inode->flags = cpu_to_le32(EXT4_EXTENTS_FL); + ext_block->eh_magic = cpu_to_le16(EXT4_EXT_MAGIC); + ext_block->eh_entries = cpu_to_le16(1); + ext_block->eh_max = cpu_to_le16(sizeof(file_inode->b) / + sizeof(*ext_block) - 1); + extent->ee_len = cpu_to_le16(file_blocks); + extent->ee_start_lo = cpu_to_le16(file_block); + + /* I'm not sure we need these, but it can't hurt */ + dot->inode = cpu_to_le32(root_ino); + dot->direntlen = cpu_to_le16(2 * sizeof(*dot)); + dot->namelen = 1; + dot->filetype = FILETYPE_DIRECTORY; + memcpy(dot + 1, ".", dot->namelen); + + dotdot->inode = cpu_to_le32(root_ino); + dotdot->direntlen = cpu_to_le16(2 * sizeof(*dotdot)); + dotdot->namelen = 2; + dotdot->filetype = FILETYPE_DIRECTORY; + memcpy(dotdot + 1, "..", dotdot->namelen); + + dirent->inode = cpu_to_le32(file_ino); + dirent->direntlen = cpu_to_le16(dirent_len); + dirent->namelen = filename_len; + dirent->filetype = FILETYPE_REG; + memcpy(dirent + 1, filename, filename_len); + + last->direntlen = block_size - dirent_len; + +out: + return (size_t)blocks * block_size; +} + +/** + * create_fat() - Create a FAT32 filesystem with a single file + * @dst: The location of the new filesystem; MUST be zeroed + * @size: The size of the file + * @filename: The name of the file + * @data_offset: Filled with the offset of the file data from @dst + * + * Budget mkfs.fat. We use FAT32 (so I don't have to deal with FAT12) with no + * info sector, and a single one-sector FAT. This limits us to 64k of data + * (enough for anyone). The filename must fit in 8.3. + * + * If @dst is %NULL, nothing is copied. + * + * Return: The size of the filesystem in bytes + */ +static size_t create_fat(void *dst, size_t size, const char *filename, + size_t *data_offset) +{ + u16 boot_sector = 0; + u16 fat_sector = 1; + u32 root_sector = 2; + u32 file_sector = 3; + + u16 sector_size = 512; + u32 file_sectors = (size + sector_size - 1) / sector_size; + u32 sectors = file_sector + file_sectors; + + char *ext; + size_t filename_len, ext_len; + int i; + + struct boot_sector *bs = dst + boot_sector * sector_size; + struct volume_info *vi = (void *)(bs + 1); + __le32 *fat = dst + fat_sector * sector_size; + struct dir_entry *dirent = dst + root_sector * sector_size; + + /* Make sure we fit in the FAT */ + if (sectors > sector_size / sizeof(u32)) + return 0; + + ext = strchr(filename, '.'); + if (ext) { + filename_len = ext - filename; + ext++; + ext_len = strlen(ext); + } else { + filename_len = strlen(filename); + ext_len = 0; + } + + if (filename_len > 8 || ext_len > 3) + return 0; + + if (data_offset) + *data_offset = file_sector * sector_size; + + if (!dst) + goto out; + + bs->sector_size[0] = sector_size & 0xff; + bs->sector_size[1] = sector_size >> 8; + bs->cluster_size = 1; + bs->reserved = cpu_to_le16(fat_sector); + bs->fats = 1; + bs->media = 0xf8; + bs->total_sect = cpu_to_le32(sectors); + bs->fat32_length = cpu_to_le32(1); + bs->root_cluster = cpu_to_le32(root_sector); + + vi->ext_boot_sign = 0x29; + memcpy(vi->fs_type, "FAT32 ", sizeof(vi->fs_type)); + + memcpy(dst + 0x1fe, "\x55\xAA", 2); + + fat[0] = cpu_to_le32(0x0ffffff8); + fat[1] = cpu_to_le32(0x0fffffff); + fat[2] = cpu_to_le32(0x0ffffff8); + for (i = file_sector; file_sectors > 1; file_sectors--, i++) + fat[i] = cpu_to_le32(i + 1); + fat[i] = cpu_to_le32(0x0ffffff8); + + for (i = 0; i < sizeof(dirent->nameext.name); i++) { + if (i < filename_len) + dirent->nameext.name[i] = toupper(filename[i]); + else + dirent->nameext.name[i] = ' '; + } + + for (i = 0; i < sizeof(dirent->nameext.ext); i++) { + if (i < ext_len) + dirent->nameext.ext[i] = toupper(ext[i]); + else + dirent->nameext.ext[i] = ' '; + } + + dirent->start = cpu_to_le16(file_sector); + dirent->size = cpu_to_le32(size); + +out: + return sectors * sector_size; +} + +typedef size_t (*create_fs_t)(void *, size_t, const char *, size_t *); + +static int spl_test_fs(struct unit_test_state *uts, const char *test_name, + create_fs_t create) +{ + const char *filename = CONFIG_SPL_FS_LOAD_PAYLOAD_NAME; + struct blk_desc *dev_desc; + char *data_write, *data_read; + void *fs; + size_t fs_size, fs_data, fs_blocks, data_size = SPL_TEST_DATA_SIZE; + loff_t actread; + + fs_size = create(NULL, data_size, filename, &fs_data); + ut_assert(fs_size); + fs = calloc(fs_size, 1); + ut_assertnonnull(fs); + + data_write = fs + fs_data; + generate_data(data_write, data_size, test_name); + ut_asserteq(fs_size, create(fs, data_size, filename, NULL)); + + dev_desc = blk_get_devnum_by_uclass_id(UCLASS_MMC, 0); + ut_assertnonnull(dev_desc); + ut_asserteq(512, dev_desc->blksz); + fs_blocks = fs_size / dev_desc->blksz; + ut_asserteq(fs_blocks, blk_dwrite(dev_desc, 0, fs_blocks, fs)); + + /* We have to use malloc so we can call virt_to_phys */ + data_read = malloc_cache_aligned(data_size); + ut_assertnonnull(data_read); + ut_assertok(fs_set_blk_dev_with_part(dev_desc, 0)); + ut_assertok(fs_read("/" CONFIG_SPL_FS_LOAD_PAYLOAD_NAME, + virt_to_phys(data_read), 0, data_size, &actread)); + ut_asserteq(data_size, actread); + ut_asserteq_mem(data_write, data_read, data_size); + + free(data_read); + free(fs); + return 0; +} + +static int spl_test_ext(struct unit_test_state *uts) +{ + return spl_test_fs(uts, __func__, create_ext2); +} +SPL_TEST(spl_test_ext, DM_FLAGS); + +static int spl_test_fat(struct unit_test_state *uts) +{ + spl_fat_force_reregister(); + return spl_test_fs(uts, __func__, create_fat); +} +SPL_TEST(spl_test_fat, DM_FLAGS); + +static bool spl_mmc_raw; + +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device) +{ + return spl_mmc_raw ? MMCSD_MODE_RAW : MMCSD_MODE_FS; +} + +static int spl_test_mmc_fs(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type, create_fs_t create_fs, + bool blk_mode) +{ + const char *filename = CONFIG_SPL_FS_LOAD_PAYLOAD_NAME; + struct blk_desc *dev_desc; + size_t fs_size, fs_data, img_size, img_data, + plain_size = SPL_TEST_DATA_SIZE; + struct spl_image_info info_write = { + .name = test_name, + .size = type == LEGACY_LZMA ? lzma_compressed_size : + plain_size, + }, info_read = { }; + struct disk_partition part = { + .start = 1, + .sys_ind = 0x83, + }; + struct spl_image_loader *loader = + SPL_LOAD_IMAGE_GET(0, BOOT_DEVICE_MMC1, spl_mmc_load_image); + struct spl_boot_device bootdev = { + .boot_device = loader->boot_device, + }; + void *fs; + char *data, *plain; + + img_size = create_image(NULL, type, &info_write, &img_data); + ut_assert(img_size); + fs_size = create_fs(NULL, img_size, filename, &fs_data); + ut_assert(fs_size); + fs = calloc(fs_size, 1); + ut_assertnonnull(fs); + + data = fs + fs_data + img_data; + if (type == LEGACY_LZMA) { + plain = malloc(plain_size); + ut_assertnonnull(plain); + generate_data(plain, plain_size, "lzma"); + memcpy(data, lzma_compressed, lzma_compressed_size); + } else { + plain = data; + generate_data(plain, plain_size, test_name); + } + ut_asserteq(img_size, create_image(fs + fs_data, type, &info_write, + NULL)); + ut_asserteq(fs_size, create_fs(fs, img_size, filename, NULL)); + + dev_desc = blk_get_devnum_by_uclass_id(UCLASS_MMC, 0); + ut_assertnonnull(dev_desc); + + ut_asserteq(512, dev_desc->blksz); + part.size = fs_size / dev_desc->blksz; + ut_assertok(write_mbr_partitions(dev_desc, &part, 1, 0)); + ut_asserteq(part.size, blk_dwrite(dev_desc, part.start, part.size, fs)); + + spl_mmc_raw = false; + if (blk_mode) + ut_assertok(spl_blk_load_image(&info_read, &bootdev, UCLASS_MMC, + 0, 1)); + else + ut_assertok(loader->load_image(&info_read, &bootdev)); + if (check_image_info(uts, &info_write, &info_read)) + return CMD_RET_FAILURE; + if (type == LEGACY_LZMA) + ut_asserteq(plain_size, info_read.size); + ut_asserteq_mem(plain, phys_to_virt(info_write.load_addr), plain_size); + + if (type == LEGACY_LZMA) + free(plain); + free(fs); + return 0; +} + +static int spl_test_blk(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + spl_fat_force_reregister(); + if (spl_test_mmc_fs(uts, test_name, type, create_fat, true)) + return CMD_RET_FAILURE; + + return spl_test_mmc_fs(uts, test_name, type, create_ext2, true); +} +SPL_IMG_TEST(spl_test_blk, LEGACY, DM_FLAGS); +SPL_IMG_TEST(spl_test_blk, LEGACY_LZMA, DM_FLAGS); +SPL_IMG_TEST(spl_test_blk, IMX8, DM_FLAGS); +SPL_IMG_TEST(spl_test_blk, FIT_EXTERNAL, DM_FLAGS); +SPL_IMG_TEST(spl_test_blk, FIT_INTERNAL, DM_FLAGS); + +static int spl_test_mmc_write_image(struct unit_test_state *uts, void *img, + size_t img_size) +{ + struct blk_desc *dev_desc; + size_t img_blocks; + + dev_desc = blk_get_devnum_by_uclass_id(UCLASS_MMC, 0); + ut_assertnonnull(dev_desc); + + img_blocks = DIV_ROUND_UP(img_size, dev_desc->blksz); + ut_asserteq(img_blocks, blk_dwrite(dev_desc, + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR, + img_blocks, img)); + + spl_mmc_raw = true; + return 0; +} + +static int spl_test_mmc(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + spl_mmc_clear_cache(); + spl_fat_force_reregister(); + + if (spl_test_mmc_fs(uts, test_name, type, create_ext2, false)) + return CMD_RET_FAILURE; + + if (spl_test_mmc_fs(uts, test_name, type, create_fat, false)) + return CMD_RET_FAILURE; + + return do_spl_test_load(uts, test_name, type, + SPL_LOAD_IMAGE_GET(0, BOOT_DEVICE_MMC1, + spl_mmc_load_image), + spl_test_mmc_write_image); +} +SPL_IMG_TEST(spl_test_mmc, LEGACY, DM_FLAGS); +SPL_IMG_TEST(spl_test_mmc, LEGACY_LZMA, DM_FLAGS); +SPL_IMG_TEST(spl_test_mmc, IMX8, DM_FLAGS); +SPL_IMG_TEST(spl_test_mmc, FIT_EXTERNAL, DM_FLAGS); +SPL_IMG_TEST(spl_test_mmc, FIT_INTERNAL, DM_FLAGS); diff --git a/test/image/spl_load_nand.c b/test/image/spl_load_nand.c new file mode 100644 index 00000000000..ec242207948 --- /dev/null +++ b/test/image/spl_load_nand.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Sean Anderson <seanga2@gmail.com> + */ + +#include <nand.h> +#include <spl.h> +#include <test/spl.h> +#include <test/ut.h> + +uint32_t spl_nand_get_uboot_raw_page(void); + +static int spl_test_nand_write_image(struct unit_test_state *uts, void *img, + size_t img_size) +{ + uint32_t off = spl_nand_get_uboot_raw_page(); + struct mtd_info *mtd; + struct erase_info erase = { }; + size_t length; + + nand_reinit(); + mtd = get_nand_dev_by_index(0); + ut_assertnonnull(mtd); + + /* Mark the first block as bad to test that it gets skipped */ + ut_assertok(mtd_block_markbad(mtd, off & ~mtd->erasesize_mask)); + off += mtd->erasesize; + + erase.mtd = mtd; + erase.len = img_size + (off & mtd->erasesize_mask); + erase.len += mtd->erasesize_mask; + erase.len &= ~mtd->erasesize_mask; + erase.addr = off & ~mtd->erasesize_mask; + erase.scrub = 1; + ut_assertok(mtd_erase(mtd, &erase)); + + ut_assertok(mtd_write(mtd, off, img_size, &length, img)); + + return 0; +} + +static int spl_test_nand(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + return do_spl_test_load(uts, test_name, type, + SPL_LOAD_IMAGE_GET(1, BOOT_DEVICE_NAND, + spl_nand_load_image), + spl_test_nand_write_image); +} +SPL_IMG_TEST(spl_test_nand, LEGACY, DM_FLAGS); +SPL_IMG_TEST(spl_test_nand, LEGACY_LZMA, DM_FLAGS); +SPL_IMG_TEST(spl_test_nand, IMX8, DM_FLAGS); +SPL_IMG_TEST(spl_test_nand, FIT_INTERNAL, DM_FLAGS); +#if !IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) +SPL_IMG_TEST(spl_test_nand, FIT_EXTERNAL, DM_FLAGS); +#endif diff --git a/test/image/spl_load_net.c b/test/image/spl_load_net.c new file mode 100644 index 00000000000..9d067a7a592 --- /dev/null +++ b/test/image/spl_load_net.c @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Sean Anderson <seanga2@gmail.com> + */ + +#include <common.h> +#include <dm.h> +#include <spl.h> +#include <test/spl.h> +#include <asm/eth.h> +#include <test/ut.h> +#include "../../net/bootp.h" + +/* + * sandbox_eth_bootp_req_to_reply() + * + * Check if a BOOTP request was sent. If so, inject a reply + * + * returns 0 if injected, -EAGAIN if not + */ +static int sandbox_eth_bootp_req_to_reply(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct ethernet_hdr *eth = packet; + struct ip_udp_hdr *ip; + struct bootp_hdr *bp; + struct ethernet_hdr *eth_recv; + struct ip_udp_hdr *ipr; + struct bootp_hdr *bpr; + + if (ntohs(eth->et_protlen) != PROT_IP) + return -EAGAIN; + + ip = packet + ETHER_HDR_SIZE; + if (ip->ip_p != IPPROTO_UDP) + return -EAGAIN; + + if (ntohs(ip->udp_dst) != PORT_BOOTPS) + return -EAGAIN; + + bp = (void *)ip + IP_UDP_HDR_SIZE; + if (bp->bp_op != OP_BOOTREQUEST) + return -EAGAIN; + + /* Don't allow the buffer to overrun */ + if (priv->recv_packets >= PKTBUFSRX) + return 0; + + /* reply to the request */ + eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets]; + memcpy(eth_recv, packet, len); + ipr = (void *)eth_recv + ETHER_HDR_SIZE; + bpr = (void *)ipr + IP_UDP_HDR_SIZE; + memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN); + memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN); + ipr->ip_sum = 0; + ipr->ip_off = 0; + net_write_ip(&ipr->ip_dst, net_ip); + net_write_ip(&ipr->ip_src, priv->fake_host_ipaddr); + ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE); + ipr->udp_src = ip->udp_dst; + ipr->udp_dst = ip->udp_src; + + bpr->bp_op = OP_BOOTREPLY; + net_write_ip(&bpr->bp_yiaddr, net_ip); + net_write_ip(&bpr->bp_siaddr, priv->fake_host_ipaddr); + copy_filename(bpr->bp_file, CONFIG_BOOTFILE, sizeof(CONFIG_BOOTFILE)); + memset(&bpr->bp_vend, 0, sizeof(bpr->bp_vend)); + + priv->recv_packet_length[priv->recv_packets] = len; + ++priv->recv_packets; + + return 0; +} + +struct spl_test_net_priv { + struct unit_test_state *uts; + void *img; + size_t img_size; + u16 port; +}; + +/* Well known TFTP port # */ +#define TFTP_PORT 69 +/* Transaction ID, chosen at random */ +#define TFTP_TID 21313 + +/* + * TFTP operations. + */ +#define TFTP_RRQ 1 +#define TFTP_DATA 3 +#define TFTP_ACK 4 + +/* default TFTP block size */ +#define TFTP_BLOCK_SIZE 512 + +struct tftp_hdr { + u16 opcode; + u16 block; +}; + +#define TFTP_HDR_SIZE sizeof(struct tftp_hdr) + +/* + * sandbox_eth_tftp_req_to_reply() + * + * Check if a TFTP request was sent. If so, inject a reply. We don't support + * options, and we don't check for rollover, so we are limited files of less + * than 32M. + * + * returns 0 if injected, -EAGAIN if not + */ +static int sandbox_eth_tftp_req_to_reply(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct spl_test_net_priv *test_priv = priv->priv; + struct ethernet_hdr *eth = packet; + struct ip_udp_hdr *ip; + struct tftp_hdr *tftp; + struct ethernet_hdr *eth_recv; + struct ip_udp_hdr *ipr; + struct tftp_hdr *tftpr; + size_t size; + u16 block; + + if (ntohs(eth->et_protlen) != PROT_IP) + return -EAGAIN; + + ip = packet + ETHER_HDR_SIZE; + if (ip->ip_p != IPPROTO_UDP) + return -EAGAIN; + + if (ntohs(ip->udp_dst) == TFTP_PORT) { + tftp = (void *)ip + IP_UDP_HDR_SIZE; + if (htons(tftp->opcode) != TFTP_RRQ) + return -EAGAIN; + + block = 0; + } else if (ntohs(ip->udp_dst) == TFTP_TID) { + tftp = (void *)ip + IP_UDP_HDR_SIZE; + if (htons(tftp->opcode) != TFTP_ACK) + return -EAGAIN; + + block = htons(tftp->block); + } else { + return -EAGAIN; + } + + if (block * TFTP_BLOCK_SIZE > test_priv->img_size) + return 0; + + size = min(test_priv->img_size - block * TFTP_BLOCK_SIZE, + (size_t)TFTP_BLOCK_SIZE); + + /* Don't allow the buffer to overrun */ + if (priv->recv_packets >= PKTBUFSRX) + return 0; + + /* reply to the request */ + eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets]; + memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN); + memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN); + eth_recv->et_protlen = htons(PROT_IP); + + ipr = (void *)eth_recv + ETHER_HDR_SIZE; + ipr->ip_hl_v = 0x45; + ipr->ip_len = htons(IP_UDP_HDR_SIZE + TFTP_HDR_SIZE + size); + ipr->ip_off = htons(IP_FLAGS_DFRAG); + ipr->ip_ttl = 255; + ipr->ip_p = IPPROTO_UDP; + ipr->ip_sum = 0; + net_copy_ip(&ipr->ip_dst, &ip->ip_src); + net_copy_ip(&ipr->ip_src, &ip->ip_dst); + ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE); + + ipr->udp_src = htons(TFTP_TID); + ipr->udp_dst = ip->udp_src; + ipr->udp_len = htons(UDP_HDR_SIZE + TFTP_HDR_SIZE + size); + ipr->udp_xsum = 0; + + tftpr = (void *)ipr + IP_UDP_HDR_SIZE; + tftpr->opcode = htons(TFTP_DATA); + tftpr->block = htons(block + 1); + memcpy((void *)tftpr + TFTP_HDR_SIZE, + test_priv->img + block * TFTP_BLOCK_SIZE, size); + + priv->recv_packet_length[priv->recv_packets] = + ETHER_HDR_SIZE + IP_UDP_HDR_SIZE + TFTP_HDR_SIZE + size; + ++priv->recv_packets; + + return 0; +} + +static int spl_net_handler(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + int old_packets = priv->recv_packets; + + priv->fake_host_ipaddr = string_to_ip("1.1.2.4"); + net_ip = string_to_ip("1.1.2.2"); + + sandbox_eth_arp_req_to_reply(dev, packet, len); + sandbox_eth_bootp_req_to_reply(dev, packet, len); + sandbox_eth_tftp_req_to_reply(dev, packet, len); + + if (old_packets == priv->recv_packets) + return 0; + + return 0; +} + +static int spl_test_net_write_image(struct unit_test_state *uts, void *img, + size_t img_size) +{ + struct spl_test_net_priv *test_priv = malloc(sizeof(*test_priv)); + + ut_assertnonnull(test_priv); + test_priv->uts = uts; + test_priv->img = img; + test_priv->img_size = img_size; + + sandbox_eth_set_tx_handler(0, spl_net_handler); + sandbox_eth_set_priv(0, test_priv); + return 0; +} + +static int spl_test_net(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + struct eth_sandbox_priv *priv; + struct udevice *dev; + int ret; + + net_server_ip = string_to_ip("1.1.2.4"); + ret = do_spl_test_load(uts, test_name, type, + SPL_LOAD_IMAGE_GET(0, BOOT_DEVICE_CPGMAC, + spl_net_load_image_cpgmac), + spl_test_net_write_image); + + sandbox_eth_set_tx_handler(0, NULL); + ut_assertok(uclass_get_device(UCLASS_ETH, 0, &dev)); + priv = dev_get_priv(dev); + free(priv->priv); + return ret; +} +SPL_IMG_TEST(spl_test_net, LEGACY, DM_FLAGS); +SPL_IMG_TEST(spl_test_net, LEGACY_LZMA, DM_FLAGS); +SPL_IMG_TEST(spl_test_net, IMX8, DM_FLAGS); +SPL_IMG_TEST(spl_test_net, FIT_INTERNAL, DM_FLAGS); +SPL_IMG_TEST(spl_test_net, FIT_EXTERNAL, DM_FLAGS); diff --git a/test/image/spl_load_nor.c b/test/image/spl_load_nor.c new file mode 100644 index 00000000000..de5686343b9 --- /dev/null +++ b/test/image/spl_load_nor.c @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Sean Anderson <seanga2@gmail.com> + */ + +#include <common.h> +#include <dm.h> +#include <spl.h> +#include <asm/io.h> +#include <test/spl.h> +#include <test/ut.h> + +static void *spl_test_nor_base; + +unsigned long spl_nor_get_uboot_base(void) +{ + return virt_to_phys(spl_test_nor_base); +} + +static int spl_test_nor_write_image(struct unit_test_state *uts, void *img, + size_t img_size) +{ + spl_test_nor_base = img; + return 0; +} + +static int spl_test_nor(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + return do_spl_test_load(uts, test_name, type, + SPL_LOAD_IMAGE_GET(0, BOOT_DEVICE_NOR, + spl_nor_load_image), + spl_test_nor_write_image); +} +SPL_IMG_TEST(spl_test_nor, LEGACY, 0); +SPL_IMG_TEST(spl_test_nor, LEGACY_LZMA, 0); +SPL_IMG_TEST(spl_test_nor, IMX8, 0); +SPL_IMG_TEST(spl_test_nor, FIT_INTERNAL, 0); +#if !IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) +SPL_IMG_TEST(spl_test_nor, FIT_EXTERNAL, 0); +#endif diff --git a/test/image/spl_load_os.c b/test/image/spl_load_os.c new file mode 100644 index 00000000000..26228a8a4a9 --- /dev/null +++ b/test/image/spl_load_os.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <common.h> +#include <image.h> +#include <os.h> +#include <spl.h> +#include <test/spl.h> +#include <test/ut.h> + +/* Context used for this test */ +struct text_ctx { + int fd; +}; + +static ulong read_fit_image(struct spl_load_info *load, ulong offset, + ulong size, void *buf) +{ + struct text_ctx *text_ctx = load->priv; + off_t ret; + ssize_t res; + + ret = os_lseek(text_ctx->fd, offset, OS_SEEK_SET); + if (ret != offset) { + printf("Failed to seek to %zx, got %zx (errno=%d)\n", offset, + ret, errno); + return 0; + } + + res = os_read(text_ctx->fd, buf, size); + if (res == -1) { + printf("Failed to read %lx bytes, got %ld (errno=%d)\n", + size, res, errno); + return 0; + } + + return size; +} + +static int spl_test_load(struct unit_test_state *uts) +{ + struct spl_image_info image; + struct legacy_img_hdr *header; + struct text_ctx text_ctx; + struct spl_load_info load; + char fname[256]; + int ret; + int fd; + + memset(&load, '\0', sizeof(load)); + spl_set_bl_len(&load, 512); + load.read = read_fit_image; + + ret = sandbox_find_next_phase(fname, sizeof(fname), true); + if (ret) + ut_assertf(0, "%s not found, error %d\n", fname, ret); + + header = spl_get_load_buffer(-sizeof(*header), sizeof(*header)); + + fd = os_open(fname, OS_O_RDONLY); + ut_assert(fd >= 0); + ut_asserteq(512, os_read(fd, header, 512)); + text_ctx.fd = fd; + + load.priv = &text_ctx; + + ut_assertok(spl_load_simple_fit(&image, &load, 0, header)); + + return 0; +} +SPL_TEST(spl_test_load, 0); diff --git a/test/image/spl_load_spi.c b/test/image/spl_load_spi.c new file mode 100644 index 00000000000..54a95465e23 --- /dev/null +++ b/test/image/spl_load_spi.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2023 Sean Anderson <seanga2@gmail.com> + */ + +#include <common.h> +#include <dm.h> +#include <spi_flash.h> +#include <spl.h> +#include <test/spl.h> +#include <test/ut.h> + +static int spl_test_spi_write_image(struct unit_test_state *uts, void *img, + size_t img_size) +{ + struct spi_flash *flash; + + flash = spi_flash_probe(spl_spi_boot_bus(), spl_spi_boot_cs(), + CONFIG_SF_DEFAULT_SPEED, + CONFIG_SF_DEFAULT_MODE); + ut_assertnonnull(flash); + ut_assertok(spi_flash_write(flash, spl_spi_get_uboot_offs(flash), + img_size, img)); + + return 0; +} + +static int spl_test_spi(struct unit_test_state *uts, const char *test_name, + enum spl_test_image type) +{ + return do_spl_test_load(uts, test_name, type, + SPL_LOAD_IMAGE_GET(1, BOOT_DEVICE_SPI, + spl_spi_load_image), + spl_test_spi_write_image); +} +SPL_IMG_TEST(spl_test_spi, LEGACY, DM_FLAGS); +SPL_IMG_TEST(spl_test_spi, LEGACY_LZMA, DM_FLAGS); +SPL_IMG_TEST(spl_test_spi, IMX8, DM_FLAGS); +SPL_IMG_TEST(spl_test_spi, FIT_INTERNAL, DM_FLAGS); +#if !IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL) +SPL_IMG_TEST(spl_test_spi, FIT_EXTERNAL, DM_FLAGS); +#endif diff --git a/test/lib/kconfig.c b/test/lib/kconfig.c index 76225ba8ffa..3914f699659 100644 --- a/test/lib/kconfig.c +++ b/test/lib/kconfig.c @@ -22,9 +22,9 @@ static int lib_test_is_enabled(struct unit_test_state *uts) ut_asserteq(0, CONFIG_IS_ENABLED(OF_PLATDATA)); ut_asserteq(0, CONFIG_IS_ENABLED(_UNDEFINED)); - ut_asserteq(0xc000, + ut_asserteq(0xb000, IF_ENABLED_INT(CONFIG_BLOBLIST_FIXED, CONFIG_BLOBLIST_ADDR)); - ut_asserteq(0xc000, + ut_asserteq(0xb000, CONFIG_IF_ENABLED_INT(BLOBLIST_FIXED, BLOBLIST_ADDR)); /* diff --git a/test/lib/lmb.c b/test/lib/lmb.c index 16288750358..15c68ce3961 100644 --- a/test/lib/lmb.c +++ b/test/lib/lmb.c @@ -451,12 +451,23 @@ static int lib_test_lmb_overlapping_reserve(struct unit_test_state *uts) ut_asserteq(ret, 0); ASSERT_LMB(&lmb, ram, ram_size, 2, 0x40010000, 0x10000, 0x40030000, 0x10000, 0, 0); - /* allocate 2nd region */ + /* allocate 2nd region , This should coalesced all region into one */ ret = lmb_reserve(&lmb, 0x40020000, 0x10000); ut_assert(ret >= 0); ASSERT_LMB(&lmb, ram, ram_size, 1, 0x40010000, 0x30000, 0, 0, 0, 0); + /* allocate 2nd region, which should be added as first region */ + ret = lmb_reserve(&lmb, 0x40000000, 0x8000); + ut_assert(ret >= 0); + ASSERT_LMB(&lmb, ram, ram_size, 2, 0x40000000, 0x8000, + 0x40010000, 0x30000, 0, 0); + + /* allocate 3rd region, coalesce with first and overlap with second */ + ret = lmb_reserve(&lmb, 0x40008000, 0x10000); + ut_assert(ret >= 0); + ASSERT_LMB(&lmb, ram, ram_size, 1, 0x40000000, 0x40000, + 0, 0, 0, 0); return 0; } diff --git a/test/py/tests/fs_helper.py b/test/py/tests/fs_helper.py index 9882ddb1daa..380f4c4dca3 100644 --- a/test/py/tests/fs_helper.py +++ b/test/py/tests/fs_helper.py @@ -9,7 +9,7 @@ import re import os from subprocess import call, check_call, check_output, CalledProcessError -def mk_fs(config, fs_type, size, prefix): +def mk_fs(config, fs_type, size, prefix, size_gran = 0x100000): """Create a file system volume Args: @@ -17,6 +17,7 @@ def mk_fs(config, fs_type, size, prefix): fs_type (str): File system type, e.g. 'ext4' size (int): Size of file system in bytes prefix (str): Prefix string of volume's file name + size_gran (int): Size granularity of file system image in bytes Raises: CalledProcessError: if any error occurs when creating the filesystem @@ -24,7 +25,9 @@ def mk_fs(config, fs_type, size, prefix): fs_img = f'{prefix}.{fs_type}.img' fs_img = os.path.join(config.persistent_data_dir, fs_img) - if fs_type == 'fat16': + if fs_type == 'fat12': + mkfs_opt = '-F 12' + elif fs_type == 'fat16': mkfs_opt = '-F 16' elif fs_type == 'fat32': mkfs_opt = '-F 32' @@ -36,7 +39,7 @@ def mk_fs(config, fs_type, size, prefix): else: fs_lnxtype = fs_type - count = (size + 0x100000 - 1) // 0x100000 + count = (size + size_gran - 1) // size_gran # Some distributions do not add /sbin to the default PATH, where mkfs lives if '/sbin' not in os.environ["PATH"].split(os.pathsep): @@ -44,7 +47,7 @@ def mk_fs(config, fs_type, size, prefix): try: check_call(f'rm -f {fs_img}', shell=True) - check_call(f'dd if=/dev/zero of={fs_img} bs=1M count={count}', + check_call(f'dd if=/dev/zero of={fs_img} bs={size_gran} count={count}', shell=True) check_call(f'mkfs.{fs_lnxtype} {mkfs_opt} {fs_img}', shell=True) if fs_type == 'ext4': diff --git a/test/py/tests/test_efi_secboot/test_signed.py b/test/py/tests/test_efi_secboot/test_signed.py index ca52e853d8f..2f862a259ad 100644 --- a/test/py/tests/test_efi_secboot/test_signed.py +++ b/test/py/tests/test_efi_secboot/test_signed.py @@ -29,7 +29,7 @@ class TestEfiSignedImage(object): output = u_boot_console.run_command_list([ 'host bind 0 %s' % disk_img, 'efidebug boot add -b 1 HELLO1 host 0:1 /helloworld.efi.signed -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'bootefi bootmgr']) assert 'Hello, world!' in ''.join(output) @@ -37,7 +37,7 @@ class TestEfiSignedImage(object): # Test Case 1b, run unsigned image if no PK output = u_boot_console.run_command_list([ 'efidebug boot add -b 2 HELLO2 host 0:1 /helloworld.efi -s ""', - 'efidebug boot next 2', + 'efidebug boot order 2', 'bootefi bootmgr']) assert 'Hello, world!' in ''.join(output) @@ -59,13 +59,13 @@ class TestEfiSignedImage(object): assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO1 host 0:1 /helloworld.efi.signed -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert('\'HELLO1\' failed' in ''.join(output)) assert('efi_start_image() returned: 26' in ''.join(output)) output = u_boot_console.run_command_list([ 'efidebug boot add -b 2 HELLO2 host 0:1 /helloworld.efi -s ""', - 'efidebug boot next 2', + 'efidebug boot order 2', 'efidebug test bootmgr']) assert '\'HELLO2\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -77,12 +77,12 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db']) assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 2', + 'efidebug boot order 2', 'efidebug test bootmgr']) assert '\'HELLO2\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 1', + 'efidebug boot order 1', 'bootefi bootmgr']) assert 'Hello, world!' in ''.join(output) @@ -105,7 +105,7 @@ class TestEfiSignedImage(object): assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -117,7 +117,7 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db']) assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -143,7 +143,7 @@ class TestEfiSignedImage(object): assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -170,7 +170,7 @@ class TestEfiSignedImage(object): assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed_2sigs -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert 'Hello, world!' in ''.join(output) @@ -181,7 +181,7 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize db']) assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert 'Hello, world!' in ''.join(output) @@ -193,7 +193,7 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx']) assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -205,7 +205,7 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -a -i 4000000:$filesize dbx']) assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -230,7 +230,7 @@ class TestEfiSignedImage(object): assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed_2sigs -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -254,7 +254,7 @@ class TestEfiSignedImage(object): assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'bootefi bootmgr']) assert 'Hello, world!' in ''.join(output) @@ -265,7 +265,7 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx']) assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -279,7 +279,7 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx']) assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -307,7 +307,7 @@ class TestEfiSignedImage(object): assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed_2sigs -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -330,7 +330,7 @@ class TestEfiSignedImage(object): assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi.signed_2sigs -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -349,7 +349,7 @@ class TestEfiSignedImage(object): output = u_boot_console.run_command_list([ 'host bind 0 %s' % disk_img, 'efidebug boot add -b 1 HELLO1 host 0:1 /helloworld_forged.efi.signed -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert('hELLO, world!' in ''.join(output)) @@ -364,7 +364,7 @@ class TestEfiSignedImage(object): 'setenv -e -nv -bs -rt -at -i 4000000:$filesize PK']) assert 'Failed to set EFI variable' not in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert(not 'hELLO, world!' in ''.join(output)) assert('\'HELLO1\' failed' in ''.join(output)) diff --git a/test/py/tests/test_efi_secboot/test_signed_intca.py b/test/py/tests/test_efi_secboot/test_signed_intca.py index d8d599d22f3..8d9a5f3e7fe 100644 --- a/test/py/tests/test_efi_secboot/test_signed_intca.py +++ b/test/py/tests/test_efi_secboot/test_signed_intca.py @@ -40,7 +40,7 @@ class TestEfiSignedImageIntca(object): output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO_a host 0:1 /helloworld.efi.signed_a -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO_a\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -49,7 +49,7 @@ class TestEfiSignedImageIntca(object): # Test Case 1b, signed and authenticated by root CA output = u_boot_console.run_command_list([ 'efidebug boot add -b 2 HELLO_ab host 0:1 /helloworld.efi.signed_ab -s ""', - 'efidebug boot next 2', + 'efidebug boot order 2', 'bootefi bootmgr']) assert 'Hello, world!' in ''.join(output) @@ -71,7 +71,7 @@ class TestEfiSignedImageIntca(object): output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO_abc host 0:1 /helloworld.efi.signed_abc -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO_abc\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -81,7 +81,7 @@ class TestEfiSignedImageIntca(object): output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 db_b.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO_abc\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) @@ -91,7 +91,7 @@ class TestEfiSignedImageIntca(object): output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 db_c.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize db', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert 'Hello, world!' in ''.join(output) @@ -117,7 +117,7 @@ class TestEfiSignedImageIntca(object): output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO_abc host 0:1 /helloworld.efi.signed_abc -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert 'Hello, world!' in ''.join(output) # Or, @@ -129,7 +129,7 @@ class TestEfiSignedImageIntca(object): output = u_boot_console.run_command_list([ 'fatload host 0:1 4000000 dbx_c.auth', 'setenv -e -nv -bs -rt -at -i 4000000:$filesize dbx', - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert '\'HELLO_abc\' failed' in ''.join(output) assert 'efi_start_image() returned: 26' in ''.join(output) diff --git a/test/py/tests/test_efi_secboot/test_unsigned.py b/test/py/tests/test_efi_secboot/test_unsigned.py index df63f0df081..7c078f220d0 100644 --- a/test/py/tests/test_efi_secboot/test_unsigned.py +++ b/test/py/tests/test_efi_secboot/test_unsigned.py @@ -36,11 +36,11 @@ class TestEfiUnsignedImage(object): output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'bootefi bootmgr']) assert '\'HELLO\' failed' in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert 'efi_start_image() returned: 26' in ''.join(output) assert 'Hello, world!' not in ''.join(output) @@ -65,7 +65,7 @@ class TestEfiUnsignedImage(object): output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'bootefi bootmgr']) assert 'Hello, world!' in ''.join(output) @@ -89,11 +89,11 @@ class TestEfiUnsignedImage(object): output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'bootefi bootmgr']) assert '\'HELLO\' failed' in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert 'efi_start_image() returned: 26' in ''.join(output) assert 'Hello, world!' not in ''.join(output) @@ -107,11 +107,11 @@ class TestEfiUnsignedImage(object): output = u_boot_console.run_command_list([ 'efidebug boot add -b 1 HELLO host 0:1 /helloworld.efi -s ""', - 'efidebug boot next 1', + 'efidebug boot order 1', 'bootefi bootmgr']) assert '\'HELLO\' failed' in ''.join(output) output = u_boot_console.run_command_list([ - 'efidebug boot next 1', + 'efidebug boot order 1', 'efidebug test bootmgr']) assert 'efi_start_image() returned: 26' in ''.join(output) assert 'Hello, world!' not in ''.join(output) diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py index 0d87d180c7b..fdd138d6ee4 100644 --- a/test/py/tests/test_fs/conftest.py +++ b/test/py/tests/test_fs/conftest.py @@ -12,9 +12,10 @@ import u_boot_utils as util from tests import fs_helper supported_fs_basic = ['fat16', 'fat32', 'ext4'] -supported_fs_ext = ['fat16', 'fat32'] -supported_fs_mkdir = ['fat16', 'fat32'] -supported_fs_unlink = ['fat16', 'fat32'] +supported_fs_ext = ['fat12', 'fat16', 'fat32'] +supported_fs_fat = ['fat12', 'fat16'] +supported_fs_mkdir = ['fat12', 'fat16', 'fat32'] +supported_fs_unlink = ['fat12', 'fat16', 'fat32'] supported_fs_symlink = ['ext4'] # @@ -49,6 +50,7 @@ def pytest_configure(config): """ global supported_fs_basic global supported_fs_ext + global supported_fs_fat global supported_fs_mkdir global supported_fs_unlink global supported_fs_symlink @@ -61,6 +63,7 @@ def pytest_configure(config): print('*** FS TYPE modified: %s' % supported_fs) supported_fs_basic = intersect(supported_fs, supported_fs_basic) supported_fs_ext = intersect(supported_fs, supported_fs_ext) + supported_fs_fat = intersect(supported_fs, supported_fs_fat) supported_fs_mkdir = intersect(supported_fs, supported_fs_mkdir) supported_fs_unlink = intersect(supported_fs, supported_fs_unlink) supported_fs_symlink = intersect(supported_fs, supported_fs_symlink) @@ -83,6 +86,9 @@ def pytest_generate_tests(metafunc): if 'fs_obj_ext' in metafunc.fixturenames: metafunc.parametrize('fs_obj_ext', supported_fs_ext, indirect=True, scope='module') + if 'fs_obj_fat' in metafunc.fixturenames: + metafunc.parametrize('fs_obj_fat', supported_fs_fat, + indirect=True, scope='module') if 'fs_obj_mkdir' in metafunc.fixturenames: metafunc.parametrize('fs_obj_mkdir', supported_fs_mkdir, indirect=True, scope='module') @@ -624,3 +630,44 @@ def fs_obj_symlink(request, u_boot_config): finally: call('rmdir %s' % mount_dir, shell=True) call('rm -f %s' % fs_img, shell=True) + +# +# Fixture for fat test +# +@pytest.fixture() +def fs_obj_fat(request, u_boot_config): + """Set up a file system to be used in fat test. + + Args: + request: Pytest request object. + u_boot_config: U-Boot configuration. + + Return: + A fixture for fat test, i.e. a duplet of file system type and + volume file name. + """ + + # the maximum size of a FAT12 filesystem resulting in 4084 clusters + MAX_FAT12_SIZE = 261695 * 1024 + + # the minimum size of a FAT16 filesystem that can be created with + # mkfs.vfat resulting in 4087 clusters + MIN_FAT16_SIZE = 8208 * 1024 + + fs_type = request.param + fs_img = '' + + fs_ubtype = fstype_to_ubname(fs_type) + check_ubconfig(u_boot_config, fs_ubtype) + + fs_size = MAX_FAT12_SIZE if fs_type == 'fat12' else MIN_FAT16_SIZE + + try: + # the volume size depends on the filesystem + fs_img = fs_helper.mk_fs(u_boot_config, fs_type, fs_size, f'{fs_size}', 1024) + except: + pytest.skip('Setup failed for filesystem: ' + fs_type) + return + else: + yield [fs_ubtype, fs_img] + call('rm -f %s' % fs_img, shell=True) diff --git a/test/py/tests/test_fs/test_erofs.py b/test/py/tests/test_fs/test_erofs.py index 458a52ba79d..87ad8f2d5fd 100644 --- a/test/py/tests/test_fs/test_erofs.py +++ b/test/py/tests/test_fs/test_erofs.py @@ -196,6 +196,15 @@ def test_erofs(u_boot_console): """ build_dir = u_boot_console.config.build_dir + # If the EFI subsystem is enabled and initialized, EFI subsystem tries to + # add EFI boot option when the new disk is detected. If there is no EFI + # System Partition exists, EFI subsystem outputs error messages and + # it ends up with test failure. + # Restart U-Boot to clear the previous state. + # TODO: Ideally EFI test cases need to be fixed, but it will + # increase the number of system reset. + u_boot_console.restart_uboot() + try: # setup test environment make_erofs_image(build_dir) diff --git a/test/py/tests/test_fs/test_fs_fat.py b/test/py/tests/test_fs/test_fs_fat.py new file mode 100644 index 00000000000..4009d0b63a3 --- /dev/null +++ b/test/py/tests/test_fs/test_fs_fat.py @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2023 Weidmüller Interface GmbH & Co. KG +# Author: Christian Taedcke <christian.taedcke@weidmueller.com> +# +# U-Boot File System: FAT Test + +""" +This test verifies fat specific file system behaviour. +""" + +import pytest +import re + +@pytest.mark.boardspec('sandbox') +@pytest.mark.slow +class TestFsFat(object): + def test_fs_fat1(self, u_boot_console, fs_obj_fat): + """Test that `fstypes` prints a result which includes `sandbox`.""" + fs_type,fs_img = fs_obj_fat + with u_boot_console.log.section('Test Case 1 - fatinfo'): + # Test Case 1 - ls + output = u_boot_console.run_command_list([ + 'host bind 0 %s' % fs_img, + 'fatinfo host 0:0']) + assert(re.search('Filesystem: %s' % fs_type.upper(), ''.join(output))) diff --git a/test/py/tests/test_fs/test_squashfs/test_sqfs_ls.py b/test/py/tests/test_fs/test_squashfs/test_sqfs_ls.py index 527a556ed80..a20a7d1a663 100644 --- a/test/py/tests/test_fs/test_squashfs/test_sqfs_ls.py +++ b/test/py/tests/test_fs/test_squashfs/test_sqfs_ls.py @@ -118,6 +118,15 @@ def test_sqfs_ls(u_boot_console): """ build_dir = u_boot_console.config.build_dir + # If the EFI subsystem is enabled and initialized, EFI subsystem tries to + # add EFI boot option when the new disk is detected. If there is no EFI + # System Partition exists, EFI subsystem outputs error messages and + # it ends up with test failure. + # Restart U-Boot to clear the previous state. + # TODO: Ideally EFI test cases need to be fixed, but it will + # increase the number of system reset. + u_boot_console.restart_uboot() + # setup test environment check_mksquashfs_version() generate_sqfs_src_dir(build_dir) diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py index cd4b4dc53cb..2495608786d 100644 --- a/test/py/tests/test_net.py +++ b/test/py/tests/test_net.py @@ -6,6 +6,8 @@ import pytest import u_boot_utils +import uuid +import datetime """ Note: This test relies on boardenv_* containing configuration values to define @@ -50,6 +52,8 @@ env__net_tftp_readable_file = { 'addr': 0x10000000, 'size': 5058624, 'crc32': 'c2244b26', + 'timeout': 50000, + 'fnu': 'ubtest-upload.bin', } # Details regarding a file that may be read from a NFS server. This variable @@ -61,6 +65,16 @@ env__net_nfs_readable_file = { 'crc32': 'c2244b26', } +# Details regarding a file that may be read from a TFTP server. This variable +# may be omitted or set to None if PXE testing is not possible or desired. +env__net_pxe_readable_file = { + 'fn': 'default', + 'addr': 0x2000000, + 'size': 74, + 'timeout': 50000, + 'pattern': 'Linux', +} + # True if a router advertisement service is connected to the network, and should # be tested. If router advertisement testing is not possible or desired, this variable may be omitted or set to False. @@ -260,3 +274,126 @@ def test_net_nfs(u_boot_console): output = u_boot_console.run_command('crc32 %x $filesize' % addr) assert expected_crc in output + +@pytest.mark.buildconfigspec("cmd_net") +@pytest.mark.buildconfigspec("cmd_pxe") +def test_net_pxe_get(u_boot_console): + """Test the pxe get command. + + A pxe configuration file is downloaded from the TFTP server and interpreted + to boot the images mentioned in pxe configuration file. + + The details of the file to download are provided by the boardenv_* file; + see the comment at the beginning of this file. + """ + + if not net_set_up: + pytest.skip("Network not initialized") + + test_net_setup_static(u_boot_console) + + f = u_boot_console.config.env.get("env__net_pxe_readable_file", None) + if not f: + pytest.skip("No PXE readable file to read") + + addr = f.get("addr", None) + timeout = f.get("timeout", u_boot_console.p.timeout) + + pxeuuid = uuid.uuid1() + u_boot_console.run_command(f"setenv pxeuuid {pxeuuid}") + expected_text_uuid = f"Retrieving file: pxelinux.cfg/{pxeuuid}" + + ethaddr = u_boot_console.run_command("echo $ethaddr") + ethaddr = ethaddr.replace(':', '-') + expected_text_ethaddr = f"Retrieving file: pxelinux.cfg/01-{ethaddr}" + + ip = u_boot_console.run_command("echo $ipaddr") + ip = ip.split('.') + ipaddr_file = "".join(['%02x' % int(x) for x in ip]).upper() + expected_text_ipaddr = f"Retrieving file: pxelinux.cfg/{ipaddr_file}" + expected_text_default = f"Retrieving file: pxelinux.cfg/default" + + with u_boot_console.temporary_timeout(timeout): + output = u_boot_console.run_command("pxe get") + + assert "TIMEOUT" not in output + assert expected_text_uuid in output + assert expected_text_ethaddr in output + assert expected_text_ipaddr in output + + i = 1 + for i in range(0, len(ipaddr_file) - 1): + expected_text_ip = f"Retrieving file: pxelinux.cfg/{ipaddr_file[:-i]}" + assert expected_text_ip in output + i += 1 + + assert expected_text_default in output + assert "Config file 'default.boot' found" in output + +@pytest.mark.buildconfigspec("cmd_crc32") +@pytest.mark.buildconfigspec("cmd_net") +@pytest.mark.buildconfigspec("cmd_tftpput") +def test_net_tftpput(u_boot_console): + """Test the tftpput command. + + A file is downloaded from the TFTP server and then uploaded to the TFTP + server, its size and its CRC32 are validated. + + The details of the file to download are provided by the boardenv_* file; + see the comment at the beginning of this file. + """ + + if not net_set_up: + pytest.skip("Network not initialized") + + f = u_boot_console.config.env.get("env__net_tftp_readable_file", None) + if not f: + pytest.skip("No TFTP readable file to read") + + addr = f.get("addr", None) + if not addr: + addr = u_boot_utils.find_ram_base(u_boot_console) + + sz = f.get("size", None) + timeout = f.get("timeout", u_boot_console.p.timeout) + fn = f["fn"] + fnu = f.get("fnu", "_".join([datetime.datetime.now().strftime("%y%m%d%H%M%S"), fn])) + expected_text = "Bytes transferred = " + if sz: + expected_text += "%d" % sz + + with u_boot_console.temporary_timeout(timeout): + output = u_boot_console.run_command("tftpboot %x %s" % (addr, fn)) + + assert "TIMEOUT" not in output + assert expected_text in output + + expected_tftpb_crc = f.get("crc32", None) + + output = u_boot_console.run_command("crc32 $fileaddr $filesize") + assert expected_tftpb_crc in output + + with u_boot_console.temporary_timeout(timeout): + output = u_boot_console.run_command( + "tftpput $fileaddr $filesize $serverip:%s" % (fnu) + ) + + expected_text = "Bytes transferred = " + if sz: + expected_text += "%d" % sz + addr = addr + sz + assert "TIMEOUT" not in output + assert "Access violation" not in output + assert expected_text in output + + with u_boot_console.temporary_timeout(timeout): + output = u_boot_console.run_command("tftpboot %x %s" % (addr, fnu)) + + expected_text = "Bytes transferred = " + if sz: + expected_text += "%d" % sz + assert "TIMEOUT" not in output + assert expected_text in output + + output = u_boot_console.run_command("crc32 $fileaddr $filesize") + assert expected_tftpb_crc in output diff --git a/test/py/tests/test_sandbox_opts.py b/test/py/tests/test_sandbox_opts.py new file mode 100644 index 00000000000..422b43cb3bc --- /dev/null +++ b/test/py/tests/test_sandbox_opts.py @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright 2022 Google LLC +# Written by Simon Glass <sjg@chromium.org> + +import pytest + +import u_boot_utils as util + +# This is needed for Azure, since the default '..' directory is not writeable +TMPDIR = '/tmp/test_cmdline' + +@pytest.mark.slow +@pytest.mark.boardspec('sandbox') +def test_sandbox_cmdline(u_boot_console): + """Test building sandbox without CONFIG_CMDLINE""" + cons = u_boot_console + + out = util.run_and_log( + cons, ['./tools/buildman/buildman', '-m', '--board', 'sandbox', + '-a', '~CMDLINE', '-o', TMPDIR]) + +@pytest.mark.slow +@pytest.mark.boardspec('sandbox') +def test_sandbox_lto(u_boot_console): + """Test building sandbox without CONFIG_LTO""" + cons = u_boot_console + + out = util.run_and_log( + cons, ['./tools/buildman/buildman', '-m', '--board', 'sandbox', + '-a', '~LTO', '-o', TMPDIR]) diff --git a/test/py/tests/test_sleep.py b/test/py/tests/test_sleep.py index 392af29db22..66a57434bff 100644 --- a/test/py/tests/test_sleep.py +++ b/test/py/tests/test_sleep.py @@ -41,3 +41,21 @@ def test_sleep(u_boot_console): if not u_boot_console.config.gdbserver: # margin is hopefully enough to account for any system overhead. assert elapsed < (sleep_time + sleep_margin) + +@pytest.mark.buildconfigspec("cmd_misc") +def test_time(u_boot_console): + """Test the time command, and validate that it gives approximately the + correct amount of command execution time.""" + + sleep_skip = u_boot_console.config.env.get("env__sleep_accurate", True) + if not sleep_skip: + pytest.skip("sleep is not accurate") + + sleep_time = u_boot_console.config.env.get("env__sleep_time", 10) + sleep_margin = u_boot_console.config.env.get("env__sleep_margin", 0.25) + output = u_boot_console.run_command("time sleep %d" % sleep_time) + execute_time = float(output.split()[1]) + assert sleep_time >= (execute_time - 0.01) + if not u_boot_console.config.gdbserver: + # margin is hopefully enough to account for any system overhead. + assert sleep_time < (execute_time + sleep_margin) diff --git a/test/py/tests/test_spl.py b/test/py/tests/test_spl.py index bd273dad893..42e4c4342b2 100644 --- a/test/py/tests/test_spl.py +++ b/test/py/tests/test_spl.py @@ -5,6 +5,16 @@ import os.path import pytest +@pytest.mark.buildconfigspec('spl_unit_test') +def test_ut_spl_init(u_boot_console): + """Initialize data for ut spl tests.""" + + fn = u_boot_console.config.source_dir + '/spi.bin' + if not os.path.exists(fn): + data = b'\x00' * (2 * 1024 * 1024) + with open(fn, 'wb') as fh: + fh.write(data) + def test_spl(u_boot_console, ut_spl_subtest): """Execute a "ut" subtest. diff --git a/test/py/tests/test_tpm2.py b/test/py/tests/test_tpm2.py index c2579fa02c5..1d654cd4a23 100644 --- a/test/py/tests/test_tpm2.py +++ b/test/py/tests/test_tpm2.py @@ -61,7 +61,7 @@ def test_tpm2_init(u_boot_console): skip_test = u_boot_console.config.env.get('env__tpm_device_test_skip', False) if skip_test: pytest.skip('skip TPM device test') - u_boot_console.run_command('tpm2 init') + u_boot_console.run_command('tpm2 autostart') output = u_boot_console.run_command('echo $?') assert output.endswith('0') @@ -100,7 +100,7 @@ def test_tpm2_sandbox_self_test_full(u_boot_console): """ if is_sandbox(u_boot_console): u_boot_console.restart_uboot() - u_boot_console.run_command('tpm2 init') + u_boot_console.run_command('tpm2 autostart') output = u_boot_console.run_command('echo $?') assert output.endswith('0') @@ -239,7 +239,7 @@ def test_tpm2_dam_parameters(u_boot_console): def test_tpm2_pcr_read(u_boot_console): """Execute a TPM2_PCR_Read command. - Perform a PCR read of the 0th PCR. Must be zero. + Perform a PCR read of the 10th PCR. Must be zero. """ if is_sandbox(u_boot_console): tpm2_sandbox_init(u_boot_console) @@ -247,7 +247,7 @@ def test_tpm2_pcr_read(u_boot_console): force_init(u_boot_console) ram = u_boot_utils.find_ram_base(u_boot_console) - read_pcr = u_boot_console.run_command('tpm2 pcr_read 0 0x%x' % ram) + read_pcr = u_boot_console.run_command('tpm2 pcr_read 10 0x%x' % ram) output = u_boot_console.run_command('echo $?') assert output.endswith('0') @@ -257,7 +257,7 @@ def test_tpm2_pcr_read(u_boot_console): updates = int(re.findall(r'\d+', str)[0]) # Check the output value - assert 'PCR #0 content' in read_pcr + assert 'PCR #10 content' in read_pcr assert '00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00' in read_pcr @pytest.mark.buildconfigspec('cmd_tpm_v2') @@ -275,19 +275,19 @@ def test_tpm2_pcr_extend(u_boot_console): force_init(u_boot_console) ram = u_boot_utils.find_ram_base(u_boot_console) - read_pcr = u_boot_console.run_command('tpm2 pcr_read 0 0x%x' % (ram + 0x20)) + read_pcr = u_boot_console.run_command('tpm2 pcr_read 10 0x%x' % (ram + 0x20)) output = u_boot_console.run_command('echo $?') assert output.endswith('0') str = re.findall(r'\d+ known updates', read_pcr)[0] updates = int(re.findall(r'\d+', str)[0]) - u_boot_console.run_command('tpm2 pcr_extend 0 0x%x' % ram) + u_boot_console.run_command('tpm2 pcr_extend 10 0x%x' % ram) output = u_boot_console.run_command('echo $?') assert output.endswith('0') # Read the value back into a different place so we can still use 'ram' as # our zero bytes - read_pcr = u_boot_console.run_command('tpm2 pcr_read 0 0x%x' % (ram + 0x20)) + read_pcr = u_boot_console.run_command('tpm2 pcr_read 10 0x%x' % (ram + 0x20)) output = u_boot_console.run_command('echo $?') assert output.endswith('0') assert 'f5 a5 fd 42 d1 6a 20 30 27 98 ef 6e d3 09 97 9b' in read_pcr @@ -297,11 +297,11 @@ def test_tpm2_pcr_extend(u_boot_console): new_updates = int(re.findall(r'\d+', str)[0]) assert (updates + 1) == new_updates - u_boot_console.run_command('tpm2 pcr_extend 0 0x%x' % ram) + u_boot_console.run_command('tpm2 pcr_extend 10 0x%x' % ram) output = u_boot_console.run_command('echo $?') assert output.endswith('0') - read_pcr = u_boot_console.run_command('tpm2 pcr_read 0 0x%x' % (ram + 0x20)) + read_pcr = u_boot_console.run_command('tpm2 pcr_read 10 0x%x' % (ram + 0x20)) output = u_boot_console.run_command('echo $?') assert output.endswith('0') assert '7a 05 01 f5 95 7b df 9c b3 a8 ff 49 66 f0 22 65' in read_pcr diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index 82932a662bf..1d9149a3f68 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -433,7 +433,6 @@ def setup_cedit_file(cons): u_boot_utils.run_and_log( cons, f'{expo_tool} -e {inhname} -l {infname} -o {outfname}') - @pytest.mark.buildconfigspec('ut_dm') def test_ut_dm_init(u_boot_console): """Initialize data for ut dm tests.""" @@ -463,6 +462,12 @@ def test_ut_dm_init(u_boot_console): fs_helper.mk_fs(u_boot_console.config, 'ext2', 0x200000, '2MB') fs_helper.mk_fs(u_boot_console.config, 'fat32', 0x100000, '1MB') + mmc_dev = 6 + fn = os.path.join(u_boot_console.config.source_dir, f'mmc{mmc_dev}.img') + data = b'\x00' * (12 * 1024 * 1024) + with open(fn, 'wb') as fh: + fh.write(data) + @pytest.mark.buildconfigspec('cmd_bootflow') def test_ut_dm_init_bootstd(u_boot_console): """Initialise data for bootflow tests""" diff --git a/test/test-main.c b/test/test-main.c index 778bf0a18a0..b7015d9f38d 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -303,7 +303,7 @@ static int test_pre_run(struct unit_test_state *uts, struct unit_test *test) if (test->flags & UT_TESTF_PROBE_TEST) ut_assertok(do_autoprobe(uts)); - if (!CONFIG_IS_ENABLED(OF_PLATDATA) && + if (CONFIG_IS_ENABLED(OF_REAL) && (test->flags & UT_TESTF_SCAN_FDT)) { /* * only set this if we know the ethernet uclass will be created @@ -476,7 +476,8 @@ static int ut_run_test_live_flat(struct unit_test_state *uts, * (for sandbox we handle this by copying the tree, but not for other * boards) */ - if ((test->flags & UT_TESTF_SCAN_FDT) && + if ((!CONFIG_IS_ENABLED(OF_LIVE) || + (test->flags & UT_TESTF_SCAN_FDT)) && !(test->flags & UT_TESTF_LIVE_TREE) && (CONFIG_IS_ENABLED(OFNODE_MULTI_TREE) || !(test->flags & UT_TESTF_OTHER_FDT)) && |