[PATCH v2 12/13] test: bootstd: cover BLS entries below a prefix

Alexey Charkov <[email protected]>
Newsgroups org.u-boot-project.lists.u-boot
Message-ID <[email protected]>
The Fedora image places its BLS entry at the root of the filesystem, so
the second entry in the bootstd prefix list is never what finds it. Add an
image for the other layout, where $BOOT is a '/boot/' directory on a
larger filesystem and only the '/boot/' prefix turns the entry up.

Its paths still name the kernel, initrd and devicetree relative to the
partition root, matching what systemd's 90-loaderentry.install writes when
$BOOT is not a mount point of its own, and booting it checks they are used
as written rather than rebased onto the prefix. The rescan before booting
covers freeing a bootflow that is still selected, which is the path a
retained bootmeth_priv would double-free.

Signed-off-by: Alexey Charkov <[email protected]>
---
 arch/sandbox/dts/test.dts |  8 +++++
 test/boot/bootflow.c      | 90 +++++++++++++++++++++++++++++++++++++++++++++++
 test/py/tests/test_ut.py  | 66 +++++++++++++++++++++++++++++++++-
 3 files changed, 163 insertions(+), 1 deletion(-)

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 189d83a81cf6..78d52c1eabb7 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -49,6 +49,7 @@
 		mmc8 = "/mmc8";
 		mmc9 = "/mmc9";
 		mmc10 = "/mmc10";
+		mmc11 = "/mmc11";
 		pci0 = &pci0;
 		pci1 = &pci1;
 		pci2 = &pci2;
@@ -1372,6 +1373,13 @@
 		filename = "mmc10.img";
 	};
 
+	/* This is used for BLS boot tests */
+	mmc11 {
+		status = "disabled";
+		compatible = "sandbox,mmc";
+		filename = "mmc11.img";
+	};
+
 	pch {
 		compatible = "sandbox,pch";
 	};
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index eb8e27fa2253..a1247e7a9e82 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -1666,6 +1666,96 @@ static int bootflow_rauc(struct unit_test_state *uts)
 }
 BOOTSTD_TEST(bootflow_rauc, UTF_CONSOLE | UTF_DM | UTF_SCAN_FDT);
 
+/*
+ * Test the BLS bootmeth against entries that live below a '/boot/' prefix,
+ * so that they are only found via the second bootstd prefix. The Fedora
+ * image used by the other tests covers the unprefixed layout.
+ */
+static int bootflow_bls_prefix(struct unit_test_state *uts)
+{
+	static const char *order[] = {NULL, NULL};
+	const char *mmc_dev = "mmc11";
+	struct bootstd_priv *std;
+	struct udevice *bootstd;
+	const char **old_order;
+	ofnode root;
+	ofnode node;
+
+	if (!CONFIG_IS_ENABLED(BOOTMETH_BLS))
+		return -EAGAIN;
+
+	order[0] = mmc_dev;
+
+	/* Enable the requested mmc node since we need a different bootflow */
+	root = oftree_root(oftree_default());
+	node = ofnode_find_subnode(root, mmc_dev);
+	ut_assert(ofnode_valid(node));
+	ut_assertok(lists_bind_fdt(gd->dm_root, node, NULL, NULL, false));
+
+	/* Change the device and bootmeth order */
+	ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
+	std = dev_get_priv(bootstd);
+	old_order = std->bootdev_order;
+	std->bootdev_order = order;
+
+	ut_assertok(bootmeth_set_order("bls"));
+
+	ut_assertok(run_command("bootflow scan", 0));
+	ut_assert_console_end();
+
+	ut_assertok(run_command("bootflow list", 0));
+	ut_assert_nextlinen("Showing all");
+	ut_assert_nextlinen("Seq");
+	ut_assert_nextlinen("---");
+	ut_assert_nextlinen("  0  bls          ready   mmc          1  mmc11.bootdev.part_1      /boot/loader/entries/aabbccdd-6.17.0-bls.conf");
+	ut_assert_nextlinen("---");
+	ut_assert_skip_to_line("(1 bootflow, 1 valid)");
+	ut_assert_console_end();
+
+	/*
+	 * The prefix the entry was found under must be recorded, and the BLS
+	 * 'title' key must surface as the OS name
+	 */
+	ut_assertok(run_command("bootflow select 0", 0));
+	ut_assert_console_end();
+	ut_assertok(run_command("bootflow info", 0));
+	ut_assert_skip_to_line("Subdir:    /boot/");
+	ut_assert_skip_to_line("OS:        BLS prefix test");
+	ut_assert_skip_to_line("Error:     0");
+	ut_assert_console_end();
+
+	/*
+	 * Rescan on top of a selected bootflow. This frees the previous
+	 * bootflow, so it walks the path that would double-free a retained
+	 * bootmeth_priv: the bootflow is shallow-copied into the bootflow list,
+	 * leaving the iterator's temporary and the stored copy sharing it.
+	 */
+	ut_assertok(run_command("bootflow scan", 0));
+	ut_assert_console_end();
+	ut_assertok(run_command("bootflow select 0", 0));
+	ut_assert_console_end();
+
+	/*
+	 * Paths inside the entry stay relative to the partition root even
+	 * though the entry itself was found under '/boot/', so they are used
+	 * as written rather than rebased onto the prefix.
+	 */
+	ut_asserteq(1, run_command("bootflow boot", 0));
+	ut_assert_nextline("** Booting bootflow 'mmc11.bootdev.part_1' with bls");
+	ut_assert_skip_to_line("Retrieving file: /boot/vmlinuz-6.17.0-bls");
+	ut_assert_skip_to_line("Retrieving file: /boot/initramfs-6.17.0-bls.img");
+	ut_assert_skip_to_line("Retrieving file: /boot/dtb-6.17.0-bls/sandbox.dtb");
+	ut_assert_skip_to_line("sandbox: continuing, as we cannot run Linux");
+	ut_assert_nextline("Boot failed (err=-22)");
+	ut_assert_console_end();
+
+	/* Restore the order used by the device tree */
+	std->bootdev_order = old_order;
+
+	return 0;
+}
+BOOTSTD_TEST(bootflow_bls_prefix, UTF_CONSOLE | UTF_DM | UTF_SCAN_FDT);
+
 /* Check 'bootflow scan' provides a list of images */
 static int bootstd_images(struct unit_test_state *uts)
 {
diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py
index 28f028453ea9..3035c7095bd7 100644
--- a/test/py/tests/test_ut.py
+++ b/test/py/tests/test_ut.py
@@ -261,6 +261,68 @@ def setup_fedora_image(ubman, devnum, basename):
     dtbdir = 'dtb-5.3.7-301.fc31.armv7hl'
     setup_extlinux_bls_image(ubman, devnum, basename, vmlinux, initrd, dtbdir)
 
+def setup_bls_prefix_image(ubman):
+    """Create a disk image holding BLS entries below a '/boot/' prefix
+
+    This is the layout where $BOOT is a directory on a larger filesystem
+    rather than a partition of its own, so the entries are only found via
+    the second bootstd prefix. The Fedora image covers the other layout,
+    where they sit at the root of the filesystem.
+
+    Paths inside the entry stay relative to the partition root either way,
+    which is both what the spec requires and what systemd's
+    90-loaderentry.install writes: it strips the mount point from the entry
+    directory, so a $BOOT that is not its own mount keeps the '/boot'
+    component.
+    """
+    mmc_dev = 11
+    vmlinux = 'vmlinuz-6.17.0-bls'
+    initrd = 'initramfs-6.17.0-bls.img'
+    dtbdir = 'dtb-6.17.0-bls'
+
+    fsh = FsHelper(ubman.config, 'ext4', 8, prefix='bls')
+    fsh.setup()
+
+    boot = os.path.join(fsh.srcdir, 'boot')
+    mkdir_cond(boot)
+    bls = os.path.join(boot, 'loader')
+    mkdir_cond(bls)
+    bls = os.path.join(bls, 'entries')
+    mkdir_cond(bls)
+
+    # Paths are relative to the partition root, so they keep the '/boot'
+    script = '''title BLS prefix test
+version 6.17.0-bls
+linux /boot/%s
+initrd /boot/%s
+devicetree /boot/%s/sandbox.dtb
+options ro root=/dev/sda1''' % (vmlinux, initrd, dtbdir)
+
+    conf = os.path.join(bls, 'aabbccdd-6.17.0-bls.conf')
+    with open(conf, 'w', encoding='ascii') as fd:
+        print(script, file=fd)
+
+    inf = os.path.join(ubman.config.persistent_data_dir, 'inf')
+    with open(inf, 'wb') as fd:
+        fd.write(gzip.compress(b'vmlinux'))
+    mkimage = ubman.config.build_dir + '/tools/mkimage'
+    utils.run_and_log(
+        ubman, f'{mkimage} -f auto -d {inf} {os.path.join(boot, vmlinux)}')
+
+    with open(os.path.join(boot, initrd), 'w', encoding='ascii') as fd:
+        print('initrd', file=fd)
+
+    mkdir_cond(os.path.join(boot, dtbdir))
+    dtb_file = os.path.join(boot, f'{dtbdir}/sandbox.dtb')
+    utils.run_and_log(ubman, f'dtc -o {dtb_file}', stdin=b'/dts-v1/; / {};')
+
+    fsh.mk_fs()
+
+    img = DiskHelper(ubman.config, mmc_dev, 'mmc', True)
+    img.add_fs(fsh, DiskHelper.EXT4)
+    img.create()
+    fsh.cleanup()
+
 def setup_cros_image(ubman):
     """Create a 20MB disk image with ChromiumOS partitions"""
     Partition = collections.namedtuple('part', 'start,size,name')
@@ -648,6 +710,7 @@ def test_ut_dm_init_bootstd(ubman):
     setup_android_image(ubman)
     setup_efi_image(ubman)
     setup_rauc_image(ubman)
+    setup_bls_prefix_image(ubman)
 
     # Restart so that the new mmc1.img is picked up
     ubman.restart_uboot()
@@ -665,7 +728,8 @@ def ut_ubman_fixture(ubman, ut_subtest):
 
     yield ubman
 
-    if ut_subtest in ("bootstd bootflow_cmd_boot", "bootstd bootflow_scan_boot"):
+    if ut_subtest in ("bootstd bootflow_cmd_boot", "bootstd bootflow_scan_boot",
+                      "bootstd bootflow_bls_prefix"):
         ubman.restart_uboot()
 
 

-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.