diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c index 2e61c853142..c39147940b6 100644 --- a/boot/bootdev-uclass.c +++ b/boot/bootdev-uclass.c @@ -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, }; diff --git a/boot/bootflow.c b/boot/bootflow.c index d8807eb109d..58a1afa7a75 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -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); +} diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c index 5b5fea39b3b..014b7588e8d 100644 --- a/boot/bootmeth-uclass.c +++ b/boot/bootmeth-uclass.c @@ -6,6 +6,7 @@ #define LOG_CATEGORY UCLASS_BOOTSTD +#include #include #include #include @@ -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; } diff --git a/boot/bootmeth_android.c b/boot/bootmeth_android.c index 3a5144aaa3b..d8c92b44a99 100644 --- a/boot/bootmeth_android.c +++ b/boot/bootmeth_android.c @@ -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 diff --git a/boot/bootmeth_cros.c b/boot/bootmeth_cros.c index 676f550ca25..c7b862e512a 100644 --- a/boot/bootmeth_cros.c +++ b/boot/bootmeth_cros.c @@ -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; } diff --git a/boot/bootmeth_efi.c b/boot/bootmeth_efi.c index f836aa655f5..a2998452666 100644 --- a/boot/bootmeth_efi.c +++ b/boot/bootmeth_efi.c @@ -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), diff --git a/boot/bootmeth_efi_mgr.c b/boot/bootmeth_efi_mgr.c index 23ae1e610ac..42b8863815e 100644 --- a/boot/bootmeth_efi_mgr.c +++ b/boot/bootmeth_efi_mgr.c @@ -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 */ diff --git a/boot/bootmeth_extlinux.c b/boot/bootmeth_extlinux.c index c6ae6dffcb7..17c6cebd2f4 100644 --- a/boot/bootmeth_extlinux.c +++ b/boot/bootmeth_extlinux.c @@ -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); diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c index 05c6bece2c1..b91e61bcbc4 100644 --- a/boot/bootmeth_pxe.c +++ b/boot/bootmeth_pxe.c @@ -23,7 +23,8 @@ #include 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; } diff --git a/boot/bootmeth_qfw.c b/boot/bootmeth_qfw.c index 2f8e00cf350..028c2481583 100644 --- a/boot/bootmeth_qfw.c +++ b/boot/bootmeth_qfw.c @@ -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; } diff --git a/boot/bootmeth_sandbox.c b/boot/bootmeth_sandbox.c index 26c713bb5f3..92ba2e3f050 100644 --- a/boot/bootmeth_sandbox.c +++ b/boot/bootmeth_sandbox.c @@ -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; } diff --git a/boot/bootmeth_script.c b/boot/bootmeth_script.c index c5cbf18c2e6..020cb8a7aec 100644 --- a/boot/bootmeth_script.c +++ b/boot/bootmeth_script.c @@ -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; diff --git a/boot/bootstd-uclass.c b/boot/bootstd-uclass.c index fdb8d69e320..8c0fd4e63c3 100644 --- a/boot/bootstd-uclass.c +++ b/boot/bootstd-uclass.c @@ -6,6 +6,7 @@ * Written by Simon Glass */ +#include #include #include #include @@ -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; } diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c index 3ae17553c6d..82f217aaf86 100644 --- a/boot/pxe_utils.c +++ b/boot/pxe_utils.c @@ -6,6 +6,7 @@ #define LOG_CATEGORY LOGC_BOOT +#include #include #include #include @@ -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; diff --git a/boot/vbe_simple.c b/boot/vbe_simple.c index 189e86d2a22..ed7b9598e38 100644 --- a/boot/vbe_simple.c +++ b/boot/vbe_simple.c @@ -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); } diff --git a/cmd/Kconfig b/cmd/Kconfig index 4c4ad9d9979..1a0985ca479 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -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 diff --git a/cmd/Makefile b/cmd/Makefile index bf322201c64..0691136054d 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -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 diff --git a/cmd/bootdev.c b/cmd/bootdev.c index fa7285ba25e..4bc229e809a 100644 --- a/cmd/bootdev.c +++ b/cmd/bootdev.c @@ -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; diff --git a/cmd/bootflow.c b/cmd/bootflow.c index f67948d7368..f88995a478f 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -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; } diff --git a/cmd/bootstd.c b/cmd/bootstd.c new file mode 100644 index 00000000000..e1d82744eb5 --- /dev/null +++ b/cmd/bootstd.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * 'bootstd' command + * + * Copyright 2024 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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)); diff --git a/cmd/pxe.c b/cmd/pxe.c index 982e2b1e7ea..37b8dea6ad6 100644 --- a/cmd/pxe.c +++ b/cmd/pxe.c @@ -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; diff --git a/cmd/sysboot.c b/cmd/sysboot.c index 8a060780cab..93d4a400830 100644 --- a/cmd/sysboot.c +++ b/cmd/sysboot.c @@ -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; diff --git a/doc/develop/bootstd/overview.rst b/doc/develop/bootstd/overview.rst index a2913cd47be..e3ce97cc4f5 100644 --- a/doc/develop/bootstd/overview.rst +++ b/doc/develop/bootstd/overview.rst @@ -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 diff --git a/doc/usage/cmd/bootstd.rst b/doc/usage/cmd/bootstd.rst new file mode 100644 index 00000000000..7d933852a91 --- /dev/null +++ b/doc/usage/cmd/bootstd.rst @@ -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_: diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 4dd00f002cd..bf2335dc8f0 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -40,6 +40,7 @@ Shell commands cmd/bootm cmd/bootmenu cmd/bootmeth + cmd/bootstd cmd/bootz cmd/button cmd/cat diff --git a/include/bootdev.h b/include/bootdev.h index ad4af0d1310..12c90c4ec1b 100644 --- a/include/bootdev.h +++ b/include/bootdev.h @@ -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 * diff --git a/include/bootflow.h b/include/bootflow.h index 4d2fc7b69b5..480cf8a5af1 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -7,7 +7,9 @@ #ifndef __bootflow_h #define __bootflow_h +#include #include +#include #include #include @@ -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 diff --git a/include/bootmeth.h b/include/bootmeth.h index a08ebf005ad..26de593a9a4 100644 --- a/include/bootmeth.h +++ b/include/bootmeth.h @@ -7,11 +7,10 @@ #ifndef __bootmeth_h #define __bootmeth_h +#include #include 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 diff --git a/include/bootstd.h b/include/bootstd.h index ac756e98d84..3398e48e88b 100644 --- a/include/bootstd.h +++ b/include/bootstd.h @@ -9,6 +9,7 @@ #ifndef __bootstd_h #define __bootstd_h +#include #include #include #include @@ -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 diff --git a/include/pxe_utils.h b/include/pxe_utils.h index 68ac40b64ad..0378f2889f7 100644 --- a/include/pxe_utils.h +++ b/include/pxe_utils.h @@ -3,6 +3,7 @@ #ifndef __PXE_UTILS_H #define __PXE_UTILS_H +#include #include /* @@ -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 diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index e33b08aa8cd..a8735c1c23d 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef CONFIG_SANDBOX #include #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); diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index 10ec7e582e0..cacf11f7c0a 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -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