From 2b80bc1eee28c20173c09ee5d887cce02097552f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 30 Jul 2022 15:52:25 -0600 Subject: [PATCH] bootstd: Support bootflows with global bootmeths Add support for handling this concept in bootflows. Update the 'bootflow' command to allow only the normal bootmeths to be used. This alllows skipping EFI bootmgr and VBE, for example. Signed-off-by: Simon Glass --- boot/bootflow.c | 58 +++++++++++++++++++++++++++++++++++++++------- cmd/bootflow.c | 8 +++++-- include/bootflow.h | 16 ++++++++++--- 3 files changed, 69 insertions(+), 13 deletions(-) diff --git a/boot/bootflow.c b/boot/bootflow.c index 37bccb823a..08ea033632 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -86,6 +86,7 @@ int bootflow_next_glob(struct bootflow **bflowp) void bootflow_iter_init(struct bootflow_iter *iter, int flags) { memset(iter, '\0', sizeof(*iter)); + iter->first_glob_method = -1; iter->flags = flags; } @@ -115,11 +116,17 @@ int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter, static void bootflow_iter_set_dev(struct bootflow_iter *iter, struct udevice *dev) { + struct bootmeth_uc_plat *ucp = dev_get_uclass_plat(iter->method); + iter->dev = dev; if ((iter->flags & (BOOTFLOWF_SHOW | BOOTFLOWF_SINGLE_DEV)) == BOOTFLOWF_SHOW) { if (dev) printf("Scanning bootdev '%s':\n", dev->name); + else if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && + ucp->flags & BOOTMETHF_GLOBAL) + printf("Scanning global bootmeth '%s':\n", + iter->method->name); else printf("No more bootdevs\n"); } @@ -133,8 +140,12 @@ static void bootflow_iter_set_dev(struct bootflow_iter *iter, static int iter_incr(struct bootflow_iter *iter) { struct udevice *dev; + bool inc_dev = true; + bool global; int ret; + global = iter->doing_global; + if (iter->err == BF_NO_MORE_DEVICES) return BF_NO_MORE_DEVICES; @@ -144,6 +155,21 @@ static int iter_incr(struct bootflow_iter *iter) iter->method = iter->method_order[iter->cur_method]; return 0; } + + /* + * If we have finished scanning the global bootmeths, start the + * normal bootdev scan + */ + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && global) { + iter->num_methods = iter->first_glob_method; + iter->doing_global = false; + + /* + * Don't move to the next dev as we haven't tried this + * one yet! + */ + inc_dev = false; + } } /* No more bootmeths; start at the first one, and... */ @@ -169,14 +195,18 @@ static int iter_incr(struct bootflow_iter *iter) /* ...select next bootdev */ if (iter->flags & BOOTFLOWF_SINGLE_DEV) { ret = -ENOENT; - } else if (++iter->cur_dev == iter->num_devs) { - ret = -ENOENT; - bootflow_iter_set_dev(iter, NULL); } else { - dev = iter->dev_order[iter->cur_dev]; - ret = device_probe(dev); - if (!log_msg_ret("probe", ret)) - bootflow_iter_set_dev(iter, dev); + if (inc_dev) + iter->cur_dev++; + if (iter->cur_dev == iter->num_devs) { + ret = -ENOENT; + bootflow_iter_set_dev(iter, NULL); + } else { + dev = iter->dev_order[iter->cur_dev]; + ret = device_probe(dev); + if (!log_msg_ret("probe", ret)) + bootflow_iter_set_dev(iter, dev); + } } /* if there are no more bootdevs, give up */ @@ -199,6 +229,15 @@ static int bootflow_check(struct bootflow_iter *iter, struct bootflow *bflow) struct udevice *dev; int ret; + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->doing_global) { + bootflow_iter_set_dev(iter, NULL); + ret = bootmeth_get_bootflow(iter->method, bflow); + if (ret) + return log_msg_ret("glob", ret); + + return 0; + } + dev = iter->dev; ret = bootdev_get_bootflow(dev, iter, bflow); @@ -231,12 +270,13 @@ int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter, { int ret; + if (dev) + flags |= BOOTFLOWF_SKIP_GLOBAL; bootflow_iter_init(iter, flags); ret = bootdev_setup_iter_order(iter, &dev); if (ret) return log_msg_ret("obdev", -ENODEV); - bootflow_iter_set_dev(iter, dev); ret = bootmeth_setup_iter_order(iter); if (ret) @@ -244,6 +284,8 @@ int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter, /* Find the first bootmeth (there must be at least one!) */ iter->method = iter->method_order[iter->cur_method]; + if (!IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) || !iter->doing_global) + bootflow_iter_set_dev(iter, dev); ret = bootflow_check(iter, bflow); if (ret) { diff --git a/cmd/bootflow.c b/cmd/bootflow.c index 47899245ee..313103d277 100644 --- a/cmd/bootflow.c +++ b/cmd/bootflow.c @@ -95,7 +95,8 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc, struct bootflow_iter iter; struct udevice *dev; struct bootflow bflow; - bool all = false, boot = false, errors = false, list = false; + bool all = false, boot = false, errors = false, no_global = false; + bool list = false; int num_valid = 0; bool has_args; int ret, i; @@ -112,6 +113,7 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc, all = strchr(argv[1], 'a'); boot = strchr(argv[1], 'b'); errors = strchr(argv[1], 'e'); + no_global = strchr(argv[1], 'G'); list = strchr(argv[1], 'l'); argc--; argv++; @@ -137,6 +139,8 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc, flags |= BOOTFLOWF_SHOW; if (all) flags |= BOOTFLOWF_ALL; + if (no_global) + flags |= BOOTFLOWF_SKIP_GLOBAL; /* * If we have a device, just scan for bootflows attached to that device @@ -383,7 +387,7 @@ static int do_bootflow_boot(struct cmd_tbl *cmdtp, int flag, int argc, #ifdef CONFIG_SYS_LONGHELP static char bootflow_help_text[] = #ifdef CONFIG_CMD_BOOTFLOW_FULL - "scan [-abel] [bdev] - scan for valid bootflows (-l list, -a all, -e errors, -b boot)\n" + "scan [-abeGl] [bdev] - scan for valid bootflows (-l list, -a all, -e errors, -b boot, -G no global)\n" "bootflow list [-e] - list scanned bootflows (-e errors)\n" "bootflow select [|] - select a bootflow\n" "bootflow info [-d] - show info on current bootflow (-d dump bootflow)\n" diff --git a/include/bootflow.h b/include/bootflow.h index 4fa482a678..6aa3d1fff8 100644 --- a/include/bootflow.h +++ b/include/bootflow.h @@ -77,12 +77,14 @@ struct bootflow { * @BOOTFLOWF_SHOW: Show each bootdev before scanning it * @BOOTFLOWF_ALL: Return bootflows with errors as well * @BOOTFLOWF_SINGLE_DEV: Just scan one bootmeth + * @BOOTFLOWF_SKIP_GLOBAL: Don't scan global bootmeths */ enum bootflow_flags_t { BOOTFLOWF_FIXED = 1 << 0, BOOTFLOWF_SHOW = 1 << 1, BOOTFLOWF_ALL = 1 << 2, BOOTFLOWF_SINGLE_DEV = 1 << 3, + BOOTFLOWF_SKIP_GLOBAL = 1 << 4, }; /** @@ -102,8 +104,10 @@ enum bootflow_flags_t { * updated to a larger value, no less than the number of available partitions. * This ensures that iteration works through all partitions on the bootdev. * - * @flags: Flags to use (see enum bootflow_flags_t) - * @dev: Current bootdev + * @flags: Flags to use (see enum bootflow_flags_t). If BOOTFLOWF_GLOBAL_FIRST is + * enabled then the global bootmeths are being scanned, otherwise we have + * moved onto the bootdevs + * @dev: Current bootdev, NULL if none * @part: Current partition number (0 for whole device) * @method: Current bootmeth * @max_part: Maximum hardware partition number in @dev, 0 if there is no @@ -117,7 +121,11 @@ enum bootflow_flags_t { * with the first one on the list * @num_methods: Number of bootmeth devices in @method_order * @cur_method: Current method number, an index into @method_order - * @method_order: List of bootmeth devices to use, in order + * @first_glob_method: First global method, if any, else -1 + * @method_order: List of bootmeth devices to use, in order. The normal methods + * appear first, then the global ones, if any + * @doing_global: true if we are iterating through the global bootmeths (which + * happens before the normal ones) */ struct bootflow_iter { int flags; @@ -131,7 +139,9 @@ struct bootflow_iter { struct udevice **dev_order; int num_methods; int cur_method; + int first_glob_method; struct udevice **method_order; + bool doing_global; }; /**