diff --git a/boot/bootflow.c b/boot/bootflow.c index 08ea0336324..5d94a27ff84 100644 --- a/boot/bootflow.c +++ b/boot/bootflow.c @@ -278,7 +278,7 @@ int bootflow_scan_bootdev(struct udevice *dev, struct bootflow_iter *iter, if (ret) return log_msg_ret("obdev", -ENODEV); - ret = bootmeth_setup_iter_order(iter); + ret = bootmeth_setup_iter_order(iter, !(flags & BOOTFLOWF_SKIP_GLOBAL)); if (ret) return log_msg_ret("obmeth", -ENODEV); diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c index 88bbb32c47f..2d7652edeab 100644 --- a/boot/bootmeth-uclass.c +++ b/boot/bootmeth-uclass.c @@ -85,18 +85,7 @@ int bootmeth_get_bootflow(struct udevice *dev, struct bootflow *bflow) return ops->read_bootflow(dev, bflow); } -/** - * bootmeth_setup_iter_order() - Set up the ordering of bootmeths to scan - * - * This sets up the ordering information in @iter, based on the selected - * ordering of the bootmethds in bootstd_priv->bootmeth_order. If there is no - * ordering there, then all bootmethods are added - * - * @iter: Iterator to update with the order - * Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve - * on other error - */ -int bootmeth_setup_iter_order(struct bootflow_iter *iter) +int bootmeth_setup_iter_order(struct bootflow_iter *iter, bool include_global) { struct bootstd_priv *std; struct udevice **order; @@ -119,31 +108,77 @@ int bootmeth_setup_iter_order(struct bootflow_iter *iter) /* If we have an ordering, copy it */ if (IS_ENABLED(CONFIG_BOOTSTD_FULL) && std->bootmeth_count) { - memcpy(order, std->bootmeth_order, - count * sizeof(struct bootmeth *)); - } else { - struct udevice *dev; - int i, upto; + int i; /* - * Get a list of bootmethods, in seq order (i.e. using aliases). - * There may be gaps so try to count up high enough to find them - * all. + * We don't support skipping global bootmeths. Instead, the user + * should omit them from the ordering */ - for (i = 0, upto = 0; upto < count && i < 20 + count * 2; i++) { - ret = uclass_get_device_by_seq(UCLASS_BOOTMETH, i, - &dev); - if (!ret) - order[upto++] = dev; + if (!include_global) + return log_msg_ret("glob", -EPERM); + memcpy(order, std->bootmeth_order, + count * sizeof(struct bootmeth *)); + + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL)) { + for (i = 0; i < count; i++) { + struct udevice *dev = order[i]; + struct bootmeth_uc_plat *ucp; + bool is_global; + + ucp = dev_get_uclass_plat(dev); + is_global = ucp->flags & + BOOTMETHF_GLOBAL; + if (is_global) { + iter->first_glob_method = i; + break; + } + } + } + } else { + struct udevice *dev; + int i, upto, pass; + + /* + * Do two passes, one to find the normal bootmeths and another + * to find the global ones, if required, The global ones go at + * the end. + */ + for (pass = 0, upto = 0; pass < 1 + include_global; pass++) { + if (pass) + iter->first_glob_method = upto; + /* + * Get a list of bootmethods, in seq order (i.e. using + * aliases). There may be gaps so try to count up high + * enough to find them all. + */ + for (i = 0; upto < count && i < 20 + count * 2; i++) { + struct bootmeth_uc_plat *ucp; + bool is_global; + + ret = uclass_get_device_by_seq(UCLASS_BOOTMETH, + i, &dev); + if (ret) + continue; + ucp = dev_get_uclass_plat(dev); + is_global = + IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && + (ucp->flags & BOOTMETHF_GLOBAL); + if (pass ? is_global : !is_global) + order[upto++] = dev; + } } count = upto; } if (!count) return log_msg_ret("count2", -ENOENT); + if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && include_global && + iter->first_glob_method != -1 && iter->first_glob_method != count) { + iter->cur_method = iter->first_glob_method; + iter->doing_global = true; + } iter->method_order = order; iter->num_methods = count; - iter->cur_method = 0; return 0; } diff --git a/include/bootmeth.h b/include/bootmeth.h index c93367b0995..50ded055f3f 100644 --- a/include/bootmeth.h +++ b/include/bootmeth.h @@ -209,10 +209,12 @@ int bootmeth_boot(struct udevice *dev, struct bootflow *bflow); * ordering there, then all bootmethods are added * * @iter: Iterator to update with the order + * @include_global: true to add the global bootmeths, in which case they appear + * first * Return: 0 if OK, -ENOENT if no bootdevs, -ENOMEM if out of memory, other -ve * on other error */ -int bootmeth_setup_iter_order(struct bootflow_iter *iter); +int bootmeth_setup_iter_order(struct bootflow_iter *iter, bool include_global); /** * bootmeth_set_order() - Set the bootmeth order diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 22eef40c0e3..07b0517718e 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -343,8 +343,9 @@ static int bootflow_system(struct unit_test_state *uts) bootstd_clear_glob(); console_record_reset_enable(); ut_assertok(run_command("bootflow scan -l", 0)); - ut_assert_skip_to_line(" 1 bootmgr ready bootstd 0 "); - ut_assert_nextline("No more bootdevs"); + ut_assert_skip_to_line( + " 0 bootmgr ready (none) 0 "); + ut_assert_skip_to_line("No more bootdevs"); ut_assert_skip_to_line("(2 bootflows, 2 valid)"); ut_assert_console_end();