[PATCH v2 25/35] bootstd: Allow scanning for global bootmeths separately

Simon Glass sjg at chromium.org
Sat Jul 30 23:52:27 CEST 2022


Typically we want to find and use global bootmeths first, since they have
the best idea of how the system should boot. We then use normal bootmeths
as a fallback.

Add the logic for this, putting global bootmeths at the end of the
ordering. We can then easily scan the global bootmeths first, then drop
them from the list for subsequent bootdev-centric scans.

This changes the ordering of global bootmeths, so update the
bootflow_system() accordingly.

Drop the comment from bootmeth_setup_iter_order() since this is an
exported function and it should be in the header file.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

(no changes since v1)

 boot/bootflow.c        |  2 +-
 boot/bootmeth-uclass.c | 79 ++++++++++++++++++++++++++++++------------
 include/bootmeth.h     |  4 ++-
 test/boot/bootflow.c   |  5 +--
 4 files changed, 64 insertions(+), 26 deletions(-)

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) {
+		int i;
+
+		/*
+		 * We don't support skipping global bootmeths. Instead, the user
+		 * should omit them from the ordering
+		 */
+		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;
+		int i, upto, pass;
 
 		/*
-		 * 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.
+		 * 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 (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;
+		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  <NULL>                    <NULL>");
-	ut_assert_nextline("No more bootdevs");
+	ut_assert_skip_to_line(
+		"  0  bootmgr      ready   (none)       0  <NULL>                    <NULL>");
+	ut_assert_skip_to_line("No more bootdevs");
 	ut_assert_skip_to_line("(2 bootflows, 2 valid)");
 	ut_assert_console_end();
 
-- 
2.37.1.455.g008518b4e5-goog



More information about the U-Boot mailing list