From 7d850f85aad74ae907290ba6f911d362a0478e61 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:19 -0600 Subject: sandbox: Enable mmc command and legacy images The mmc command is useful for testing mmc disk images in sandbox, so enable it. We also need to enable legacy images so that we can run tests which use them. Disable it for a few avb tests since MMC is not implemented there yet. Signed-off-by: Simon Glass --- test/py/tests/test_android/test_avb.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test') diff --git a/test/py/tests/test_android/test_avb.py b/test/py/tests/test_android/test_avb.py index a3f883136b..bc5c5b5582 100644 --- a/test/py/tests/test_android/test_avb.py +++ b/test/py/tests/test_android/test_avb.py @@ -39,6 +39,7 @@ def test_avb_verify(u_boot_console): @pytest.mark.buildconfigspec('cmd_avb') @pytest.mark.buildconfigspec('cmd_mmc') +@pytest.mark.notbuildconfigspec('sandbox') def test_avb_mmc_uuid(u_boot_console): """Check if 'avb get_uuid' works, compare results with 'part list mmc 1' output @@ -97,6 +98,7 @@ def test_avb_is_unlocked(u_boot_console): @pytest.mark.buildconfigspec('cmd_avb') @pytest.mark.buildconfigspec('cmd_mmc') +@pytest.mark.notbuildconfigspec('sandbox') def test_avb_mmc_read(u_boot_console): """Test mmc read operation """ -- cgit v1.2.3 From 0e38bd848d41bcfc7a113603ee37805016a09a42 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:32 -0600 Subject: video: Add font functions to the vidconsole API Support for fonts currently depends on the type of vidconsole in use. Add two new methods to enumerate fonts and to set the font. Fix a few other method comments while we are here. Signed-off-by: Simon Glass --- cmd/font.c | 11 ++++-- drivers/video/console_truetype.c | 27 +++++++++----- drivers/video/vidconsole-uclass.c | 33 +++++++++++++++++ include/video_console.h | 75 ++++++++++++++++++++++++++++++++------- test/cmd/font.c | 6 ++-- 5 files changed, 127 insertions(+), 25 deletions(-) (limited to 'test') diff --git a/cmd/font.c b/cmd/font.c index 3e522f3aaa..7b4347f32b 100644 --- a/cmd/font.c +++ b/cmd/font.c @@ -15,7 +15,11 @@ static int do_font_list(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { - vidconsole_list_fonts(); + struct udevice *dev; + + if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev)) + return CMD_RET_FAILURE; + vidconsole_list_fonts(dev); return 0; } @@ -47,6 +51,7 @@ static int do_font_select(struct cmd_tbl *cmdtp, int flag, int argc, static int do_font_size(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { + const char *font_name; struct udevice *dev; uint size; int ret; @@ -56,9 +61,11 @@ static int do_font_size(struct cmd_tbl *cmdtp, int flag, int argc, if (uclass_first_device_err(UCLASS_VIDEO_CONSOLE, &dev)) return CMD_RET_FAILURE; + font_name = vidconsole_get_font_size(dev, &size); size = dectoul(argv[1], NULL); - ret = vidconsole_select_font(dev, NULL, size); + + ret = vidconsole_select_font(dev, font_name, size); if (ret) { printf("Failed (error %d)\n", ret); return CMD_RET_FAILURE; diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index 4abc0bc2ff..9cac9a6de4 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -584,14 +584,20 @@ static struct font_info *console_truetype_find_font(void) return NULL; } -void vidconsole_list_fonts(void) +int console_truetype_get_font(struct udevice *dev, int seq, + struct vidfont_info *info) { struct font_info *tab; + int i; - for (tab = font_table; tab->begin; tab++) { - if (abs(tab->begin - tab->end) > 4) - printf("%s\n", tab->name); + for (i = 0, tab = font_table; tab->begin; tab++, i++) { + if (i == seq && font_valid(tab)) { + info->name = tab->name; + return 0; + } } + + return -ENOENT; } /** @@ -674,7 +680,8 @@ static void select_metrics(struct udevice *dev, struct console_tt_metrics *met) vc_priv->tab_width_frac = VID_TO_POS(met->font_size) * 8 / 2; } -int vidconsole_select_font(struct udevice *dev, const char *name, uint size) +static int truetype_select_font(struct udevice *dev, const char *name, + uint size) { struct console_tt_priv *priv = dev_get_priv(dev); struct console_tt_metrics *met; @@ -684,7 +691,7 @@ int vidconsole_select_font(struct udevice *dev, const char *name, uint size) if (!size) size = CONFIG_CONSOLE_TRUETYPE_SIZE; if (!name) - name = priv->cur_met->font_name; + name = font_table->name; met = find_metrics(dev, name, size); if (!met) { @@ -694,7 +701,9 @@ int vidconsole_select_font(struct udevice *dev, const char *name, uint size) int ret; ret = truetype_add_metrics(dev, - tab->name, size, tab->begin); + tab->name, + size, + tab->begin); if (ret < 0) return log_msg_ret("add", ret); @@ -715,7 +724,7 @@ int vidconsole_select_font(struct udevice *dev, const char *name, uint size) return 0; } -const char *vidconsole_get_font(struct udevice *dev, uint *sizep) +const char *vidconsole_get_font_size(struct udevice *dev, uint *sizep) { struct console_tt_priv *priv = dev_get_priv(dev); struct console_tt_metrics *met = priv->cur_met; @@ -763,6 +772,8 @@ struct vidconsole_ops console_truetype_ops = { .set_row = console_truetype_set_row, .backspace = console_truetype_backspace, .entry_start = console_truetype_entry_start, + .get_font = console_truetype_get_font, + .select_font = truetype_select_font, }; U_BOOT_DRIVER(vidconsole_truetype) = { diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 6bdfb6e37d..aadd54bfd4 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -557,6 +557,39 @@ static void vidconsole_puts(struct stdio_dev *sdev, const char *s) } } +void vidconsole_list_fonts(struct udevice *dev) +{ + struct vidfont_info info; + int ret, i; + + for (i = 0, ret = 0; !ret; i++) { + ret = vidconsole_get_font(dev, i, &info); + if (!ret) + printf("%s\n", info.name); + } +} + +int vidconsole_get_font(struct udevice *dev, int seq, + struct vidfont_info *info) +{ + struct vidconsole_ops *ops = vidconsole_get_ops(dev); + + if (!ops->get_font) + return -ENOSYS; + + return ops->get_font(dev, seq, info); +} + +int vidconsole_select_font(struct udevice *dev, const char *name, uint size) +{ + struct vidconsole_ops *ops = vidconsole_get_ops(dev); + + if (!ops->select_font) + return -ENOSYS; + + return ops->select_font(dev, name, size); +} + /* Set up the number of rows and colours (rotated drivers override this) */ static int vidconsole_pre_probe(struct udevice *dev) { diff --git a/include/video_console.h b/include/video_console.h index d755eb73cf..9d2c0f210e 100644 --- a/include/video_console.h +++ b/include/video_console.h @@ -62,6 +62,15 @@ struct vidconsole_priv { char escape_buf[32]; }; +/** + * struct vidfont_info - information about a font + * + * @name: Font name, e.g. nimbus_sans_l_regular + */ +struct vidfont_info { + const char *name; +}; + /** * struct vidconsole_ops - Video console operations * @@ -111,6 +120,9 @@ struct vidconsole_ops { /** * entry_start() - Indicate that text entry is starting afresh * + * @dev: Device to adjust + * Returns: 0 on success, -ve on error + * * Consoles which use proportional fonts need to track the position of * each character output so that backspace will return to the correct * place. This method signals to the console driver that a new entry @@ -123,6 +135,9 @@ struct vidconsole_ops { /** * backspace() - Handle erasing the last character * + * @dev: Device to adjust + * Returns: 0 on success, -ve on error + * * With proportional fonts the vidconsole uclass cannot itself erase * the previous character. This optional method will be called when * a backspace is needed. The driver should erase the previous @@ -133,11 +148,53 @@ struct vidconsole_ops { * characters. */ int (*backspace)(struct udevice *dev); + + /** + * get_font() - Obtain information about a font (optional) + * + * @dev: Device to check + * @seq: Font number to query (0=first, 1=second, etc.) + * @info: Returns font information on success + * Returns: 0 on success, -ENOENT if no such font + */ + int (*get_font)(struct udevice *dev, int seq, + struct vidfont_info *info); + + /** + * select_font() - Select a particular font by name / size + * + * @dev: Device to adjust + * @name: Font name to use (NULL to use default) + * @size: Font size to use (0 to use default) + * Returns: 0 on success, -ENOENT if no such font + */ + int (*select_font)(struct udevice *dev, const char *name, uint size); }; /* Get a pointer to the driver operations for a video console device */ #define vidconsole_get_ops(dev) ((struct vidconsole_ops *)(dev)->driver->ops) +/** + * vidconsole_get_font() - Obtain information about a font + * + * @dev: Device to check + * @seq: Font number to query (0=first, 1=second, etc.) + * @info: Returns font information on success + * Returns: 0 on success, -ENOENT if no such font, -ENOSYS if there is no such + * method + */ +int vidconsole_get_font(struct udevice *dev, int seq, + struct vidfont_info *info); + +/** + * vidconsole_select_font() - Select a particular font by name / size + * + * @dev: Device to adjust + * @name: Font name to use (NULL to use default) + * @size: Font size to use (0 to use default) + */ +int vidconsole_select_font(struct udevice *dev, const char *name, uint size); + /** * vidconsole_putc_xy() - write a single character to a position * @@ -234,27 +291,21 @@ void vidconsole_set_cursor_pos(struct udevice *dev, int x, int y); /** * vidconsole_list_fonts() - List the available fonts * - * This shows a list on the console - */ -void vidconsole_list_fonts(void); - -/** - * vidconsole_select_font() - Select a font to use + * @dev: vidconsole device to check * - * @dev: vidconsole device - * @name: Font name - * @size: Size of the font (norminal pixel height) or 0 for default + * This shows a list of fonts known by this vidconsole. The list is displayed on + * the console (not necessarily @dev but probably) */ -int vidconsole_select_font(struct udevice *dev, const char *name, uint size); +void vidconsole_list_fonts(struct udevice *dev); /** - * vidconsole_get_font() - get the current font name and size + * vidconsole_get_font_size() - get the current font name and size * * @dev: vidconsole device * @sizep: Place to put the font size (nominal height in pixels) * Returns: Current font name */ -const char *vidconsole_get_font(struct udevice *dev, uint *sizep); +const char *vidconsole_get_font_size(struct udevice *dev, uint *sizep); #ifdef CONFIG_VIDEO_COPY /** diff --git a/test/cmd/font.c b/test/cmd/font.c index 7a4156ade6..adb353965a 100644 --- a/test/cmd/font.c +++ b/test/cmd/font.c @@ -33,7 +33,7 @@ static int font_test_base(struct unit_test_state *uts) ut_assertok(ut_check_console_end(uts)); ut_asserteq_str("nimbus_sans_l_regular", - vidconsole_get_font(dev, &size)); + vidconsole_get_font_size(dev, &size)); ut_asserteq(18, size); max_metrics = 1; @@ -53,14 +53,14 @@ static int font_test_base(struct unit_test_state *uts) ut_assertok(ut_check_console_end(uts)); ut_asserteq_str("cantoraone_regular", - vidconsole_get_font(dev, &size)); + vidconsole_get_font_size(dev, &size)); ut_asserteq(40, size); ut_assertok(run_command("font size 30", 0)); ut_assertok(ut_check_console_end(uts)); ut_asserteq_str("cantoraone_regular", - vidconsole_get_font(dev, &size)); + vidconsole_get_font_size(dev, &size)); ut_asserteq(30, size); return 0; -- cgit v1.2.3 From 2175e76a51e53798ee4e19903b368a7e6c98356a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:33 -0600 Subject: bootstd: Read the Operating System name for distro/scripts Add the concept of an OS name to the bootflow. This typically includes the OS name, version and kernel version. Implement this for the distro and script bootmeths so that it works with Armbian and older version of Fedora. Signed-off-by: Simon Glass --- boot/bootflow.c | 1 + boot/bootmeth_distro.c | 36 ++++++++++++++++++++++++++++++++++++ boot/bootmeth_script.c | 34 ++++++++++++++++++++++++++++++++++ cmd/bootflow.c | 1 + include/bootflow.h | 3 +++ test/boot/bootflow.c | 1 + 6 files changed, 76 insertions(+) (limited to 'test') diff --git a/boot/bootflow.c b/boot/bootflow.c index f9ad409924..163cd4953d 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -354,6 +354,7 @@ void bootflow_free(struct bootflow *bflow) free(bflow->subdir); free(bflow->fname); free(bflow->buf); + free(bflow->os_name); } void bootflow_remove(struct bootflow *bflow) diff --git a/boot/bootmeth_distro.c b/boot/bootmeth_distro.c index 5c6c687f0a..6ef0fa1f2c 100644 --- a/boot/bootmeth_distro.c +++ b/boot/bootmeth_distro.c @@ -66,6 +66,38 @@ static int distro_check(struct udevice *dev, struct bootflow_iter *iter) return 0; } +/** + * distro_fill_info() - Decode the extlinux file to find out distro info + * + * @bflow: Bootflow to process + * @return 0 if OK, -ve on error + */ +static int distro_fill_info(struct bootflow *bflow) +{ + struct membuff mb; + char line[200]; + char *data; + int len; + + log_debug("parsing bflow file size %x\n", bflow->size); + membuff_init(&mb, bflow->buf, bflow->size); + membuff_putraw(&mb, bflow->size, true, &data); + while (len = membuff_readline(&mb, line, sizeof(line) - 1, ' '), len) { + char *tok, *p = line; + + tok = strsep(&p, " "); + if (p) { + if (!strcmp("label", tok)) { + bflow->os_name = strdup(p); + if (!bflow->os_name) + return log_msg_ret("os", -ENOMEM); + } + } + } + + return 0; +} + static int distro_read_bootflow(struct udevice *dev, struct bootflow *bflow) { struct blk_desc *desc; @@ -99,6 +131,10 @@ static int distro_read_bootflow(struct udevice *dev, struct bootflow *bflow) if (ret) return log_msg_ret("read", ret); + ret = distro_fill_info(bflow); + if (ret) + return log_msg_ret("inf", ret); + return 0; } diff --git a/boot/bootmeth_script.c b/boot/bootmeth_script.c index 5799c89a46..ba8e5d0438 100644 --- a/boot/bootmeth_script.c +++ b/boot/bootmeth_script.c @@ -35,6 +35,36 @@ static int script_check(struct udevice *dev, struct bootflow_iter *iter) return 0; } +/** + * script_fill_info() - Decode the U-Boot script to find out distro info + * + * @bflow: Bootflow to process + * @return 0 if OK, -ve on error + */ +static int script_fill_info(struct bootflow *bflow) +{ + char *name = NULL; + char *data; + uint len; + int ret; + + log_debug("parsing bflow file size %x\n", bflow->size); + + ret = image_locate_script(bflow->buf, bflow->size, NULL, NULL, &data, &len); + if (!ret) { + if (strstr(data, "armbianEnv")) + name = "Armbian"; + } + + if (name) { + bflow->os_name = strdup(name); + if (!bflow->os_name) + return log_msg_ret("os", -ENOMEM); + } + + return 0; +} + static int script_read_bootflow(struct udevice *dev, struct bootflow *bflow) { struct blk_desc *desc = NULL; @@ -75,6 +105,10 @@ static int script_read_bootflow(struct udevice *dev, struct bootflow *bflow) if (ret) return log_msg_ret("read", ret); + ret = script_fill_info(bflow); + if (ret) + return log_msg_ret("inf", ret); + return 0; } diff --git a/cmd/bootflow.c b/cmd/bootflow.c index 313103d277..6b8ac8c850 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -337,6 +337,7 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc, printf("Filename: %s\n", bflow->fname); printf("Buffer: %lx\n", (ulong)map_to_sysmem(bflow->buf)); printf("Size: %x (%d bytes)\n", bflow->size, bflow->size); + printf("OS: %s\n", bflow->os_name ? bflow->os_name : "(none)"); printf("Error: %d\n", bflow->err); if (dump && bflow->buf) { /* Set some sort of maximum on the size */ diff --git a/include/bootflow.h b/include/bootflow.h index 32dbbbbe26..776158c65d 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -52,6 +52,8 @@ enum bootflow_state_t { * @buf: Bootflow file contents (allocated) * @size: Size of bootflow file in bytes * @err: Error number received (0 if OK) + * @os_name: Name of the OS / distro being booted, or NULL if not known + * (allocated) */ struct bootflow { struct list_head bm_node; @@ -68,6 +70,7 @@ struct bootflow { char *buf; int size; int err; + char *os_name; }; /** diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index e1e0708210..3296316cf0 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -188,6 +188,7 @@ static int bootflow_cmd_info(struct unit_test_state *uts) ut_assert_nextline("Filename: /extlinux/extlinux.conf"); ut_assert_nextlinen("Buffer: "); ut_assert_nextline("Size: 253 (595 bytes)"); + ut_assert_nextline("OS: Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)"); ut_assert_nextline("Error: 0"); ut_assert_console_end(); -- cgit v1.2.3 From 24d8e1b37b90760a6c9867f37210aa4b1f2e8f63 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:34 -0600 Subject: bootstd: Allow reading a logo for the OS Some operating systems provide a logo in bmp format. Read this in if present so it can be displayed in the menu. Signed-off-by: Simon Glass --- boot/bootmeth-uclass.c | 69 +++++++++++++++++++++++++++++++++++++++++++------- boot/bootmeth_script.c | 4 +++ cmd/bootflow.c | 6 +++++ include/bootflow.h | 4 +++ include/bootmeth.h | 16 ++++++++++++ test/boot/bootflow.c | 1 + 6 files changed, 91 insertions(+), 9 deletions(-) (limited to 'test') diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c index 25552dd96f..4c3529d155 100644 --- a/boot/bootmeth-uclass.c +++ b/boot/bootmeth-uclass.c @@ -290,25 +290,19 @@ int bootmeth_try_file(struct bootflow *bflow, struct blk_desc *desc, return 0; } -int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align) +static int alloc_file(const char *fname, uint size, void **bufp) { loff_t bytes_read; ulong addr; char *buf; - uint size; int ret; - size = bflow->size; - log_debug(" - script file size %x\n", size); - if (size > size_limit) - return log_msg_ret("chk", -E2BIG); - - buf = memalign(align, size + 1); + buf = malloc(size + 1); if (!buf) return log_msg_ret("buf", -ENOMEM); addr = map_to_sysmem(buf); - ret = fs_read(bflow->fname, addr, 0, 0, &bytes_read); + ret = fs_read(fname, addr, 0, size, &bytes_read); if (ret) { free(buf); return log_msg_ret("read", ret); @@ -316,12 +310,69 @@ int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align) if (size != bytes_read) return log_msg_ret("bread", -EINVAL); buf[size] = '\0'; + + *bufp = buf; + + return 0; +} + +int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align) +{ + void *buf; + uint size; + int ret; + + size = bflow->size; + log_debug(" - script file size %x\n", size); + if (size > size_limit) + return log_msg_ret("chk", -E2BIG); + + ret = alloc_file(bflow->fname, bflow->size, &buf); + if (ret) + return log_msg_ret("all", ret); + bflow->state = BOOTFLOWST_READY; bflow->buf = buf; return 0; } +int bootmeth_alloc_other(struct bootflow *bflow, const char *fname, + void **bufp, uint *sizep) +{ + struct blk_desc *desc = NULL; + char path[200]; + loff_t size; + void *buf; + int ret; + + snprintf(path, sizeof(path), "%s%s", bflow->subdir, fname); + log_debug("trying: %s\n", path); + + if (bflow->blk) + desc = dev_get_uclass_plat(bflow->blk); + + ret = setup_fs(bflow, desc); + if (ret) + return log_msg_ret("fs", ret); + + ret = fs_size(path, &size); + log_debug(" %s - err=%d\n", path, ret); + + ret = setup_fs(bflow, desc); + if (ret) + return log_msg_ret("fs", ret); + + ret = alloc_file(path, size, &buf); + if (ret) + return log_msg_ret("all", ret); + + *bufp = buf; + *sizep = size; + + return 0; +} + int bootmeth_common_read_file(struct udevice *dev, struct bootflow *bflow, const char *file_path, ulong addr, ulong *sizep) { diff --git a/boot/bootmeth_script.c b/boot/bootmeth_script.c index ba8e5d0438..c7061eb998 100644 --- a/boot/bootmeth_script.c +++ b/boot/bootmeth_script.c @@ -109,6 +109,10 @@ static int script_read_bootflow(struct udevice *dev, struct bootflow *bflow) if (ret) return log_msg_ret("inf", ret); + ret = bootmeth_alloc_other(bflow, "boot.bmp", &bflow->logo, + &bflow->logo_size); + /* ignore error */ + return 0; } diff --git a/cmd/bootflow.c b/cmd/bootflow.c index 6b8ac8c850..495ef85f25 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -338,6 +338,12 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc, printf("Buffer: %lx\n", (ulong)map_to_sysmem(bflow->buf)); printf("Size: %x (%d bytes)\n", bflow->size, bflow->size); printf("OS: %s\n", bflow->os_name ? bflow->os_name : "(none)"); + printf("Logo: %s\n", bflow->logo ? + simple_xtoa((ulong)map_to_sysmem(bflow->logo)) : "(none)"); + if (bflow->logo) { + printf("Logo size: %x (%d bytes)\n", bflow->logo_size, + bflow->logo_size); + } printf("Error: %d\n", bflow->err); if (dump && bflow->buf) { /* Set some sort of maximum on the size */ diff --git a/include/bootflow.h b/include/bootflow.h index 776158c65d..8a07ab3019 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -49,6 +49,8 @@ enum bootflow_state_t { * @state: Current state (enum bootflow_state_t) * @subdir: Subdirectory to fetch files from (with trailing /), or NULL if none * @fname: Filename of bootflow file (allocated) + * @logo: Logo to display for this bootflow (BMP format) + * @logo_size: Size of the logo in bytes * @buf: Bootflow file contents (allocated) * @size: Size of bootflow file in bytes * @err: Error number received (0 if OK) @@ -67,6 +69,8 @@ struct bootflow { enum bootflow_state_t state; char *subdir; char *fname; + void *logo; + uint logo_size; char *buf; int size; int err; diff --git a/include/bootmeth.h b/include/bootmeth.h index 50ded055f3..669b14ce81 100644 --- a/include/bootmeth.h +++ b/include/bootmeth.h @@ -265,6 +265,22 @@ int bootmeth_try_file(struct bootflow *bflow, struct blk_desc *desc, */ int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align); +/** + * bootmeth_alloc_other() - Allocate and read a file for a bootflow + * + * This reads an arbitrary file in the same directory as the bootflow, + * allocating memory for it. The buffer is one byte larger than the file length, + * so that it can be nul-terminated. + * + * @bflow: Information about file to read + * @fname: Filename to read from (within bootflow->subdir) + * @bufp: Returns a pointer to the allocated buffer + * @sizep: Returns the size of the buffer + * Return: 0 if OK, -ENOMEM if out of memory, other -ve on other error + */ +int bootmeth_alloc_other(struct bootflow *bflow, const char *fname, + void **bufp, uint *sizep); + /** * bootmeth_common_read_file() - Common handler for reading a file * diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 3296316cf0..00dfd99068 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -189,6 +189,7 @@ static int bootflow_cmd_info(struct unit_test_state *uts) ut_assert_nextlinen("Buffer: "); ut_assert_nextline("Size: 253 (595 bytes)"); ut_assert_nextline("OS: Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)"); + ut_assert_nextline("Logo: (none)"); ut_assert_nextline("Error: 0"); ut_assert_console_end(); -- cgit v1.2.3 From fe93c14b4c62c47120bf95a79269fe94779c21f4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:39 -0600 Subject: expo: Add basic tests Add some tests for the expo, including setting up and rendering an expo. Signed-off-by: Simon Glass --- test/boot/Makefile | 2 + test/boot/expo.c | 539 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 541 insertions(+) create mode 100644 test/boot/expo.c (limited to 'test') diff --git a/test/boot/Makefile b/test/boot/Makefile index d724629d3b..22ed61c8fa 100644 --- a/test/boot/Makefile +++ b/test/boot/Makefile @@ -5,6 +5,8 @@ obj-$(CONFIG_BOOTSTD) += bootdev.o bootstd_common.o bootflow.o bootmeth.o obj-$(CONFIG_FIT) += image.o +obj-$(CONFIG_EXPO) += expo.o + ifdef CONFIG_OF_LIVE obj-$(CONFIG_BOOTMETH_VBE_SIMPLE) += vbe_simple.o endif diff --git a/test/boot/expo.c b/test/boot/expo.c new file mode 100644 index 0000000000..7104dff05e --- /dev/null +++ b/test/boot/expo.c @@ -0,0 +1,539 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2022 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "bootstd_common.h" +#include "../../boot/scene_internal.h" + +enum { + /* scenes */ + SCENE1 = 7, + SCENE2, + + /* objects */ + OBJ_LOGO, + OBJ_TEXT, + OBJ_TEXT2, + OBJ_MENU, + OBJ_MENU_TITLE, + + /* strings */ + STR_TEXT, + STR_TEXT2, + STR_MENU_TITLE, + STR_POINTER_TEXT, + + STR_ITEM1_LABEL, + STR_ITEM1_DESC, + STR_ITEM1_KEY, + STR_ITEM1_PREVIEW, + + STR_ITEM2_LABEL, + STR_ITEM2_DESC, + STR_ITEM2_KEY, + STR_ITEM2_PREVIEW, + + /* menu items */ + ITEM1, + ITEM1_LABEL, + ITEM1_DESC, + ITEM1_KEY, + ITEM1_PREVIEW, + + ITEM2, + ITEM2_LABEL, + ITEM2_DESC, + ITEM2_KEY, + ITEM2_PREVIEW, + + /* pointer to current item */ + POINTER_TEXT, +}; + +#define BAD_POINTER ((void *)1) + +/* names for various things */ +#define EXPO_NAME "my menus" +#define SCENE_NAME1 "main" +#define SCENE_NAME2 "second" +#define SCENE_TITLE "Main Menu" +#define LOGO_NAME "logo" + +/* Check base expo support */ +static int expo_base(struct unit_test_state *uts) +{ + struct udevice *dev; + struct expo *exp; + ulong start_mem; + char name[100]; + int i; + + ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev)); + + start_mem = ut_check_free(); + + exp = NULL; + strcpy(name, EXPO_NAME); + ut_assertok(expo_new(name, NULL, &exp)); + *name = '\0'; + ut_assertnonnull(exp); + ut_asserteq(0, exp->scene_id); + ut_asserteq(0, exp->next_id); + + /* Make sure the name was allocated */ + ut_assertnonnull(exp->name); + ut_asserteq_str(EXPO_NAME, exp->name); + + ut_assertok(expo_set_display(exp, dev)); + expo_destroy(exp); + ut_assertok(ut_check_delta(start_mem)); + + /* test handling out-of-memory conditions */ + for (i = 0; i < 2; i++) { + struct expo *exp2; + + malloc_enable_testing(i); + exp2 = BAD_POINTER; + ut_asserteq(-ENOMEM, expo_new(EXPO_NAME, NULL, &exp2)); + ut_asserteq_ptr(BAD_POINTER, exp2); + malloc_disable_testing(); + } + + return 0; +} +BOOTSTD_TEST(expo_base, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check creating a scene */ +static int expo_scene(struct unit_test_state *uts) +{ + struct scene *scn; + struct expo *exp; + ulong start_mem; + char name[100]; + int id; + + start_mem = ut_check_free(); + + ut_assertok(expo_new(EXPO_NAME, NULL, &exp)); + + scn = NULL; + ut_asserteq(0, exp->next_id); + strcpy(name, SCENE_NAME1); + id = scene_new(exp, name, SCENE1, &scn); + *name = '\0'; + ut_assertnonnull(scn); + ut_asserteq(SCENE1, id); + ut_asserteq(SCENE1 + 1, exp->next_id); + ut_asserteq_ptr(exp, scn->expo); + + /* Make sure the name was allocated */ + ut_assertnonnull(scn->name); + ut_asserteq_str(SCENE_NAME1, scn->name); + + /* Set the title */ + strcpy(name, SCENE_TITLE); + ut_assertok(scene_title_set(scn, name)); + *name = '\0'; + ut_assertnonnull(scn->title); + ut_asserteq_str(SCENE_TITLE, scn->title); + + /* Use an allocated ID */ + scn = NULL; + id = scene_new(exp, SCENE_NAME2, 0, &scn); + ut_assertnonnull(scn); + ut_asserteq(SCENE2, id); + ut_asserteq(SCENE2 + 1, exp->next_id); + ut_asserteq_ptr(exp, scn->expo); + + ut_asserteq_str(SCENE_NAME2, scn->name); + + expo_destroy(exp); + + ut_assertok(ut_check_delta(start_mem)); + + return 0; +} +BOOTSTD_TEST(expo_scene, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check creating a scene with objects */ +static int expo_object(struct unit_test_state *uts) +{ + struct scene_obj_img *img; + struct scene_obj_txt *txt; + struct scene *scn; + struct expo *exp; + ulong start_mem; + char name[100]; + char *data; + int id; + + start_mem = ut_check_free(); + + ut_assertok(expo_new(EXPO_NAME, NULL, &exp)); + id = scene_new(exp, SCENE_NAME1, SCENE1, &scn); + ut_assert(id > 0); + + ut_asserteq(0, scene_obj_count(scn)); + + data = NULL; + strcpy(name, LOGO_NAME); + id = scene_img(scn, name, OBJ_LOGO, data, &img); + ut_assert(id > 0); + *name = '\0'; + ut_assertnonnull(img); + ut_asserteq(OBJ_LOGO, id); + ut_asserteq(OBJ_LOGO + 1, exp->next_id); + ut_asserteq_ptr(scn, img->obj.scene); + ut_asserteq(SCENEOBJT_IMAGE, img->obj.type); + + ut_asserteq_ptr(data, img->data); + + /* Make sure the name was allocated */ + ut_assertnonnull(scn->name); + ut_asserteq_str(SCENE_NAME1, scn->name); + + ut_asserteq(1, scene_obj_count(scn)); + + id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", &txt); + ut_assert(id > 0); + ut_assertnonnull(txt); + ut_asserteq(OBJ_TEXT, id); + ut_asserteq(SCENEOBJT_TEXT, txt->obj.type); + ut_asserteq(2, scene_obj_count(scn)); + + /* Check passing NULL as the final parameter */ + id = scene_txt_str(scn, "text2", OBJ_TEXT2, STR_TEXT2, "another string", + NULL); + ut_assert(id > 0); + ut_asserteq(3, scene_obj_count(scn)); + + expo_destroy(exp); + + ut_assertok(ut_check_delta(start_mem)); + + return 0; +} +BOOTSTD_TEST(expo_object, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check setting object attributes */ +static int expo_object_attr(struct unit_test_state *uts) +{ + struct scene_obj_menu *menu; + struct scene_obj_img *img; + struct scene_obj_txt *txt; + struct scene *scn; + struct expo *exp; + ulong start_mem; + char name[100]; + char *data; + int id; + + start_mem = ut_check_free(); + + ut_assertok(expo_new(EXPO_NAME, NULL, &exp)); + id = scene_new(exp, SCENE_NAME1, SCENE1, &scn); + ut_assert(id > 0); + + data = NULL; + id = scene_img(scn, LOGO_NAME, OBJ_LOGO, data, &img); + ut_assert(id > 0); + + ut_assertok(scene_obj_set_pos(scn, OBJ_LOGO, 123, 456)); + ut_asserteq(123, img->obj.x); + ut_asserteq(456, img->obj.y); + + ut_asserteq(-ENOENT, scene_obj_set_pos(scn, OBJ_TEXT2, 0, 0)); + + id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", &txt); + ut_assert(id > 0); + + strcpy(name, "font2"); + ut_assertok(scene_txt_set_font(scn, OBJ_TEXT, name, 42)); + ut_asserteq_ptr(name, txt->font_name); + ut_asserteq(42, txt->font_size); + + ut_asserteq(-ENOENT, scene_txt_set_font(scn, OBJ_TEXT2, name, 42)); + + id = scene_menu(scn, "main", OBJ_MENU, &menu); + ut_assert(id > 0); + + ut_assertok(scene_menu_set_title(scn, OBJ_MENU, OBJ_TEXT)); + + ut_asserteq(-ENOENT, scene_menu_set_title(scn, OBJ_TEXT2, OBJ_TEXT)); + ut_asserteq(-EINVAL, scene_menu_set_title(scn, OBJ_MENU, OBJ_TEXT2)); + + expo_destroy(exp); + + ut_assertok(ut_check_delta(start_mem)); + + return 0; +} +BOOTSTD_TEST(expo_object_attr, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check creating a scene with a menu */ +static int expo_object_menu(struct unit_test_state *uts) +{ + struct scene_obj_menu *menu; + struct scene_menitem *item; + int id, label_id, desc_id, key_id, pointer_id, preview_id; + struct scene_obj_txt *ptr, *name1, *desc1, *key1, *tit, *prev1; + struct scene *scn; + struct expo *exp; + ulong start_mem; + + start_mem = ut_check_free(); + + ut_assertok(expo_new(EXPO_NAME, NULL, &exp)); + id = scene_new(exp, SCENE_NAME1, SCENE1, &scn); + ut_assert(id > 0); + + id = scene_menu(scn, "main", OBJ_MENU, &menu); + ut_assert(id > 0); + ut_assertnonnull(menu); + ut_asserteq(OBJ_MENU, id); + ut_asserteq(SCENEOBJT_MENU, menu->obj.type); + ut_asserteq(0, menu->title_id); + ut_asserteq(0, menu->pointer_id); + + ut_assertok(scene_obj_set_pos(scn, OBJ_MENU, 50, 400)); + ut_asserteq(50, menu->obj.x); + ut_asserteq(400, menu->obj.y); + + id = scene_txt_str(scn, "title", OBJ_MENU_TITLE, STR_MENU_TITLE, + "Main Menu", &tit); + ut_assert(id > 0); + ut_assertok(scene_menu_set_title(scn, OBJ_MENU, OBJ_MENU_TITLE)); + ut_asserteq(OBJ_MENU_TITLE, menu->title_id); + + pointer_id = scene_txt_str(scn, "cur_item", POINTER_TEXT, + STR_POINTER_TEXT, ">", &ptr); + ut_assert(pointer_id > 0); + + ut_assertok(scene_menu_set_pointer(scn, OBJ_MENU, POINTER_TEXT)); + ut_asserteq(POINTER_TEXT, menu->pointer_id); + + label_id = scene_txt_str(scn, "label1", ITEM1_LABEL, STR_ITEM1_LABEL, + "Play", &name1); + ut_assert(label_id > 0); + + desc_id = scene_txt_str(scn, "desc1", ITEM1_DESC, STR_ITEM1_DESC, + "Lord Melchett", &desc1); + ut_assert(desc_id > 0); + + key_id = scene_txt_str(scn, "item1-key", ITEM1_KEY, STR_ITEM1_KEY, "1", + &key1); + ut_assert(key_id > 0); + + preview_id = scene_txt_str(scn, "item1-preview", ITEM1_PREVIEW, + STR_ITEM1_PREVIEW, "(preview1)", &prev1); + ut_assert(preview_id > 0); + + id = scene_menuitem(scn, OBJ_MENU, "linux", ITEM1, ITEM1_KEY, + ITEM1_LABEL, ITEM1_DESC, ITEM1_PREVIEW, 0, &item); + ut_asserteq(ITEM1, id); + ut_asserteq(id, item->id); + ut_asserteq(key_id, item->key_id); + ut_asserteq(label_id, item->label_id); + ut_asserteq(desc_id, item->desc_id); + ut_asserteq(preview_id, item->preview_id); + + /* adding an item should cause the first item to become current */ + ut_asserteq(id, menu->cur_item_id); + + /* the title should be at the top */ + ut_asserteq(menu->obj.x, tit->obj.x); + ut_asserteq(menu->obj.y, tit->obj.y); + + /* the first item should be next */ + ut_asserteq(menu->obj.x, name1->obj.x); + ut_asserteq(menu->obj.y + 32, name1->obj.y); + + ut_asserteq(menu->obj.x + 230, key1->obj.x); + ut_asserteq(menu->obj.y + 32, key1->obj.y); + + ut_asserteq(menu->obj.x + 200, ptr->obj.x); + ut_asserteq(menu->obj.y + 32, ptr->obj.y); + + ut_asserteq(menu->obj.x + 280, desc1->obj.x); + ut_asserteq(menu->obj.y + 32, desc1->obj.y); + + ut_asserteq(-4, prev1->obj.x); + ut_asserteq(menu->obj.y + 32, prev1->obj.y); + ut_asserteq(false, prev1->obj.hide); + + expo_destroy(exp); + + ut_assertok(ut_check_delta(start_mem)); + + return 0; +} +BOOTSTD_TEST(expo_object_menu, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check rendering a scene */ +static int expo_render_image(struct unit_test_state *uts) +{ + struct scene_obj_menu *menu; + struct scene *scn, *scn2; + struct expo_action act; + struct scene_obj *obj; + struct udevice *dev; + struct expo *exp; + int id; + + console_record_reset_enable(); + ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev)); + + ut_assertok(expo_new(EXPO_NAME, NULL, &exp)); + id = scene_new(exp, SCENE_NAME1, SCENE1, &scn); + ut_assert(id > 0); + ut_assertok(expo_set_display(exp, dev)); + + id = scene_img(scn, "logo", OBJ_LOGO, video_get_u_boot_logo(), NULL); + ut_assert(id > 0); + ut_assertok(scene_obj_set_pos(scn, OBJ_LOGO, 50, 20)); + + id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", NULL); + ut_assert(id > 0); + ut_assertok(scene_txt_set_font(scn, OBJ_TEXT, "cantoraone_regular", + 40)); + ut_assertok(scene_obj_set_pos(scn, OBJ_TEXT, 400, 100)); + + id = scene_txt_str(scn, "text", OBJ_TEXT2, STR_TEXT2, "another string", + NULL); + ut_assert(id > 0); + ut_assertok(scene_txt_set_font(scn, OBJ_TEXT2, "nimbus_sans_l_regular", + 60)); + ut_assertok(scene_obj_set_pos(scn, OBJ_TEXT2, 200, 600)); + + id = scene_menu(scn, "main", OBJ_MENU, &menu); + ut_assert(id > 0); + + id = scene_txt_str(scn, "title", OBJ_MENU_TITLE, STR_MENU_TITLE, + "Main Menu", NULL); + ut_assert(id > 0); + ut_assertok(scene_menu_set_title(scn, OBJ_MENU, OBJ_MENU_TITLE)); + + id = scene_txt_str(scn, "cur_item", POINTER_TEXT, STR_POINTER_TEXT, ">", + NULL); + ut_assert(id > 0); + ut_assertok(scene_menu_set_pointer(scn, OBJ_MENU, POINTER_TEXT)); + + id = scene_txt_str(scn, "label1", ITEM1_LABEL, STR_ITEM1_LABEL, "Play", + NULL); + ut_assert(id > 0); + id = scene_txt_str(scn, "item1 txt", ITEM1_DESC, STR_ITEM1_DESC, + "Lord Melchett", NULL); + ut_assert(id > 0); + id = scene_txt_str(scn, "item1-key", ITEM1_KEY, STR_ITEM1_KEY, "1", + NULL); + ut_assert(id > 0); + id = scene_img(scn, "item1-preview", ITEM1_PREVIEW, + video_get_u_boot_logo(), NULL); + id = scene_menuitem(scn, OBJ_MENU, "item1", ITEM1, ITEM1_KEY, + ITEM1_LABEL, ITEM1_DESC, ITEM1_PREVIEW, 0, NULL); + ut_assert(id > 0); + + id = scene_txt_str(scn, "label2", ITEM2_LABEL, STR_ITEM2_LABEL, "Now", + NULL); + ut_assert(id > 0); + id = scene_txt_str(scn, "item2 txt", ITEM2_DESC, STR_ITEM2_DESC, + "Lord Percy", NULL); + ut_assert(id > 0); + id = scene_txt_str(scn, "item2-key", ITEM2_KEY, STR_ITEM2_KEY, "2", + NULL); + ut_assert(id > 0); + id = scene_img(scn, "item2-preview", ITEM2_PREVIEW, + video_get_u_boot_logo(), NULL); + ut_assert(id > 0); + + id = scene_menuitem(scn, OBJ_MENU, "item2", ITEM2, ITEM2_KEY, + ITEM2_LABEL, ITEM2_DESC, ITEM2_PREVIEW, 0, NULL); + ut_assert(id > 0); + + ut_assertok(scene_obj_set_pos(scn, OBJ_MENU, 50, 400)); + + scn2 = expo_lookup_scene_id(exp, SCENE1); + ut_asserteq_ptr(scn, scn2); + scn2 = expo_lookup_scene_id(exp, SCENE2); + ut_assertnull(scn2); + + /* render without a scene */ + ut_asserteq(-ECHILD, expo_render(exp)); + + /* render it */ + expo_set_scene_id(exp, SCENE1); + ut_assertok(expo_render(exp)); + + /* move down */ + ut_assertok(expo_send_key(exp, BKEY_DOWN)); + + ut_assertok(expo_action_get(exp, &act)); + + ut_asserteq(EXPOACT_POINT, act.type); + ut_asserteq(ITEM2, act.select.id); + ut_assertok(expo_render(exp)); + + /* make sure only the preview for the second item is shown */ + obj = scene_obj_find(scn, ITEM1_PREVIEW, SCENEOBJT_NONE); + ut_asserteq(true, obj->hide); + + obj = scene_obj_find(scn, ITEM2_PREVIEW, SCENEOBJT_NONE); + ut_asserteq(false, obj->hide); + + /* select it */ + ut_assertok(expo_send_key(exp, BKEY_SELECT)); + + ut_assertok(expo_action_get(exp, &act)); + ut_asserteq(EXPOACT_SELECT, act.type); + ut_asserteq(ITEM2, act.select.id); + + /* make sure the action doesn't come again */ + ut_asserteq(-EAGAIN, expo_action_get(exp, &act)); + + /* make sure there was no console output */ + ut_assert_console_end(); + + /* now try in text mode */ + exp_set_text_mode(exp, true); + ut_assertok(expo_render(exp)); + + ut_assert_nextline("U-Boot : Boot Menu"); + ut_assert_nextline("%s", ""); + ut_assert_nextline("Main Menu"); + ut_assert_nextline("%s", ""); + ut_assert_nextline(" 1 Play Lord Melchett"); + ut_assert_nextline(" > 2 Now Lord Percy"); + + /* Move back up to the first item */ + ut_assertok(expo_send_key(exp, BKEY_UP)); + + ut_assertok(expo_action_get(exp, &act)); + + ut_asserteq(EXPOACT_POINT, act.type); + ut_asserteq(ITEM1, act.select.id); + + ut_assertok(expo_render(exp)); + ut_assert_nextline("U-Boot : Boot Menu"); + ut_assert_nextline("%s", ""); + ut_assert_nextline("Main Menu"); + ut_assert_nextline("%s", ""); + ut_assert_nextline(" > 1 Play Lord Melchett"); + ut_assert_nextline(" 2 Now Lord Percy"); + + ut_assert_console_end(); + + expo_destroy(exp); + + return 0; +} +BOOTSTD_TEST(expo_render_image, UT_TESTF_DM | UT_TESTF_SCAN_FDT); -- cgit v1.2.3 From d985f1dbddb241c21a9150abf59dd386ba1ffe05 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:41 -0600 Subject: bootstd: Add a test for the bootstd menu Add a test which checks that two operating systems can be displayed in a menu, allowing one to be selected. Enable a few things on snow so that the unit tests build. Signed-off-by: Simon Glass --- arch/sandbox/dts/test.dts | 11 ++ configs/snow_defconfig | 4 + test/boot/bootflow.c | 51 ++++++++ test/py/tests/bootstd/armbian.bmp.xz | Bin 0 -> 1384 bytes test/py/tests/bootstd/mmc4.img.xz | Bin 0 -> 7072 bytes test/py/tests/test_ut.py | 218 ++++++++++++++++++++++++++++++++--- 6 files changed, 265 insertions(+), 19 deletions(-) create mode 100644 test/py/tests/bootstd/armbian.bmp.xz create mode 100644 test/py/tests/bootstd/mmc4.img.xz (limited to 'test') diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index dffe10adbf..2e580f980f 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -94,6 +94,10 @@ compatible = "u-boot,distro-efi"; }; + theme { + font-size = <30>; + }; + /* * This is used for the VBE OS-request tests. A FAT filesystem * created in a partition with the VBE information appearing @@ -1013,6 +1017,13 @@ non-removable; }; + /* This is used for bootstd bootmenu tests */ + mmc4 { + status = "disabled"; + compatible = "sandbox,mmc"; + filename = "mmc4.img"; + }; + pch { compatible = "sandbox,pch"; }; diff --git a/configs/snow_defconfig b/configs/snow_defconfig index 6921c5667d..faa3a944c0 100644 --- a/configs/snow_defconfig +++ b/configs/snow_defconfig @@ -28,7 +28,11 @@ CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0x2050000 CONFIG_FIT=y CONFIG_FIT_BEST_MATCH=y +CONFIG_BOOTSTD_FULL=y CONFIG_SILENT_CONSOLE=y +CONFIG_BLOBLIST=y +# CONFIG_SPL_BLOBLIST is not set +CONFIG_BLOBLIST_ADDR=0x43d00000 # CONFIG_SPL_FRAMEWORK is not set CONFIG_SPL_FOOTPRINT_LIMIT=y CONFIG_SPL_MAX_FOOTPRINT=0x3800 diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 00dfd99068..abafa44b2e 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -11,15 +11,21 @@ #include #include #include +#include #include #ifdef CONFIG_SANDBOX #include #endif +#include #include #include #include #include "bootstd_common.h" +DECLARE_GLOBAL_DATA_PTR; + +extern U_BOOT_DRIVER(bootmeth_script); + static int inject_response(struct unit_test_state *uts) { /* @@ -462,3 +468,48 @@ static int bootflow_cmd_boot(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootflow_cmd_boot, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check 'bootflow menu' to select a bootflow */ +static int bootflow_cmd_menu(struct unit_test_state *uts) +{ + static const char *order[] = {"mmc2", "mmc1", "mmc4", NULL}; + struct udevice *dev, *bootstd; + struct bootstd_priv *std; + const char **old_order; + char prev[3]; + ofnode node; + + /* Enable the mmc4 node since we need a second bootflow */ + node = ofnode_path("/mmc4"); + ut_assertok(lists_bind_fdt(gd->dm_root, node, &dev, NULL, false)); + + /* Enable the script bootmeth too */ + ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd)); + ut_assertok(device_bind(bootstd, DM_DRIVER_REF(bootmeth_script), + "bootmeth_script", 0, ofnode_null(), &dev)); + + /* Change the order to include mmc4 */ + std = dev_get_priv(bootstd); + old_order = std->bootdev_order; + std->bootdev_order = order; + + console_record_reset_enable(); + ut_assertok(run_command("bootflow scan", 0)); + ut_assert_console_end(); + + /* Restore the order used by the device tree */ + std->bootdev_order = old_order; + + /* Add keypresses to move to and select the second one in the list */ + prev[0] = CTL_CH('n'); + prev[1] = '\r'; + prev[2] = '\0'; + ut_asserteq(2, console_in_puts(prev)); + + ut_assertok(run_command("bootflow menu", 0)); + ut_assert_nextline("Selected: Armbian"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootflow_cmd_menu, UT_TESTF_DM | UT_TESTF_SCAN_FDT); diff --git a/test/py/tests/bootstd/armbian.bmp.xz b/test/py/tests/bootstd/armbian.bmp.xz new file mode 100644 index 0000000000..ad137ea6e6 Binary files /dev/null and b/test/py/tests/bootstd/armbian.bmp.xz differ diff --git a/test/py/tests/bootstd/mmc4.img.xz b/test/py/tests/bootstd/mmc4.img.xz new file mode 100644 index 0000000000..f4db011969 Binary files /dev/null and b/test/py/tests/bootstd/mmc4.img.xz differ diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index bab8b97672..6958fabfa3 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. +import getpass import gzip import os import os.path @@ -13,34 +14,217 @@ def mkdir_cond(dirname): """Create a directory if it doesn't already exist Args: - dirname: Name of directory to create + dirname (str): Name of directory to create """ if not os.path.exists(dirname): os.mkdir(dirname) -def setup_bootflow_image(u_boot_console): - """Create a 20MB disk image with a single FAT partition""" - cons = u_boot_console - fname = os.path.join(cons.config.source_dir, 'mmc1.img') +def setup_image(cons, mmc_dev, part_type): + """Create a 20MB disk image with a single partition + + Args: + cons (ConsoleBase): Console to use + mmc_dev (int): MMC device number to use, e.g. 1 + part_type (int): Partition type, e.g. 0xc for FAT32 + + Returns: + tuple: + str: Filename of MMC image + str: Directory name of 'mnt' directory + """ + fname = os.path.join(cons.config.source_dir, f'mmc{mmc_dev}.img') mnt = os.path.join(cons.config.persistent_data_dir, 'mnt') mkdir_cond(mnt) u_boot_utils.run_and_log(cons, 'qemu-img create %s 20M' % fname) u_boot_utils.run_and_log(cons, 'sudo sfdisk %s' % fname, - stdin=b'type=c') + stdin=f'type={part_type:x}'.encode('utf-8')) + return fname, mnt + +def mount_image(cons, fname, mnt, fstype): + """Create a filesystem and mount it on partition 1 + + Args: + cons (ConsoleBase): Console to use + fname (str): Filename of MMC image + mnt (str): Directory name of 'mnt' directory + fstype (str): Filesystem type ('vfat' or 'ext4') + + Returns: + str: Name of loop device used + """ + out = u_boot_utils.run_and_log(cons, 'sudo losetup --show -f -P %s' % fname) + loop = out.strip() + part = f'{loop}p1' + u_boot_utils.run_and_log(cons, f'sudo mkfs.{fstype} {part}') + opts = '' + if fstype == 'vfat': + opts += ' -o uid={os.getuid()},gid={os.getgid()}' + u_boot_utils.run_and_log(cons, f'sudo mount -o loop {part} {mnt}{opts}') + u_boot_utils.run_and_log(cons, f'sudo chown {getpass.getuser()} {mnt}') + return loop + +def copy_prepared_image(cons, mmc_dev, fname): + """Use a prepared image since we cannot create one + + Args: + cons (ConsoleBase): Console touse + mmc_dev (int): MMC device number + fname (str): Filename of MMC image + """ + infname = os.path.join(cons.config.source_dir, + f'test/py/tests/bootstd/mmc{mmc_dev}.img.xz') + u_boot_utils.run_and_log( + cons, + ['sh', '-c', 'xz -dc %s >%s' % (infname, fname)]) + +def setup_bootmenu_image(cons): + """Create a 20MB disk image with a single ext4 partition + + This is modelled on Armbian 22.08 Jammy + """ + mmc_dev = 4 + fname, mnt = setup_image(cons, mmc_dev, 0x83) loop = None mounted = False complete = False try: - out = u_boot_utils.run_and_log(cons, - 'sudo losetup --show -f -P %s' % fname) - loop = out.strip() - fatpart = '%sp1' % loop - u_boot_utils.run_and_log(cons, 'sudo mkfs.vfat %s' % fatpart) + loop = mount_image(cons, fname, mnt, 'ext4') + mounted = True + + vmlinux = 'Image' + initrd = 'uInitrd' + dtbdir = 'dtb' + script = '''# DO NOT EDIT THIS FILE +# +# Please edit /boot/armbianEnv.txt to set supported parameters +# + +setenv load_addr "0x9000000" +setenv overlay_error "false" +# default values +setenv rootdev "/dev/mmcblk%dp1" +setenv verbosity "1" +setenv console "both" +setenv bootlogo "false" +setenv rootfstype "ext4" +setenv docker_optimizations "on" +setenv earlycon "off" + +echo "Boot script loaded from ${devtype} ${devnum}" + +if test -e ${devtype} ${devnum} ${prefix}armbianEnv.txt; then + load ${devtype} ${devnum} ${load_addr} ${prefix}armbianEnv.txt + env import -t ${load_addr} ${filesize} +fi + +if test "${logo}" = "disabled"; then setenv logo "logo.nologo"; fi + +if test "${console}" = "display" || test "${console}" = "both"; then setenv consoleargs "console=tty1"; fi +if test "${console}" = "serial" || test "${console}" = "both"; then setenv consoleargs "console=ttyS2,1500000 ${consoleargs}"; fi +if test "${earlycon}" = "on"; then setenv consoleargs "earlycon ${consoleargs}"; fi +if test "${bootlogo}" = "true"; then setenv consoleargs "bootsplash.bootfile=bootsplash.armbian ${consoleargs}"; fi + +# get PARTUUID of first partition on SD/eMMC the boot script was loaded from +if test "${devtype}" = "mmc"; then part uuid mmc ${devnum}:1 partuuid; fi + +setenv bootargs "root=${rootdev} rootwait rootfstype=${rootfstype} ${consoleargs} consoleblank=0 loglevel=${verbosity} ubootpart=${partuuid} usb-storage.quirks=${usbstoragequirks} ${extraargs} ${extraboardargs}" + +if test "${docker_optimizations}" = "on"; then setenv bootargs "${bootargs} cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1"; fi + +load ${devtype} ${devnum} ${ramdisk_addr_r} ${prefix}uInitrd +load ${devtype} ${devnum} ${kernel_addr_r} ${prefix}Image + +load ${devtype} ${devnum} ${fdt_addr_r} ${prefix}dtb/${fdtfile} +fdt addr ${fdt_addr_r} +fdt resize 65536 +for overlay_file in ${overlays}; do + if load ${devtype} ${devnum} ${load_addr} ${prefix}dtb/rockchip/overlay/${overlay_prefix}-${overlay_file}.dtbo; then + echo "Applying kernel provided DT overlay ${overlay_prefix}-${overlay_file}.dtbo" + fdt apply ${load_addr} || setenv overlay_error "true" + fi +done +for overlay_file in ${user_overlays}; do + if load ${devtype} ${devnum} ${load_addr} ${prefix}overlay-user/${overlay_file}.dtbo; then + echo "Applying user provided DT overlay ${overlay_file}.dtbo" + fdt apply ${load_addr} || setenv overlay_error "true" + fi +done +if test "${overlay_error}" = "true"; then + echo "Error applying DT overlays, restoring original DT" + load ${devtype} ${devnum} ${fdt_addr_r} ${prefix}dtb/${fdtfile} +else + if load ${devtype} ${devnum} ${load_addr} ${prefix}dtb/rockchip/overlay/${overlay_prefix}-fixup.scr; then + echo "Applying kernel provided DT fixup script (${overlay_prefix}-fixup.scr)" + source ${load_addr} + fi + if test -e ${devtype} ${devnum} ${prefix}fixup.scr; then + load ${devtype} ${devnum} ${load_addr} ${prefix}fixup.scr + echo "Applying user provided fixup script (fixup.scr)" + source ${load_addr} + fi +fi +booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r} + +# Recompile with: +# mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scr +''' % (mmc_dev) + bootdir = os.path.join(mnt, 'boot') + mkdir_cond(bootdir) + cmd_fname = os.path.join(bootdir, 'boot.cmd') + scr_fname = os.path.join(bootdir, 'boot.scr') + with open(cmd_fname, 'w') as outf: + print(script, file=outf) + + infname = os.path.join(cons.config.source_dir, + 'test/py/tests/bootstd/armbian.bmp.xz') + bmp_file = os.path.join(bootdir, 'boot.bmp') + u_boot_utils.run_and_log( + cons, + ['sh', '-c', f'xz -dc {infname} >{bmp_file}']) + + u_boot_utils.run_and_log( + cons, f'mkimage -C none -A arm -T script -d {cmd_fname} {scr_fname}') + + kernel = 'vmlinuz-5.15.63-rockchip64' + target = os.path.join(bootdir, kernel) + with open(target, 'wb') as outf: + print('kernel', outf) + + symlink = os.path.join(bootdir, 'Image') + if os.path.exists(symlink): + os.remove(symlink) + u_boot_utils.run_and_log( + cons, f'echo here {kernel} {symlink}') + os.symlink(kernel, symlink) + u_boot_utils.run_and_log( - cons, 'sudo mount -o loop %s %s -o uid=%d,gid=%d' % - (fatpart, mnt, os.getuid(), os.getgid())) + cons, f'mkimage -C none -A arm -T script -d {cmd_fname} {scr_fname}') + complete = True + + except ValueError as exc: + print('Falled to create image, failing back to prepared copy: %s', + str(exc)) + finally: + if mounted: + u_boot_utils.run_and_log(cons, 'sudo umount %s' % mnt) + if loop: + u_boot_utils.run_and_log(cons, 'sudo losetup -d %s' % loop) + + if not complete: + copy_prepared_image(cons, mmc_dev, fname) + +def setup_bootflow_image(cons): + """Create a 20MB disk image with a single FAT partition""" + mmc_dev = 1 + fname, mnt = setup_image(cons, mmc_dev, 0xc) + + loop = None + mounted = False + complete = False + try: + loop = mount_image(cons, fname, mnt, 'vfat') mounted = True vmlinux = 'vmlinuz-5.3.7-301.fc31.armv7hl' @@ -90,12 +274,7 @@ label Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl) u_boot_utils.run_and_log(cons, 'sudo losetup -d %s' % loop) if not complete: - # Use a prepared image since we cannot create one - infname = os.path.join(cons.config.source_dir, - 'test/py/tests/bootstd/mmc1.img.xz') - u_boot_utils.run_and_log( - cons, - ['sh', '-c', 'xz -dc %s >%s' % (infname, fname)]) + copy_prepared_image(cons, mmc_dev, fname) @pytest.mark.buildconfigspec('ut_dm') @@ -134,6 +313,7 @@ def test_ut_dm_init_bootstd(u_boot_console): """Initialise data for bootflow tests""" setup_bootflow_image(u_boot_console) + setup_bootmenu_image(u_boot_console) # Restart so that the new mmc1.img is picked up u_boot_console.restart_uboot() -- cgit v1.2.3 From e64c29521c0e6111b446fd67e85c6dd3d491103c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:42 -0600 Subject: bootstd: Support setting a theme for the menu Allow a theme to be set. For now this is very simple, just a default font size to use for all elements. Signed-off-by: Simon Glass --- boot/bootflow_menu.c | 43 ++++++++++++++++++++++++++ boot/bootstd-uclass.c | 2 ++ include/bootflow.h | 10 +++++++ include/bootstd.h | 4 +++ test/boot/bootflow.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 139 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/boot/bootflow_menu.c b/boot/bootflow_menu.c index 1105783afe..7f06dac0af 100644 --- a/boot/bootflow_menu.c +++ b/boot/bootflow_menu.c @@ -129,6 +129,43 @@ int bootflow_menu_new(struct expo **expp) return 0; } +int bootflow_menu_apply_theme(struct expo *exp, ofnode node) +{ + struct menu_priv *priv = exp->priv; + struct scene *scn; + u32 font_size; + int ret; + + log_debug("Applying theme %s\n", ofnode_get_name(node)); + scn = expo_lookup_scene_id(exp, MAIN); + if (!scn) + return log_msg_ret("scn", -ENOENT); + + /* Avoid error-checking optional items */ + if (!ofnode_read_u32(node, "font-size", &font_size)) { + int i; + + log_debug("font size %d\n", font_size); + scene_txt_set_font(scn, OBJ_PROMPT, NULL, font_size); + scene_txt_set_font(scn, OBJ_POINTER, NULL, font_size); + for (i = 0; i < priv->num_bootflows; i++) { + ret = scene_txt_set_font(scn, ITEM_DESC + i, NULL, + font_size); + if (ret) + return log_msg_ret("des", ret); + scene_txt_set_font(scn, ITEM_KEY + i, NULL, font_size); + scene_txt_set_font(scn, ITEM_LABEL + i, NULL, + font_size); + } + } + + ret = scene_arrange(scn); + if (ret) + return log_msg_ret("arr", ret); + + return 0; +} + int bootflow_menu_run(struct bootstd_priv *std, bool text_mode, struct bootflow **bflowp) { @@ -149,6 +186,12 @@ int bootflow_menu_run(struct bootstd_priv *std, bool text_mode, if (ret) return log_msg_ret("exp", ret); + if (ofnode_valid(std->theme)) { + ret = bootflow_menu_apply_theme(exp, std->theme); + if (ret) + return log_msg_ret("thm", ret); + } + /* For now we only support a video console */ ret = uclass_first_device_err(UCLASS_VIDEO, &dev); if (ret) diff --git a/boot/bootstd-uclass.c b/boot/bootstd-uclass.c index 565c22a36e..7887acdc11 100644 --- a/boot/bootstd-uclass.c +++ b/boot/bootstd-uclass.c @@ -33,6 +33,8 @@ static int bootstd_of_to_plat(struct udevice *dev) &priv->prefixes); dev_read_string_list(dev, "bootdev-order", &priv->bootdev_order); + + priv->theme = ofnode_find_subnode(dev_ofnode(dev), "theme"); } return 0; diff --git a/include/bootflow.h b/include/bootflow.h index e7a09568f1..c201246c6d 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -7,6 +7,7 @@ #ifndef __bootflow_h #define __bootflow_h +#include #include struct bootstd_priv; @@ -347,6 +348,15 @@ int bootflow_iter_uses_system(const struct bootflow_iter *iter); */ int bootflow_menu_new(struct expo **expp); +/** + * bootflow_menu_apply_theme() - Apply a theme to a bootmenu + * + * @exp: Expo to update + * @node: Node containing the theme information + * Returns 0 on success, -ve on error + */ +int bootflow_menu_apply_theme(struct expo *exp, ofnode node); + /** * bootflow_menu_run() - Create and run a menu of available bootflows * diff --git a/include/bootstd.h b/include/bootstd.h index 01be249d16..4fa0d53100 100644 --- a/include/bootstd.h +++ b/include/bootstd.h @@ -9,6 +9,8 @@ #ifndef __bootstd_h #define __bootstd_h +#include + struct udevice; /** @@ -27,6 +29,7 @@ struct udevice; * @bootmeth_count: Number of bootmeth devices in @bootmeth_order * @bootmeth_order: List of bootmeth devices to use, in order, NULL-terminated * @vbe_bootmeth: Currently selected VBE bootmeth, NULL if none + * @theme: Node containing the theme information */ struct bootstd_priv { const char **prefixes; @@ -37,6 +40,7 @@ struct bootstd_priv { int bootmeth_count; struct udevice **bootmeth_order; struct udevice *vbe_bootmeth; + ofnode theme; }; /** diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index abafa44b2e..5b76cd3ab1 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef CONFIG_SANDBOX #include #endif @@ -21,6 +22,8 @@ #include #include #include "bootstd_common.h" +#include "../../boot/bootflow_internal.h" +#include "../../boot/scene_internal.h" DECLARE_GLOBAL_DATA_PTR; @@ -469,14 +472,18 @@ static int bootflow_cmd_boot(struct unit_test_state *uts) } BOOTSTD_TEST(bootflow_cmd_boot, UT_TESTF_DM | UT_TESTF_SCAN_FDT); -/* Check 'bootflow menu' to select a bootflow */ -static int bootflow_cmd_menu(struct unit_test_state *uts) +/** + * prep_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 const char *order[] = {"mmc2", "mmc1", "mmc4", NULL}; struct udevice *dev, *bootstd; struct bootstd_priv *std; const char **old_order; - char prev[3]; ofnode node; /* Enable the mmc4 node since we need a second bootflow */ @@ -500,6 +507,16 @@ static int bootflow_cmd_menu(struct unit_test_state *uts) /* Restore the order used by the device tree */ std->bootdev_order = old_order; + return 0; +} + +/* Check 'bootflow menu' to select a bootflow */ +static int bootflow_cmd_menu(struct unit_test_state *uts) +{ + char prev[3]; + + ut_assertok(prep_mmc4_bootdev(uts)); + /* Add keypresses to move to and select the second one in the list */ prev[0] = CTL_CH('n'); prev[1] = '\r'; @@ -513,3 +530,63 @@ static int bootflow_cmd_menu(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootflow_cmd_menu, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/** + * check_font() - Check that the font size for an item matches expectations + * + * @uts: Unit test state + * @scn: Scene containing the text object + * @id: ID of the text object + * Returns 0 on success, -ve on failure + */ +static int check_font(struct unit_test_state *uts, struct scene *scn, uint id, + int font_size) +{ + struct scene_obj_txt *txt; + + txt = scene_obj_find(scn, id, SCENEOBJT_TEXT); + ut_assertnonnull(txt); + + ut_asserteq(font_size, txt->font_size); + + return 0; +} + +/* Check themes work with a bootflow menu */ +static int bootflow_menu_theme(struct unit_test_state *uts) +{ + const int font_size = 30; + struct scene *scn; + struct expo *exp; + ofnode node; + int i; + + ut_assertok(prep_mmc4_bootdev(uts)); + + ut_assertok(bootflow_menu_new(&exp)); + node = ofnode_path("/bootstd/theme"); + ut_assert(ofnode_valid(node)); + ut_assertok(bootflow_menu_apply_theme(exp, node)); + + scn = expo_lookup_scene_id(exp, MAIN); + ut_assertnonnull(scn); + + /* + * Check that the txt objects have the correct font size from the + * device tree node: bootstd/theme + * + * Check both menu items, since there are two bootflows + */ + ut_assertok(check_font(uts, scn, OBJ_PROMPT, font_size)); + ut_assertok(check_font(uts, scn, OBJ_POINTER, font_size)); + for (i = 0; i < 2; i++) { + ut_assertok(check_font(uts, scn, ITEM_DESC + i, font_size)); + ut_assertok(check_font(uts, scn, ITEM_KEY + i, font_size)); + ut_assertok(check_font(uts, scn, ITEM_LABEL + i, font_size)); + } + + expo_destroy(exp); + + return 0; +} +BOOTSTD_TEST(bootflow_menu_theme, UT_TESTF_DM | UT_TESTF_SCAN_FDT); -- cgit v1.2.3