"Das U-Boot" Source Tree
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+685 -178
+21 -57
boot/bootdev-uclass.c
··· 33 33 BOOT_TARGETS_MAX_LEN = 100, 34 34 }; 35 35 36 - int bootdev_add_bootflow(struct bootflow *bflow) 36 + int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp) 37 37 { 38 38 struct bootstd_priv *std; 39 - struct bootflow *new; 39 + struct bootflow *bflow; 40 40 int ret; 41 41 42 42 ret = bootstd_get_priv(&std); 43 43 if (ret) 44 - return ret; 45 - 46 - new = malloc(sizeof(*bflow)); 47 - if (!new) 48 - return log_msg_ret("bflow", -ENOMEM); 49 - memcpy(new, bflow, sizeof(*bflow)); 50 - 51 - list_add_tail(&new->glob_node, &std->glob_head); 52 - if (bflow->dev) { 53 - struct bootdev_uc_plat *ucp = dev_get_uclass_plat(bflow->dev); 54 - 55 - list_add_tail(&new->bm_node, &ucp->bootflow_head); 56 - } 44 + return log_msg_ret("bff", ret); 57 45 58 - return 0; 59 - } 60 - 61 - int bootdev_first_bootflow(struct udevice *dev, struct bootflow **bflowp) 62 - { 63 - struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); 64 - 65 - if (list_empty(&ucp->bootflow_head)) 46 + bflow = alist_getw(&std->bootflows, 0, struct bootflow); 47 + if (!bflow) 66 48 return -ENOENT; 67 - 68 - *bflowp = list_first_entry(&ucp->bootflow_head, struct bootflow, 69 - bm_node); 49 + *bflowp = bflow; 70 50 71 51 return 0; 72 52 } 73 53 74 54 int bootdev_next_bootflow(struct bootflow **bflowp) 75 55 { 76 - struct bootflow *bflow = *bflowp; 77 - struct bootdev_uc_plat *ucp = dev_get_uclass_plat(bflow->dev); 56 + struct bootstd_priv *std; 57 + struct bootflow *bflow; 58 + int ret; 78 59 79 - *bflowp = NULL; 60 + ret = bootstd_get_priv(&std); 61 + if (ret) 62 + return log_msg_ret("bff", ret); 80 63 81 - if (list_is_last(&bflow->bm_node, &ucp->bootflow_head)) 64 + bflow = alist_nextw(&std->bootflows, *bflowp); 65 + if (!bflow) 82 66 return -ENOENT; 83 - 84 - *bflowp = list_entry(bflow->bm_node.next, struct bootflow, bm_node); 67 + *bflowp = bflow; 85 68 86 69 return 0; 87 70 } ··· 342 325 return 0; 343 326 } 344 327 345 - static int bootdev_get_from_blk(struct udevice *blk, struct udevice **bootdevp) 328 + int bootdev_get_from_blk(struct udevice *blk, struct udevice **bootdevp) 346 329 { 347 330 struct udevice *parent = dev_get_parent(blk); 348 331 struct udevice *bootdev; ··· 588 571 return ops->get_bootflow(dev, iter, bflow); 589 572 } 590 573 591 - void bootdev_clear_bootflows(struct udevice *dev) 592 - { 593 - struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); 594 - 595 - while (!list_empty(&ucp->bootflow_head)) { 596 - struct bootflow *bflow; 597 - 598 - bflow = list_first_entry(&ucp->bootflow_head, struct bootflow, 599 - bm_node); 600 - bootflow_remove(bflow); 601 - } 602 - } 603 - 604 574 int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp, 605 575 int *method_flagsp) 606 576 { ··· 955 925 printf("(total hunters: %d)\n", n_ent); 956 926 } 957 927 958 - static int bootdev_post_bind(struct udevice *dev) 959 - { 960 - struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); 961 - 962 - INIT_LIST_HEAD(&ucp->bootflow_head); 963 - 964 - return 0; 965 - } 966 - 967 928 static int bootdev_pre_unbind(struct udevice *dev) 968 929 { 969 - bootdev_clear_bootflows(dev); 930 + int ret; 931 + 932 + ret = bootstd_clear_bootflows_for_bootdev(dev); 933 + if (ret) 934 + return log_msg_ret("bun", ret); 970 935 971 936 return 0; 972 937 } ··· 976 941 .name = "bootdev", 977 942 .flags = DM_UC_FLAG_SEQ_ALIAS, 978 943 .per_device_plat_auto = sizeof(struct bootdev_uc_plat), 979 - .post_bind = bootdev_post_bind, 980 944 .pre_unbind = bootdev_pre_unbind, 981 945 };
+63 -14
boot/bootflow.c
··· 23 23 BF_NO_MORE_DEVICES = -ENODEV, 24 24 }; 25 25 26 + static const char *const bootflow_img[BFI_COUNT - BFI_FIRST] = { 27 + "extlinux_cfg", 28 + "logo", 29 + "efi", 30 + "cmdline", 31 + }; 32 + 26 33 /** 27 34 * bootflow_state - name for each state 28 35 * ··· 55 62 if (ret) 56 63 return ret; 57 64 58 - if (list_empty(&std->glob_head)) 65 + if (!std->bootflows.count) 59 66 return -ENOENT; 60 67 61 - *bflowp = list_first_entry(&std->glob_head, struct bootflow, 62 - glob_node); 68 + *bflowp = alist_getw(&std->bootflows, 0, struct bootflow); 63 69 64 70 return 0; 65 71 } ··· 67 73 int bootflow_next_glob(struct bootflow **bflowp) 68 74 { 69 75 struct bootstd_priv *std; 70 - struct bootflow *bflow = *bflowp; 71 76 int ret; 72 77 73 78 ret = bootstd_get_priv(&std); 74 79 if (ret) 75 80 return ret; 76 81 77 - *bflowp = NULL; 78 - 79 - if (list_is_last(&bflow->glob_node, &std->glob_head)) 82 + *bflowp = alist_nextw(&std->bootflows, *bflowp); 83 + if (!*bflowp) 80 84 return -ENOENT; 81 - 82 - *bflowp = list_entry(bflow->glob_node.next, struct bootflow, glob_node); 83 85 84 86 return 0; 85 87 } ··· 460 462 bflow->dev = bootdev; 461 463 bflow->method = meth; 462 464 bflow->state = BOOTFLOWST_BASE; 465 + alist_init_struct(&bflow->images, struct bootflow_img); 463 466 } 464 467 465 468 void bootflow_free(struct bootflow *bflow) 466 469 { 470 + struct bootflow_img *img; 471 + 467 472 free(bflow->name); 468 473 free(bflow->subdir); 469 474 free(bflow->fname); ··· 472 477 free(bflow->os_name); 473 478 free(bflow->fdt_fname); 474 479 free(bflow->bootmeth_priv); 480 + 481 + alist_for_each(img, &bflow->images) 482 + free(img->fname); 483 + alist_empty(&bflow->images); 475 484 } 476 485 477 486 void bootflow_remove(struct bootflow *bflow) 478 487 { 479 - if (bflow->dev) 480 - list_del(&bflow->bm_node); 481 - list_del(&bflow->glob_node); 482 - 483 488 bootflow_free(bflow); 484 - free(bflow); 485 489 } 486 490 487 491 #if CONFIG_IS_ENABLED(BOOTSTD_FULL) ··· 960 964 961 965 return 0; 962 966 } 967 + 968 + const char *bootflow_img_type_name(enum bootflow_img_t type) 969 + { 970 + const char *name; 971 + 972 + if (type >= BFI_FIRST && type < BFI_COUNT) 973 + name = bootflow_img[type - BFI_FIRST]; 974 + else 975 + name = genimg_get_type_short_name(type); 976 + 977 + return name; 978 + } 979 + 980 + struct bootflow_img *bootflow_img_add(struct bootflow *bflow, const char *fname, 981 + enum bootflow_img_t type, ulong addr, 982 + ulong size) 983 + { 984 + struct bootflow_img img, *ptr; 985 + 986 + memset(&img, '\0', sizeof(struct bootflow_img)); 987 + img.fname = strdup(fname); 988 + if (!img.fname) 989 + return NULL; 990 + 991 + img.type = type; 992 + img.addr = addr; 993 + img.size = size; 994 + ptr = alist_add(&bflow->images, img); 995 + if (!ptr) 996 + return NULL; 997 + 998 + return ptr; 999 + } 1000 + 1001 + int bootflow_get_seq(const struct bootflow *bflow) 1002 + { 1003 + struct bootstd_priv *std; 1004 + int ret; 1005 + 1006 + ret = bootstd_get_priv(&std); 1007 + if (ret) 1008 + return ret; 1009 + 1010 + return alist_calc_index(&std->bootflows, bflow); 1011 + }
+24 -5
boot/bootmeth-uclass.c
··· 6 6 7 7 #define LOG_CATEGORY UCLASS_BOOTSTD 8 8 9 + #include <alist.h> 9 10 #include <blk.h> 10 11 #include <bootflow.h> 11 12 #include <bootmeth.h> ··· 83 84 } 84 85 85 86 int bootmeth_read_file(struct udevice *dev, struct bootflow *bflow, 86 - const char *file_path, ulong addr, ulong *sizep) 87 + const char *file_path, ulong addr, 88 + enum bootflow_img_t type, ulong *sizep) 87 89 { 88 90 const struct bootmeth_ops *ops = bootmeth_get_ops(dev); 89 91 90 92 if (!ops->read_file) 91 93 return -ENOSYS; 92 94 93 - return ops->read_file(dev, bflow, file_path, addr, sizep); 95 + return ops->read_file(dev, bflow, file_path, addr, type, sizep); 94 96 } 95 97 96 98 int bootmeth_get_bootflow(struct udevice *dev, struct bootflow *bflow) ··· 326 328 return 0; 327 329 } 328 330 329 - int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align) 331 + int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align, 332 + enum bootflow_img_t type) 330 333 { 334 + struct blk_desc *desc = NULL; 331 335 void *buf; 332 336 uint size; 333 337 int ret; ··· 344 348 bflow->state = BOOTFLOWST_READY; 345 349 bflow->buf = buf; 346 350 351 + if (bflow->blk) 352 + desc = dev_get_uclass_plat(bflow->blk); 353 + 354 + if (!bootflow_img_add(bflow, bflow->fname, type, map_to_sysmem(buf), 355 + size)) 356 + return log_msg_ret("bai", -ENOMEM); 357 + 347 358 return 0; 348 359 } 349 360 350 361 int bootmeth_alloc_other(struct bootflow *bflow, const char *fname, 351 - void **bufp, uint *sizep) 362 + enum bootflow_img_t type, void **bufp, uint *sizep) 352 363 { 353 364 struct blk_desc *desc = NULL; 354 365 char path[200]; ··· 377 388 if (ret) 378 389 return log_msg_ret("all", ret); 379 390 391 + if (!bootflow_img_add(bflow, bflow->fname, type, map_to_sysmem(buf), 392 + size)) 393 + return log_msg_ret("boi", -ENOMEM); 394 + 380 395 *bufp = buf; 381 396 *sizep = size; 382 397 ··· 384 399 } 385 400 386 401 int bootmeth_common_read_file(struct udevice *dev, struct bootflow *bflow, 387 - const char *file_path, ulong addr, ulong *sizep) 402 + const char *file_path, ulong addr, 403 + enum bootflow_img_t type, ulong *sizep) 388 404 { 389 405 struct blk_desc *desc = NULL; 390 406 loff_t len_read; ··· 412 428 if (ret) 413 429 return ret; 414 430 *sizep = len_read; 431 + 432 + if (!bootflow_img_add(bflow, bflow->fname, type, addr, size)) 433 + return log_msg_ret("bci", -ENOMEM); 415 434 416 435 return 0; 417 436 }
+2 -1
boot/bootmeth_android.c
··· 323 323 } 324 324 325 325 static int android_read_file(struct udevice *dev, struct bootflow *bflow, 326 - const char *file_path, ulong addr, ulong *sizep) 326 + const char *file_path, ulong addr, 327 + enum bootflow_img_t type, ulong *sizep) 327 328 { 328 329 /* 329 330 * Reading individual files is not supported since we only
+16 -1
boot/bootmeth_cros.c
··· 243 243 ret = copy_cmdline(map_sysmem(cmdline, 0), uuid, &bflow->cmdline); 244 244 if (ret) 245 245 return log_msg_ret("cmd", ret); 246 + 247 + if (!bootflow_img_add(bflow, "setup", 248 + (enum bootflow_img_t)IH_TYPE_X86_SETUP, 249 + setup, 0x3000)) 250 + return log_msg_ret("cri", -ENOMEM); 251 + 246 252 bflow->x86_setup = map_sysmem(setup, 0); 253 + 254 + if (!bootflow_img_add(bflow, "cmdline", BFI_CMDLINE, cmdline, 0x1000)) 255 + return log_msg_ret("crc", -ENOMEM); 247 256 248 257 return 0; 249 258 } ··· 305 314 return log_msg_ret("pro", ret); 306 315 } 307 316 priv->info_buf = buf; 317 + 318 + if (!bootflow_img_add(bflow, "kernel", 319 + (enum bootflow_img_t)IH_TYPE_KERNEL, 0, 320 + priv->body_size)) 321 + return log_msg_ret("crk", -ENOMEM); 308 322 309 323 return 0; 310 324 } ··· 400 414 } 401 415 402 416 static int cros_read_file(struct udevice *dev, struct bootflow *bflow, 403 - const char *file_path, ulong addr, ulong *sizep) 417 + const char *file_path, ulong addr, 418 + enum bootflow_img_t type, ulong *sizep) 404 419 { 405 420 return -ENOSYS; 406 421 }
+9 -7
boot/bootmeth_efi.c
··· 89 89 static int efiload_read_file(struct bootflow *bflow, ulong addr) 90 90 { 91 91 struct blk_desc *desc = NULL; 92 - loff_t bytes_read; 92 + ulong size; 93 93 int ret; 94 94 95 95 if (bflow->blk) 96 96 desc = dev_get_uclass_plat(bflow->blk); 97 - ret = bootmeth_setup_fs(bflow, desc); 98 - if (ret) 99 - return log_msg_ret("set", ret); 100 97 101 - ret = fs_read(bflow->fname, addr, 0, bflow->size, &bytes_read); 98 + size = SZ_1G; 99 + ret = bootmeth_common_read_file(bflow->method, bflow, bflow->fname, 100 + addr, BFI_EFI, &size); 102 101 if (ret) 103 - return log_msg_ret("read", ret); 102 + return log_msg_ret("rdf", ret); 104 103 bflow->buf = map_sysmem(addr, bflow->size); 105 104 106 105 set_efi_bootdev(desc, bflow); ··· 173 172 /* Limit FDT files to 4MB */ 174 173 size = SZ_4M; 175 174 ret = bootmeth_common_read_file(dev, bflow, fname, 176 - fdt_addr, &size); 175 + fdt_addr, (enum bootflow_img_t)IH_TYPE_FLATDT, 176 + &size); 177 177 } 178 178 } 179 179 ··· 252 252 if (!bootfile_name) 253 253 return log_msg_ret("bootfile_name", ret); 254 254 bflow->fname = strdup(bootfile_name); 255 + if (!bflow->fname) 256 + return log_msg_ret("fi0", -ENOMEM); 255 257 256 258 /* do the hideous EFI hack */ 257 259 efi_set_bootdev("Net", "", bflow->fname, map_sysmem(addr, 0),
+2 -1
boot/bootmeth_efi_mgr.c
··· 74 74 } 75 75 76 76 static int efi_mgr_read_file(struct udevice *dev, struct bootflow *bflow, 77 - const char *file_path, ulong addr, ulong *sizep) 77 + const char *file_path, ulong addr, 78 + enum bootflow_img_t type, ulong *sizep) 78 79 { 79 80 /* Files are loaded by the 'bootefi bootmgr' command */ 80 81
+5 -3
boot/bootmeth_extlinux.c
··· 69 69 } 70 70 71 71 static int extlinux_getfile(struct pxe_context *ctx, const char *file_path, 72 - char *file_addr, ulong *sizep) 72 + char *file_addr, enum bootflow_img_t type, 73 + ulong *sizep) 73 74 { 74 75 struct extlinux_info *info = ctx->userdata; 75 76 ulong addr; ··· 80 81 /* Allow up to 1GB */ 81 82 *sizep = 1 << 30; 82 83 ret = bootmeth_read_file(info->dev, info->bflow, file_path, addr, 83 - sizep); 84 + type, sizep); 84 85 if (ret) 85 86 return log_msg_ret("read", ret); 86 87 ··· 160 161 return log_msg_ret("try", ret); 161 162 size = bflow->size; 162 163 163 - ret = bootmeth_alloc_file(bflow, 0x10000, ARCH_DMA_MINALIGN); 164 + ret = bootmeth_alloc_file(bflow, 0x10000, ARCH_DMA_MINALIGN, 165 + BFI_EXTLINUX_CFG); 164 166 if (ret) 165 167 return log_msg_ret("read", ret); 166 168
+7 -3
boot/bootmeth_pxe.c
··· 23 23 #include <pxe_utils.h> 24 24 25 25 static int extlinux_pxe_getfile(struct pxe_context *ctx, const char *file_path, 26 - char *file_addr, ulong *sizep) 26 + char *file_addr, enum bootflow_img_t type, 27 + ulong *sizep) 27 28 { 28 29 struct extlinux_info *info = ctx->userdata; 29 30 ulong addr; ··· 34 35 /* Allow up to 1GB */ 35 36 *sizep = 1 << 30; 36 37 ret = bootmeth_read_file(info->dev, info->bflow, file_path, addr, 37 - sizep); 38 + type, sizep); 38 39 if (ret) 39 40 return log_msg_ret("read", ret); 40 41 ··· 113 114 114 115 static int extlinux_pxe_read_file(struct udevice *dev, struct bootflow *bflow, 115 116 const char *file_path, ulong addr, 116 - ulong *sizep) 117 + enum bootflow_img_t type, ulong *sizep) 117 118 { 118 119 char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; 119 120 struct pxe_context *ctx = dev_get_priv(dev); ··· 133 134 if (size > *sizep) 134 135 return log_msg_ret("spc", -ENOSPC); 135 136 *sizep = size; 137 + 138 + if (!bootflow_img_add(bflow, file_path, type, addr, size)) 139 + return log_msg_ret("pxi", -ENOMEM); 136 140 137 141 return 0; 138 142 }
+2 -1
boot/bootmeth_qfw.c
··· 52 52 } 53 53 54 54 static int qfw_read_file(struct udevice *dev, struct bootflow *bflow, 55 - const char *file_path, ulong addr, ulong *sizep) 55 + const char *file_path, ulong addr, 56 + enum bootflow_img_t type, ulong *sizep) 56 57 { 57 58 return -ENOSYS; 58 59 }
+2 -1
boot/bootmeth_sandbox.c
··· 27 27 } 28 28 29 29 static int sandbox_read_file(struct udevice *dev, struct bootflow *bflow, 30 - const char *file_path, ulong addr, ulong *sizep) 30 + const char *file_path, ulong addr, 31 + enum bootflow_img_t type, ulong *sizep) 31 32 { 32 33 return -ENOSYS; 33 34 }
+4 -3
boot/bootmeth_script.c
··· 98 98 if (!bflow->subdir) 99 99 return log_msg_ret("prefix", -ENOMEM); 100 100 101 - ret = bootmeth_alloc_file(bflow, 0x10000, ARCH_DMA_MINALIGN); 101 + ret = bootmeth_alloc_file(bflow, 0x10000, ARCH_DMA_MINALIGN, 102 + (enum bootflow_img_t)IH_TYPE_SCRIPT); 102 103 if (ret) 103 104 return log_msg_ret("read", ret); 104 105 ··· 106 107 if (ret) 107 108 return log_msg_ret("inf", ret); 108 109 109 - ret = bootmeth_alloc_other(bflow, "boot.bmp", &bflow->logo, 110 - &bflow->logo_size); 110 + ret = bootmeth_alloc_other(bflow, "boot.bmp", BFI_LOGO, 111 + &bflow->logo, &bflow->logo_size); 111 112 /* ignore error */ 112 113 113 114 return 0;
+54 -6
boot/bootstd-uclass.c
··· 6 6 * Written by Simon Glass <sjg@chromium.org> 7 7 */ 8 8 9 + #include <alist.h> 9 10 #include <bootflow.h> 10 11 #include <bootstd.h> 11 12 #include <dm.h> ··· 42 43 43 44 static void bootstd_clear_glob_(struct bootstd_priv *priv) 44 45 { 45 - while (!list_empty(&priv->glob_head)) { 46 - struct bootflow *bflow; 46 + struct bootflow *bflow; 47 47 48 - bflow = list_first_entry(&priv->glob_head, struct bootflow, 49 - glob_node); 48 + alist_for_each(bflow, &priv->bootflows) 50 49 bootflow_remove(bflow); 51 - } 50 + alist_empty(&priv->bootflows); 52 51 } 53 52 54 53 void bootstd_clear_glob(void) ··· 61 60 bootstd_clear_glob_(std); 62 61 } 63 62 63 + int bootstd_add_bootflow(struct bootflow *bflow) 64 + { 65 + struct bootstd_priv *std; 66 + int ret; 67 + 68 + ret = bootstd_get_priv(&std); 69 + if (ret) 70 + return ret; 71 + 72 + ret = std->bootflows.count; 73 + bflow = alist_add(&std->bootflows, *bflow); 74 + if (!bflow) 75 + return log_msg_ret("bf2", -ENOMEM); 76 + 77 + return ret; 78 + } 79 + 80 + int bootstd_clear_bootflows_for_bootdev(struct udevice *dev) 81 + { 82 + struct bootstd_priv *std = bootstd_try_priv(); 83 + struct bootflow *from, *to; 84 + 85 + /* if bootstd does not exist we cannot have any bootflows */ 86 + if (!std) 87 + return 0; 88 + 89 + /* Drop any bootflows that mention this dev */ 90 + alist_for_each_filter(from, to, &std->bootflows) { 91 + if (from->dev == dev) 92 + bootflow_remove(from); 93 + else 94 + *to++ = *from; 95 + } 96 + alist_update_end(&std->bootflows, to); 97 + 98 + return 0; 99 + } 100 + 64 101 static int bootstd_remove(struct udevice *dev) 65 102 { 66 103 struct bootstd_priv *priv = dev_get_priv(dev); ··· 100 137 return std->prefixes ? std->prefixes : default_prefixes; 101 138 } 102 139 140 + struct bootstd_priv *bootstd_try_priv(void) 141 + { 142 + struct udevice *dev; 143 + 144 + dev = uclass_try_first_device(UCLASS_BOOTSTD); 145 + if (!dev || !device_active(dev)) 146 + return NULL; 147 + 148 + return dev_get_priv(dev); 149 + } 150 + 103 151 int bootstd_get_priv(struct bootstd_priv **stdp) 104 152 { 105 153 struct udevice *dev; ··· 117 165 { 118 166 struct bootstd_priv *std = dev_get_priv(dev); 119 167 120 - INIT_LIST_HEAD(&std->glob_head); 168 + alist_init_struct(&std->bootflows, struct bootflow); 121 169 122 170 return 0; 123 171 }
+18 -18
boot/pxe_utils.c
··· 6 6 7 7 #define LOG_CATEGORY LOGC_BOOT 8 8 9 + #include <bootflow.h> 9 10 #include <command.h> 10 11 #include <dm.h> 11 12 #include <env.h> ··· 97 98 * Returns 1 for success, or < 0 on error 98 99 */ 99 100 static int get_relfile(struct pxe_context *ctx, const char *file_path, 100 - unsigned long file_addr, ulong *filesizep) 101 + unsigned long file_addr, enum bootflow_img_t type, 102 + ulong *filesizep) 101 103 { 102 104 size_t path_len; 103 105 char relfile[MAX_TFTP_PATH_LEN + 1]; ··· 124 126 125 127 sprintf(addr_buf, "%lx", file_addr); 126 128 127 - ret = ctx->getfile(ctx, relfile, addr_buf, &size); 129 + ret = ctx->getfile(ctx, relfile, addr_buf, type, &size); 128 130 if (ret < 0) 129 131 return log_msg_ret("get", ret); 130 132 if (filesizep) ··· 133 135 return 1; 134 136 } 135 137 136 - /** 137 - * get_pxe_file() - read a file 138 - * 139 - * The file is read and nul-terminated 140 - * 141 - * @ctx: PXE context 142 - * @file_path: File path to read (relative to the PXE file) 143 - * @file_addr: Address to load file to 144 - * Returns 1 for success, or < 0 on error 145 - */ 146 138 int get_pxe_file(struct pxe_context *ctx, const char *file_path, 147 139 ulong file_addr) 148 140 { ··· 150 142 int err; 151 143 char *buf; 152 144 153 - err = get_relfile(ctx, file_path, file_addr, &size); 145 + err = get_relfile(ctx, file_path, file_addr, BFI_EXTLINUX_CFG, 146 + &size); 154 147 if (err < 0) 155 148 return err; 156 149 ··· 199 192 * @file_path: File path to read (relative to the PXE file) 200 193 * @envaddr_name: Name of environment variable which contains the address to 201 194 * load to 195 + * @type: File type 202 196 * @filesizep: Returns the file size in bytes 203 197 * Returns 1 on success, -ENOENT if @envaddr_name does not exist as an 204 198 * environment variable, -EINVAL if its format is not valid hex, or other 205 199 * value < 0 on other error 206 200 */ 207 201 static int get_relfile_envaddr(struct pxe_context *ctx, const char *file_path, 208 - const char *envaddr_name, ulong *filesizep) 202 + const char *envaddr_name, 203 + enum bootflow_img_t type, ulong *filesizep) 209 204 { 210 205 unsigned long file_addr; 211 206 char *envaddr; ··· 217 212 if (strict_strtoul(envaddr, 16, &file_addr) < 0) 218 213 return -EINVAL; 219 214 220 - return get_relfile(ctx, file_path, file_addr, filesizep); 215 + return get_relfile(ctx, file_path, file_addr, type, filesizep); 221 216 } 222 217 223 218 /** ··· 405 400 406 401 /* Load overlay file */ 407 402 err = get_relfile_envaddr(ctx, overlayfile, "fdtoverlay_addr_r", 403 + (enum bootflow_img_t)IH_TYPE_FLATDT, 408 404 NULL); 409 405 if (err < 0) { 410 406 printf("Failed loading overlay %s\n", overlayfile); ··· 490 486 } 491 487 492 488 if (get_relfile_envaddr(ctx, label->kernel, "kernel_addr_r", 493 - NULL) < 0) { 489 + (enum bootflow_img_t)IH_TYPE_KERNEL, NULL) 490 + < 0) { 494 491 printf("Skipping %s for failure retrieving kernel\n", 495 492 label->name); 496 493 return 1; ··· 516 513 } else if (label->initrd) { 517 514 ulong size; 518 515 if (get_relfile_envaddr(ctx, label->initrd, "ramdisk_addr_r", 516 + (enum bootflow_img_t)IH_TYPE_RAMDISK, 519 517 &size) < 0) { 520 518 printf("Skipping %s for failure retrieving initrd\n", 521 519 label->name); ··· 661 659 662 660 if (fdtfile) { 663 661 int err = get_relfile_envaddr(ctx, fdtfile, 664 - "fdt_addr_r", NULL); 662 + "fdt_addr_r", 663 + (enum bootflow_img_t)IH_TYPE_FLATDT, NULL); 665 664 666 665 free(fdtfilefree); 667 666 if (err < 0) { ··· 1548 1547 if (IS_ENABLED(CONFIG_CMD_BMP)) { 1549 1548 /* display BMP if available */ 1550 1549 if (cfg->bmp) { 1551 - if (get_relfile(ctx, cfg->bmp, image_load_addr, NULL)) { 1550 + if (get_relfile(ctx, cfg->bmp, image_load_addr, 1551 + BFI_LOGO, NULL)) { 1552 1552 #if defined(CONFIG_VIDEO) 1553 1553 struct udevice *dev; 1554 1554
+3 -2
boot/vbe_simple.c
··· 160 160 } 161 161 162 162 static int vbe_simple_read_file(struct udevice *dev, struct bootflow *bflow, 163 - const char *file_path, ulong addr, ulong *sizep) 163 + const char *file_path, ulong addr, 164 + enum bootflow_img_t type, ulong *sizep) 164 165 { 165 166 int ret; 166 167 167 168 if (vbe_phase() == VBE_PHASE_OS) { 168 169 ret = bootmeth_common_read_file(dev, bflow, file_path, addr, 169 - sizep); 170 + type, sizep); 170 171 if (ret) 171 172 return log_msg_ret("os", ret); 172 173 }
+9
cmd/Kconfig
··· 328 328 329 329 This command is not necessary for bootstd to work. 330 330 331 + config CMD_BOOTSTD 332 + bool "bootstd" 333 + depends on BOOTSTD 334 + default y if BOOTSTD_FULL 335 + help 336 + Provide general information and control for bootstd. 337 + 338 + This command is not necessary for bootstd to work. 339 + 331 340 config BOOTM_EFI 332 341 bool "Support booting UEFI FIT images" 333 342 depends on EFI_BINARY_EXEC && CMD_BOOTM && FIT
+1
cmd/Makefile
··· 23 23 obj-$(CONFIG_CMD_BOOTDEV) += bootdev.o 24 24 obj-$(CONFIG_CMD_BOOTFLOW) += bootflow.o 25 25 obj-$(CONFIG_CMD_BOOTMETH) += bootmeth.o 26 + obj-$(CONFIG_CMD_BOOTSTD) += bootstd.o 26 27 obj-$(CONFIG_CMD_SOURCE) += source.o 27 28 obj-$(CONFIG_CMD_BCB) += bcb.o 28 29 obj-$(CONFIG_CMD_BDI) += bdinfo.o
+1 -1
cmd/bootdev.c
··· 81 81 82 82 dev = priv->cur_bootdev; 83 83 84 - /* Count the number of bootflows, including how many are valid*/ 84 + /* Count the number of bootflows, including how many are valid */ 85 85 num_valid = 0; 86 86 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0; 87 87 !ret;
+3 -3
cmd/bootflow.c
··· 197 197 show_header(); 198 198 } 199 199 if (dev) 200 - bootdev_clear_bootflows(dev); 200 + bootstd_clear_bootflows_for_bootdev(dev); 201 201 else 202 202 bootstd_clear_glob(); 203 203 for (i = 0, ··· 207 207 bflow.err = ret; 208 208 if (!ret) 209 209 num_valid++; 210 - ret = bootdev_add_bootflow(&bflow); 211 - if (ret) { 210 + ret = bootstd_add_bootflow(&bflow); 211 + if (ret < 0) { 212 212 printf("Out of memory\n"); 213 213 return CMD_RET_FAILURE; 214 214 }
+65
cmd/bootstd.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * 'bootstd' command 4 + * 5 + * Copyright 2024 Google LLC 6 + * Written by Simon Glass <sjg@chromium.org> 7 + */ 8 + 9 + #include <bootdev.h> 10 + #include <bootflow.h> 11 + #include <bootmeth.h> 12 + #include <bootstd.h> 13 + #include <command.h> 14 + #include <dm.h> 15 + #include <malloc.h> 16 + #include <dm/uclass-internal.h> 17 + 18 + static int do_bootstd_images(struct cmd_tbl *cmdtp, int flag, int argc, 19 + char *const argv[]) 20 + { 21 + const struct bootflow *bflow; 22 + struct bootstd_priv *std; 23 + int ret, i; 24 + 25 + ret = bootstd_get_priv(&std); 26 + if (ret) { 27 + printf("Cannot get bootstd (err=%d)\n", ret); 28 + return CMD_RET_FAILURE; 29 + } 30 + 31 + printf("Seq Bootflow Type At Size Filename\n"); 32 + printf("--- ------------------- -------------- -------- -------- ----------------\n"); 33 + 34 + /* 35 + * Use the ordering if we have one, so long as we are not trying to list 36 + * all bootmethds 37 + */ 38 + i = 0; 39 + alist_for_each(bflow, &std->bootflows) { 40 + const struct bootflow_img *img; 41 + 42 + alist_for_each(img, &bflow->images) { 43 + printf("%3d %-20.20s %-15.15s ", 44 + bootflow_get_seq(bflow), bflow->name, 45 + bootflow_img_type_name(img->type)); 46 + if (img->addr) 47 + printf("%8lx", img->addr); 48 + else 49 + printf("%8s", "-"); 50 + printf(" %8lx %s\n", img->size, img->fname); 51 + i++; 52 + } 53 + } 54 + 55 + printf("--- ------------------- -------------- -------- -------- ----------------\n"); 56 + printf("(%d image%s)\n", i, i != 1 ? "s" : ""); 57 + 58 + return 0; 59 + } 60 + 61 + U_BOOT_LONGHELP(bootstd, 62 + "images - list loaded images"); 63 + 64 + U_BOOT_CMD_WITH_SUBCMDS(bootstd, "Standard-boot operation", bootstd_help_text, 65 + U_BOOT_SUBCMD_MKENT(images, 1, 1, do_bootstd_images));
+1 -1
cmd/pxe.c
··· 27 27 }; 28 28 29 29 static int do_get_tftp(struct pxe_context *ctx, const char *file_path, 30 - char *file_addr, ulong *sizep) 30 + char *file_addr, enum bootflow_img_t type, ulong *sizep) 31 31 { 32 32 char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; 33 33 int ret;
+4 -2
cmd/sysboot.c
··· 23 23 }; 24 24 25 25 static int sysboot_read_file(struct pxe_context *ctx, const char *file_path, 26 - char *file_addr, ulong *sizep) 26 + char *file_addr, enum bootflow_img_t type, 27 + ulong *sizep) 27 28 { 28 29 struct sysboot_info *info = ctx->userdata; 29 30 loff_t len_read; ··· 110 111 return CMD_RET_FAILURE; 111 112 } 112 113 113 - if (get_pxe_file(&ctx, filename, pxefile_addr_r) < 0) { 114 + if (get_pxe_file(&ctx, filename, pxefile_addr_r) 115 + < 0) { 114 116 printf("Error reading config file\n"); 115 117 pxe_destroy_ctx(&ctx); 116 118 return 1;
+20 -1
doc/develop/bootstd/overview.rst
··· 453 453 Command interface 454 454 ----------------- 455 455 456 - Three commands are available: 456 + Four commands are available: 457 457 458 458 `bootdev` 459 459 Allows listing of available bootdevs, selecting a particular one and ··· 467 467 `bootmeth` 468 468 Allow listing of available bootmethds, setting the order in which they are 469 469 tried and bootmeth specific configuration. See :doc:`/usage/cmd/bootmeth` 470 + 471 + `bootstd` 472 + Allow access to standard boot itself, so far only for listing images across 473 + all bootflows. See :doc:`/usage/cmd/bootstd` 474 + 475 + Images 476 + ------ 477 + 478 + Standard boot keeps track of images which can or have been loaded. These are 479 + kept in a list attached to each bootflow. They can be listed using the 480 + ``bootstd images`` command (see :doc:`/usage/cmd/bootstd`). 481 + 482 + For now most bootmeths load their images when scanning. Over time, some may 483 + adjust to load them only when needed, but in this case the images will still 484 + be visible. 485 + 486 + Once a bootflow has been selected, images for those that are not selected can 487 + potentially be dropped from the memory map. For now, this is not implemented. 488 + 470 489 471 490 .. _BootflowStates: 472 491
+79
doc/usage/cmd/bootstd.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0+: 2 + 3 + .. index:: 4 + single: bootstd (command) 5 + 6 + bootstd command 7 + =============== 8 + 9 + Synopsis 10 + -------- 11 + 12 + :: 13 + 14 + bootstd images 15 + 16 + Description 17 + ----------- 18 + 19 + The `bootstd` command is used to manage standard boot. At present the only 20 + functionality available is to look at the images which have been loaded, or 21 + could be loaded should a particular bootflow be selected. 22 + 23 + See :doc:`/develop/bootstd/index` for more information. 24 + 25 + bootflow images 26 + ~~~~~~~~~~~~~~~ 27 + 28 + Lists the available images and their location in memory. 29 + 30 + Example 31 + ------- 32 + 33 + This shows listing images attached to various bootflows, then checking the 34 + content of a few of them:: 35 + 36 + => bootflow scan 37 + => bootflow list 38 + Showing all bootflows 39 + Seq Method State Uclass Part Name Filename 40 + --- ----------- ------ -------- ---- ------------------------ ---------------- 41 + 0 extlinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf 42 + 1 script ready mmc 1 mmc4.bootdev.part_1 /boot/boot.scr 43 + 2 cros ready mmc 2 mmc5.bootdev.part_2 44 + 3 cros ready mmc 4 mmc5.bootdev.part_4 45 + --- ----------- ------ -------- ---- ------------------------ ---------------- 46 + (4 bootflows, 4 valid) 47 + => 48 + => bootstd images 49 + Seq Bootflow Type At Size Filename 50 + --- ------------------- -------------- -------- -------- ---------------- 51 + 0 mmc1.bootdev.part_1 extlinux_cfg 8ed5a70 253 /extlinux/extlinux.conf 52 + 1 mmc4.bootdev.part_1 script 8ed9550 c73 /boot/boot.scr 53 + 1 mmc4.bootdev.part_1 logo 8eda2a0 5d42 boot.bmp 54 + 2 mmc5.bootdev.part_2 x86_setup 8ee84d0 3000 setup 55 + 2 mmc5.bootdev.part_2 cmdline 8ee84d0 1000 cmdline 56 + 2 mmc5.bootdev.part_2 kernel - 4000 kernel 57 + 3 mmc5.bootdev.part_4 x86_setup 8eeb4e0 3000 setup 58 + 3 mmc5.bootdev.part_4 cmdline 8eeb4e0 1000 cmdline 59 + 3 mmc5.bootdev.part_4 kernel - 4000 kernel 60 + --- ------------------- -------------- -------- -------- ---------------- 61 + (9 images) 62 + => md 8eda2a0 10 63 + 08eda2a0: 5d424d42 00000000 008a0000 007c0000 BMB]..........|. 64 + 08eda2b0: 00ac0000 002e0000 00010000 00000018 ................ 65 + 08eda2c0: 5cb80000 0b130000 0b130000 00000000 ...\............ 66 + 08eda2d0: 00000000 00000000 ff0000ff 00ff0000 ................ 67 + => md 8ee84d0 10 68 + 08ee84d0: 544f4f42 414d495f 2f3d4547 696c6d76 BOOT_IMAGE=/vmli 69 + 08ee84e0: 2d7a756e 35312e35 312d302e 672d3132 nuz-5.15.0-121-g 70 + 08ee84f0: 72656e65 72206369 3d746f6f 7665642f eneric root=/dev 71 + 08ee8500: 6d766e2f 316e3065 72203170 7571206f /nvme0n1p1 ro qu 72 + 73 + Return value 74 + ------------ 75 + 76 + The return value $? is always 0 (true). 77 + 78 + 79 + .. BootflowStates_:
+1
doc/usage/index.rst
··· 40 40 cmd/bootm 41 41 cmd/bootmenu 42 42 cmd/bootmeth 43 + cmd/bootstd 43 44 cmd/bootz 44 45 cmd/button 45 46 cmd/cat
+9 -27
include/bootdev.h
··· 109 109 * This is attached to each device in the bootdev uclass and accessible via 110 110 * dev_get_uclass_plat(dev) 111 111 * 112 - * @bootflows: List of available bootflows for this bootdev 113 112 * @piro: Priority of this bootdev 114 113 */ 115 114 struct bootdev_uc_plat { 116 - struct list_head bootflow_head; 117 115 enum bootdev_prio_t prio; 118 116 }; 119 117 ··· 184 182 * @probe: true to probe devices, false to leave them as is 185 183 */ 186 184 void bootdev_list(bool probe); 187 - 188 - /** 189 - * bootdev_clear_bootflows() - Clear bootflows from a bootdev 190 - * 191 - * Each bootdev maintains a list of discovered bootflows. This provides a 192 - * way to clear it. These bootflows are removed from the global list too. 193 - * 194 - * @dev: bootdev device to update 195 - */ 196 - void bootdev_clear_bootflows(struct udevice *dev); 197 - 198 - /** 199 - * bootdev_add_bootflow() - Add a bootflow to the bootdev's list 200 - * 201 - * All fields in @bflow must be set up. Note that @bflow->dev is used to add the 202 - * bootflow to that device. 203 - * 204 - * @dev: Bootdev device to add to 205 - * @bflow: Bootflow to add. Note that fields within bflow must be allocated 206 - * since this function takes over ownership of these. This functions makes 207 - * a copy of @bflow itself (without allocating its fields again), so the 208 - * caller must dispose of the memory used by the @bflow pointer itself 209 - * Return: 0 if OK, -ENOMEM if out of memory 210 - */ 211 - int bootdev_add_bootflow(struct bootflow *bflow); 212 185 213 186 /** 214 187 * bootdev_first_bootflow() - Get the first bootflow from a bootdev ··· 427 400 * error 428 401 */ 429 402 int bootdev_get_sibling_blk(struct udevice *dev, struct udevice **blkp); 403 + 404 + /** 405 + * bootdev_get_from_blk() - Get the bootdev given a block device 406 + * 407 + * @blk: Block device to check 408 + * @bootdebp: Returns the bootdev found, if any 409 + * Return 0 if OK, -ve on error 410 + */ 411 + int bootdev_get_from_blk(struct udevice *blk, struct udevice **bootdevp); 430 412 431 413 /** 432 414 * bootdev_unbind_dev() - Unbind a bootdev device
+76 -9
include/bootflow.h
··· 7 7 #ifndef __bootflow_h 8 8 #define __bootflow_h 9 9 10 + #include <alist.h> 10 11 #include <bootdev.h> 12 + #include <image.h> 11 13 #include <dm/ofnode_decl.h> 12 14 #include <linux/list.h> 13 15 ··· 56 58 /** 57 59 * struct bootflow - information about a bootflow 58 60 * 59 - * This is connected into two separate linked lists: 61 + * All bootflows are listed in bootstd's bootflow alist in struct bootstd_priv 60 62 * 61 - * bm_sibling - links all bootflows in the same bootdev 62 - * glob_sibling - links all bootflows in all bootdevs 63 - * 64 - * @bm_node: Points to siblings in the same bootdev 65 - * @glob_node: Points to siblings in the global list (all bootdev) 66 63 * @dev: Bootdev device which produced this bootflow, NULL for flows created by 67 64 * BOOTMETHF_GLOBAL bootmeths 68 65 * @blk: Block device which contains this bootflow, NULL if this is a network ··· 90 87 * @cmdline: OS command line, or NULL if not known (allocated) 91 88 * @x86_setup: Pointer to x86 setup block inside @buf, NULL if not present 92 89 * @bootmeth_priv: Private data for the bootmeth 90 + * @images: List of loaded images (struct bootstd_img) 93 91 */ 94 92 struct bootflow { 95 - struct list_head bm_node; 96 - struct list_head glob_node; 97 93 struct udevice *dev; 98 94 struct udevice *blk; 99 95 int part; ··· 116 112 char *cmdline; 117 113 void *x86_setup; 118 114 void *bootmeth_priv; 115 + struct alist images; 116 + }; 117 + 118 + /** 119 + * bootflow_img_t: Supported image types 120 + * 121 + * This uses image_type_t for most types, but extends it 122 + * 123 + * @BFI_EXTLINUX_CFG: extlinux configuration-file 124 + * @BFI_LOGO: logo image 125 + * @BFI_EFI: EFI PE image 126 + * @BFI_CMDLINE: OS command-line string 127 + */ 128 + enum bootflow_img_t { 129 + BFI_FIRST = IH_TYPE_COUNT, 130 + BFI_EXTLINUX_CFG = BFI_FIRST, 131 + BFI_LOGO, 132 + BFI_EFI, 133 + BFI_CMDLINE, 134 + 135 + BFI_COUNT, 136 + }; 137 + 138 + /** 139 + * struct bootflow_img - Information about an image which has been loaded 140 + * 141 + * This keeps track of a single, loaded image. 142 + * 143 + * @fname: Filename used to load the image (allocated) 144 + * @type: Image type (IH_TYPE_...) 145 + * @addr: Address to which the image was loaded, 0 if not yet loaded 146 + * @size: Size of the image 147 + */ 148 + struct bootflow_img { 149 + char *fname; 150 + enum bootflow_img_t type; 151 + ulong addr; 152 + ulong size; 119 153 }; 120 154 121 155 /** ··· 393 427 /** 394 428 * bootflow_remove() - Remove a bootflow and free its memory 395 429 * 396 - * This updates the linked lists containing the bootflow then frees it. 430 + * This updates the 'global' linked list containing the bootflow, then frees it. 431 + * It does not remove it from bootflows alist in struct bootstd_priv 432 + * 433 + * This does not free bflow itself, since this is assumed to be in an alist 397 434 * 398 435 * @bflow: Bootflow to remove 399 436 */ ··· 568 605 * Return: 0 if OK -ve on error 569 606 */ 570 607 int bootflow_cmdline_auto(struct bootflow *bflow, const char *arg); 608 + 609 + /** 610 + * bootflow_img_type_name() - Get the name for an image type 611 + * 612 + * @type: Type to check (either enum bootflow_img_t or enum image_type_t 613 + * Return: Image name, or "unknown" if not known 614 + */ 615 + const char *bootflow_img_type_name(enum bootflow_img_t type); 616 + 617 + /** 618 + * bootflow_img_add() - Add a new image to a bootflow 619 + * 620 + * @bflow: Bootflow to add to 621 + * @fname: Image filename (will be allocated) 622 + * @type: Image type 623 + * @addr: Address the image was loaded to, or 0 if not loaded 624 + * @size: Image size 625 + * Return: pointer to the added image, or NULL if out of memory 626 + */ 627 + struct bootflow_img *bootflow_img_add(struct bootflow *bflow, const char *fname, 628 + enum bootflow_img_t type, ulong addr, 629 + ulong size); 630 + /** 631 + * bootflow_get_seq() - Get the sequence number of a bootflow 632 + * 633 + * Bootflows are numbered by their position in the bootstd list. 634 + * 635 + * Return: Sequence number of bootflow (0 = first) 636 + */ 637 + int bootflow_get_seq(const struct bootflow *bflow); 571 638 572 639 #endif
+15 -7
include/bootmeth.h
··· 7 7 #ifndef __bootmeth_h 8 8 #define __bootmeth_h 9 9 10 + #include <bootflow.h> 10 11 #include <linux/bitops.h> 11 12 12 13 struct blk_desc; 13 - struct bootflow; 14 - struct bootflow_iter; 15 14 struct udevice; 16 15 17 16 /** ··· 117 116 * @bflow: Bootflow providing info on where to read from 118 117 * @file_path: Path to file (may be absolute or relative) 119 118 * @addr: Address to load file 119 + * @type: File type (IH_TYPE_...) 120 120 * @sizep: On entry provides the maximum permitted size; on exit 121 121 * returns the size of the file 122 122 * Return: 0 if OK, -ENOSPC if the file is too large for @sizep, other 123 123 * -ve value if something else goes wrong 124 124 */ 125 125 int (*read_file)(struct udevice *dev, struct bootflow *bflow, 126 - const char *file_path, ulong addr, ulong *sizep); 126 + const char *file_path, ulong addr, 127 + enum bootflow_img_t type, ulong *sizep); 127 128 #if CONFIG_IS_ENABLED(BOOTSTD_FULL) 128 129 /** 129 130 * readall() - read all files for a bootflow ··· 245 246 * @bflow: Bootflow providing info on where to read from 246 247 * @file_path: Path to file (may be absolute or relative) 247 248 * @addr: Address to load file 249 + * @type: File type (IH_TYPE_...) 248 250 * @sizep: On entry provides the maximum permitted size; on exit 249 251 * returns the size of the file 250 252 * Return: 0 if OK, -ENOSPC if the file is too large for @sizep, other 251 253 * -ve value if something else goes wrong 252 254 */ 253 255 int bootmeth_read_file(struct udevice *dev, struct bootflow *bflow, 254 - const char *file_path, ulong addr, ulong *sizep); 256 + const char *file_path, ulong addr, 257 + enum bootflow_img_t type, ulong *sizep); 255 258 256 259 /** 257 260 * bootmeth_read_all() - read all bootflow files ··· 365 368 * @bflow: Information about file to read 366 369 * @size_limit: Maximum file size to permit 367 370 * @align: Allocation alignment (1 for unaligned) 371 + * @type: File type (IH_TYPE_...) 368 372 * Return: 0 if OK, -E2BIG if file is too large, -ENOMEM if out of memory, 369 373 * other -ve on other error 370 374 */ 371 - int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align); 375 + int bootmeth_alloc_file(struct bootflow *bflow, uint size_limit, uint align, 376 + enum bootflow_img_t type); 372 377 373 378 /** 374 379 * bootmeth_alloc_other() - Allocate and read a file for a bootflow ··· 379 384 * 380 385 * @bflow: Information about file to read 381 386 * @fname: Filename to read from (within bootflow->subdir) 387 + * @type: File type (IH_TYPE_...) 382 388 * @bufp: Returns a pointer to the allocated buffer 383 389 * @sizep: Returns the size of the buffer 384 390 * Return: 0 if OK, -ENOMEM if out of memory, other -ve on other error 385 391 */ 386 392 int bootmeth_alloc_other(struct bootflow *bflow, const char *fname, 387 - void **bufp, uint *sizep); 393 + enum bootflow_img_t type, void **bufp, uint *sizep); 388 394 389 395 /** 390 396 * bootmeth_common_read_file() - Common handler for reading a file ··· 395 401 * @bflow: Bootflow information 396 402 * @file_path: Path to file 397 403 * @addr: Address to load file to 404 + * @type: File type (IH_TYPE_...) 398 405 * @sizep: On entry, the maximum file size to accept, on exit the actual file 399 406 * size read 400 407 */ 401 408 int bootmeth_common_read_file(struct udevice *dev, struct bootflow *bflow, 402 - const char *file_path, ulong addr, ulong *sizep); 409 + const char *file_path, ulong addr, 410 + enum bootflow_img_t type, ulong *sizep); 403 411 404 412 /** 405 413 * bootmeth_get_bootflow() - Get a bootflow from a global bootmeth
+48 -2
include/bootstd.h
··· 9 9 #ifndef __bootstd_h 10 10 #define __bootstd_h 11 11 12 + #include <alist.h> 12 13 #include <dm/ofnode_decl.h> 13 14 #include <linux/list.h> 14 15 #include <linux/types.h> ··· 30 31 * terminated) 31 32 * @cur_bootdev: Currently selected bootdev (for commands) 32 33 * @cur_bootflow: Currently selected bootflow (for commands) 33 - * @glob_head: Head for the global list of all bootflows across all bootdevs 34 + * @bootflows: (struct bootflow) Global list of all bootflows across all 35 + * bootdevs 34 36 * @bootmeth_count: Number of bootmeth devices in @bootmeth_order 35 37 * @bootmeth_order: List of bootmeth devices to use, in order, NULL-terminated 36 38 * @vbe_bootmeth: Currently selected VBE bootmeth, NULL if none ··· 44 46 const char **env_order; 45 47 struct udevice *cur_bootdev; 46 48 struct bootflow *cur_bootflow; 47 - struct list_head glob_head; 49 + struct alist bootflows; 48 50 int bootmeth_count; 49 51 struct udevice **bootmeth_order; 50 52 struct udevice *vbe_bootmeth; ··· 90 92 int bootstd_get_priv(struct bootstd_priv **stdp); 91 93 92 94 /** 95 + * bootstd_try_priv() - Try to get the (single) state for the bootstd system 96 + * 97 + * The state holds a global list of all bootflows that have been found. This 98 + * function returns the state if available, but takes care not to create the 99 + * device (or uclass) if it doesn't exist. 100 + * 101 + * This function is safe to use in the 'unbind' path. It will always return NULL 102 + * unless the bootstd device is probed and ready, e.g. bootstd_get_priv() has 103 + * previously been called. 104 + * 105 + * TODO(sjg@chromium.org): Consider adding a bootstd pointer to global_data 106 + * 107 + * Return: pointer if the device exists, else NULL 108 + */ 109 + struct bootstd_priv *bootstd_try_priv(void); 110 + 111 + /** 93 112 * bootstd_clear_glob() - Clear the global list of bootflows 94 113 * 95 114 * This removes all bootflows globally and across all bootdevs. ··· 104 123 * Returns: -ve error value (does not return except on failure to boot) 105 124 */ 106 125 int bootstd_prog_boot(void); 126 + 127 + /** 128 + * bootstd_add_bootflow() - Add a bootflow to the global list 129 + * 130 + * All fields in @bflow must be set up. Note that @bflow->dev is used to add the 131 + * bootflow to that device. 132 + * 133 + * The bootflow is also added to the global list of all bootflows 134 + * 135 + * @dev: Bootdev device to add to 136 + * @bflow: Bootflow to add. Note that fields within bflow must be allocated 137 + * since this function takes over ownership of these. This functions makes 138 + * a copy of @bflow itself (without allocating its fields again), so the 139 + * caller must dispose of the memory used by the @bflow pointer itself 140 + * Return: element number in the list, if OK, -ENOMEM if out of memory 141 + */ 142 + int bootstd_add_bootflow(struct bootflow *bflow); 143 + 144 + /** 145 + * bootstd_clear_bootflows_for_bootdev() - Clear bootflows from a bootdev 146 + * 147 + * Each bootdev maintains a list of discovered bootflows. This provides a 148 + * way to clear it. These bootflows are removed from the global list too. 149 + * 150 + * @dev: bootdev device to update 151 + */ 152 + int bootstd_clear_bootflows_for_bootdev(struct udevice *dev); 107 153 108 154 #endif
+13 -1
include/pxe_utils.h
··· 3 3 #ifndef __PXE_UTILS_H 4 4 #define __PXE_UTILS_H 5 5 6 + #include <bootflow.h> 6 7 #include <linux/list.h> 7 8 8 9 /* ··· 82 83 }; 83 84 84 85 struct pxe_context; 86 + 87 + /** 88 + * Read a file 89 + * 90 + * @ctx: PXE context 91 + * @file_path: Full path to filename to read 92 + * @file_addr: String containing the to which to read the file 93 + * @type: File type 94 + * @fileszeip: Returns file size 95 + */ 85 96 typedef int (*pxe_getfile_func)(struct pxe_context *ctx, const char *file_path, 86 - char *file_addr, ulong *filesizep); 97 + char *file_addr, enum bootflow_img_t type, 98 + ulong *filesizep); 87 99 88 100 /** 89 101 * struct pxe_context - context information for PXE parsing
+106
test/boot/bootflow.c
··· 15 15 #include <efi.h> 16 16 #include <efi_loader.h> 17 17 #include <expo.h> 18 + #include <mapmem.h> 18 19 #ifdef CONFIG_SANDBOX 19 20 #include <asm/test.h> 20 21 #endif ··· 75 76 ut_assert_nextline(" 0 extlinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf"); 76 77 ut_assert_nextlinen("---"); 77 78 ut_assert_nextline("(1 bootflow, 1 valid)"); 79 + ut_assert_console_end(); 80 + 81 + ut_assertok(run_command("bootstd images", 0)); 82 + ut_assert_nextlinen("Seq"); 83 + ut_assert_nextlinen("---"); 84 + ut_assert_nextlinen(" 0 mmc1.bootdev.part_1 extlinux_cfg"); 85 + ut_assert_nextlinen("---"); 86 + ut_assert_nextline("(1 image)"); 78 87 ut_assert_console_end(); 79 88 80 89 return 0; ··· 1193 1202 ut_assert_nextlinen("---"); 1194 1203 ut_assert_skip_to_line("(3 bootflows, 3 valid)"); 1195 1204 1205 + ut_assertok(run_command("bootstd images", 0)); 1206 + ut_assert_nextlinen("Seq"); 1207 + ut_assert_nextlinen("---"); 1208 + ut_assert_nextlinen(" 0 mmc1.bootdev.part_1 extlinux_cfg"); 1209 + ut_assert_nextlinen(" 1 mmc5.bootdev.part_2 x86_setup"); 1210 + ut_assert_nextlinen(" 1 mmc5.bootdev.part_2 cmdline"); 1211 + ut_assert_nextlinen(" 1 mmc5.bootdev.part_2 kernel - 4000 kernel"); 1212 + ut_assert_nextlinen(" 2 mmc5.bootdev.part_4 x86_setup"); 1213 + ut_assert_nextlinen(" 2 mmc5.bootdev.part_4 cmdline"); 1214 + ut_assert_nextlinen(" 2 mmc5.bootdev.part_4 kernel - 4000 kernel"); 1215 + ut_assert_nextlinen("---"); 1216 + ut_assert_nextline("(7 images)"); 1217 + 1196 1218 ut_assert_console_end(); 1197 1219 1198 1220 return 0; ··· 1307 1329 return 0; 1308 1330 } 1309 1331 BOOTSTD_TEST(bootflow_efi, UTF_CONSOLE); 1332 + 1333 + /* Check 'bootflow scan' provides a list of images */ 1334 + static int bootstd_images(struct unit_test_state *uts) 1335 + { 1336 + static const char *order[] = {"mmc2", "mmc1", "mmc4", "mmc5", NULL}; 1337 + const struct legacy_img_hdr *hdr; 1338 + const struct bootflow_img *img; 1339 + const struct bootflow *bflow; 1340 + struct bootstd_priv *std; 1341 + const char **old_order; 1342 + struct udevice *dev; 1343 + ofnode root, node; 1344 + ulong data, len; 1345 + char *ptr; 1346 + 1347 + /* get access to the current bootflow */ 1348 + ut_assertok(bootstd_get_priv(&std)); 1349 + 1350 + ut_assertok(prep_mmc_bootdev(uts, "mmc4", true, &old_order)); 1351 + 1352 + /* bind mmc5 too, for cros */ 1353 + root = oftree_root(oftree_default()); 1354 + node = ofnode_find_subnode(root, "mmc5"); 1355 + ut_assert(ofnode_valid(node)); 1356 + ut_assertok(lists_bind_fdt(gd->dm_root, node, &dev, NULL, false)); 1357 + 1358 + std->bootdev_order = order; 1359 + ut_assertok(run_command("bootflow scan", 0)); 1360 + ut_assert_console_end(); 1361 + std->bootdev_order = old_order; 1362 + 1363 + ut_assertok(run_command("bootflow list", 0)); 1364 + ut_assert_skip_to_line("(4 bootflows, 4 valid)"); 1365 + 1366 + ut_assertok(run_command("bootstd images", 0)); 1367 + ut_assert_nextlinen("Seq"); 1368 + ut_assert_nextlinen("---"); 1369 + ut_assert_nextlinen(" 0 mmc1.bootdev.part_1 extlinux_cfg"); 1370 + ut_assert_nextlinen(" 1 mmc4.bootdev.part_1 script"); 1371 + ut_assert_nextlinen(" 1 mmc4.bootdev.part_1 logo"); 1372 + ut_assert_nextlinen(" 2 mmc5.bootdev.part_2 x86_setup"); 1373 + ut_assert_nextlinen(" 2 mmc5.bootdev.part_2 cmdline"); 1374 + ut_assert_nextlinen(" 2 mmc5.bootdev.part_2 kernel -"); 1375 + ut_assert_nextlinen(" 3 mmc5.bootdev.part_4 x86_setup"); 1376 + ut_assert_nextlinen(" 3 mmc5.bootdev.part_4 cmdline"); 1377 + ut_assert_nextlinen(" 3 mmc5.bootdev.part_4 kernel -"); 1378 + ut_assert_nextlinen("---"); 1379 + ut_assert_nextline("(9 images)"); 1380 + 1381 + /* check the first image */ 1382 + bflow = alist_get(&std->bootflows, 0, struct bootflow); 1383 + img = alist_get(&bflow->images, 0, struct bootflow_img); 1384 + ut_asserteq_strn("# extlinux.conf", map_sysmem(img->addr, 0)); 1385 + 1386 + /* check the second image */ 1387 + bflow = alist_get(&std->bootflows, 1, struct bootflow); 1388 + img = alist_get(&bflow->images, 0, struct bootflow_img); 1389 + 1390 + /* this is the length of the script in bytes */ 1391 + hdr = map_sysmem(img->addr, 0); 1392 + image_multi_getimg(hdr, 0, &data, &len); 1393 + ptr = (void *)data; 1394 + ut_asserteq_strn("# DO NOT EDIT THIS FILE", ptr); 1395 + 1396 + /* check the ChromiumOS images */ 1397 + bflow = alist_get(&std->bootflows, 2, struct bootflow); 1398 + img = alist_get(&bflow->images, 1, struct bootflow_img); 1399 + ptr = map_sysmem(img->addr, 0); 1400 + ut_asserteq_strn("BOOT_IMAGE=/vmlinuz-5.15.0-121-generic root=", ptr); 1401 + 1402 + /* 1403 + * the x86 setup is not a real binary, so just check that it is empty, 1404 + * so that if this changes in the future someone will notice and update 1405 + * this test 1406 + */ 1407 + img = alist_get(&bflow->images, 0, struct bootflow_img); 1408 + ptr = map_sysmem(img->addr, 0); 1409 + ut_asserteq(0, *(ulong *)ptr); 1410 + 1411 + ut_assert_console_end(); 1412 + 1413 + return 0; 1414 + } 1415 + BOOTSTD_TEST(bootstd_images, UTF_CONSOLE);
+2 -1
test/py/tests/test_ut.py
··· 343 343 start, size, num, name = line.split(maxsplit=3) 344 344 parts[int(num)] = Partition(int(start), int(size), name) 345 345 346 + # Set up the kernel command-line 346 347 dummy = os.path.join(cons.config.result_dir, 'dummy.txt') 347 348 with open(dummy, 'wb') as outf: 348 - outf.write(b'dummy\n') 349 + outf.write(b'BOOT_IMAGE=/vmlinuz-5.15.0-121-generic root=/dev/nvme0n1p1 ro quiet splash vt.handoff=7') 349 350 350 351 # For now we just use dummy kernels. This limits testing to just detecting 351 352 # a signed kernel. We could add support for the x86 data structures so that