[PATCH 61/71] bootstd: Allow iterating to the next label in a list

Simon Glass sjg at chromium.org
Wed Dec 7 09:51:27 CET 2022


Add a function which moves to the next label in a list of labels. This
allows processing the boot_targets environment variable.

This works using a new label list in the bootflow iterator. The logic to
set this up is included in a subsequent commit.

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

 boot/bootdev-uclass.c | 26 ++++++++++++--
 include/bootdev.h     | 16 +++++++++
 include/bootflow.h    |  4 +++
 test/boot/bootdev.c   | 80 ++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 123 insertions(+), 3 deletions(-)

diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c
index dcaed4c2692..ae08430ca8c 100644
--- a/boot/bootdev-uclass.c
+++ b/boot/bootdev-uclass.c
@@ -566,6 +566,25 @@ void bootdev_clear_bootflows(struct udevice *dev)
 	}
 }
 
+int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp,
+		       int *method_flagsp)
+{
+	struct udevice *dev;
+
+	log_debug("next\n");
+	for (dev = NULL; !dev && iter->labels[++iter->cur_label];) {
+		log_debug("Scanning: %s\n", iter->labels[iter->cur_label]);
+		bootdev_hunt_and_find_by_label(iter->labels[iter->cur_label],
+					       &dev, method_flagsp);
+	}
+
+	if (!dev)
+		return log_msg_ret("fin", -ENODEV);
+	*devp = dev;
+
+	return 0;
+}
+
 /**
  * h_cmp_bootdev() - Compare two bootdevs to find out which should go first
  *
@@ -763,8 +782,11 @@ int bootdev_hunt(const char *spec, bool show)
 
 		log_debug("looking at %.*s for %s\n",
 			  (int)max(strlen(name), len), spec, name);
-		if (spec && strncmp(spec, name, max(strlen(name), len)))
-			continue;
+		if (spec && strncmp(spec, name, max(strlen(name), len))) {
+			if (info->uclass != UCLASS_ETH ||
+			    (strcmp("dhcp", spec) && strcmp("pxe", spec)))
+				continue;
+		}
 		ret = bootdev_hunt_drv(info, i, show);
 		if (ret)
 			result = ret;
diff --git a/include/bootdev.h b/include/bootdev.h
index b1e320a7d8e..300bc736427 100644
--- a/include/bootdev.h
+++ b/include/bootdev.h
@@ -333,6 +333,22 @@ int bootdev_hunt_prio(enum bootdev_prio_t prio, bool show);
 int bootdev_hunt_and_find_by_label(const char *label, struct udevice **devp,
 				   int *method_flagsp);
 
+/**
+ * bootdev_next_label() - Move to the next bootdev in the label sequence
+ *
+ * Looks through the remaining labels until it finds one that matches a bootdev.
+ * Bootdev scanners are used as needed. For example a label "mmc1" results in
+ * running the "mmc" bootdrv.
+ *
+ * @iter: Interation info, containing iter->cur_label
+ * @devp: New bootdev found, if any was found
+ * @method_flagsp: If non-NULL, returns any flags implied by the label
+ * (enum bootflow_meth_flags_t), 0 if none
+ * Returns 0 if OK, -ENODEV if no bootdev was found
+ */
+int bootdev_next_label(struct bootflow_iter *iter, struct udevice **devp,
+		       int *method_flagsp);
+
 #if CONFIG_IS_ENABLED(BOOTSTD)
 /**
  * bootdev_setup_for_dev() - Bind a new bootdev device (deprecated)
diff --git a/include/bootflow.h b/include/bootflow.h
index a912088deb0..5d845b3a6f0 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -164,6 +164,8 @@ enum bootflow_meth_flags_t {
  * @cur_dev: Current bootdev number, an index into @dev_order[]
  * @dev_order: List of bootdevs to scan, in order of priority. The scan starts
  *	with the first one on the list
+ * @labels: List of labels to scan for bootdevs
+ * @cur_label: Current label being processed
  * @num_methods: Number of bootmeth devices in @method_order
  * @cur_method: Current method number, an index into @method_order
  * @first_glob_method: First global method, if any, else -1
@@ -185,6 +187,8 @@ struct bootflow_iter {
 	int num_devs;
 	int cur_dev;
 	struct udevice **dev_order;
+	const char *const *labels;
+	int cur_label;
 	int num_methods;
 	int cur_method;
 	int first_glob_method;
diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c
index 1fa0909e893..608aef15265 100644
--- a/test/boot/bootdev.c
+++ b/test/boot/bootdev.c
@@ -355,7 +355,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts)
 	ut_assert_console_end();
 
 	/* Scan all hunters */
-	sandbox_set_eth_enable(false);
+	test_set_eth_enable(false);
 	test_set_skip_delays(true);
 	ut_assertok(run_command("bootdev hunt", 0));
 	ut_assert_nextline("Hunting with: ethernet");
@@ -510,3 +510,81 @@ static int bootdev_test_hunt_label(struct unit_test_state *uts)
 	return 0;
 }
 BOOTSTD_TEST(bootdev_test_hunt_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+
+/* Check iterating to the next label in a list */
+static int bootdev_test_next_label(struct unit_test_state *uts)
+{
+	const char *const labels[] = {"mmc0", "scsi", "dhcp", "pxe", NULL};
+	struct bootflow_iter iter;
+	struct bootstd_priv *std;
+	struct bootflow bflow;
+	struct udevice *dev;
+	int mflags;
+
+	test_set_eth_enable(false);
+
+	/* get access to the used hunters */
+	ut_assertok(bootstd_get_priv(&std));
+
+	memset(&iter, '\0', sizeof(iter));
+	memset(&bflow, '\0', sizeof(bflow));
+	iter.part = 0;
+	uclass_first_device(UCLASS_BOOTMETH, &bflow.method);
+	iter.cur_label = -1;
+	iter.labels = labels;
+
+	dev = NULL;
+	mflags = 123;
+	ut_assertok(bootdev_next_label(&iter, &dev, &mflags));
+	console_record_reset_enable();
+	ut_assert_console_end();
+	ut_assertnonnull(dev);
+	ut_asserteq_str("mmc0.bootdev", dev->name);
+	ut_asserteq(0, mflags);
+
+	ut_assertok(bootstd_test_check_mmc_hunter(uts));
+
+	ut_assertok(bootdev_next_label(&iter, &dev, &mflags));
+	ut_assert_nextline("scanning bus for devices...");
+	ut_assert_skip_to_line(
+		"            Capacity: 1.9 MB = 0.0 GB (4095 x 512)");
+	ut_assert_console_end();
+	ut_assertnonnull(dev);
+	ut_asserteq_str("scsi.id0lun0.bootdev", dev->name);
+	ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS, mflags);
+
+	/* SCSI is fifth in the list, so bit 4 */
+	ut_asserteq(BIT(2) | BIT(4), std->hunters_used);
+
+	ut_assertok(bootdev_next_label(&iter, &dev, &mflags));
+	ut_assert_console_end();
+	ut_assertnonnull(dev);
+	ut_asserteq_str("eth at 10002000.bootdev", dev->name);
+	ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_DHCP_ONLY,
+		    mflags);
+
+	/* dhcp: Ethernet is first so bit 0 */
+	ut_asserteq(BIT(2) | BIT(4) | BIT(0), std->hunters_used);
+
+	ut_assertok(bootdev_next_label(&iter, &dev, &mflags));
+	ut_assert_console_end();
+	ut_assertnonnull(dev);
+	ut_asserteq_str("eth at 10002000.bootdev", dev->name);
+	ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY,
+		    mflags);
+
+	/* pxe: Ethernet is first so bit 0 */
+	ut_asserteq(BIT(2) | BIT(4) | BIT(0), std->hunters_used);
+
+	mflags = 123;
+	ut_asserteq(-ENODEV, bootdev_next_label(&iter, &dev, &mflags));
+	ut_asserteq(123, mflags);
+	ut_assert_console_end();
+
+	/* no change */
+	ut_asserteq(BIT(2) | BIT(4) | BIT(0), std->hunters_used);
+
+	return 0;
+}
+BOOTSTD_TEST(bootdev_test_next_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT |
+	     UT_TESTF_ETH_BOOTDEV | UT_TESTF_SF_BOOTDEV);
-- 
2.39.0.rc0.267.gcb52ba06e7-goog



More information about the U-Boot mailing list