@@ -1296,6 +1296,13 @@
filename = "mmc14.img";
};
+ /* This is used for BLS tests */
+ mmc15 {
+ status = "disabled";
+ compatible = "sandbox,mmc";
+ filename = "mmc15.img";
+ };
+
pch {
compatible = "sandbox,pch";
};
@@ -36,6 +36,7 @@ DECLARE_GLOBAL_DATA_PTR;
extern U_BOOT_DRIVER(bootmeth_android);
extern U_BOOT_DRIVER(bootmeth_cros);
extern U_BOOT_DRIVER(bootmeth_2script);
+extern U_BOOT_DRIVER(bootmeth_2bls);
/* Use this as the vendor for EFI to tell the app to exit boot services */
static u16 __efi_runtime_data test_vendor[] = u"U-Boot testing";
@@ -684,6 +685,13 @@ static int prep_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev,
"android", 0, ofnode_null(), &dev));
}
+ /* Enable the BLS bootmeth if needed */
+ if (IS_ENABLED(CONFIG_BOOTMETH_BLS) && bind_cros_android) {
+ ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
+ ut_assertok(device_bind(bootstd, DM_DRIVER_REF(bootmeth_2bls),
+ "bls", 0, ofnode_null(), &dev));
+ }
+
/* Change the order to include the device */
std = dev_get_priv(bootstd);
old_order = std->bootdev_order;
@@ -1809,3 +1817,49 @@ static int bootflow_cmd_info_encrypted(struct unit_test_state *uts)
return 0;
}
BOOTSTD_TEST(bootflow_cmd_info_encrypted, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* Check 'bootflow scan' finds a BLS bootflow */
+static int bootflow_cmd_bls(struct unit_test_state *uts)
+{
+ struct bootstd_priv *std;
+ const char **old_order;
+
+ ut_assertok(prep_mmc_bootdev(uts, "mmc15", true, &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;
+
+ ut_assertok(run_command("bootflow list", 0));
+ ut_assert_nextline("Showing all bootflows");
+ ut_assert_nextline("Seq Method State Uclass Part E Name Filename");
+ ut_assert_nextlinen("---");
+ ut_assert_nextlinen(" 0 extlinux");
+ ut_assert_nextline(" 1 bls ready mmc 1 mmc15.bootdev.part_1 /loader/entry.conf");
+ ut_assert_nextlinen("---");
+ ut_assert_nextline("(2 bootflows, 2 valid)");
+ ut_assert_console_end();
+
+ /* Select the BLS bootflow and check info */
+ ut_assertok(run_command("bootflow select 1", 0));
+ ut_assert_console_end();
+ ut_assertok(run_command("bootflow info", 0));
+ ut_assert_nextline("Name: mmc15.bootdev.part_1");
+ ut_assert_nextline("Device: mmc15.bootdev");
+ ut_assert_nextline("Block dev: mmc15.blk");
+ ut_assert_nextline("Method: bls");
+ ut_assert_nextline("State: ready");
+ ut_assert_nextline("Partition: 1");
+ if (IS_ENABLED(CONFIG_BLK_LUKS))
+ ut_assert_nextline("Encrypted: no");
+ ut_assert_nextline("Subdir: (none)");
+ ut_assert_nextline("Filename: /loader/entry.conf");
+ ut_assert_skip_to_line("Error: 0");
+ ut_assert_console_end();
+
+ return 0;
+}
+BOOTSTD_TEST(bootflow_cmd_bls, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
new file mode 100644
@@ -0,0 +1,70 @@
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright 2026 Canonical Ltd
+
+"""Create BLS test disk images"""
+
+import gzip
+import os
+
+import utils
+from fs_helper import DiskHelper, FsHelper
+from img.common import mkdir_cond
+
+
+def setup_bls_image(config, log, devnum, basename):
+ """Create a 20MB BLS disk image with a single FAT partition
+
+ Args:
+ config (ArbitraryAttributeContainer): Configuration
+ log (multiplexed_log.Logfile): Log to write to
+ devnum (int): Device number to use, e.g. 5
+ basename (str): Base name to use in the filename, e.g. 'mmc'
+ """
+ vmlinux = 'vmlinuz-6.8.0'
+ initrd = 'initrd.img-6.8.0'
+ dtb = 'sandbox.dtb'
+
+ # BLS Type #1 entry format
+ script = f'''title Test Boot
+version 6.8.0
+linux /{vmlinux}
+options root=/dev/mmcblk0p2 ro quiet
+initrd /{initrd}
+devicetree /{dtb}'''
+
+ fsh = FsHelper(config, 'vfat', 18, prefix=basename)
+ fsh.setup()
+
+ # Create loader directory for BLS entry
+ loader = os.path.join(fsh.srcdir, 'loader')
+ mkdir_cond(loader)
+
+ # Create BLS entry file
+ conf = os.path.join(loader, 'entry.conf')
+ with open(conf, 'w', encoding='ascii') as fd:
+ print(script, file=fd)
+
+ # Create compressed kernel image
+ inf = os.path.join(config.persistent_data_dir, 'inf')
+ with open(inf, 'wb') as fd:
+ fd.write(gzip.compress(b'vmlinux'))
+ mkimage = config.build_dir + '/tools/mkimage'
+ utils.run_and_log_no_ubman(
+ log, f'{mkimage} -f auto -d {inf} {os.path.join(fsh.srcdir, vmlinux)}')
+
+ # Create initrd file
+ with open(os.path.join(fsh.srcdir, initrd), 'w', encoding='ascii') as fd:
+ print('initrd', file=fd)
+
+ # Create device tree blob
+ dtb_file = os.path.join(fsh.srcdir, dtb)
+ utils.run_and_log_no_ubman(
+ log, f'dtc -o {dtb_file}', stdin=b'/dts-v1/; / {};')
+
+ fsh.mk_fs()
+
+ # Create disk image with single bootable partition
+ img = DiskHelper(config, devnum, basename)
+ img.add_fs(fsh, DiskHelper.VFAT, bootable=True)
+ img.create()
+ fsh.cleanup()
@@ -23,6 +23,7 @@ from img.common import mkdir_cond, copy_partition, setup_extlinux_image
from img.fedora import setup_fedora_image
from img.ubuntu import setup_ubuntu_image
from img.armbian import setup_bootmenu_image
+from img.bls import setup_bls_image
from img.chromeos import setup_cros_image
from img.android import setup_android_image
from img.efi import setup_efi_image
@@ -79,6 +80,7 @@ def test_ut_dm_init_bootstd(u_boot_config, u_boot_log):
u_boot_log (multiplexed_log.Logfile): Log to write to
"""
setup_fedora_image(u_boot_config, u_boot_log, 1, 'mmc')
+ setup_bls_image(u_boot_config, u_boot_log, 15, 'mmc')
setup_bootmenu_image(u_boot_config, u_boot_log)
setup_cedit_file(u_boot_config, u_boot_log)
setup_cros_image(u_boot_config, u_boot_log)