diff options
41 files changed, 1521 insertions, 65 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index df046192ea0..0399ed1dbf6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -58,6 +58,13 @@ F: cmd/acpi.c F: include/acpi/ F: lib/acpi/ +ALIST: +M: Simon Glass <sjg@chromium.org> +S: Maintained +F: include/alist.h +F: lib/alist.c +F: test/lib/alist.c + ANDROID AB M: Igor Opaniuk <igor.opaniuk@gmail.com> M: Mattijs Korpershoek <mkorpershoek@baylibre.com> diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c index 06f8c13fab9..d1c4dcf0764 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -253,6 +253,19 @@ phys_addr_t map_to_sysmem(const void *ptr) return mentry->tag; } +void sandbox_map_list(void) +{ + struct sandbox_mapmem_entry *mentry; + struct sandbox_state *state = state_get_current(); + + printf("Sandbox memory-mapping\n"); + printf("%8s %16s %6s\n", "Addr", "Mapping", "Refcnt"); + list_for_each_entry(mentry, &state->mapmem_head, sibling_node) { + printf("%8lx %p %6d\n", mentry->tag, mentry->ptr, + mentry->refcnt); + } +} + unsigned long sandbox_read(const void *addr, enum sandboxio_size_t size) { struct sandbox_state *state = state_get_current(); diff --git a/arch/sandbox/include/asm/cpu.h b/arch/sandbox/include/asm/cpu.h index c97ac7ba95b..682bb3376d1 100644 --- a/arch/sandbox/include/asm/cpu.h +++ b/arch/sandbox/include/asm/cpu.h @@ -8,4 +8,7 @@ void cpu_sandbox_set_current(const char *name); +/* show the mapping of sandbox addresses to pointers */ +void sandbox_map_list(void); + #endif /* __SANDBOX_CPU_H */ diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h index a23bd64994a..3d09170063f 100644 --- a/arch/sandbox/include/asm/io.h +++ b/arch/sandbox/include/asm/io.h @@ -235,7 +235,7 @@ static inline void unmap_sysmem(const void *vaddr) * nomap_sysmem() - pass through an address unchanged * * This is used to indicate an address which should NOT be mapped, e.g. in - * SMBIOS tables. Using this function instead of a case shows that the sandbox + * SMBIOS tables. Using this function instead of a cast shows that the sandbox * conversion has been done */ static inline void *nomap_sysmem(phys_addr_t paddr, unsigned long len) diff --git a/arch/x86/dts/coreboot.dts b/arch/x86/dts/coreboot.dts index b867468e16c..39d1d325db9 100644 --- a/arch/x86/dts/coreboot.dts +++ b/arch/x86/dts/coreboot.dts @@ -54,6 +54,13 @@ menu-inset = <3>; menuitem-gap-y = <1>; }; + + cedit-theme { + font-size = <30>; + menu-inset = <3>; + menuitem-gap-y = <1>; + menu-title-margin-x = <30>; + }; }; sysinfo { diff --git a/boot/Makefile b/boot/Makefile index 0e0afad68d1..43def7c33d7 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -59,6 +59,9 @@ obj-$(CONFIG_$(PHASE_)LOAD_FIT) += common_fit.o obj-$(CONFIG_$(PHASE_)EXPO) += expo.o scene.o expo_build.o obj-$(CONFIG_$(PHASE_)EXPO) += scene_menu.o scene_textline.o +ifdef CONFIG_COREBOOT_SYSINFO +obj-$(CONFIG_$(SPL_TPL_)EXPO) += expo_build_cb.o +endif obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE) += vbe.o obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_REQUEST) += vbe_request.o diff --git a/boot/expo_build_cb.c b/boot/expo_build_cb.c new file mode 100644 index 00000000000..442ad760e79 --- /dev/null +++ b/boot/expo_build_cb.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Building an expo from an FDT description + * + * Copyright 2022 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#define LOG_CATEGORY LOGC_EXPO + +#include <cedit.h> +#include <ctype.h> +#include <errno.h> +#include <expo.h> +#include <log.h> +#include <malloc.h> +#include <vsprintf.h> +#include <asm/cb_sysinfo.h> + +/** + * struct build_info - Information to use when building + */ +struct build_info { + const struct cb_cmos_option_table *tab; + struct cedit_priv *priv; +}; + +/** + * convert_to_title() - Convert text to 'title' format and allocate a string + * + * Converts "this_is_a_test" to "This is a test" so it looks better + * + * @text: Text to convert + * Return: Allocated string, or NULL if out of memory + */ +static char *convert_to_title(const char *text) +{ + int len = strlen(text); + char *buf, *s; + + buf = malloc(len + 1); + if (!buf) + return NULL; + + for (s = buf; *text; s++, text++) { + if (s == buf) + *s = toupper(*text); + else if (*text == '_') + *s = ' '; + else + *s = *text; + } + *s = '\0'; + + return buf; +} + +/** + * menu_build() - Build a menu and add it to a scene + * + * See doc/developer/expo.rst for a description of the format + * + * @info: Build information + * @entry: CMOS entry to build a menu for + * @scn: Scene to add the menu to + * @objp: Returns the object pointer + * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format + * error, -ENOENT if there is a references to a non-existent string + */ +static int menu_build(struct build_info *info, + const struct cb_cmos_entries *entry, struct scene *scn, + struct scene_obj **objp) +{ + struct scene_obj_menu *menu; + const void *ptr, *end; + uint menu_id; + char *title; + int ret, i; + + ret = scene_menu(scn, entry->name, 0, &menu); + if (ret < 0) + return log_msg_ret("men", ret); + menu_id = ret; + + title = convert_to_title(entry->name); + if (!title) + return log_msg_ret("con", -ENOMEM); + + /* Set the title */ + ret = scene_txt_str(scn, "title", 0, 0, title, NULL); + if (ret < 0) + return log_msg_ret("tit", ret); + menu->title_id = ret; + + end = (void *)info->tab + info->tab->size; + for (ptr = (void *)info->tab + info->tab->header_length, i = 0; + ptr < end; i++) { + const struct cb_cmos_enums *enums = ptr; + struct scene_menitem *item; + uint label; + + ptr += enums->size; + if (enums->tag != CB_TAG_OPTION_ENUM || + enums->config_id != entry->config_id) + continue; + + ret = scene_txt_str(scn, enums->text, 0, 0, enums->text, NULL); + if (ret < 0) + return log_msg_ret("tit", ret); + label = ret; + + ret = scene_menuitem(scn, menu_id, simple_xtoa(i), 0, 0, label, + 0, 0, 0, &item); + if (ret < 0) + return log_msg_ret("mi", ret); + item->value = enums->value; + } + *objp = &menu->obj; + + return 0; +} + +/** + * scene_build() - Build a scene and all its objects + * + * See doc/developer/expo.rst for a description of the format + * + * @info: Build information + * @scn: Scene to add the object to + * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format + * error, -ENOENT if there is a references to a non-existent string + */ +static int scene_build(struct build_info *info, struct expo *exp) +{ + struct scene_obj_menu *menu; + const void *ptr, *end; + struct scene_obj *obj; + struct scene *scn; + uint label, menu_id; + int ret; + + ret = scene_new(exp, "cmos", 0, &scn); + if (ret < 0) + return log_msg_ret("scn", ret); + + ret = scene_txt_str(scn, "title", 0, 0, "CMOS RAM settings", NULL); + if (ret < 0) + return log_msg_ret("add", ret); + scn->title_id = ret; + + ret = scene_txt_str(scn, "prompt", 0, 0, + "UP and DOWN to choose, ENTER to select", NULL); + if (ret < 0) + return log_msg_ret("add", ret); + + end = (void *)info->tab + info->tab->size; + for (ptr = (void *)info->tab + info->tab->header_length; ptr < end;) { + const struct cb_cmos_entries *entry; + const struct cb_record *rec = ptr; + + entry = ptr; + ptr += rec->size; + if (rec->tag != CB_TAG_OPTION) + continue; + switch (entry->config) { + case 'e': + ret = menu_build(info, entry, scn, &obj); + break; + default: + continue; + } + if (ret < 0) + return log_msg_ret("add", ret); + + obj->start_bit = entry->bit; + obj->bit_length = entry->length; + } + + ret = scene_menu(scn, "save", EXPOID_SAVE, &menu); + if (ret < 0) + return log_msg_ret("men", ret); + menu_id = ret; + + ret = scene_txt_str(scn, "save", 0, 0, "Save and exit", NULL); + if (ret < 0) + return log_msg_ret("sav", ret); + label = ret; + ret = scene_menuitem(scn, menu_id, "save", 0, 0, label, + 0, 0, 0, NULL); + if (ret < 0) + return log_msg_ret("mi", ret); + + ret = scene_menu(scn, "nosave", EXPOID_DISCARD, &menu); + if (ret < 0) + return log_msg_ret("men", ret); + menu_id = ret; + + ret = scene_txt_str(scn, "nosave", 0, 0, "Exit without saving", NULL); + if (ret < 0) + return log_msg_ret("nos", ret); + label = ret; + ret = scene_menuitem(scn, menu_id, "exit", 0, 0, label, + 0, 0, 0, NULL); + if (ret < 0) + return log_msg_ret("mi", ret); + + return 0; +} + +static int build_it(struct build_info *info, struct expo **expp) +{ + struct expo *exp; + int ret; + + ret = expo_new("coreboot", NULL, &exp); + if (ret) + return log_msg_ret("exp", ret); + expo_set_dynamic_start(exp, EXPOID_BASE_ID); + + ret = scene_build(info, exp); + if (ret < 0) + return log_msg_ret("scn", ret); + + *expp = exp; + + return 0; +} + +int cb_expo_build(struct expo **expp) +{ + struct build_info info; + struct expo *exp; + int ret; + + info.tab = lib_sysinfo.option_table; + if (!info.tab) + return log_msg_ret("tab", -ENOENT); + + ret = build_it(&info, &exp); + if (ret) + return log_msg_ret("bui", ret); + *expp = exp; + + return 0; +} diff --git a/cmd/Kconfig b/cmd/Kconfig index 4fba9fe6703..636833646f6 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2871,6 +2871,17 @@ config CMD_CBSYSINFO memory by coreboot before jumping to U-Boot. It can be useful for debugging the beaaviour of coreboot or U-Boot. +config CMD_CBCMOS + bool "cbcmos" + depends on X86 + default y if SYS_COREBOOT + help + This provides information options to check the CMOS RAM checksum, + if present, as well as to update it. + + It is useful when coreboot CMOS-RAM settings must be examined or + updated. + config CMD_CYCLIC bool "cyclic - Show information about cyclic functions" depends on CYCLIC diff --git a/cmd/bootflow.c b/cmd/bootflow.c index 1588f277a4a..f67948d7368 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -393,7 +393,11 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc, printf("Partition: %d\n", bflow->part); printf("Subdir: %s\n", bflow->subdir ? bflow->subdir : "(none)"); printf("Filename: %s\n", bflow->fname); - printf("Buffer: %lx\n", (ulong)map_to_sysmem(bflow->buf)); + printf("Buffer: "); + if (bflow->buf) + printf("%lx\n", (ulong)map_to_sysmem(bflow->buf)); + else + printf("(not loaded)\n"); printf("Size: %x (%d bytes)\n", bflow->size, bflow->size); printf("OS: %s\n", bflow->os_name ? bflow->os_name : "(none)"); printf("Cmdline: "); @@ -403,7 +407,8 @@ static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc, puts("(none)"); putc('\n'); if (bflow->x86_setup) - printf("X86 setup: %p\n", bflow->x86_setup); + printf("X86 setup: %lx\n", + (ulong)map_to_sysmem(bflow->x86_setup)); printf("Logo: %s\n", bflow->logo ? simple_xtoa((ulong)map_to_sysmem(bflow->logo)) : "(none)"); if (bflow->logo) { diff --git a/cmd/cedit.c b/cmd/cedit.c index fec67a8e334..f696356419e 100644 --- a/cmd/cedit.c +++ b/cmd/cedit.c @@ -67,6 +67,28 @@ static int do_cedit_load(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } +#ifdef CONFIG_COREBOOT_SYSINFO +static int do_cedit_cb_load(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct expo *exp; + int ret; + + if (argc > 1) + return CMD_RET_USAGE; + + ret = cb_expo_build(&exp); + if (ret) { + printf("Failed to build expo: %dE\n", ret); + return CMD_RET_FAILURE; + } + + cur_exp = exp; + + return 0; +} +#endif /* CONFIG_COREBOOT_SYSINFO */ + static int do_cedit_write_fdt(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -271,6 +293,9 @@ static int do_cedit_run(struct cmd_tbl *cmdtp, int flag, int argc, U_BOOT_LONGHELP(cedit, "load <interface> <dev[:part]> <filename> - load config editor\n" +#ifdef CONFIG_COREBOOT_SYSINFO + "cb_load - load coreboot CMOS editor\n" +#endif "cedit read_fdt <i/f> <dev[:part]> <filename> - read settings\n" "cedit write_fdt <i/f> <dev[:part]> <filename> - write settings\n" "cedit read_env [-v] - read settings from env vars\n" @@ -281,6 +306,9 @@ U_BOOT_LONGHELP(cedit, U_BOOT_CMD_WITH_SUBCMDS(cedit, "Configuration editor", cedit_help_text, U_BOOT_SUBCMD_MKENT(load, 5, 1, do_cedit_load), +#ifdef CONFIG_COREBOOT_SYSINFO + U_BOOT_SUBCMD_MKENT(cb_load, 5, 1, do_cedit_cb_load), +#endif U_BOOT_SUBCMD_MKENT(read_fdt, 5, 1, do_cedit_read_fdt), U_BOOT_SUBCMD_MKENT(write_fdt, 5, 1, do_cedit_write_fdt), U_BOOT_SUBCMD_MKENT(read_env, 2, 1, do_cedit_read_env), @@ -7,6 +7,7 @@ #include <command.h> #include <dm.h> #include <spl.h> +#include <asm/cpu.h> #include <asm/global_data.h> #include <asm/state.h> @@ -29,6 +30,14 @@ static int do_sb_handoff(struct cmd_tbl *cmdtp, int flag, int argc, #endif } +static int do_sb_map(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + sandbox_map_list(); + + return 0; +} + static int do_sb_state(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -40,29 +49,12 @@ static int do_sb_state(struct cmd_tbl *cmdtp, int flag, int argc, return 0; } -static struct cmd_tbl cmd_sb_sub[] = { - U_BOOT_CMD_MKENT(handoff, 1, 0, do_sb_handoff, "", ""), - U_BOOT_CMD_MKENT(state, 1, 0, do_sb_state, "", ""), -}; - -static int do_sb(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) -{ - struct cmd_tbl *c; - - /* Skip past 'sb' */ - argc--; - argv++; - - c = find_cmd_tbl(argv[0], cmd_sb_sub, ARRAY_SIZE(cmd_sb_sub)); - if (c) - return c->cmd(cmdtp, flag, argc, argv); - else - return CMD_RET_USAGE; -} - -U_BOOT_CMD( - sb, 8, 1, do_sb, - "Sandbox status commands", +U_BOOT_LONGHELP(sb, "handoff - Show handoff data received from SPL\n" - "sb state - Show sandbox state" -); + "sb map - Show mapped memory\n" + "sb state - Show sandbox state"); + +U_BOOT_CMD_WITH_SUBCMDS(sb, "Sandbox status commands", sb_help_text, + U_BOOT_SUBCMD_MKENT(handoff, 1, 1, do_sb_handoff), + U_BOOT_SUBCMD_MKENT(map, 1, 1, do_sb_map), + U_BOOT_SUBCMD_MKENT(state, 1, 1, do_sb_state)); diff --git a/cmd/x86/Makefile b/cmd/x86/Makefile index 925215235d3..5f3f5be2882 100644 --- a/cmd/x86/Makefile +++ b/cmd/x86/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_CMD_CBSYSINFO) += cbsysinfo.o obj-y += cpuid.o msr.o mtrr.o +obj-$(CONFIG_CMD_CBCMOS) += cbcmos.o obj-$(CONFIG_CMD_EXCEPTION) += exception.o obj-$(CONFIG_USE_HOB) += hob.o obj-$(CONFIG_HAVE_FSP) += fsp.o diff --git a/cmd/x86/cbcmos.c b/cmd/x86/cbcmos.c new file mode 100644 index 00000000000..fe5582fbf51 --- /dev/null +++ b/cmd/x86/cbcmos.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Support for booting from coreboot + * + * Copyright 2021 Google LLC + */ + +#define LOG_CATEGORY UCLASS_RTC + +#include <command.h> +#include <dm.h> +#include <rtc.h> +#include <asm/cb_sysinfo.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +const struct sysinfo_t *get_table(void) +{ + if (!gd->arch.coreboot_table) { + printf("No coreboot sysinfo table found\n"); + return NULL; + } + + return &lib_sysinfo; +} + +static int calc_sum(struct udevice *dev, uint start_bit, uint bit_count) +{ + uint start_byte = start_bit / 8; + uint byte_count = bit_count / 8; + int ret, i; + uint sum; + + log_debug("Calc sum from %x: %x bytes\n", start_byte, byte_count); + sum = 0; + for (i = 0; i < bit_count / 8; i++) { + ret = rtc_read8(dev, start_bit / 8 + i); + if (ret < 0) + return ret; + sum += ret; + } + + return (sum & 0xff) << 8 | (sum & 0xff00) >> 8; +} + +/** + * prep_cbcmos() - Prepare for a CMOS-RAM command + * + * @tab: coreboot table + * @devnum: RTC device name to use, or NULL for the first one + * @dep: Returns RTC device on success + * Return: calculated checksum for CMOS RAM or -ve on error + */ +static int prep_cbcmos(const struct sysinfo_t *tab, const char *devname, + struct udevice **devp) +{ + struct udevice *dev; + int ret; + + if (!tab) + return CMD_RET_FAILURE; + if (devname) + ret = uclass_get_device_by_name(UCLASS_RTC, devname, &dev); + else + ret = uclass_first_device_err(UCLASS_RTC, &dev); + if (ret) { + printf("Failed to get RTC device: %dE\n", ret); + return ret; + } + + ret = calc_sum(dev, tab->cmos_range_start, + tab->cmos_range_end + 1 - tab->cmos_range_start); + if (ret < 0) { + printf("Failed to read RTC device: %dE\n", ret); + return ret; + } + *devp = dev; + + return ret; +} + +static int do_cbcmos_check(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + const struct sysinfo_t *tab = get_table(); + struct udevice *dev; + u16 cur, sum; + int ret; + + ret = prep_cbcmos(tab, argv[1], &dev); + if (ret < 0) + return CMD_RET_FAILURE; + sum = ret; + + ret = rtc_read16(dev, tab->cmos_checksum_location / 8, &cur); + if (ret < 0) { + printf("Failed to read RTC device: %dE\n", ret); + return CMD_RET_FAILURE; + } + if (sum != cur) { + printf("Checksum %04x error: calculated %04x\n", cur, sum); + return CMD_RET_FAILURE; + } + + return 0; +} + +static int do_cbcmos_update(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + const struct sysinfo_t *tab = get_table(); + struct udevice *dev; + u16 sum; + int ret; + + ret = prep_cbcmos(tab, argv[1], &dev); + if (ret < 0) + return CMD_RET_FAILURE; + sum = ret; + + ret = rtc_write16(dev, tab->cmos_checksum_location / 8, sum); + if (ret < 0) { + printf("Failed to read RTC device: %dE\n", ret); + return CMD_RET_FAILURE; + } + printf("Checksum %04x written\n", sum); + + return 0; +} + +U_BOOT_LONGHELP(cbcmos, + "check - check CMOS RAM\n" + "cbcmos update - Update CMOS-RAM checksum"; +); + +U_BOOT_CMD_WITH_SUBCMDS(cbcmos, "coreboot CMOS RAM", cbcmos_help_text, + U_BOOT_SUBCMD_MKENT(check, 2, 1, do_cbcmos_check), + U_BOOT_SUBCMD_MKENT(update, 2, 1, do_cbcmos_update)); diff --git a/cmd/x86/cbsysinfo.c b/cmd/x86/cbsysinfo.c index 7ca2e13ae2f..ea4d89616f6 100644 --- a/cmd/x86/cbsysinfo.c +++ b/cmd/x86/cbsysinfo.c @@ -184,6 +184,77 @@ static const char *timestamp_name(uint32_t id) return "<unknown>"; } +static void show_option_vals(const struct cb_cmos_option_table *tab, + uint id) +{ + const void *ptr, *end; + bool found = false; + + end = (void *)tab + tab->size; + for (ptr = (void *)tab + tab->header_length; ptr < end;) { + const struct cb_record *rec = ptr; + + switch (rec->tag) { + case CB_TAG_OPTION_ENUM: { + const struct cb_cmos_enums *enums = ptr; + + if (enums->config_id == id) { + if (!found) + printf(" "); + printf(" %d:%s", enums->value, enums->text); + found = true; + } + break; + } + break; + case CB_TAG_OPTION_DEFAULTS: + case CB_TAG_OPTION_CHECKSUM: + case CB_TAG_OPTION: + break; + default: + printf("tag %x\n", rec->tag); + break; + } + ptr += rec->size; + } +} + +static void show_option_table(const struct cb_cmos_option_table *tab) +{ + const void *ptr, *end; + + print_ptr("option_table", tab); + if (!tab->size) + return; + + printf(" Bit Len Cfg ID Name\n"); + end = (void *)tab + tab->size; + for (ptr = (void *)tab + tab->header_length; ptr < end;) { + const struct cb_record *rec = ptr; + + switch (rec->tag) { + case CB_TAG_OPTION: { + const struct cb_cmos_entries *entry = ptr; + + printf("%4x %4x %3c %3x %-20s", entry->bit, + entry->length, entry->config, entry->config_id, + entry->name); + show_option_vals(tab, entry->config_id); + printf("\n"); + break; + } + case CB_TAG_OPTION_ENUM: + case CB_TAG_OPTION_DEFAULTS: + case CB_TAG_OPTION_CHECKSUM: + break; + default: + printf("tag %x\n", rec->tag); + break; + } + ptr += rec->size; + } +} + static void show_table(struct sysinfo_t *info, bool verbose) { struct cb_serial *ser = info->serial; @@ -218,7 +289,7 @@ static void show_table(struct sysinfo_t *info, bool verbose) printf("%12d: %02x:%-8s %016llx %016llx\n", i, mr->type, get_mem_name(mr->type), mr->base, mr->size); } - print_ptr("option_table", info->option_table); + show_option_table(info->option_table); print_hex("CMOS start", info->cmos_range_start); if (info->cmos_range_start) { diff --git a/common/bootstage.c b/common/bootstage.c index c7bb204501a..4532100acea 100644 --- a/common/bootstage.c +++ b/common/bootstage.c @@ -249,6 +249,8 @@ static uint32_t print_time_record(struct bootstage_record *rec, uint32_t prev) printf("%11s", ""); print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS); } else { + if (prev > rec->time_us) + prev = 0; print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS); print_grouped_ull(rec->time_us - prev, BOOTSTAGE_DIGITS); } @@ -257,13 +259,6 @@ static uint32_t print_time_record(struct bootstage_record *rec, uint32_t prev) return rec->time_us; } -static int h_compare_record(const void *r1, const void *r2) -{ - const struct bootstage_record *rec1 = r1, *rec2 = r2; - - return rec1->time_us > rec2->time_us ? 1 : -1; -} - #ifdef CONFIG_OF_LIBFDT /** * Add all bootstage timings to a device tree. @@ -342,9 +337,6 @@ void bootstage_report(void) prev = print_time_record(rec, 0); - /* Sort records by increasing time */ - qsort(data->record, data->rec_count, sizeof(*rec), h_compare_record); - for (i = 1, rec++; i < data->rec_count; i++, rec++) { if (rec->id && !rec->start_us) prev = print_time_record(rec, prev); diff --git a/common/log.c b/common/log.c index b83a6618900..c9fe35230d6 100644 --- a/common/log.c +++ b/common/log.c @@ -32,6 +32,7 @@ static const char *const log_cat_name[] = { "fs", "expo", "console", + "test", }; _Static_assert(ARRAY_SIZE(log_cat_name) == LOGC_COUNT - LOGC_NONE, diff --git a/configs/coreboot64_defconfig b/configs/coreboot64_defconfig index 553f1dc83f0..706c0cd71d7 100644 --- a/configs/coreboot64_defconfig +++ b/configs/coreboot64_defconfig @@ -17,6 +17,7 @@ CONFIG_SHOW_BOOT_PROGRESS=y CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro" CONFIG_BOOTCOMMAND="bootflow scan -l; if bootflow menu; then cls; bootflow boot; fi" +CONFIG_CEDIT=y CONFIG_SYS_PBSIZE=532 CONFIG_PRE_CONSOLE_BUFFER=y CONFIG_SYS_CONSOLE_INFO_QUIET=y @@ -46,6 +47,7 @@ CONFIG_TFTP_TSIZE=y CONFIG_USE_ROOTPATH=y CONFIG_REGMAP=y CONFIG_SYSCON=y +CONFIG_OFNODE_MULTI_TREE=y # CONFIG_ACPIGEN is not set CONFIG_SYS_IDE_MAXDEVICE=4 CONFIG_SYS_ATA_DATA_OFFSET=0 diff --git a/configs/coreboot_defconfig b/configs/coreboot_defconfig index 881bf8dd180..bd190e40ffc 100644 --- a/configs/coreboot_defconfig +++ b/configs/coreboot_defconfig @@ -16,6 +16,7 @@ CONFIG_SHOW_BOOT_PROGRESS=y CONFIG_USE_BOOTARGS=y CONFIG_BOOTARGS="root=/dev/sdb3 init=/sbin/init rootwait ro" CONFIG_BOOTCOMMAND="bootflow scan -l; if bootflow menu; then cls; bootflow boot; fi" +CONFIG_CEDIT=y CONFIG_PRE_CONSOLE_BUFFER=y CONFIG_SYS_CONSOLE_INFO_QUIET=y CONFIG_LOG=y @@ -42,6 +43,7 @@ CONFIG_TFTP_TSIZE=y CONFIG_USE_ROOTPATH=y CONFIG_REGMAP=y CONFIG_SYSCON=y +CONFIG_OFNODE_MULTI_TREE=y # CONFIG_ACPIGEN is not set CONFIG_SYS_IDE_MAXDEVICE=4 CONFIG_SYS_ATA_DATA_OFFSET=0 diff --git a/doc/board/coreboot/coreboot.rst b/doc/board/coreboot/coreboot.rst index a177265c16e..f52b24ff43d 100644 --- a/doc/board/coreboot/coreboot.rst +++ b/doc/board/coreboot/coreboot.rst @@ -182,3 +182,9 @@ CI runs tests using a pre-built coreboot image. This ensures that U-Boot can boot as a coreboot payload, based on a known-good build of coreboot. To update the `coreboot.rom` file which is used, see ``tools/Dockerfile`` + +Editing CMOS RAM settings +------------------------- + +U-Boot supports creating a configuration editor to edit coreboot CMOS-RAM +settings. See :ref:`cedit_cb_load`. diff --git a/doc/develop/cedit.rst b/doc/develop/cedit.rst index 310be889240..1ac55ab1219 100644 --- a/doc/develop/cedit.rst +++ b/doc/develop/cedit.rst @@ -172,4 +172,4 @@ Cedit provides several options for persistent settings: For now, reading and writing settings is not automatic. See the :doc:`../usage/cmd/cedit` for how to do this on the command line or in a -script. +script. For x86 devices, see :ref:`cedit_cb_load`. diff --git a/doc/usage/cmd/cbcmos.rst b/doc/usage/cmd/cbcmos.rst new file mode 100644 index 00000000000..9395cf1cbd7 --- /dev/null +++ b/doc/usage/cmd/cbcmos.rst @@ -0,0 +1,45 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +cbcmos +====== + +Synopis +------- + +:: + + cbcmos check [<dev>] + cbcmos update [<dev>] + + +Description +----------- + +This checks or updates the CMOS-RAM checksum value against the CMOS-RAM +contents. It is used with coreboot, which provides information about where to +find the checksum and what part of the CMOS RAM it covers. + +If `<dev>` is provided then the named real-time clock (RTC) device is used. +Otherwise the default RTC is used. + +Example +------- + +This shows checking and updating a checksum across bytes 38 and 39 of the +CMOS RAM:: + + => rtc read 38 2 + 00000038: 71 00 q. + => cbc check + => rtc write 38 66 + => rtc read 38 2 + 00000038: 66 00 f. + => cbc check + Checksum 7100 error: calculated 6600 + => cbc update + Checksum 6600 written + => cbc check + => + +See also :ref:`cedit_cb_load` which shows an example that includes the +configuration editor. diff --git a/doc/usage/cmd/cbsysinfo.rst b/doc/usage/cmd/cbsysinfo.rst index 80d8ba1b662..28f61d9c63e 100644 --- a/doc/usage/cmd/cbsysinfo.rst +++ b/doc/usage/cmd/cbsysinfo.rst @@ -23,3 +23,102 @@ Example :: => cbsysinfo + Coreboot table at 500, size 5c4, records 1d (dec 29), decoded to 000000007dce4520, forwarded to 000000007ff9a000 + + CPU KHz : 0 + Serial I/O port: 00000000 + base : 00000000 + pointer : 000000007ff9a370 + type : 1 + base : 000003f8 + baud : 0d115200 + regwidth : 1 + input_hz : 0d1843200 + PCI addr : 00000010 + Mem ranges : 7 + id: type || base || size + 0: 10:table 0000000000000000 0000000000001000 + 1: 01:ram 0000000000001000 000000000009f000 + 2: 02:reserved 00000000000a0000 0000000000060000 + 3: 01:ram 0000000000100000 000000007fe6d000 + 4: 10:table 000000007ff6d000 0000000000093000 + 5: 02:reserved 00000000fec00000 0000000000001000 + 6: 02:reserved 00000000ff800000 0000000000800000 + option_table: 000000007ff9a018 + Bit Len Cfg ID Name + 0 180 r 0 reserved_memory + 180 1 e 4 boot_option 0:Fallback 1:Normal + 184 4 h 0 reboot_counter + 190 8 r 0 reserved_century + 1b8 8 r 0 reserved_ibm_ps2_century + 1c0 1 e 1 power_on_after_fail 0:Disable 1:Enable + 1c4 4 e 6 debug_level 5:Notice 6:Info 7:Debug 8:Spew + 1d0 80 r 0 vbnv + 3f0 10 h 0 check_sum + CMOS start : 1c0 + CMOS end : 1cf + CMOS csum loc: 3f0 + VBNV start : ffffffff + VBNV size : ffffffff + CB version : 4.21-5-g7e6eae9679e3-dirty + Extra : + Build : Thu Sep 07 14:52:41 UTC 2023 + Time : 14:52:41 + Framebuffer : 000000007ff9a410 + Phys addr : fd000000 + X res : 0d800 + X res : 0d600 + Bytes / line: c80 + Bpp : 0d32 + pos/size red 16/8, green 8/8, blue 0/8, reserved 24/8 + GPIOs : 0 + id: port polarity val name + MACs : 0d10 + 0: 12:00:00:00:28:00 + 1: 00:00:00:fd:00:00 + 2: 20:03:00:00:58:02 + 3: 80:0c:00:00:20:10 + 4: 08:00:08:18:08:00 + 5: 16:00:00:00:10:00 + 6: 00:d0:fd:7f:00:00 + 7: 17:00:00:00:10:00 + 8: 00:e0:fd:7f:00:00 + 9: 37:00:00:00:10:00 + Multiboot tab: 0000000000000000 + CB header : 000000007ff9a000 + CB mainboard: 000000007ff9a344 + vendor : 0: Emulation + part_number : 10: QEMU x86 i440fx/piix4 + vboot handoff: 0000000000000000 + size : 0 + vdat addr : 0000000000000000 + size : 0 + SMBIOS : 7ff6d000 + size : 8000 + ROM MTRR : 0 + Tstamp table: 000000007ffdd000 + CBmem cons : 000000007ffde000 + Size : 1fff8 + Cursor : 3332 + MRC cache : 0000000000000000 + ACPI GNVS : 0000000000000000 + Board ID : ffffffff + RAM code : ffffffff + WiFi calib : 0000000000000000 + Ramoops buff: 0 + size : 0 + SF size : 0 + SF sector : 0 + SF erase cmd: 0 + FMAP offset : 0 + CBFS offset : 200 + CBFS size : 3ffe00 + Boot media size: 400000 + MTC start : 0 + MTC size : 0 + Chrome OS VPD: 0000000000000000 + RSDP : 000000007ff75000 + Unimpl. : 10 37 40 + => + +Note that "Unimpl." shows tags which U-Boot does not currently implement. diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst index f29f1b3f388..e54ea204b9f 100644 --- a/doc/usage/cmd/cedit.rst +++ b/doc/usage/cmd/cedit.rst @@ -18,6 +18,7 @@ Synopsis cedit write_env [-v] cedit read_env [-v] cedit write_cmos [-v] [dev] + cedit cb_load Description ----------- @@ -92,6 +93,13 @@ updated. Normally the first RTC device is used to hold the data. You can specify a different device by name using the `dev` parameter. +.. _cedit_cb_load: + +cedit cb_load +~~~~~~~~~~~~~ + +This is supported only on x86 devices booted from coreboot. It creates a new +configuration editor which can be used to edit CMOS settings. Example ------- @@ -158,3 +166,71 @@ Here is an example with the device specified:: => cedit write_cmos rtc@43 => + +This example shows editing coreboot CMOS-RAM settings. A script could be used +to automate this:: + + => cbsysinfo + Coreboot table at 500, size 5c4, records 1d (dec 29), decoded to 000000007dce3f40, forwarded to 000000007ff9a000 + + CPU KHz : 0 + Serial I/O port: 00000000 + base : 00000000 + pointer : 000000007ff9a370 + type : 1 + base : 000003f8 + baud : 0d115200 + regwidth : 1 + input_hz : 0d1843200 + PCI addr : 00000010 + Mem ranges : 7 + id: type || base || size + 0: 10:table 0000000000000000 0000000000001000 + 1: 01:ram 0000000000001000 000000000009f000 + 2: 02:reserved 00000000000a0000 0000000000060000 + 3: 01:ram 0000000000100000 000000007fe6d000 + 4: 10:table 000000007ff6d000 0000000000093000 + 5: 02:reserved 00000000fec00000 0000000000001000 + 6: 02:reserved 00000000ff800000 0000000000800000 + option_table: 000000007ff9a018 + Bit Len Cfg ID Name + 0 180 r 0 reserved_memory + 180 1 e 4 boot_option 0:Fallback 1:Normal + 184 4 h 0 reboot_counter + 190 8 r 0 reserved_century + 1b8 8 r 0 reserved_ibm_ps2_century + 1c0 1 e 1 power_on_after_fail 0:Disable 1:Enable + 1c4 4 e 6 debug_level 5:Notice 6:Info 7:Debug 8:Spew + 1d0 80 r 0 vbnv + 3f0 10 h 0 check_sum + CMOS start : 1c0 + CMOS end : 1cf + CMOS csum loc: 3f0 + VBNV start : ffffffff + VBNV size : ffffffff + ... + Unimpl. : 10 37 40 + +Check that the CMOS RAM checksum is correct, then create a configuration editor +and load the settings from CMOS RAM:: + + => cbcmos check + => cedit cb + => cedit read_cmos + +Now run the cedit. In this case the user selected 'save' so `cedit run` returns +success:: + + => if cedit run; then cedit write_cmos -v; fi + Write 2 bytes from offset 30 to 38 + => echo $? + 0 + +Update the checksum in CMOS RAM:: + + => cbcmos check + Checksum 6100 error: calculated 7100 + => cbcmos update + Checksum 7100 written + => cbcmos check + => diff --git a/doc/usage/cmd/sb.rst b/doc/usage/cmd/sb.rst new file mode 100644 index 00000000000..37431aff7c8 --- /dev/null +++ b/doc/usage/cmd/sb.rst @@ -0,0 +1,79 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +.. index:: + single: sbi (command) + +sbi command +=========== + +Synopsis +-------- + +:: + + sb handoff + sb map + sb state + +Description +----------- + +The *sb* command is used to display information about sandbox's internal +operation. See :doc:`/arch/sandbox/index` for more information. + +sb handoff +~~~~~~~~~~ + +This shows information about any handoff information received from SPL. If +U-Boot is started from an SPL build, it shows a valid magic number. + +sb map +~~~~~~ + +This shows any mappings between sandbox's emulated RAM and the underlying host +address-space. + +Fields shown are: + +Addr + Address in emulated RAM + +Mapping + Equivalent address in the host address-space. While sandbox requests address + ``0x10000000`` from the OS, this is not always available. + +Refcnt + Shows the number of references to this mapping. + +sb state +~~~~~~~~ + +This shows basic information about the sandbox state, currently just the +command-line with which sandbox was started. + +Example +------- + +This shows checking for the presence of SPL-handoff information. For this to +work, ``u-boot-spl`` must be run, with build that enables ``CONFIG_SPL``, such +as ``sandbox_spl``:: + + => sb handoff + SPL handoff magic 14f93c7b + +This shows output from the *sb map* subcommand, with a single mapping:: + + Sandbox memory-mapping + Addr Mapping Refcnt + ff000000 000056185b46d6d0 2 + +This shows output from the *sb state* subcommand:: + + => sb state + Arguments: + /tmp/b/sandbox/u-boot -D + +Configuration +------------- + +The *sb handoff* command is only supported if CONFIG_HANDOFF is enabled. diff --git a/doc/usage/index.rst b/doc/usage/index.rst index db71711c393..cb7a23f1170 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -43,6 +43,7 @@ Shell commands cmd/bootz cmd/button cmd/cat + cmd/cbcmos cmd/cbsysinfo cmd/cedit cmd/cli @@ -103,6 +104,7 @@ Shell commands cmd/reset cmd/rng cmd/saves + cmd/sb cmd/sbi cmd/scmi cmd/scp03 diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 7ae0884a75e..f846a35d6b2 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -304,6 +304,17 @@ int uclass_find_device_by_name(enum uclass_id id, const char *name, return uclass_find_device_by_namelen(id, name, strlen(name), devp); } +struct udevice *uclass_try_first_device(enum uclass_id id) +{ + struct uclass *uc; + + uc = uclass_find(id); + if (!uc || list_empty(&uc->dev_head)) + return NULL; + + return list_first_entry(&uc->dev_head, struct udevice, uclass_node); +} + int uclass_find_next_free_seq(struct uclass *uc) { struct udevice *dev; diff --git a/include/alist.h b/include/alist.h index 68d268f01af..b00d9ea97d6 100644 --- a/include/alist.h +++ b/include/alist.h @@ -72,6 +72,21 @@ static inline bool alist_has(struct alist *lst, uint index) } /** + * alist_calc_index() - Calculate the index of an item in the list + * + * The returned element number will be -1 if the list is empty or the pointer + * pointers to before the list starts. + * + * If the pointer points to after the last item, the calculated element-number + * will be returned, even though it is greater than lst->count + * + * @lst: alist to check + * @ptr: pointer to check + * Return: element number of the pointer + */ +int alist_calc_index(const struct alist *lst, const void *ptr); + +/** * alist_err() - Check if the alist is still valid * * @lst: List to check @@ -116,7 +131,12 @@ static inline const void *alist_getd(struct alist *lst, uint index) return lst->data + index * lst->obj_size; } -/** get an entry as a constant */ +/** + * alist_get() - get an entry as a constant + * + * Use as (to obtain element 2 of the list): + * const struct my_struct *ptr = alist_get(lst, 2, struct my_struct) + */ #define alist_get(_lst, _index, _struct) \ ((const _struct *)alist_get_ptr(_lst, _index)) @@ -151,8 +171,9 @@ void *alist_ensure_ptr(struct alist *lst, uint index); * alist_add_placeholder() - Add a new item to the end of the list * * @lst: alist to add to - * Return: Pointer to the newly added position. Note that this is not inited so - * the caller must copy the requested struct to the returned pointer + * Return: Pointer to the newly added position, or NULL if out of memory. Note + * that this is not inited so the caller must copy the requested struct to the + * returned pointer */ void *alist_add_placeholder(struct alist *lst); @@ -184,6 +205,112 @@ bool alist_expand_by(struct alist *lst, uint inc_by); #define alist_add(_lst, _obj) \ ((typeof(_obj) *)alist_add_ptr(_lst, &(_obj))) +/** get next entry as a constant */ +#define alist_next(_lst, _objp) \ + ((const typeof(_objp))alist_next_ptrd(_lst, _objp)) + +/** get next entry, which can be written to */ +#define alist_nextw(_lst, _objp) \ + ((typeof(_objp))alist_next_ptrd(_lst, _objp)) + +/** + * alist_next_ptrd() - Get a pointer to the next list element + * + * This returns NULL if the requested element is beyond lst->count + * + * @lst: List to check + * @ptr: Pointer to current element (must be valid) + * Return: Pointer to next element, or NULL if @ptr is the last + */ +const void *alist_next_ptrd(const struct alist *lst, const void *ptr); + +/** + * alist_chk_ptr() - Check whether a pointer is within a list + * + * Checks if the pointer points to an existing element of the list. The pointer + * must point to the start of an element, either in the list, or just outside of + * it. This function is only useful for handling for() loops + * + * Return: true if @ptr is within the list (0..count-1), else false + */ +bool alist_chk_ptr(const struct alist *lst, const void *ptr); + +/** + * alist_start() - Get the start of the list (first element) + * + * Note that this will always return ->data even if it is not NULL + * + * Usage: + * const struct my_struct *obj; # 'const' is optional + * + * alist_start(&lst, struct my_struct) + */ +#define alist_start(_lst, _struct) \ + ((_struct *)(_lst)->data) + +/** + * alist_end() - Get the end of the list (just after last element) + * + * Usage: + * const struct my_struct *obj; # 'const' is optional + * + * alist_end(&lst, struct my_struct) + */ +#define alist_end(_lst, _struct) \ + ((_struct *)(_lst)->data + (_lst)->count) + +/** + * alist_for_each() - Iterate over an alist (with constant pointer) + * + * Use as: + * const struct my_struct *obj; # 'const' is optional + * + * alist_for_each(obj, &lst) { + * obj->... + * } + */ +#define alist_for_each(_pos, _lst) \ + for (_pos = alist_start(_lst, typeof(*(_pos))); \ + _pos < alist_end(_lst, typeof(*(_pos))); \ + _pos++) + +/** + * alist_for_each_filter() - version which sets up a 'from' pointer too + * + * This is used for filtering out information in the list. It works by iterating + * through the list, copying elements down over the top of elements to be + * deleted. + * + * In this example, 'from' iterates through the list from start to end,, 'to' + * also begins at the start, but only increments if the element at 'from' should + * be kept. This provides an O(n) filtering operation. Note that + * alist_update_end() must be called after the loop, to update the count. + * + * alist_for_each_filter(from, to, &lst) { + * if (from->val != 2) + * *to++ = *from; + * } + * alist_update_end(&lst, to); + */ +#define alist_for_each_filter(_pos, _from, _lst) \ + for (_pos = _from = alist_start(_lst, typeof(*(_pos))); \ + _pos < alist_end(_lst, typeof(*(_pos))); \ + _pos++) + +/** + * alist_update_end() - Set the element count based on a given pointer + * + * Set the given element as the final one + */ +void alist_update_end(struct alist *lst, const void *end); + +/** + * alist_empty() - Empty an alist + * + * This removes all entries from the list, without changing the allocated size + */ +void alist_empty(struct alist *lst); + /** * alist_init() - Set up a new object list * @@ -197,6 +324,12 @@ bool alist_expand_by(struct alist *lst, uint inc_by); */ bool alist_init(struct alist *lst, uint obj_size, uint alloc_size); +/** + * alist_init_struct() - Typed version of alist_init() + * + * Use as: + * alist_init(&lst, struct my_struct); + */ #define alist_init_struct(_lst, _struct) \ alist_init(_lst, sizeof(_struct), 0) diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index bf593d96a84..26277b93976 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -545,8 +545,10 @@ static_assert(sizeof(struct global_data) == GD_SIZE); #if CONFIG_IS_ENABLED(BLOBLIST) #define gd_bloblist() gd->bloblist +#define gd_set_bloblist(_val) gd->bloblist = (_val) #else #define gd_bloblist() NULL +#define gd_set_bloblist(_val) #endif #if CONFIG_IS_ENABLED(BOOTSTAGE) diff --git a/include/dm/uclass.h b/include/dm/uclass.h index 456eef7f2f3..c2793040923 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -436,6 +436,17 @@ int uclass_first_device_drvdata(enum uclass_id id, ulong driver_data, struct udevice **devp); /** + * uclass_try_first_device()- See if there is a device for a uclass + * + * If the uclass exists, this returns the first device on that uclass, without + * probing it. If the uclass does not exist, it gives up + * + * @id: Uclass ID to check + * Return: Pointer to device, if found, else NULL + */ +struct udevice *uclass_try_first_device(enum uclass_id id); + +/** * uclass_probe_all() - Probe all devices based on an uclass ID * * This function probes all devices associated with a uclass by diff --git a/include/expo.h b/include/expo.h index 8cb37260db5..3c383d2e2ee 100644 --- a/include/expo.h +++ b/include/expo.h @@ -762,4 +762,12 @@ int expo_apply_theme(struct expo *exp, ofnode node); */ int expo_build(ofnode root, struct expo **expp); +/** + * cb_expo_build() - Build an expo for coreboot CMOS RAM + * + * @expp: Returns the expo created + * Return: 0 if OK, -ve on error + */ +int cb_expo_build(struct expo **expp); + #endif /*__EXPO_H */ diff --git a/include/log.h b/include/log.h index bf81a27011f..4f6d6a2c2cf 100644 --- a/include/log.h +++ b/include/log.h @@ -106,6 +106,8 @@ enum log_category_t { LOGC_EXPO, /** @LOGC_CONSOLE: Related to the console and stdio */ LOGC_CONSOLE, + /** @LOGC_TEST: Related to testing */ + LOGC_TEST, /** @LOGC_COUNT: Number of log categories */ LOGC_COUNT, /** @LOGC_END: Sentinel value for lists of log categories */ diff --git a/include/test/test.h b/include/test/test.h index 92eec2eb6f9..21c0478befe 100644 --- a/include/test/test.h +++ b/include/test/test.h @@ -29,6 +29,7 @@ * @of_other: Live tree for the other FDT * @runs_per_test: Number of times to run each test (typically 1) * @force_run: true to run tests marked with the UTF_MANUAL flag + * @old_bloblist: stores the old gd->bloblist pointer * @expect_str: Temporary string used to hold expected string value * @actual_str: Temporary string used to hold actual string value */ @@ -50,6 +51,7 @@ struct unit_test_state { struct device_node *of_other; int runs_per_test; bool force_run; + void *old_bloblist; char expect_str[512]; char actual_str[512]; }; @@ -73,6 +75,7 @@ enum ut_flags { UTF_MANUAL = BIT(8), UTF_ETH_BOOTDEV = BIT(9), /* enable Ethernet bootdevs */ UTF_SF_BOOTDEV = BIT(10), /* enable SPI flash bootdevs */ + UFT_BLOBLIST = BIT(11), /* test changes gd->bloblist */ }; /** diff --git a/lib/alist.c b/lib/alist.c index b7928cad520..4ce651f5c45 100644 --- a/lib/alist.c +++ b/lib/alist.c @@ -41,6 +41,11 @@ void alist_uninit(struct alist *lst) memset(lst, '\0', sizeof(struct alist)); } +void alist_empty(struct alist *lst) +{ + lst->count = 0; +} + /** * alist_expand_to() - Expand a list to the given size * @@ -106,6 +111,42 @@ const void *alist_get_ptr(const struct alist *lst, uint index) return lst->data + index * lst->obj_size; } +int alist_calc_index(const struct alist *lst, const void *ptr) +{ + uint index; + + if (!lst->count || ptr < lst->data) + return -1; + + index = (ptr - lst->data) / lst->obj_size; + + return index; +} + +void alist_update_end(struct alist *lst, const void *ptr) +{ + int index; + + index = alist_calc_index(lst, ptr); + lst->count = index == -1 ? 0 : index; +} + +bool alist_chk_ptr(const struct alist *lst, const void *ptr) +{ + int index = alist_calc_index(lst, ptr); + + return index >= 0 && index < lst->count; +} + +const void *alist_next_ptrd(const struct alist *lst, const void *ptr) +{ + int index = alist_calc_index(lst, ptr); + + assert(index != -1); + + return alist_get_ptr(lst, index + 1); +} + void *alist_ensure_ptr(struct alist *lst, uint index) { uint minsize = index + 1; diff --git a/test/bloblist.c b/test/bloblist.c index fd85c7ab79e..e0ad94e77d8 100644 --- a/test/bloblist.c +++ b/test/bloblist.c @@ -94,7 +94,7 @@ static int bloblist_test_init(struct unit_test_state *uts) return 1; } -BLOBLIST_TEST(bloblist_test_init, 0); +BLOBLIST_TEST(bloblist_test_init, UFT_BLOBLIST); static int bloblist_test_blob(struct unit_test_state *uts) { @@ -134,7 +134,7 @@ static int bloblist_test_blob(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_blob, 0); +BLOBLIST_TEST(bloblist_test_blob, UFT_BLOBLIST); /* Check bloblist_ensure_size_ret() */ static int bloblist_test_blob_ensure(struct unit_test_state *uts) @@ -168,7 +168,7 @@ static int bloblist_test_blob_ensure(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_blob_ensure, 0); +BLOBLIST_TEST(bloblist_test_blob_ensure, UFT_BLOBLIST); static int bloblist_test_bad_blob(struct unit_test_state *uts) { @@ -184,7 +184,7 @@ static int bloblist_test_bad_blob(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_bad_blob, 0); +BLOBLIST_TEST(bloblist_test_bad_blob, UFT_BLOBLIST); static int bloblist_test_checksum(struct unit_test_state *uts) { @@ -257,7 +257,7 @@ static int bloblist_test_checksum(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_checksum, 0); +BLOBLIST_TEST(bloblist_test_checksum, UFT_BLOBLIST); /* Test the 'bloblist info' command */ static int bloblist_test_cmd_info(struct unit_test_state *uts) @@ -278,7 +278,7 @@ static int bloblist_test_cmd_info(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_cmd_info, UTF_CONSOLE); +BLOBLIST_TEST(bloblist_test_cmd_info, UFT_BLOBLIST | UTF_CONSOLE); /* Test the 'bloblist list' command */ static int bloblist_test_cmd_list(struct unit_test_state *uts) @@ -300,7 +300,7 @@ static int bloblist_test_cmd_list(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_cmd_list, UTF_CONSOLE); +BLOBLIST_TEST(bloblist_test_cmd_list, UFT_BLOBLIST | UTF_CONSOLE); /* Test alignment of bloblist blobs */ static int bloblist_test_align(struct unit_test_state *uts) @@ -358,7 +358,7 @@ static int bloblist_test_align(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_align, 0); +BLOBLIST_TEST(bloblist_test_align, UFT_BLOBLIST); /* Test relocation of a bloblist */ static int bloblist_test_reloc(struct unit_test_state *uts) @@ -392,7 +392,7 @@ static int bloblist_test_reloc(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_reloc, 0); +BLOBLIST_TEST(bloblist_test_reloc, UFT_BLOBLIST); /* Test expansion of a blob */ static int bloblist_test_grow(struct unit_test_state *uts) @@ -445,7 +445,7 @@ static int bloblist_test_grow(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_grow, 0); +BLOBLIST_TEST(bloblist_test_grow, UFT_BLOBLIST); /* Test shrinking of a blob */ static int bloblist_test_shrink(struct unit_test_state *uts) @@ -495,7 +495,7 @@ static int bloblist_test_shrink(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_shrink, 0); +BLOBLIST_TEST(bloblist_test_shrink, UFT_BLOBLIST); /* Test failing to adjust a blob size */ static int bloblist_test_resize_fail(struct unit_test_state *uts) @@ -530,7 +530,7 @@ static int bloblist_test_resize_fail(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_resize_fail, 0); +BLOBLIST_TEST(bloblist_test_resize_fail, UFT_BLOBLIST); /* Test expanding the last blob in a bloblist */ static int bloblist_test_resize_last(struct unit_test_state *uts) @@ -581,7 +581,7 @@ static int bloblist_test_resize_last(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_resize_last, 0); +BLOBLIST_TEST(bloblist_test_resize_last, UFT_BLOBLIST); /* Check a completely full bloblist */ static int bloblist_test_blob_maxsize(struct unit_test_state *uts) @@ -604,7 +604,7 @@ static int bloblist_test_blob_maxsize(struct unit_test_state *uts) return 0; } -BLOBLIST_TEST(bloblist_test_blob_maxsize, 0); +BLOBLIST_TEST(bloblist_test_blob_maxsize, UFT_BLOBLIST); int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 0d4e966892e..2f859c40adb 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -370,7 +370,7 @@ static int bootflow_iter(struct unit_test_state *uts) return 0; } -BOOTSTD_TEST(bootflow_iter, UTF_DM | UTF_SCAN_FDT); +BOOTSTD_TEST(bootflow_iter, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE); #if defined(CONFIG_SANDBOX) && defined(CONFIG_BOOTMETH_GLOBAL) /* Check using the system bootdev */ @@ -542,7 +542,7 @@ static int prep_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev, /* Enable the script bootmeth too */ ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd)); ut_assertok(device_bind(bootstd, DM_DRIVER_REF(bootmeth_2script), - "bootmeth_script", 0, ofnode_null(), &dev)); + "script", 0, ofnode_null(), &dev)); /* Enable the cros bootmeth if needed */ if (IS_ENABLED(CONFIG_BOOTMETH_CROS) && bind_cros_android) { diff --git a/test/cmd/Makefile b/test/cmd/Makefile index fe7a2165af2..0055330dbec 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -15,6 +15,7 @@ obj-y += exit.o mem.o obj-$(CONFIG_X86) += cpuid.o msr.o obj-$(CONFIG_CMD_ADDRMAP) += addrmap.o obj-$(CONFIG_CMD_BDI) += bdinfo.o +obj-$(CONFIG_COREBOOT_SYSINFO) += coreboot.o obj-$(CONFIG_CMD_FDT) += fdt.o obj-$(CONFIG_CONSOLE_TRUETYPE) += font.o obj-$(CONFIG_CMD_HISTORY) += history.o diff --git a/test/cmd/coreboot.c b/test/cmd/coreboot.c new file mode 100644 index 00000000000..a99898d15c4 --- /dev/null +++ b/test/cmd/coreboot.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for coreboot commands + * + * Copyright 2023 Google LLC + * Written by Simon Glass <sjg@chromium.org> + */ + +#include <cedit.h> +#include <command.h> +#include <dm.h> +#include <expo.h> +#include <rtc.h> +#include <test/cedit-test.h> +#include <test/cmd.h> +#include <test/test.h> +#include <test/ut.h> +#include "../../boot/scene_internal.h" + +enum { + CSUM_LOC = 0x3f0 / 8, +}; + +/** + * test_cmd_cbsysinfo() - test the cbsysinfo command produces expected output + * + * This includes ensuring that the coreboot build has the expected options + * enabled + */ +static int test_cmd_cbsysinfo(struct unit_test_state *uts) +{ + ut_assertok(run_command("cbsysinfo", 0)); + ut_assert_nextlinen("Coreboot table at"); + + /* Make sure CMOS options are enabled */ + ut_assert_skip_to_line( + " 1c0 1 e 1 power_on_after_fail 0:Disable 1:Enable"); + ut_assert_skip_to_line("CMOS start : 1c0"); + ut_assert_nextline(" CMOS end : 1cf"); + ut_assert_nextline(" CMOS csum loc: 3f0"); + + /* Make sure the linear frame buffer is enabled */ + ut_assert_skip_to_linen("Framebuffer"); + ut_assert_nextlinen(" Phys addr"); + + ut_assert_skip_to_line("Chrome OS VPD: 00000000"); + ut_assert_nextlinen("RSDP"); + ut_assert_nextlinen("Unimpl."); + ut_assert_console_end(); + + return 0; +} +CMD_TEST(test_cmd_cbsysinfo, UTF_CONSOLE); + +/* test cbcmos command */ +static int test_cmd_cbcmos(struct unit_test_state *uts) +{ + u16 old_csum, new_csum; + struct udevice *dev; + + /* initially the checksum should be correct */ + ut_assertok(run_command("cbcmos check", 0)); + ut_assert_console_end(); + + /* make a change to the checksum */ + ut_assertok(uclass_first_device_err(UCLASS_RTC, &dev)); + ut_assertok(rtc_read16(dev, CSUM_LOC, &old_csum)); + ut_assertok(rtc_write16(dev, CSUM_LOC, old_csum + 1)); + + /* now the command should fail */ + ut_asserteq(1, run_command("cbcmos check", 0)); + ut_assert_nextline("Checksum %04x error: calculated %04x", + old_csum + 1, old_csum); + ut_assert_console_end(); + + /* now get it to fix the checksum */ + ut_assertok(run_command("cbcmos update", 0)); + ut_assert_nextline("Checksum %04x written", old_csum); + ut_assert_console_end(); + + /* check the RTC looks right */ + ut_assertok(rtc_read16(dev, CSUM_LOC, &new_csum)); + ut_asserteq(old_csum, new_csum); + ut_assert_console_end(); + + return 0; +} +CMD_TEST(test_cmd_cbcmos, UTF_CONSOLE); + +/* test 'cedit cb_load' command */ +static int test_cmd_cedit_cb_load(struct unit_test_state *uts) +{ + struct scene_obj_menu *menu; + struct video_priv *vid_priv; + struct scene_obj_txt *txt; + struct scene *scn; + struct expo *exp; + int scn_id; + + ut_assertok(run_command("cedit cb_load", 0)); + ut_assertok(run_command("cedit read_cmos", 0)); + ut_assert_console_end(); + + exp = cur_exp; + scn_id = cedit_prepare(exp, &vid_priv, &scn); + ut_assert(scn_id > 0); + ut_assertnonnull(scn); + + /* just do a very basic test that the first menu is present */ + menu = scene_obj_find(scn, scn->highlight_id, SCENEOBJT_NONE); + ut_assertnonnull(menu); + + txt = scene_obj_find(scn, menu->title_id, SCENEOBJT_NONE); + ut_assertnonnull(txt); + ut_asserteq_str("Boot option", expo_get_str(exp, txt->str_id)); + + return 0; +} +CMD_TEST(test_cmd_cedit_cb_load, UTF_CONSOLE); diff --git a/test/dm/core.c b/test/dm/core.c index e0c5b9e0017..7371d3ff426 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -1351,3 +1351,25 @@ static int dm_test_dev_get_mem(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_dev_get_mem, UTF_SCAN_FDT); + +/* Test uclass_try_first_device() */ +static int dm_test_try_first_device(struct unit_test_state *uts) +{ + struct udevice *dev; + + /* Check that it doesn't create a device or uclass */ + ut_assertnull(uclass_find(UCLASS_TEST)); + ut_assertnull(uclass_try_first_device(UCLASS_TEST)); + ut_assertnull(uclass_try_first_device(UCLASS_TEST)); + ut_assertnull(uclass_find(UCLASS_TEST)); + + /* Create a test device */ + ut_assertok(device_bind_by_name(uts->root, false, &driver_info_manual, + &dev)); + dev = uclass_try_first_device(UCLASS_TEST); + ut_assertnonnull(dev); + ut_asserteq(UCLASS_TEST, device_get_uclass_id(dev)); + + return 0; +} +DM_TEST(dm_test_try_first_device, 0); diff --git a/test/lib/alist.c b/test/lib/alist.c index d41845c7e6c..0bf24578d2e 100644 --- a/test/lib/alist.c +++ b/test/lib/alist.c @@ -240,3 +240,256 @@ static int lib_test_alist_add(struct unit_test_state *uts) return 0; } LIB_TEST(lib_test_alist_add, 0); + +/* Test alist_next() */ +static int lib_test_alist_next(struct unit_test_state *uts) +{ + const struct my_struct *ptr; + struct my_struct data, *ptr2; + struct alist lst; + ulong start; + + start = ut_check_free(); + + ut_assert(alist_init_struct(&lst, struct my_struct)); + data.val = 123; + data.other_val = 0; + alist_add(&lst, data); + + data.val = 321; + alist_add(&lst, data); + + data.val = 789; + alist_add(&lst, data); + + ptr = alist_get(&lst, 0, struct my_struct); + ut_assertnonnull(ptr); + ut_asserteq(123, ptr->val); + + ptr = alist_next(&lst, ptr); + ut_assertnonnull(ptr); + ut_asserteq(321, ptr->val); + + ptr2 = (struct my_struct *)ptr; + ptr2 = alist_nextw(&lst, ptr2); + ut_assertnonnull(ptr2); + + ptr = alist_next(&lst, ptr); + ut_assertnonnull(ptr); + ut_asserteq(789, ptr->val); + ut_asserteq_ptr(ptr, ptr2); + ptr2->val = 89; + ut_asserteq(89, ptr->val); + + ptr = alist_next(&lst, ptr); + ut_assertnull(ptr); + + alist_uninit(&lst); + + /* Check for memory leaks */ + ut_assertok(ut_check_delta(start)); + + return 0; +} +LIB_TEST(lib_test_alist_next, 0); + +/* Test alist_for_each() */ +static int lib_test_alist_for_each(struct unit_test_state *uts) +{ + const struct my_struct *ptr; + struct my_struct data, *ptr2; + struct alist lst; + ulong start; + int sum; + + start = ut_check_free(); + + ut_assert(alist_init_struct(&lst, struct my_struct)); + ut_asserteq_ptr(NULL, alist_end(&lst, struct my_struct)); + + sum = 0; + alist_for_each(ptr, &lst) + sum++; + ut_asserteq(0, sum); + + alist_for_each(ptr, &lst) + sum++; + ut_asserteq(0, sum); + + /* add three items */ + data.val = 1; + data.other_val = 0; + alist_add(&lst, data); + + ptr = lst.data; + ut_asserteq_ptr(ptr + 1, alist_end(&lst, struct my_struct)); + + data.val = 2; + alist_add(&lst, data); + ut_asserteq_ptr(ptr + 2, alist_end(&lst, struct my_struct)); + + data.val = 3; + alist_add(&lst, data); + ut_asserteq_ptr(ptr + 3, alist_end(&lst, struct my_struct)); + + /* check alist_chk_ptr() */ + ut_asserteq(true, alist_chk_ptr(&lst, ptr + 2)); + ut_asserteq(false, alist_chk_ptr(&lst, ptr + 3)); + ut_asserteq(false, alist_chk_ptr(&lst, ptr + 4)); + ut_asserteq(true, alist_chk_ptr(&lst, ptr)); + ut_asserteq(false, alist_chk_ptr(&lst, ptr - 1)); + + /* sum all items */ + sum = 0; + alist_for_each(ptr, &lst) + sum += ptr->val; + ut_asserteq(6, sum); + + /* increment all items */ + alist_for_each(ptr2, &lst) + ptr2->val += 1; + + /* sum all items again */ + sum = 0; + alist_for_each(ptr, &lst) + sum += ptr->val; + ut_asserteq(9, sum); + + ptr = lst.data; + ut_asserteq_ptr(ptr + 3, alist_end(&lst, struct my_struct)); + + /* empty the list and try again */ + alist_empty(&lst); + ut_asserteq_ptr(ptr, alist_end(&lst, struct my_struct)); + ut_assertnull(alist_get(&lst, 0, struct my_struct)); + + sum = 0; + alist_for_each(ptr, &lst) + sum += ptr->val; + ut_asserteq(0, sum); + + alist_uninit(&lst); + + /* Check for memory leaks */ + ut_assertok(ut_check_delta(start)); + + return 0; +} +LIB_TEST(lib_test_alist_for_each, 0); + +/* Test alist_empty() */ +static int lib_test_alist_empty(struct unit_test_state *uts) +{ + struct my_struct data; + struct alist lst; + ulong start; + + start = ut_check_free(); + + ut_assert(alist_init_struct(&lst, struct my_struct)); + ut_asserteq(0, lst.count); + data.val = 1; + data.other_val = 0; + alist_add(&lst, data); + ut_asserteq(1, lst.count); + ut_asserteq(4, lst.alloc); + + alist_empty(&lst); + ut_asserteq(0, lst.count); + ut_asserteq(4, lst.alloc); + ut_assertnonnull(lst.data); + ut_asserteq(sizeof(data), lst.obj_size); + + alist_uninit(&lst); + + /* Check for memory leaks */ + ut_assertok(ut_check_delta(start)); + + return 0; +} +LIB_TEST(lib_test_alist_empty, 0); + +static int lib_test_alist_filter(struct unit_test_state *uts) +{ + struct my_struct *from, *to, *ptr; + struct my_struct data; + struct alist lst; + ulong start; + int count; + + start = ut_check_free(); + + ut_assert(alist_init_struct(&lst, struct my_struct)); + data.val = 1; + data.other_val = 0; + alist_add(&lst, data); + + data.val = 2; + alist_add(&lst, data); + + data.val = 3; + alist_add(&lst, data); + ptr = lst.data; + + /* filter out all values except 2 */ + alist_for_each_filter(from, to, &lst) { + if (from->val != 2) + *to++ = *from; + } + alist_update_end(&lst, to); + + ut_asserteq(2, lst.count); + ut_assertnonnull(lst.data); + + ut_asserteq(1, alist_get(&lst, 0, struct my_struct)->val); + ut_asserteq(3, alist_get(&lst, 1, struct my_struct)->val); + ut_asserteq_ptr(ptr + 3, from); + ut_asserteq_ptr(ptr + 2, to); + + /* filter out nothing */ + alist_for_each_filter(from, to, &lst) { + if (from->val != 2) + *to++ = *from; + } + alist_update_end(&lst, to); + ut_asserteq_ptr(ptr + 2, from); + ut_asserteq_ptr(ptr + 2, to); + + ut_asserteq(2, lst.count); + ut_assertnonnull(lst.data); + + ut_asserteq(1, alist_get(&lst, 0, struct my_struct)->val); + ut_asserteq(3, alist_get(&lst, 1, struct my_struct)->val); + + /* filter out everything */ + alist_for_each_filter(from, to, &lst) { + if (from->val == 2) + *to++ = *from; + } + alist_update_end(&lst, to); + ut_asserteq_ptr(ptr + 2, from); + ut_asserteq_ptr(ptr, to); + + /* filter out everything (nop) */ + count = 0; + alist_for_each_filter(from, to, &lst) { + if (from->val == 2) + *to++ = *from; + count++; + } + alist_update_end(&lst, to); + ut_asserteq_ptr(ptr, from); + ut_asserteq_ptr(ptr, to); + ut_asserteq(0, count); + + ut_asserteq(0, lst.count); + ut_assertnonnull(lst.data); + + alist_uninit(&lst); + + /* Check for memory leaks */ + ut_assertok(ut_check_delta(start)); + + return 0; +} +LIB_TEST(lib_test_alist_filter, 0); diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index 39aa1035e34..9166c8f6b6e 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -208,8 +208,6 @@ booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r} cons, f'echo here {kernel} {symlink}') os.symlink(kernel, symlink) - u_boot_utils.run_and_log( - cons, f'mkimage -C none -A arm -T script -d {cmd_fname} {scr_fname}') complete = True except ValueError as exc: diff --git a/test/test-main.c b/test/test-main.c index da5b07ce00b..7a1f74a2c84 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -4,6 +4,8 @@ * Written by Simon Glass <sjg@chromium.org> */ +#define LOG_CATEGORY LOGC_TEST + #include <blk.h> #include <console.h> #include <cyclic.h> @@ -240,15 +242,22 @@ static bool test_matches(const char *prefix, const char *test_name, * ut_list_has_dm_tests() - Check if a list of tests has driver model ones * * @tests: List of tests to run - * @count: Number of tests to ru + * @count: Number of tests to run + * @prefix: String prefix for the tests. Any tests that have this prefix will be + * printed without the prefix, so that it is easier to see the unique part + * of the test name. If NULL, no prefix processing is done + * @select_name: Name of a single test being run (from the list provided). If + * NULL all tests are being run * Return: true if any of the tests have the UTF_DM flag */ -static bool ut_list_has_dm_tests(struct unit_test *tests, int count) +static bool ut_list_has_dm_tests(struct unit_test *tests, int count, + const char *prefix, const char *select_name) { struct unit_test *test; for (test = tests; test < tests + count; test++) { - if (test->flags & UTF_DM) + if (test_matches(prefix, test->name, select_name) && + (test->flags & UTF_DM)) return true; } @@ -379,6 +388,12 @@ static int test_pre_run(struct unit_test_state *uts, struct unit_test *test) return -EAGAIN; } } + if (test->flags & UFT_BLOBLIST) { + log_debug("save bloblist %p\n", gd_bloblist()); + uts->old_bloblist = gd_bloblist(); + gd_set_bloblist(NULL); + } + ut_silence_console(uts); return 0; @@ -402,6 +417,11 @@ static int test_post_run(struct unit_test_state *uts, struct unit_test *test) free(uts->of_other); uts->of_other = NULL; + if (test->flags & UFT_BLOBLIST) { + gd_set_bloblist(uts->old_bloblist); + log_debug("restore bloblist %p\n", gd_bloblist()); + } + blkcache_free(); return 0; @@ -550,6 +570,9 @@ static int ut_run_test_live_flat(struct unit_test_state *uts, * @count: Number of tests to run * @select_name: Name of a single test to run (from the list provided). If NULL * then all tests are run + * @test_insert: String describing a test to run after n other tests run, in the + * format n:name where n is the number of tests to run before this one and + * name is the name of the test to run * Return: 0 if all tests passed, -ENOENT if test @select_name was not found, * -EBADF if any failed */ @@ -646,7 +669,7 @@ int ut_run_list(const char *category, const char *prefix, int ret; if (!CONFIG_IS_ENABLED(OF_PLATDATA) && - ut_list_has_dm_tests(tests, count)) { + ut_list_has_dm_tests(tests, count, prefix, select_name)) { has_dm_tests = true; /* * If we have no device tree, or it only has a root node, then |