[Concept,06/12] pxe: Add pxe_boot_entry() to boot a specific label by index

Message ID 20260324221911.3678307-7-sjg@u-boot.org
State New
Headers
Series bootstd: Support multiple bootflows per partition |

Commit Message

Simon Glass March 24, 2026, 10:19 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

Add pxe_boot_entry() which parses a PXE config, walks to the Nth label,
loads its files and boots it. This is used by multi-entry bootmeths to
boot the specific label that was selected during scanning, rather than
presenting the full menu.

Update extlinux_boot() to always use pxe_boot_entry(), so that each
entry (including entry 0) boots its label directly without a menu.

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

 boot/ext_pxe_common.c |  3 ++-
 boot/pxe_utils.c      | 30 ++++++++++++++++++++++++++++++
 include/pxe_utils.h   | 14 ++++++++++++++
 test/boot/bootflow.c  |  6 ++++++
 4 files changed, 52 insertions(+), 1 deletion(-)
  

Patch

diff --git a/boot/ext_pxe_common.c b/boot/ext_pxe_common.c
index 8a59b29ead8..4ea7f8f455d 100644
--- a/boot/ext_pxe_common.c
+++ b/boot/ext_pxe_common.c
@@ -136,7 +136,8 @@  int extlinux_boot(struct udevice *dev, struct bootflow *bflow,
 			return log_msg_ret("elb", ret);
 		ctx->restart = restart;
 		addr = map_to_sysmem(bflow->buf);
-		ret = pxe_process_str(ctx, addr, false);
+
+		ret = pxe_boot_entry(ctx, addr, bflow->entry);
 	}
 	if (ret)
 		return log_msg_ret("elb", -EFAULT);
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c
index f5f8e38de2e..a7c5e87bef0 100644
--- a/boot/pxe_utils.c
+++ b/boot/pxe_utils.c
@@ -1510,3 +1510,33 @@  int pxe_boot(struct pxe_context *ctx)
 
 	return 0;
 }
+
+int pxe_boot_entry(struct pxe_context *ctx, ulong addr, int entry)
+{
+	struct pxe_label *label;
+	struct pxe_menu *cfg;
+	int ret, i = 0;
+	void *ptr;
+
+	ptr = map_sysmem(addr, 0);
+	ctx->pxe_file_size = strnlen(ptr, SZ_64K);
+	unmap_sysmem(ptr);
+
+	cfg = pxe_prepare(ctx, addr, false);
+	if (!cfg)
+		return log_msg_ret("prp", -EINVAL);
+
+	list_for_each_entry(label, &cfg->labels, list) {
+		if (i == entry)
+			goto found;
+		i++;
+	}
+	pxe_menu_uninit(cfg);
+	return log_msg_ret("lab", -ENOENT);
+
+found:
+	ret = label_boot(ctx, label);
+	pxe_menu_uninit(cfg);
+
+	return ret;
+}
diff --git a/include/pxe_utils.h b/include/pxe_utils.h
index 3367230eb1c..8b607095721 100644
--- a/include/pxe_utils.h
+++ b/include/pxe_utils.h
@@ -611,4 +611,18 @@  void pxe_load(struct pxe_file *file, ulong addr, ulong size);
  */
 void pxe_cleanup(struct pxe_context *ctx);
 
+/**
+ * pxe_boot_entry() - Parse a PXE config and boot a specific entry by index
+ *
+ * This parses the config file, walks to the Nth label, loads its files and
+ * boots it. Used by multi-entry bootmeths to boot a specific label that was
+ * selected during scanning.
+ *
+ * @ctx: PXE context (must be set up with pxe_setup_ctx())
+ * @addr: Address where config file is loaded
+ * @entry: Entry index (0 for first label, 1 for second, etc.)
+ * Return: Does not return on success, -ve on error
+ */
+int pxe_boot_entry(struct pxe_context *ctx, ulong addr, int entry);
+
 #endif /* __PXE_UTILS_H */
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 73ea1102af5..2ff203c186c 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -1962,6 +1962,12 @@  static int bootflow_multi(struct unit_test_state *uts)
 			bflow->os_name);
 	ut_asserteq(1, bflow->entry);
 
+	/* Try booting the second entry (rescue) - exercises pxe_boot_entry() */
+	ut_assertok(env_set("kernel_addr_r", "1000000"));
+	ut_assertok(env_set("ramdisk_addr_r", "2000000"));
+	std->cur_bootflow = bflow;
+	ut_asserteq(-EFAULT, bootflow_boot(bflow));
+
 	return 0;
 }
 BOOTSTD_TEST(bootflow_multi, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);