CI: https://source.denx.de/u-boot/custodians/u-boot-dm/-/pipelines/23152
CI: https://dev.azure.com/simon0972/u-boot/_build/results?buildId=71&view=results

- alist enhancements and fixes
- minor test and sandbox fixes
- some more x86/coreboot patches
This commit is contained in:
Tom Rini 2024-11-03 17:23:29 -06:00
commit bf066dc3eb
41 changed files with 1521 additions and 65 deletions

View File

@ -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>

View File

@ -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();

View File

@ -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 */

View File

@ -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)

View File

@ -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 {

View File

@ -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

245
boot/expo_build_cb.c Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -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) {

View File

@ -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),

View File

@ -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));

View File

@ -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

139
cmd/x86/cbcmos.c Normal file
View File

@ -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));

View File

@ -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) {

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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`.

View File

@ -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`.

45
doc/usage/cmd/cbcmos.rst Normal file
View File

@ -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.

View File

@ -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.

View File

@ -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
=>

79
doc/usage/cmd/sb.rst Normal file
View File

@ -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.

View File

@ -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

View File

@ -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;

View File

@ -71,6 +71,21 @@ static inline bool alist_has(struct alist *lst, uint index)
return index < lst->count;
}
/**
* 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
*
@ -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)

View File

@ -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)

View File

@ -435,6 +435,17 @@ int uclass_next_device_check(struct udevice **devp);
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
*

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */
};
/**

View File

@ -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;

View File

@ -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[])

View File

@ -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) {

View File

@ -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

119
test/cmd/coreboot.c Normal file
View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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:

View File

@ -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