summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS7
-rw-r--r--arch/sandbox/cpu/cpu.c13
-rw-r--r--arch/sandbox/include/asm/cpu.h3
-rw-r--r--arch/sandbox/include/asm/io.h2
-rw-r--r--arch/x86/dts/coreboot.dts7
-rw-r--r--boot/Makefile3
-rw-r--r--boot/expo_build_cb.c245
-rw-r--r--cmd/Kconfig11
-rw-r--r--cmd/bootflow.c9
-rw-r--r--cmd/cedit.c28
-rw-r--r--cmd/sb.c42
-rw-r--r--cmd/x86/Makefile1
-rw-r--r--cmd/x86/cbcmos.c139
-rw-r--r--cmd/x86/cbsysinfo.c73
-rw-r--r--common/bootstage.c12
-rw-r--r--common/log.c1
-rw-r--r--configs/coreboot64_defconfig2
-rw-r--r--configs/coreboot_defconfig2
-rw-r--r--doc/board/coreboot/coreboot.rst6
-rw-r--r--doc/develop/cedit.rst2
-rw-r--r--doc/usage/cmd/cbcmos.rst45
-rw-r--r--doc/usage/cmd/cbsysinfo.rst99
-rw-r--r--doc/usage/cmd/cedit.rst76
-rw-r--r--doc/usage/cmd/sb.rst79
-rw-r--r--doc/usage/index.rst2
-rw-r--r--drivers/core/uclass.c11
-rw-r--r--include/alist.h139
-rw-r--r--include/asm-generic/global_data.h2
-rw-r--r--include/dm/uclass.h11
-rw-r--r--include/expo.h8
-rw-r--r--include/log.h2
-rw-r--r--include/test/test.h3
-rw-r--r--lib/alist.c41
-rw-r--r--test/bloblist.c28
-rw-r--r--test/boot/bootflow.c4
-rw-r--r--test/cmd/Makefile1
-rw-r--r--test/cmd/coreboot.c119
-rw-r--r--test/dm/core.c22
-rw-r--r--test/lib/alist.c253
-rw-r--r--test/py/tests/test_ut.py2
-rw-r--r--test/test-main.c31
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),
diff --git a/cmd/sb.c b/cmd/sb.c
index db485fddfca..9245052492e 100644
--- a/cmd/sb.c
+++ b/cmd/sb.c
@@ -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