part: Add a function to find the first bootable partition
authorSimon Glass <sjg@chromium.org>
Tue, 17 Jan 2023 17:47:41 +0000 (10:47 -0700)
committerTom Rini <trini@konsulko.com>
Mon, 23 Jan 2023 23:11:40 +0000 (18:11 -0500)
If a disk has a bootable partition we are expected to use it to locate the
boot files. Add a function to find it.

To test this, update mmc1 to have two paritions, fixing up other tests
accordingly.

Signed-off-by: Simon Glass <sjg@chromium.org>
disk/part.c
include/part.h
test/boot/bootflow.c
test/dm/part.c
test/py/tests/bootstd/mmc1.img.xz
test/py/tests/test_ut.py

index 5ee60a7..d449635 100644 (file)
@@ -770,3 +770,19 @@ void part_set_generic_name(const struct blk_desc *dev_desc,
 
        sprintf(name, "%s%c%d", devtype, 'a' + dev_desc->devnum, part_num);
 }
+
+int part_get_bootable(struct blk_desc *desc)
+{
+       struct disk_partition info;
+       int p;
+
+       for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+               int ret;
+
+               ret = part_get_info(desc, p, &info);
+               if (!ret && info.bootable)
+                       return p;
+       }
+
+       return 0;
+}
index 807370d..be75c73 100644 (file)
@@ -303,6 +303,14 @@ part_get_info_by_dev_and_name_or_num(const char *dev_iface,
 }
 #endif
 
+/**
+ * part_get_bootable() - Find the first bootable partition
+ *
+ * @desc: Block-device descriptor
+ * @return first bootable partition, or 0 if there is none
+ */
+int part_get_bootable(struct blk_desc *desc);
+
 struct udevice;
 /**
  * part_create_block_devices - Create block devices for disk partitions
index 1297600..38ffe8f 100644 (file)
@@ -315,15 +315,15 @@ static int bootflow_iter(struct unit_test_state *uts)
        ut_asserteq(BOOTFLOWST_FS, bflow.state);
        bootflow_free(&bflow);
 
-       /* Then more to partition 2 which doesn't exist */
-       ut_asserteq(-ENOENT, bootflow_scan_next(&iter, &bflow));
+       /* Then more to partition 2 which exists but is not bootable */
+       ut_asserteq(-EPERM, bootflow_scan_next(&iter, &bflow));
        ut_asserteq(2, iter.num_methods);
        ut_asserteq(0, iter.cur_method);
        ut_asserteq(2, iter.part);
        ut_asserteq(0x1e, iter.max_part);
        ut_asserteq_str("syslinux", iter.method->name);
        ut_asserteq(0, bflow.err);
-       ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
+       ut_asserteq(BOOTFLOWST_PART, bflow.state);
        bootflow_free(&bflow);
 
        bootflow_iter_uninit(&iter);
index b606871..35e99ee 100644 (file)
@@ -93,3 +93,16 @@ static int dm_test_part(struct unit_test_state *uts)
        return ret;
 }
 DM_TEST(dm_test_part, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
+
+static int dm_test_part_bootable(struct unit_test_state *uts)
+{
+       struct blk_desc *desc;
+       struct udevice *dev;
+
+       ut_assertok(uclass_get_device_by_name(UCLASS_BLK, "mmc1.blk", &dev));
+       desc = dev_get_uclass_plat(dev);
+       ut_asserteq(1, part_get_bootable(desc));
+
+       return 0;
+}
+DM_TEST(dm_test_part_bootable, UT_TESTF_SCAN_FDT);
index 4e7f39b..cebf7b9 100644 (file)
Binary files a/test/py/tests/bootstd/mmc1.img.xz and b/test/py/tests/bootstd/mmc1.img.xz differ
index 6958fab..e8c8a6d 100644 (file)
@@ -19,13 +19,14 @@ def mkdir_cond(dirname):
     if not os.path.exists(dirname):
         os.mkdir(dirname)
 
-def setup_image(cons, mmc_dev, part_type):
+def setup_image(cons, mmc_dev, part_type, second_part=False):
     """Create a 20MB disk image with a single partition
 
     Args:
         cons (ConsoleBase): Console to use
         mmc_dev (int): MMC device number to use, e.g. 1
         part_type (int): Partition type, e.g. 0xc for FAT32
+        second_part (bool): True to contain a small second partition
 
     Returns:
         tuple:
@@ -36,9 +37,13 @@ def setup_image(cons, mmc_dev, part_type):
     mnt = os.path.join(cons.config.persistent_data_dir, 'mnt')
     mkdir_cond(mnt)
 
+    spec = f'type={part_type:x}, size=18M, bootable'
+    if second_part:
+        spec += '\ntype=c'
+
     u_boot_utils.run_and_log(cons, 'qemu-img create %s 20M' % fname)
     u_boot_utils.run_and_log(cons, 'sudo sfdisk %s' % fname,
-                             stdin=f'type={part_type:x}'.encode('utf-8'))
+                             stdin=spec.encode('utf-8'))
     return fname, mnt
 
 def mount_image(cons, fname, mnt, fstype):
@@ -59,7 +64,7 @@ def mount_image(cons, fname, mnt, fstype):
     u_boot_utils.run_and_log(cons, f'sudo mkfs.{fstype} {part}')
     opts = ''
     if fstype == 'vfat':
-         opts += ' -o uid={os.getuid()},gid={os.getgid()}'
+         opts += f' -o uid={os.getuid()},gid={os.getgid()}'
     u_boot_utils.run_and_log(cons, f'sudo mount -o loop {part} {mnt}{opts}')
     u_boot_utils.run_and_log(cons, f'sudo chown {getpass.getuser()} {mnt}')
     return loop
@@ -218,7 +223,7 @@ booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}
 def setup_bootflow_image(cons):
     """Create a 20MB disk image with a single FAT partition"""
     mmc_dev = 1
-    fname, mnt = setup_image(cons, mmc_dev, 0xc)
+    fname, mnt = setup_image(cons, mmc_dev, 0xc, second_part=True)
 
     loop = None
     mounted = False