[PATCH 4/5] pxe_utils: Support a backup for localboot

Simon Glass sjg at chromium.org
Fri Dec 20 05:01:19 CET 2024


The current localboot implementation assumes that a 'localcmd'
environment variable is provided, with the instructions to follow. This
may not be included, so provide a fallback in that case.

Add a test image and test as well.

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

 arch/sandbox/dts/test.dts |  8 +++++++
 boot/Kconfig              |  9 ++++++++
 boot/pxe_utils.c          | 33 ++++++++++++++++++++++++---
 test/boot/bootflow.c      | 47 +++++++++++++++++++++++++++++++++++++++
 test/py/tests/test_ut.py  | 17 ++++++++++++++
 5 files changed, 111 insertions(+), 3 deletions(-)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 36cfbf213e4..47e17070886 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -45,6 +45,7 @@
 		mmc6 = "/mmc6";
 		mmc7 = "/mmc7";
 		mmc8 = "/mmc8";
+		mmc9 = "/mmc9";
 		pci0 = &pci0;
 		pci1 = &pci1;
 		pci2 = &pci2;
@@ -1153,6 +1154,13 @@
 		filename = "mmc8.img";
 	};
 
+	/* This is used for extlinux localboot */
+	mmc9 {
+		status = "disabled";
+		compatible = "sandbox,mmc";
+		filename = "mmc9.img";
+	};
+
 	pch {
 		compatible = "sandbox,pch";
 	};
diff --git a/boot/Kconfig b/boot/Kconfig
index 705947cfa95..1356699021a 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -556,6 +556,15 @@ config BOOTMETH_EXTLINUX_PXE
 
 	  This provides a way to try out standard boot on an existing boot flow.
 
+config BOOTMETH_EXTLINUX_LOCALBOOT
+	bool "Boot method for extlinux localboot"
+	depends on BOOTMETH_EXTLINUX
+	default y
+	help
+	  Enables standard boot support for the extlinux 'localboot' feature.
+	  This attempts to find a kernel and initrd on the disk and boot it,
+	  in the case where there is no "localcmd" in the environment.
+
 config BOOTMETH_EFILOADER
 	bool "Bootdev support for EFI boot"
 	depends on EFI_BINARY_EXEC
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c
index 8bebf4ec925..5d52a5965d6 100644
--- a/boot/pxe_utils.c
+++ b/boot/pxe_utils.c
@@ -640,6 +640,25 @@ static int label_run_boot(struct pxe_context *ctx, struct pxe_label *label,
 	return 0;
 }
 
+/**
+ * generate_localboot() - Try to come up with a localboot definition
+ *
+ * Adds a default kernel and initrd filename for use with localboot
+ *
+ * @label: Label to process
+ * Return 0 if OK, -ENOMEM if out of memory
+ */
+static int generate_localboot(struct pxe_label *label)
+{
+	label->kernel = strdup("/vmlinuz");
+	label->kernel_label = strdup(label->kernel);
+	label->initrd = strdup("/initrd.img");
+	if (!label->kernel || !label->kernel_label || !label->initrd)
+		return -ENOMEM;
+
+	return 0;
+}
+
 /**
  * label_boot() - Boot according to the contents of a pxe_label
  *
@@ -677,9 +696,17 @@ static int label_boot(struct pxe_context *ctx, struct pxe_label *label)
 	label->attempted = 1;
 
 	if (label->localboot) {
-		if (label->localboot_val >= 0)
-			label_localboot(label);
-		return 0;
+		if (label->localboot_val >= 0) {
+			ret = label_localboot(label);
+
+			if (IS_ENABLED(CONFIG_BOOTMETH_EXTLINUX_LOCALBOOT) &&
+			    ret == -ENOENT)
+				ret = generate_localboot(label);
+			if (ret)
+				return ret;
+		} else {
+			return 0;
+		}
 	}
 
 	if (!label->kernel) {
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 4d7d795cbe1..db1af0e5729 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -1510,3 +1510,50 @@ static int bootflow_scan_extlinux(struct unit_test_state *uts)
 	return 0;
 }
 BOOTSTD_TEST(bootflow_scan_extlinux, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* Check automatically generating a extlinux 'localboot' */
+static int bootflow_extlinux_localboot(struct unit_test_state *uts)
+{
+	const struct bootflow_img *img;
+	struct bootstd_priv *std;
+	const char **old_order;
+	struct bootflow *bflow;
+
+	ut_assertok(prep_mmc_bootdev(uts, "mmc9", false, &old_order));
+
+	ut_assertok(run_command("bootflow scan", 0));
+	ut_assert_console_end();
+
+	/* Restore the order used by the device tree */
+	ut_assertok(bootstd_get_priv(&std));
+	free(std->bootdev_order);
+	std->bootdev_order = old_order;
+
+	/* boot the second bootflow */
+	ut_asserteq(2, std->bootflows.count);
+	bflow = alist_getw(&std->bootflows, 1, struct bootflow);
+	std->cur_bootflow = bflow;
+
+	/* read all the images, but don't actually boot */
+	ut_assertok(bootflow_read_all(bflow));
+	ut_assert_nextline("1:\tlocal");
+	ut_assert_nextline("missing environment variable: localcmd");
+	ut_assert_nextline("Retrieving file: /vmlinuz");
+	ut_assert_nextline("Retrieving file: /initrd.img");
+
+	ut_assert_console_end();
+
+	ut_asserteq(3, bflow->images.count);
+
+	/* check the two localboot images */
+	img = alist_get(&bflow->images, 1, struct bootflow_img);
+	ut_asserteq(IH_TYPE_KERNEL, img->type);
+	ut_asserteq(0x1000000, img->addr);	/* kernel_addr_r */
+
+	img = alist_get(&bflow->images, 2, struct bootflow_img);
+	ut_asserteq(IH_TYPE_RAMDISK, img->type);
+	ut_asserteq(0x2000000, img->addr);	/* ramdisk_addr_r */
+
+	return 0;
+}
+BOOTSTD_TEST(bootflow_extlinux_localboot, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py
index e3b988efe23..b6b4717c834 100644
--- a/test/py/tests/test_ut.py
+++ b/test/py/tests/test_ut.py
@@ -575,6 +575,22 @@ def setup_efi_image(cons):
     u_boot_utils.run_and_log(cons, f'rm -rf {mnt}')
     u_boot_utils.run_and_log(cons, f'rm -f {fsfile}')
 
+
+def setup_localboot_image(cons):
+    """Create a 20MB disk image with a single FAT partition"""
+    mmc_dev = 9
+    fname, mnt = setup_image(cons, mmc_dev, 0xc, second_part=True)
+
+    script = '''DEFAULT local
+
+LABEL local
+  LOCALBOOT 0
+'''
+    vmlinux = 'vmlinuz'
+    initrd = 'initrd.img'
+    setup_extlinux_image(cons, mmc_dev, vmlinux, initrd, None, script)
+
+
 @pytest.mark.buildconfigspec('cmd_bootflow')
 @pytest.mark.buildconfigspec('sandbox')
 def test_ut_dm_init_bootstd(u_boot_console):
@@ -586,6 +602,7 @@ def test_ut_dm_init_bootstd(u_boot_console):
     setup_cros_image(u_boot_console)
     setup_android_image(u_boot_console)
     setup_efi_image(u_boot_console)
+    setup_localboot_image(u_boot_console)
 
     # Restart so that the new mmc1.img is picked up
     u_boot_console.restart_uboot()
-- 
2.34.1



More information about the U-Boot mailing list