Merge patch series "bootstd: Support recording images"

Simon Glass <sjg@chromium.org> says:

This series provides a way to keep track of the images used in bootstd,
including the type of each image.

At present this is sort-of handled by struct bootflow but in quite an
ad-hoc way. The structure has become quite large and is hard to query.
Future work will be able to reduce its size.

Ultimately the 'bootflow info' command may change to also show images as
a list, but that is left for later, as this series is already fairly
long. So for now, just introduce the concept and adjust bootstd to use
it, with a simple command to list the images.

This series includes various alist enhancements, to make use of this new
data structure a little easier.

[trini: Drop patch 18 and 19 for now due to size considerations]

Link: https://lore.kernel.org/r/20241115231926.211999-1-sjg@chromium.org
This commit is contained in:
Tom Rini 2025-01-15 17:34:26 -06:00
commit 178f6ecb21
32 changed files with 685 additions and 178 deletions

View file

@ -33,55 +33,38 @@ enum {
BOOT_TARGETS_MAX_LEN = 100,
};
int bootdev_add_bootflow(struct bootflow *bflow)
int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp)
{
struct bootstd_priv *std;
struct bootflow *new;
struct bootflow *bflow;
int ret;
ret = bootstd_get_priv(&std);
if (ret)
return ret;
return log_msg_ret("bff", ret);
new = malloc(sizeof(*bflow));
if (!new)
return log_msg_ret("bflow", -ENOMEM);
memcpy(new, bflow, sizeof(*bflow));
list_add_tail(&new->glob_node, &std->glob_head);
if (bflow->dev) {
struct bootdev_uc_plat *ucp = dev_get_uclass_plat(bflow->dev);
list_add_tail(&new->bm_node, &ucp->bootflow_head);
}
return 0;
}
int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp)
{
struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
if (list_empty(&ucp->bootflow_head))
bflow = alist_getw(&std->bootflows, 0, struct bootflow);
if (!bflow)
return -ENOENT;
*bflowp = list_first_entry(&ucp->bootflow_head, struct bootflow,
bm_node);
*bflowp = bflow;
return 0;
}
int bootdev_next_bootflow(struct bootflow **bflowp)
{
struct bootflow *bflow = *bflowp;
struct bootdev_uc_plat *ucp = dev_get_uclass_plat(bflow->dev);
struct bootstd_priv *std;
struct bootflow *bflow;
int ret;
*bflowp = NULL;
ret = bootstd_get_priv(&std);
if (ret)
return log_msg_ret("bff", ret);
if (list_is_last(&bflow->bm_node, &ucp->bootflow_head))
bflow = alist_nextw(&std->bootflows, *bflowp);
if (!bflow)
return -ENOENT;
*bflowp = list_entry(bflow->bm_node.next, struct bootflow, bm_node);
*bflowp = bflow;
return 0;
}
@ -342,7 +325,7 @@ int bootdev_get_sibling_blk(struct udevice *dev, struct udevice **blkp)
return 0;
}
static int bootdev_get_from_blk(struct udevice *blk, struct udevice **bootdevp)
int bootdev_get_from_blk(struct udevice *blk, struct udevice **bootdevp)
{
struct udevice *parent = dev_get_parent(blk);
struct udevice *bootdev;
@ -588,19 +571,6 @@ int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
return ops->get_bootflow(dev, iter, bflow);
}
void bootdev_clear_bootflows(struct udevice *dev)
{
struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
while (!list_empty(&ucp->bootflow_head)) {
struct bootflow *bflow;
bflow = list_first_entry(&ucp->bootflow_head, struct bootflow,
bm_node);
bootflow_remove(bflow);
}
}
int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp,
int *method_flagsp)
{
@ -955,18 +925,13 @@ void bootdev_list_hunters(struct bootstd_priv *std)
printf("(total hunters: %d)\n", n_ent);
}
static int bootdev_post_bind(struct udevice *dev)
{
struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
INIT_LIST_HEAD(&ucp->bootflow_head);
return 0;
}
static int bootdev_pre_unbind(struct udevice *dev)
{
bootdev_clear_bootflows(dev);
int ret;
ret = bootstd_clear_bootflows_for_bootdev(dev);
if (ret)
return log_msg_ret("bun", ret);
return 0;
}
@ -976,6 +941,5 @@ UCLASS_DRIVER(bootdev) = {
.name = "bootdev",
.flags = DM_UC_FLAG_SEQ_ALIAS,
.per_device_plat_auto = sizeof(struct bootdev_uc_plat),
.post_bind = bootdev_post_bind,
.pre_unbind = bootdev_pre_unbind,
};

View file

@ -23,6 +23,13 @@ enum {
BF_NO_MORE_DEVICES = -ENODEV,
};
static const char *const bootflow_img[BFI_COUNT - BFI_FIRST] = {
"extlinux_cfg",
"logo",
"efi",
"cmdline",
};
/**
* bootflow_state - name for each state
*
@ -55,11 +62,10 @@ int bootflow_first_glob(struct bootflow **bflowp)
if (ret)
return ret;
if (list_empty(&std->glob_head))
if (!std->bootflows.count)
return -ENOENT;
*bflowp = list_first_entry(&std->glob_head, struct bootflow,
glob_node);
*bflowp = alist_getw(&std->bootflows, 0, struct bootflow);
return 0;
}
@ -67,20 +73,16 @@ int bootflow_first_glob(struct bootflow **bflowp)
int bootflow_next_glob(struct bootflow **bflowp)
{
struct bootstd_priv *std;
struct bootflow *bflow = *bflowp;
int ret;
ret = bootstd_get_priv(&std);
if (ret)
return ret;
*bflowp = NULL;
if (list_is_last(&bflow->glob_node, &std->glob_head))
*bflowp = alist_nextw(&std->bootflows, *bflowp);
if (!*bflowp)
return -ENOENT;
*bflowp = list_entry(bflow->glob_node.next, struct bootflow, glob_node);
return 0;
}
@ -460,10 +462,13 @@ void bootflow_init(struct bootflow *bflow, struct udevice *bootdev,
bflow->dev = bootdev;
bflow->method = meth;
bflow->state = BOOTFLOWST_BASE;
alist_init_struct(&bflow->images, struct bootflow_img);
}
void bootflow_free(struct bootflow *bflow)
{
struct bootflow_img *img;
free(bflow->name);
free(bflow->subdir);
free(bflow->fname);
@ -472,16 +477,15 @@ void bootflow_free(struct bootflow *bflow)
free(bflow->os_name);
free(bflow->fdt_fname);
free(bflow->bootmeth_priv);
alist_for_each(img, &bflow->images)
free(img->fname);
alist_empty(&bflow->images);
}
void bootflow_remove(struct bootflow *bflow)
{
if (bflow->dev)
list_del(&bflow->bm_node);
list_del(&bflow->glob_node);
bootflow_free(bflow);
free(bflow);
}
#if CONFIG_IS_ENABLED(BOOTSTD_FULL)
@ -960,3 +964,48 @@ int bootflow_cmdline_auto(struct bootflow *bflow, const char *arg)
return 0;
}
const char *bootflow_img_type_name(enum bootflow_img_t type)
{
const char *name;
if (type >= BFI_FIRST && type < BFI_COUNT)
name = bootflow_img[type - BFI_FIRST];
else
name = genimg_get_type_short_name(type);
return name;
}
struct bootflow_img *bootflow_img_add(struct bootflow *bflow, const char *fname,
enum bootflow_img_t type, ulong addr,
ulong size)
{
struct bootflow_img img, *ptr;
memset(&img, '\0', sizeof(struct bootflow_img));
img.fname = strdup(fname);
if (!img.fname)
return NULL;
img.type = type;
img.addr = addr;
img.size = size;
ptr = alist_add(&bflow->images, img);
if (!ptr)
return NULL;
return ptr;
}
int bootflow_get_seq(const struct bootflow *bflow)
{
struct bootstd_priv *std;
int ret;
ret = bootstd_get_priv(&std);
if (ret)
return ret;
return alist_calc_index(&std->bootflows, bflow);
}

View file

@ -6,6 +6,7 @@
#define LOG_CATEGORY UCLASS_BOOTSTD
#include <alist.h>
#include <blk.h>
#include <bootflow.h>
#include <bootmeth.h>
@ -83,14 +84,15 @@ int bootmeth_boot(struct udevice *dev, struct bootflow *bflow)
}
int bootmeth_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep)
const char *file_path, ulong addr,
enum bootflow_img_t type, ulong *sizep)
{
const struct bootmeth_ops *ops = bootmeth_get_ops(dev);
if (!ops->read_file)
return -ENOSYS;
return ops->read_file(dev, bflow, file_path, addr, sizep);
return ops->read_file(dev, bflow, file_path, addr, type, sizep);
}
int bootmeth_get_bootflow(struct udevice *dev, struct bootflow *bflow)
@ -326,8 +328,10 @@ int bootmeth_try_file(struct bootflow *bflow, struct blk_desc *desc,
return 0;
}
int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align)
int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align,
enum bootflow_img_t type)
{
struct blk_desc *desc = NULL;
void *buf;
uint size;
int ret;
@ -344,11 +348,18 @@ int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align)
bflow->state = BOOTFLOWST_READY;
bflow->buf = buf;
if (bflow->blk)
desc = dev_get_uclass_plat(bflow->blk);
if (!bootflow_img_add(bflow, bflow->fname, type, map_to_sysmem(buf),
size))
return log_msg_ret("bai", -ENOMEM);
return 0;
}
int bootmeth_alloc_other(struct bootflow *bflow, const char *fname,
void **bufp, uint *sizep)
enum bootflow_img_t type, void **bufp, uint *sizep)
{
struct blk_desc *desc = NULL;
char path[200];
@ -377,6 +388,10 @@ int bootmeth_alloc_other(struct bootflow *bflow, const char *fname,
if (ret)
return log_msg_ret("all", ret);
if (!bootflow_img_add(bflow, bflow->fname, type, map_to_sysmem(buf),
size))
return log_msg_ret("boi", -ENOMEM);
*bufp = buf;
*sizep = size;
@ -384,7 +399,8 @@ int bootmeth_alloc_other(struct bootflow *bflow, const char *fname,
}
int bootmeth_common_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep)
const char *file_path, ulong addr,
enum bootflow_img_t type, ulong *sizep)
{
struct blk_desc *desc = NULL;
loff_t len_read;
@ -413,6 +429,9 @@ int bootmeth_common_read_file(struct udevice *dev, struct bootflow *bflow,
return ret;
*sizep = len_read;
if (!bootflow_img_add(bflow, bflow->fname, type, addr, size))
return log_msg_ret("bci", -ENOMEM);
return 0;
}

View file

@ -323,7 +323,8 @@ static int android_read_bootflow(struct udevice *dev, struct bootflow *bflow)
}
static int android_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep)
const char *file_path, ulong addr,
enum bootflow_img_t type, ulong *sizep)
{
/*
* Reading individual files is not supported since we only

View file

@ -243,8 +243,17 @@ static int cros_read_buf(struct bootflow *bflow, void *buf, ulong size,
ret = copy_cmdline(map_sysmem(cmdline, 0), uuid, &bflow->cmdline);
if (ret)
return log_msg_ret("cmd", ret);
if (!bootflow_img_add(bflow, "setup",
(enum bootflow_img_t)IH_TYPE_X86_SETUP,
setup, 0x3000))
return log_msg_ret("cri", -ENOMEM);
bflow->x86_setup = map_sysmem(setup, 0);
if (!bootflow_img_add(bflow, "cmdline", BFI_CMDLINE, cmdline, 0x1000))
return log_msg_ret("crc", -ENOMEM);
return 0;
}
@ -306,6 +315,11 @@ static int cros_read_info(struct bootflow *bflow, const char *uuid,
}
priv->info_buf = buf;
if (!bootflow_img_add(bflow, "kernel",
(enum bootflow_img_t)IH_TYPE_KERNEL, 0,
priv->body_size))
return log_msg_ret("crk", -ENOMEM);
return 0;
}
@ -400,7 +414,8 @@ static int cros_read_bootflow(struct udevice *dev, struct bootflow *bflow)
}
static int cros_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep)
const char *file_path, ulong addr,
enum bootflow_img_t type, ulong *sizep)
{
return -ENOSYS;
}

View file

@ -89,18 +89,17 @@ static void set_efi_bootdev(struct blk_desc *desc, struct bootflow *bflow)
static int efiload_read_file(struct bootflow *bflow, ulong addr)
{
struct blk_desc *desc = NULL;
loff_t bytes_read;
ulong size;
int ret;
if (bflow->blk)
desc = dev_get_uclass_plat(bflow->blk);
ret = bootmeth_setup_fs(bflow, desc);
if (ret)
return log_msg_ret("set", ret);
ret = fs_read(bflow->fname, addr, 0, bflow->size, &bytes_read);
size = SZ_1G;
ret = bootmeth_common_read_file(bflow->method, bflow, bflow->fname,
addr, BFI_EFI, &size);
if (ret)
return log_msg_ret("read", ret);
return log_msg_ret("rdf", ret);
bflow->buf = map_sysmem(addr, bflow->size);
set_efi_bootdev(desc, bflow);
@ -173,7 +172,8 @@ static int distro_efi_try_bootflow_files(struct udevice *dev,
/* Limit FDT files to 4MB */
size = SZ_4M;
ret = bootmeth_common_read_file(dev, bflow, fname,
fdt_addr, &size);
fdt_addr, (enum bootflow_img_t)IH_TYPE_FLATDT,
&size);
}
}
@ -252,6 +252,8 @@ static int distro_efi_read_bootflow_net(struct bootflow *bflow)
if (!bootfile_name)
return log_msg_ret("bootfile_name", ret);
bflow->fname = strdup(bootfile_name);
if (!bflow->fname)
return log_msg_ret("fi0", -ENOMEM);
/* do the hideous EFI hack */
efi_set_bootdev("Net", "", bflow->fname, map_sysmem(addr, 0),

View file

@ -74,7 +74,8 @@ static int efi_mgr_read_bootflow(struct udevice *dev, struct bootflow *bflow)
}
static int efi_mgr_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep)
const char *file_path, ulong addr,
enum bootflow_img_t type, ulong *sizep)
{
/* Files are loaded by the 'bootefi bootmgr' command */

View file

@ -69,7 +69,8 @@ static int extlinux_get_state_desc(struct udevice *dev, char *buf, int maxsize)
}
static int extlinux_getfile(struct pxe_context *ctx, const char *file_path,
char *file_addr, ulong *sizep)
char *file_addr, enum bootflow_img_t type,
ulong *sizep)
{
struct extlinux_info *info = ctx->userdata;
ulong addr;
@ -80,7 +81,7 @@ static int extlinux_getfile(struct pxe_context *ctx, const char *file_path,
/* Allow up to 1GB */
*sizep = 1 << 30;
ret = bootmeth_read_file(info->dev, info->bflow, file_path, addr,
sizep);
type, sizep);
if (ret)
return log_msg_ret("read", ret);
@ -160,7 +161,8 @@ static int extlinux_read_bootflow(struct udevice *dev, struct bootflow *bflow)
return log_msg_ret("try", ret);
size = bflow->size;
ret = bootmeth_alloc_file(bflow, 0x10000, ARCH_DMA_MINALIGN);
ret = bootmeth_alloc_file(bflow, 0x10000, ARCH_DMA_MINALIGN,
BFI_EXTLINUX_CFG);
if (ret)
return log_msg_ret("read", ret);

View file

@ -23,7 +23,8 @@
#include <pxe_utils.h>
static int extlinux_pxe_getfile(struct pxe_context *ctx, const char *file_path,
char *file_addr, ulong *sizep)
char *file_addr, enum bootflow_img_t type,
ulong *sizep)
{
struct extlinux_info *info = ctx->userdata;
ulong addr;
@ -34,7 +35,7 @@ static int extlinux_pxe_getfile(struct pxe_context *ctx, const char *file_path,
/* Allow up to 1GB */
*sizep = 1 << 30;
ret = bootmeth_read_file(info->dev, info->bflow, file_path, addr,
sizep);
type, sizep);
if (ret)
return log_msg_ret("read", ret);
@ -113,7 +114,7 @@ static int extlinux_pxe_read_bootflow(struct udevice *dev,
static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr,
ulong *sizep)
enum bootflow_img_t type, ulong *sizep)
{
char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
struct pxe_context *ctx = dev_get_priv(dev);
@ -134,6 +135,9 @@ static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow,
return log_msg_ret("spc", -ENOSPC);
*sizep = size;
if (!bootflow_img_add(bflow, file_path, type, addr, size))
return log_msg_ret("pxi", -ENOMEM);
return 0;
}

View file

@ -52,7 +52,8 @@ static int qfw_read_bootflow(struct udevice *dev, struct bootflow *bflow)
}
static int qfw_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep)
const char *file_path, ulong addr,
enum bootflow_img_t type, ulong *sizep)
{
return -ENOSYS;
}

View file

@ -27,7 +27,8 @@ static int sandbox_read_bootflow(struct udevice *dev, struct bootflow *bflow)
}
static int sandbox_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep)
const char *file_path, ulong addr,
enum bootflow_img_t type, ulong *sizep)
{
return -ENOSYS;
}

View file

@ -98,7 +98,8 @@ static int script_read_bootflow_file(struct udevice *bootstd,
if (!bflow->subdir)
return log_msg_ret("prefix", -ENOMEM);
ret = bootmeth_alloc_file(bflow, 0x10000, ARCH_DMA_MINALIGN);
ret = bootmeth_alloc_file(bflow, 0x10000, ARCH_DMA_MINALIGN,
(enum bootflow_img_t)IH_TYPE_SCRIPT);
if (ret)
return log_msg_ret("read", ret);
@ -106,8 +107,8 @@ static int script_read_bootflow_file(struct udevice *bootstd,
if (ret)
return log_msg_ret("inf", ret);
ret = bootmeth_alloc_other(bflow, "boot.bmp", &bflow->logo,
&bflow->logo_size);
ret = bootmeth_alloc_other(bflow, "boot.bmp", BFI_LOGO,
&bflow->logo, &bflow->logo_size);
/* ignore error */
return 0;

View file

@ -6,6 +6,7 @@
* Written by Simon Glass <sjg@chromium.org>
*/
#include <alist.h>
#include <bootflow.h>
#include <bootstd.h>
#include <dm.h>
@ -42,13 +43,11 @@ static int bootstd_of_to_plat(struct udevice *dev)
static void bootstd_clear_glob_(struct bootstd_priv *priv)
{
while (!list_empty(&priv->glob_head)) {
struct bootflow *bflow;
struct bootflow *bflow;
bflow = list_first_entry(&priv->glob_head, struct bootflow,
glob_node);
alist_for_each(bflow, &priv->bootflows)
bootflow_remove(bflow);
}
alist_empty(&priv->bootflows);
}
void bootstd_clear_glob(void)
@ -61,6 +60,44 @@ void bootstd_clear_glob(void)
bootstd_clear_glob_(std);
}
int bootstd_add_bootflow(struct bootflow *bflow)
{
struct bootstd_priv *std;
int ret;
ret = bootstd_get_priv(&std);
if (ret)
return ret;
ret = std->bootflows.count;
bflow = alist_add(&std->bootflows, *bflow);
if (!bflow)
return log_msg_ret("bf2", -ENOMEM);
return ret;
}
int bootstd_clear_bootflows_for_bootdev(struct udevice *dev)
{
struct bootstd_priv *std = bootstd_try_priv();
struct bootflow *from, *to;
/* if bootstd does not exist we cannot have any bootflows */
if (!std)
return 0;
/* Drop any bootflows that mention this dev */
alist_for_each_filter(from, to, &std->bootflows) {
if (from->dev == dev)
bootflow_remove(from);
else
*to++ = *from;
}
alist_update_end(&std->bootflows, to);
return 0;
}
static int bootstd_remove(struct udevice *dev)
{
struct bootstd_priv *priv = dev_get_priv(dev);
@ -100,6 +137,17 @@ const char *const *const bootstd_get_prefixes(struct udevice *dev)
return std->prefixes ? std->prefixes : default_prefixes;
}
struct bootstd_priv *bootstd_try_priv(void)
{
struct udevice *dev;
dev = uclass_try_first_device(UCLASS_BOOTSTD);
if (!dev || !device_active(dev))
return NULL;
return dev_get_priv(dev);
}
int bootstd_get_priv(struct bootstd_priv **stdp)
{
struct udevice *dev;
@ -117,7 +165,7 @@ static int bootstd_probe(struct udevice *dev)
{
struct bootstd_priv *std = dev_get_priv(dev);
INIT_LIST_HEAD(&std->glob_head);
alist_init_struct(&std->bootflows, struct bootflow);
return 0;
}

View file

@ -6,6 +6,7 @@
#define LOG_CATEGORY LOGC_BOOT
#include <bootflow.h>
#include <command.h>
#include <dm.h>
#include <env.h>
@ -97,7 +98,8 @@ int format_mac_pxe(char *outbuf, size_t outbuf_len)
* Returns 1 for success, or < 0 on error
*/
static int get_relfile(struct pxe_context *ctx, const char *file_path,
unsigned long file_addr, ulong *filesizep)
unsigned long file_addr, enum bootflow_img_t type,
ulong *filesizep)
{
size_t path_len;
char relfile[MAX_TFTP_PATH_LEN + 1];
@ -124,7 +126,7 @@ static int get_relfile(struct pxe_context *ctx, const char *file_path,
sprintf(addr_buf, "%lx", file_addr);
ret = ctx->getfile(ctx, relfile, addr_buf, &size);
ret = ctx->getfile(ctx, relfile, addr_buf, type, &size);
if (ret < 0)
return log_msg_ret("get", ret);
if (filesizep)
@ -133,16 +135,6 @@ static int get_relfile(struct pxe_context *ctx, const char *file_path,
return 1;
}
/**
* get_pxe_file() - read a file
*
* The file is read and nul-terminated
*
* @ctx: PXE context
* @file_path: File path to read (relative to the PXE file)
* @file_addr: Address to load file to
* Returns 1 for success, or < 0 on error
*/
int get_pxe_file(struct pxe_context *ctx, const char *file_path,
ulong file_addr)
{
@ -150,7 +142,8 @@ int get_pxe_file(struct pxe_context *ctx, const char *file_path,
int err;
char *buf;
err = get_relfile(ctx, file_path, file_addr, &size);
err = get_relfile(ctx, file_path, file_addr, BFI_EXTLINUX_CFG,
&size);
if (err < 0)
return err;
@ -199,13 +192,15 @@ int get_pxelinux_path(struct pxe_context *ctx, const char *file,
* @file_path: File path to read (relative to the PXE file)
* @envaddr_name: Name of environment variable which contains the address to
* load to
* @type: File type
* @filesizep: Returns the file size in bytes
* Returns 1 on success, -ENOENT if @envaddr_name does not exist as an
* environment variable, -EINVAL if its format is not valid hex, or other
* value < 0 on other error
*/
static int get_relfile_envaddr(struct pxe_context *ctx, const char *file_path,
const char *envaddr_name, ulong *filesizep)
const char *envaddr_name,
enum bootflow_img_t type, ulong *filesizep)
{
unsigned long file_addr;
char *envaddr;
@ -217,7 +212,7 @@ static int get_relfile_envaddr(struct pxe_context *ctx, const char *file_path,
if (strict_strtoul(envaddr, 16, &file_addr) < 0)
return -EINVAL;
return get_relfile(ctx, file_path, file_addr, filesizep);
return get_relfile(ctx, file_path, file_addr, type, filesizep);
}
/**
@ -405,6 +400,7 @@ static void label_boot_fdtoverlay(struct pxe_context *ctx,
/* Load overlay file */
err = get_relfile_envaddr(ctx, overlayfile, "fdtoverlay_addr_r",
(enum bootflow_img_t)IH_TYPE_FLATDT,
NULL);
if (err < 0) {
printf("Failed loading overlay %s\n", overlayfile);
@ -490,7 +486,8 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
}
if (get_relfile_envaddr(ctx, label->kernel, "kernel_addr_r",
NULL) < 0) {
(enum bootflow_img_t)IH_TYPE_KERNEL, NULL)
< 0) {
printf("Skipping %s for failure retrieving kernel\n",
label->name);
return 1;
@ -516,6 +513,7 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
} else if (label->initrd) {
ulong size;
if (get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r",
(enum bootflow_img_t)IH_TYPE_RAMDISK,
&size) < 0) {
printf("Skipping %s for failure retrieving initrd\n",
label->name);
@ -661,7 +659,8 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
if (fdtfile) {
int err = get_relfile_envaddr(ctx, fdtfile,
"fdt_addr_r", NULL);
"fdt_addr_r",
(enum bootflow_img_t)IH_TYPE_FLATDT, NULL);
free(fdtfilefree);
if (err < 0) {
@ -1548,7 +1547,8 @@ void handle_pxe_menu(struct pxe_context *ctx, struct pxe_menu *cfg)
if (IS_ENABLED(CONFIG_CMD_BMP)) {
/* display BMP if available */
if (cfg->bmp) {
if (get_relfile(ctx, cfg->bmp, image_load_addr, NULL)) {
if (get_relfile(ctx, cfg->bmp, image_load_addr,
BFI_LOGO, NULL)) {
#if defined(CONFIG_VIDEO)
struct udevice *dev;

View file

@ -160,13 +160,14 @@ static int vbe_simple_read_bootflow(struct udevice *dev, struct bootflow *bflow)
}
static int vbe_simple_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep)
const char *file_path, ulong addr,
enum bootflow_img_t type, ulong *sizep)
{
int ret;
if (vbe_phase() == VBE_PHASE_OS) {
ret = bootmeth_common_read_file(dev, bflow, file_path, addr,
sizep);
type, sizep);
if (ret)
return log_msg_ret("os", ret);
}

View file

@ -328,6 +328,15 @@ config CMD_BOOTMETH
This command is not necessary for bootstd to work.
config CMD_BOOTSTD
bool "bootstd"
depends on BOOTSTD
default y if BOOTSTD_FULL
help
Provide general information and control for bootstd.
This command is not necessary for bootstd to work.
config BOOTM_EFI
bool "Support booting UEFI FIT images"
depends on EFI_BINARY_EXEC && CMD_BOOTM && FIT

View file

@ -23,6 +23,7 @@ obj-$(CONFIG_BLK) += blk_common.o
obj-$(CONFIG_CMD_BOOTDEV) += bootdev.o
obj-$(CONFIG_CMD_BOOTFLOW) += bootflow.o
obj-$(CONFIG_CMD_BOOTMETH) += bootmeth.o
obj-$(CONFIG_CMD_BOOTSTD) += bootstd.o
obj-$(CONFIG_CMD_SOURCE) += source.o
obj-$(CONFIG_CMD_BCB) += bcb.o
obj-$(CONFIG_CMD_BDI) += bdinfo.o

View file

@ -81,7 +81,7 @@ static int do_bootdev_info(struct cmd_tbl *cmdtp, int flag, int argc,
dev = priv->cur_bootdev;
/* Count the number of bootflows, including how many are valid*/
/* Count the number of bootflows, including how many are valid */
num_valid = 0;
for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
!ret;

View file

@ -197,7 +197,7 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
show_header();
}
if (dev)
bootdev_clear_bootflows(dev);
bootstd_clear_bootflows_for_bootdev(dev);
else
bootstd_clear_glob();
for (i = 0,
@ -207,8 +207,8 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
bflow.err = ret;
if (!ret)
num_valid++;
ret = bootdev_add_bootflow(&bflow);
if (ret) {
ret = bootstd_add_bootflow(&bflow);
if (ret < 0) {
printf("Out of memory\n");
return CMD_RET_FAILURE;
}

65
cmd/bootstd.c Normal file
View file

@ -0,0 +1,65 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* 'bootstd' command
*
* Copyright 2024 Google LLC
* Written by Simon Glass <sjg@chromium.org>
*/
#include <bootdev.h>
#include <bootflow.h>
#include <bootmeth.h>
#include <bootstd.h>
#include <command.h>
#include <dm.h>
#include <malloc.h>
#include <dm/uclass-internal.h>
static int do_bootstd_images(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
const struct bootflow *bflow;
struct bootstd_priv *std;
int ret, i;
ret = bootstd_get_priv(&std);
if (ret) {
printf("Cannot get bootstd (err=%d)\n", ret);
return CMD_RET_FAILURE;
}
printf("Seq Bootflow Type At Size Filename\n");
printf("--- ------------------- -------------- -------- -------- ----------------\n");
/*
* Use the ordering if we have one, so long as we are not trying to list
* all bootmethds
*/
i = 0;
alist_for_each(bflow, &std->bootflows) {
const struct bootflow_img *img;
alist_for_each(img, &bflow->images) {
printf("%3d %-20.20s %-15.15s ",
bootflow_get_seq(bflow), bflow->name,
bootflow_img_type_name(img->type));
if (img->addr)
printf("%8lx", img->addr);
else
printf("%8s", "-");
printf(" %8lx %s\n", img->size, img->fname);
i++;
}
}
printf("--- ------------------- -------------- -------- -------- ----------------\n");
printf("(%d image%s)\n", i, i != 1 ? "s" : "");
return 0;
}
U_BOOT_LONGHELP(bootstd,
"images - list loaded images");
U_BOOT_CMD_WITH_SUBCMDS(bootstd, "Standard-boot operation", bootstd_help_text,
U_BOOT_SUBCMD_MKENT(images, 1, 1, do_bootstd_images));

View file

@ -27,7 +27,7 @@ const char *pxe_default_paths[] = {
};
static int do_get_tftp(struct pxe_context *ctx, const char *file_path,
char *file_addr, ulong *sizep)
char *file_addr, enum bootflow_img_t type, ulong *sizep)
{
char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
int ret;

View file

@ -23,7 +23,8 @@ struct sysboot_info {
};
static int sysboot_read_file(struct pxe_context *ctx, const char *file_path,
char *file_addr, ulong *sizep)
char *file_addr, enum bootflow_img_t type,
ulong *sizep)
{
struct sysboot_info *info = ctx->userdata;
loff_t len_read;
@ -110,7 +111,8 @@ static int do_sysboot(struct cmd_tbl *cmdtp, int flag, int argc,
return CMD_RET_FAILURE;
}
if (get_pxe_file(&ctx, filename, pxefile_addr_r) < 0) {
if (get_pxe_file(&ctx, filename, pxefile_addr_r)
< 0) {
printf("Error reading config file\n");
pxe_destroy_ctx(&ctx);
return 1;

View file

@ -453,7 +453,7 @@ drivers are bound automatically.
Command interface
-----------------
Three commands are available:
Four commands are available:
`bootdev`
Allows listing of available bootdevs, selecting a particular one and
@ -468,6 +468,25 @@ Three commands are available:
Allow listing of available bootmethds, setting the order in which they are
tried and bootmeth specific configuration. See :doc:`/usage/cmd/bootmeth`
`bootstd`
Allow access to standard boot itself, so far only for listing images across
all bootflows. See :doc:`/usage/cmd/bootstd`
Images
------
Standard boot keeps track of images which can or have been loaded. These are
kept in a list attached to each bootflow. They can be listed using the
``bootstd images`` command (see :doc:`/usage/cmd/bootstd`).
For now most bootmeths load their images when scanning. Over time, some may
adjust to load them only when needed, but in this case the images will still
be visible.
Once a bootflow has been selected, images for those that are not selected can
potentially be dropped from the memory map. For now, this is not implemented.
.. _BootflowStates:
Bootflow states

79
doc/usage/cmd/bootstd.rst Normal file
View file

@ -0,0 +1,79 @@
.. SPDX-License-Identifier: GPL-2.0+:
.. index::
single: bootstd (command)
bootstd command
===============
Synopsis
--------
::
bootstd images
Description
-----------
The `bootstd` command is used to manage standard boot. At present the only
functionality available is to look at the images which have been loaded, or
could be loaded should a particular bootflow be selected.
See :doc:`/develop/bootstd/index` for more information.
bootflow images
~~~~~~~~~~~~~~~
Lists the available images and their location in memory.
Example
-------
This shows listing images attached to various bootflows, then checking the
content of a few of them::
=> bootflow scan
=> bootflow list
Showing all bootflows
Seq Method State Uclass Part Name Filename
--- ----------- ------ -------- ---- ------------------------ ----------------
0 extlinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf
1 script ready mmc 1 mmc4.bootdev.part_1 /boot/boot.scr
2 cros ready mmc 2 mmc5.bootdev.part_2
3 cros ready mmc 4 mmc5.bootdev.part_4
--- ----------- ------ -------- ---- ------------------------ ----------------
(4 bootflows, 4 valid)
=>
=> bootstd images
Seq Bootflow Type At Size Filename
--- ------------------- -------------- -------- -------- ----------------
0 mmc1.bootdev.part_1 extlinux_cfg 8ed5a70 253 /extlinux/extlinux.conf
1 mmc4.bootdev.part_1 script 8ed9550 c73 /boot/boot.scr
1 mmc4.bootdev.part_1 logo 8eda2a0 5d42 boot.bmp
2 mmc5.bootdev.part_2 x86_setup 8ee84d0 3000 setup
2 mmc5.bootdev.part_2 cmdline 8ee84d0 1000 cmdline
2 mmc5.bootdev.part_2 kernel - 4000 kernel
3 mmc5.bootdev.part_4 x86_setup 8eeb4e0 3000 setup
3 mmc5.bootdev.part_4 cmdline 8eeb4e0 1000 cmdline
3 mmc5.bootdev.part_4 kernel - 4000 kernel
--- ------------------- -------------- -------- -------- ----------------
(9 images)
=> md 8eda2a0 10
08eda2a0: 5d424d42 00000000 008a0000 007c0000 BMB]..........|.
08eda2b0: 00ac0000 002e0000 00010000 00000018 ................
08eda2c0: 5cb80000 0b130000 0b130000 00000000 ...\............
08eda2d0: 00000000 00000000 ff0000ff 00ff0000 ................
=> md 8ee84d0 10
08ee84d0: 544f4f42 414d495f 2f3d4547 696c6d76 BOOT_IMAGE=/vmli
08ee84e0: 2d7a756e 35312e35 312d302e 672d3132 nuz-5.15.0-121-g
08ee84f0: 72656e65 72206369 3d746f6f 7665642f eneric root=/dev
08ee8500: 6d766e2f 316e3065 72203170 7571206f /nvme0n1p1 ro qu
Return value
------------
The return value $? is always 0 (true).
.. BootflowStates_:

View file

@ -40,6 +40,7 @@ Shell commands
cmd/bootm
cmd/bootmenu
cmd/bootmeth
cmd/bootstd
cmd/bootz
cmd/button
cmd/cat

View file

@ -109,11 +109,9 @@ struct bootdev_hunter {
* This is attached to each device in the bootdev uclass and accessible via
* dev_get_uclass_plat(dev)
*
* @bootflows: List of available bootflows for this bootdev
* @piro: Priority of this bootdev
*/
struct bootdev_uc_plat {
struct list_head bootflow_head;
enum bootdev_prio_t prio;
};
@ -185,31 +183,6 @@ int bootdev_find_in_blk(struct udevice *dev, struct udevice *blk,
*/
void bootdev_list(bool probe);
/**
* bootdev_clear_bootflows() - Clear bootflows from a bootdev
*
* Each bootdev maintains a list of discovered bootflows. This provides a
* way to clear it. These bootflows are removed from the global list too.
*
* @dev: bootdev device to update
*/
void bootdev_clear_bootflows(struct udevice *dev);
/**
* bootdev_add_bootflow() - Add a bootflow to the bootdev's list
*
* All fields in @bflow must be set up. Note that @bflow->dev is used to add the
* bootflow to that device.
*
* @dev: Bootdev device to add to
* @bflow: Bootflow to add. Note that fields within bflow must be allocated
* since this function takes over ownership of these. This functions makes
* a copy of @bflow itself (without allocating its fields again), so the
* caller must dispose of the memory used by the @bflow pointer itself
* Return: 0 if OK, -ENOMEM if out of memory
*/
int bootdev_add_bootflow(struct bootflow *bflow);
/**
* bootdev_first_bootflow() - Get the first bootflow from a bootdev
*
@ -428,6 +401,15 @@ static int bootdev_setup_for_sibling_blk(struct udevice *blk,
*/
int bootdev_get_sibling_blk(struct udevice *dev, struct udevice **blkp);
/**
* bootdev_get_from_blk() - Get the bootdev given a block device
*
* @blk: Block device to check
* @bootdebp: Returns the bootdev found, if any
* Return 0 if OK, -ve on error
*/
int bootdev_get_from_blk(struct udevice *blk, struct udevice **bootdevp);
/**
* bootdev_unbind_dev() - Unbind a bootdev device
*

View file

@ -7,7 +7,9 @@
#ifndef __bootflow_h
#define __bootflow_h
#include <alist.h>
#include <bootdev.h>
#include <image.h>
#include <dm/ofnode_decl.h>
#include <linux/list.h>
@ -56,13 +58,8 @@ enum bootflow_flags_t {
/**
* struct bootflow - information about a bootflow
*
* This is connected into two separate linked lists:
* All bootflows are listed in bootstd's bootflow alist in struct bootstd_priv
*
* bm_sibling - links all bootflows in the same bootdev
* glob_sibling - links all bootflows in all bootdevs
*
* @bm_node: Points to siblings in the same bootdev
* @glob_node: Points to siblings in the global list (all bootdev)
* @dev: Bootdev device which produced this bootflow, NULL for flows created by
* BOOTMETHF_GLOBAL bootmeths
* @blk: Block device which contains this bootflow, NULL if this is a network
@ -90,10 +87,9 @@ enum bootflow_flags_t {
* @cmdline: OS command line, or NULL if not known (allocated)
* @x86_setup: Pointer to x86 setup block inside @buf, NULL if not present
* @bootmeth_priv: Private data for the bootmeth
* @images: List of loaded images (struct bootstd_img)
*/
struct bootflow {
struct list_head bm_node;
struct list_head glob_node;
struct udevice *dev;
struct udevice *blk;
int part;
@ -116,6 +112,44 @@ struct bootflow {
char *cmdline;
void *x86_setup;
void *bootmeth_priv;
struct alist images;
};
/**
* bootflow_img_t: Supported image types
*
* This uses image_type_t for most types, but extends it
*
* @BFI_EXTLINUX_CFG: extlinux configuration-file
* @BFI_LOGO: logo image
* @BFI_EFI: EFI PE image
* @BFI_CMDLINE: OS command-line string
*/
enum bootflow_img_t {
BFI_FIRST = IH_TYPE_COUNT,
BFI_EXTLINUX_CFG = BFI_FIRST,
BFI_LOGO,
BFI_EFI,
BFI_CMDLINE,
BFI_COUNT,
};
/**
* struct bootflow_img - Information about an image which has been loaded
*
* This keeps track of a single, loaded image.
*
* @fname: Filename used to load the image (allocated)
* @type: Image type (IH_TYPE_...)
* @addr: Address to which the image was loaded, 0 if not yet loaded
* @size: Size of the image
*/
struct bootflow_img {
char *fname;
enum bootflow_img_t type;
ulong addr;
ulong size;
};
/**
@ -393,7 +427,10 @@ const char *bootflow_state_get_name(enum bootflow_state_t state);
/**
* bootflow_remove() - Remove a bootflow and free its memory
*
* This updates the linked lists containing the bootflow then frees it.
* This updates the 'global' linked list containing the bootflow, then frees it.
* It does not remove it from bootflows alist in struct bootstd_priv
*
* This does not free bflow itself, since this is assumed to be in an alist
*
* @bflow: Bootflow to remove
*/
@ -569,4 +606,34 @@ int bootflow_cmdline_get_arg(struct bootflow *bflow, const char *arg,
*/
int bootflow_cmdline_auto(struct bootflow *bflow, const char *arg);
/**
* bootflow_img_type_name() - Get the name for an image type
*
* @type: Type to check (either enum bootflow_img_t or enum image_type_t
* Return: Image name, or "unknown" if not known
*/
const char *bootflow_img_type_name(enum bootflow_img_t type);
/**
* bootflow_img_add() - Add a new image to a bootflow
*
* @bflow: Bootflow to add to
* @fname: Image filename (will be allocated)
* @type: Image type
* @addr: Address the image was loaded to, or 0 if not loaded
* @size: Image size
* Return: pointer to the added image, or NULL if out of memory
*/
struct bootflow_img *bootflow_img_add(struct bootflow *bflow, const char *fname,
enum bootflow_img_t type, ulong addr,
ulong size);
/**
* bootflow_get_seq() - Get the sequence number of a bootflow
*
* Bootflows are numbered by their position in the bootstd list.
*
* Return: Sequence number of bootflow (0 = first)
*/
int bootflow_get_seq(const struct bootflow *bflow);
#endif

View file

@ -7,11 +7,10 @@
#ifndef __bootmeth_h
#define __bootmeth_h
#include <bootflow.h>
#include <linux/bitops.h>
struct blk_desc;
struct bootflow;
struct bootflow_iter;
struct udevice;
/**
@ -117,13 +116,15 @@ struct bootmeth_ops {
* @bflow: Bootflow providing info on where to read from
* @file_path: Path to file (may be absolute or relative)
* @addr: Address to load file
* @type: File type (IH_TYPE_...)
* @sizep: On entry provides the maximum permitted size; on exit
* returns the size of the file
* Return: 0 if OK, -ENOSPC if the file is too large for @sizep, other
* -ve value if something else goes wrong
*/
int (*read_file)(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep);
const char *file_path, ulong addr,
enum bootflow_img_t type, ulong *sizep);
#if CONFIG_IS_ENABLED(BOOTSTD_FULL)
/**
* readall() - read all files for a bootflow
@ -245,13 +246,15 @@ int bootmeth_set_bootflow(struct udevice *dev, struct bootflow *bflow,
* @bflow: Bootflow providing info on where to read from
* @file_path: Path to file (may be absolute or relative)
* @addr: Address to load file
* @type: File type (IH_TYPE_...)
* @sizep: On entry provides the maximum permitted size; on exit
* returns the size of the file
* Return: 0 if OK, -ENOSPC if the file is too large for @sizep, other
* -ve value if something else goes wrong
*/
int bootmeth_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep);
const char *file_path, ulong addr,
enum bootflow_img_t type, ulong *sizep);
/**
* bootmeth_read_all() - read all bootflow files
@ -365,10 +368,12 @@ int bootmeth_try_file(struct bootflow *bflow, struct blk_desc *desc,
* @bflow: Information about file to read
* @size_limit: Maximum file size to permit
* @align: Allocation alignment (1 for unaligned)
* @type: File type (IH_TYPE_...)
* Return: 0 if OK, -E2BIG if file is too large, -ENOMEM if out of memory,
* other -ve on other error
*/
int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align);
int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align,
enum bootflow_img_t type);
/**
* bootmeth_alloc_other() - Allocate and read a file for a bootflow
@ -379,12 +384,13 @@ int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align);
*
* @bflow: Information about file to read
* @fname: Filename to read from (within bootflow->subdir)
* @type: File type (IH_TYPE_...)
* @bufp: Returns a pointer to the allocated buffer
* @sizep: Returns the size of the buffer
* Return: 0 if OK, -ENOMEM if out of memory, other -ve on other error
*/
int bootmeth_alloc_other(struct bootflow *bflow, const char *fname,
void **bufp, uint *sizep);
enum bootflow_img_t type, void **bufp, uint *sizep);
/**
* bootmeth_common_read_file() - Common handler for reading a file
@ -395,11 +401,13 @@ int bootmeth_alloc_other(struct bootflow *bflow, const char *fname,
* @bflow: Bootflow information
* @file_path: Path to file
* @addr: Address to load file to
* @type: File type (IH_TYPE_...)
* @sizep: On entry, the maximum file size to accept, on exit the actual file
* size read
*/
int bootmeth_common_read_file(struct udevice *dev, struct bootflow *bflow,
const char *file_path, ulong addr, ulong *sizep);
const char *file_path, ulong addr,
enum bootflow_img_t type, ulong *sizep);
/**
* bootmeth_get_bootflow() - Get a bootflow from a global bootmeth

View file

@ -9,6 +9,7 @@
#ifndef __bootstd_h
#define __bootstd_h
#include <alist.h>
#include <dm/ofnode_decl.h>
#include <linux/list.h>
#include <linux/types.h>
@ -30,7 +31,8 @@ struct udevice;
* terminated)
* @cur_bootdev: Currently selected bootdev (for commands)
* @cur_bootflow: Currently selected bootflow (for commands)
* @glob_head: Head for the global list of all bootflows across all bootdevs
* @bootflows: (struct bootflow) Global list of all bootflows across all
* bootdevs
* @bootmeth_count: Number of bootmeth devices in @bootmeth_order
* @bootmeth_order: List of bootmeth devices to use, in order, NULL-terminated
* @vbe_bootmeth: Currently selected VBE bootmeth, NULL if none
@ -44,7 +46,7 @@ struct bootstd_priv {
const char **env_order;
struct udevice *cur_bootdev;
struct bootflow *cur_bootflow;
struct list_head glob_head;
struct alist bootflows;
int bootmeth_count;
struct udevice **bootmeth_order;
struct udevice *vbe_bootmeth;
@ -89,6 +91,23 @@ const char *const *const bootstd_get_prefixes(struct udevice *dev);
*/
int bootstd_get_priv(struct bootstd_priv **stdp);
/**
* bootstd_try_priv() - Try to get the (single) state for the bootstd system
*
* The state holds a global list of all bootflows that have been found. This
* function returns the state if available, but takes care not to create the
* device (or uclass) if it doesn't exist.
*
* This function is safe to use in the 'unbind' path. It will always return NULL
* unless the bootstd device is probed and ready, e.g. bootstd_get_priv() has
* previously been called.
*
* TODO(sjg@chromium.org): Consider adding a bootstd pointer to global_data
*
* Return: pointer if the device exists, else NULL
*/
struct bootstd_priv *bootstd_try_priv(void);
/**
* bootstd_clear_glob() - Clear the global list of bootflows
*
@ -105,4 +124,31 @@ void bootstd_clear_glob(void);
*/
int bootstd_prog_boot(void);
/**
* bootstd_add_bootflow() - Add a bootflow to the global list
*
* All fields in @bflow must be set up. Note that @bflow->dev is used to add the
* bootflow to that device.
*
* The bootflow is also added to the global list of all bootflows
*
* @dev: Bootdev device to add to
* @bflow: Bootflow to add. Note that fields within bflow must be allocated
* since this function takes over ownership of these. This functions makes
* a copy of @bflow itself (without allocating its fields again), so the
* caller must dispose of the memory used by the @bflow pointer itself
* Return: element number in the list, if OK, -ENOMEM if out of memory
*/
int bootstd_add_bootflow(struct bootflow *bflow);
/**
* bootstd_clear_bootflows_for_bootdev() - Clear bootflows from a bootdev
*
* Each bootdev maintains a list of discovered bootflows. This provides a
* way to clear it. These bootflows are removed from the global list too.
*
* @dev: bootdev device to update
*/
int bootstd_clear_bootflows_for_bootdev(struct udevice *dev);
#endif

View file

@ -3,6 +3,7 @@
#ifndef __PXE_UTILS_H
#define __PXE_UTILS_H
#include <bootflow.h>
#include <linux/list.h>
/*
@ -82,8 +83,19 @@ struct pxe_menu {
};
struct pxe_context;
/**
* Read a file
*
* @ctx: PXE context
* @file_path: Full path to filename to read
* @file_addr: String containing the to which to read the file
* @type: File type
* @fileszeip: Returns file size
*/
typedef int (*pxe_getfile_func)(struct pxe_context *ctx, const char *file_path,
char *file_addr, ulong *filesizep);
char *file_addr, enum bootflow_img_t type,
ulong *filesizep);
/**
* struct pxe_context - context information for PXE parsing

View file

@ -15,6 +15,7 @@
#include <efi.h>
#include <efi_loader.h>
#include <expo.h>
#include <mapmem.h>
#ifdef CONFIG_SANDBOX
#include <asm/test.h>
#endif
@ -77,6 +78,14 @@ static int bootflow_cmd(struct unit_test_state *uts)
ut_assert_nextline("(1 bootflow, 1 valid)");
ut_assert_console_end();
ut_assertok(run_command("bootstd images", 0));
ut_assert_nextlinen("Seq");
ut_assert_nextlinen("---");
ut_assert_nextlinen(" 0 mmc1.bootdev.part_1 extlinux_cfg");
ut_assert_nextlinen("---");
ut_assert_nextline("(1 image)");
ut_assert_console_end();
return 0;
}
BOOTSTD_TEST(bootflow_cmd, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
@ -1193,6 +1202,19 @@ static int bootflow_cros(struct unit_test_state *uts)
ut_assert_nextlinen("---");
ut_assert_skip_to_line("(3 bootflows, 3 valid)");
ut_assertok(run_command("bootstd images", 0));
ut_assert_nextlinen("Seq");
ut_assert_nextlinen("---");
ut_assert_nextlinen(" 0 mmc1.bootdev.part_1 extlinux_cfg");
ut_assert_nextlinen(" 1 mmc5.bootdev.part_2 x86_setup");
ut_assert_nextlinen(" 1 mmc5.bootdev.part_2 cmdline");
ut_assert_nextlinen(" 1 mmc5.bootdev.part_2 kernel - 4000 kernel");
ut_assert_nextlinen(" 2 mmc5.bootdev.part_4 x86_setup");
ut_assert_nextlinen(" 2 mmc5.bootdev.part_4 cmdline");
ut_assert_nextlinen(" 2 mmc5.bootdev.part_4 kernel - 4000 kernel");
ut_assert_nextlinen("---");
ut_assert_nextline("(7 images)");
ut_assert_console_end();
return 0;
@ -1307,3 +1329,87 @@ static int bootflow_efi(struct unit_test_state *uts)
return 0;
}
BOOTSTD_TEST(bootflow_efi, UTF_CONSOLE);
/* Check 'bootflow scan' provides a list of images */
static int bootstd_images(struct unit_test_state *uts)
{
static const char *order[] = {"mmc2", "mmc1", "mmc4", "mmc5", NULL};
const struct legacy_img_hdr *hdr;
const struct bootflow_img *img;
const struct bootflow *bflow;
struct bootstd_priv *std;
const char **old_order;
struct udevice *dev;
ofnode root, node;
ulong data, len;
char *ptr;
/* get access to the current bootflow */
ut_assertok(bootstd_get_priv(&std));
ut_assertok(prep_mmc_bootdev(uts, "mmc4", true, &old_order));
/* bind mmc5 too, for cros */
root = oftree_root(oftree_default());
node = ofnode_find_subnode(root, "mmc5");
ut_assert(ofnode_valid(node));
ut_assertok(lists_bind_fdt(gd->dm_root, node, &dev, NULL, false));
std->bootdev_order = order;
ut_assertok(run_command("bootflow scan", 0));
ut_assert_console_end();
std->bootdev_order = old_order;
ut_assertok(run_command("bootflow list", 0));
ut_assert_skip_to_line("(4 bootflows, 4 valid)");
ut_assertok(run_command("bootstd images", 0));
ut_assert_nextlinen("Seq");
ut_assert_nextlinen("---");
ut_assert_nextlinen(" 0 mmc1.bootdev.part_1 extlinux_cfg");
ut_assert_nextlinen(" 1 mmc4.bootdev.part_1 script");
ut_assert_nextlinen(" 1 mmc4.bootdev.part_1 logo");
ut_assert_nextlinen(" 2 mmc5.bootdev.part_2 x86_setup");
ut_assert_nextlinen(" 2 mmc5.bootdev.part_2 cmdline");
ut_assert_nextlinen(" 2 mmc5.bootdev.part_2 kernel -");
ut_assert_nextlinen(" 3 mmc5.bootdev.part_4 x86_setup");
ut_assert_nextlinen(" 3 mmc5.bootdev.part_4 cmdline");
ut_assert_nextlinen(" 3 mmc5.bootdev.part_4 kernel -");
ut_assert_nextlinen("---");
ut_assert_nextline("(9 images)");
/* check the first image */
bflow = alist_get(&std->bootflows, 0, struct bootflow);
img = alist_get(&bflow->images, 0, struct bootflow_img);
ut_asserteq_strn("# extlinux.conf", map_sysmem(img->addr, 0));
/* check the second image */
bflow = alist_get(&std->bootflows, 1, struct bootflow);
img = alist_get(&bflow->images, 0, struct bootflow_img);
/* this is the length of the script in bytes */
hdr = map_sysmem(img->addr, 0);
image_multi_getimg(hdr, 0, &data, &len);
ptr = (void *)data;
ut_asserteq_strn("# DO NOT EDIT THIS FILE", ptr);
/* check the ChromiumOS images */
bflow = alist_get(&std->bootflows, 2, struct bootflow);
img = alist_get(&bflow->images, 1, struct bootflow_img);
ptr = map_sysmem(img->addr, 0);
ut_asserteq_strn("BOOT_IMAGE=/vmlinuz-5.15.0-121-generic root=", ptr);
/*
* the x86 setup is not a real binary, so just check that it is empty,
* so that if this changes in the future someone will notice and update
* this test
*/
img = alist_get(&bflow->images, 0, struct bootflow_img);
ptr = map_sysmem(img->addr, 0);
ut_asserteq(0, *(ulong *)ptr);
ut_assert_console_end();
return 0;
}
BOOTSTD_TEST(bootstd_images, UTF_CONSOLE);

View file

@ -343,9 +343,10 @@ def setup_cros_image(cons):
start, size, num, name = line.split(maxsplit=3)
parts[int(num)] = Partition(int(start), int(size), name)
# Set up the kernel command-line
dummy = os.path.join(cons.config.result_dir, 'dummy.txt')
with open(dummy, 'wb') as outf:
outf.write(b'dummy\n')
outf.write(b'BOOT_IMAGE=/vmlinuz-5.15.0-121-generic root=/dev/nvme0n1p1 ro quiet splash vt.handoff=7')
# For now we just use dummy kernels. This limits testing to just detecting
# a signed kernel. We could add support for the x86 data structures so that