
On Thu 11 Jul 2024 at 15:11, Mattijs Korpershoek mkorpershoek@baylibre.com wrote:
Add a unit test for testing the Android bootmethod.
This requires another mmc image (mmc7) to contain the following partitions:
- misc: contains the Bootloader Control Block (BCB)
- boot_a: contains a fake generic kernel image
- vendor_boot_a: contains a fake vendor_boot image
Also add BOOTMETH_ANDROID as a dependency on sandbox so that we can test this with:
$ ./test/py/test.py --bd sandbox --build -k test_ut # build the mmc7.img $ ./test/py/test.py --bd sandbox --build -k bootflow_android
Signed-off-by: Mattijs Korpershoek mkorpershoek@baylibre.com
arch/sandbox/dts/test.dts | 8 +++++ configs/sandbox_defconfig | 2 +- test/boot/bootflow.c | 68 ++++++++++++++++++++++++++++++++++++++-- test/py/tests/test_ut.py | 79 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 4 deletions(-)
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index a012f5c4c9ba..5fb5eac862ec 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -43,6 +43,7 @@ mmc4 = "/mmc4"; mmc5 = "/mmc5"; mmc6 = "/mmc6";
pci0 = &pci0; pci1 = &pci1; pci2 = &pci2;mmc7 = "/mmc7";
@@ -1129,6 +1130,13 @@ filename = "mmc6.img"; };
- /* This is used for Android tests */
- mmc7 {
status = "disabled";
compatible = "sandbox,mmc";
filename = "mmc7.img";
- };
- pch { compatible = "sandbox,pch"; };
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index da8c1976d7bd..36e43e0e21ab 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -15,6 +15,7 @@ CONFIG_FIT=y CONFIG_FIT_RSASSA_PSS=y CONFIG_FIT_CIPHER=y CONFIG_FIT_VERBOSE=y +CONFIG_BOOTMETH_ANDROID=y CONFIG_LEGACY_IMAGE_FORMAT=y CONFIG_MEASURED_BOOT=y CONFIG_BOOTSTAGE=y @@ -40,7 +41,6 @@ CONFIG_LOG_MAX_LEVEL=9 CONFIG_LOG_DEFAULT_LEVEL=6 CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_STACKPROTECTOR=y -CONFIG_ANDROID_AB=y CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y CONFIG_CMD_SMBIOS=y diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 4511cfa7f9bf..8b46256fa48d 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -27,6 +27,7 @@
DECLARE_GLOBAL_DATA_PTR;
+extern U_BOOT_DRIVER(bootmeth_android); extern U_BOOT_DRIVER(bootmeth_cros); extern U_BOOT_DRIVER(bootmeth_2script);
@@ -518,12 +519,12 @@ BOOTSTD_TEST(bootflow_cmd_boot, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
- @uts: Unit test state
- @mmc_dev: MMC device to use, e.g. "mmc4". Note that this must remain valid
- in the caller until
- @bind_cros: true to bind the ChromiumOS bootmeth
*/
- @bind_cros: true to bind the ChromiumOS and Android bootmeths
- @old_orderp: Returns the original bootdev order, which must be restored
- Returns 0 on success, -ve on failure
static int prep_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev,
bool bind_cros, const char ***old_orderp)
bool bind_cros_android, const char ***old_orderp)
{ static const char *order[] = {"mmc2", "mmc1", NULL, NULL}; struct udevice *dev, *bootstd; @@ -545,12 +546,19 @@ static int prep_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev, "bootmeth_script", 0, ofnode_null(), &dev));
/* Enable the cros bootmeth if needed */
- if (IS_ENABLED(CONFIG_BOOTMETH_CROS) && bind_cros) {
if (IS_ENABLED(CONFIG_BOOTMETH_CROS) && bind_cros_android) { ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd)); ut_assertok(device_bind(bootstd, DM_DRIVER_REF(bootmeth_cros), "cros", 0, ofnode_null(), &dev)); }
/* Enable the android bootmeths if needed */
if (IS_ENABLED(CONFIG_BOOTMETH_ANDROID) && bind_cros_android) {
ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
ut_assertok(device_bind(bootstd, DM_DRIVER_REF(bootmeth_android),
"android", 0, ofnode_null(), &dev));
}
/* Change the order to include the device */ std = dev_get_priv(bootstd); old_order = std->bootdev_order;
@@ -589,6 +597,37 @@ static int scan_mmc_bootdev(struct unit_test_state *uts, const char *mmc_dev, return 0; }
+/**
- scan_mmc_android_bootdev() - Set up an mmc bootdev so we can access other
- distros. Android bootflow might print "ANDROID:*" while scanning
- @uts: Unit test state
- @mmc_dev: MMC device to use, e.g. "mmc4"
- Returns 0 on success, -ve on failure
- */
+static int scan_mmc_android_bootdev(struct unit_test_state *uts, const char *mmc_dev) +{
- struct bootstd_priv *std;
- struct udevice *bootstd;
- const char **old_order;
- ut_assertok(prep_mmc_bootdev(uts, mmc_dev, true, &old_order));
- console_record_reset_enable();
- ut_assertok(run_command("bootflow scan", 0));
- /* Android bootflow might print one or two 'ANDROID:*' logs */
- ut_check_skipline(uts);
- ut_check_skipline(uts);
- ut_assert_console_end();
- /* Restore the order used by the device tree */
- ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd));
- std = dev_get_priv(bootstd);
- std->bootdev_order = old_order;
- return 0;
+}
/**
- scan_mmc4_bootdev() - Set up the mmc4 bootdev so we can access a fake Armbian
@@ -1160,3 +1199,26 @@ static int bootflow_cros(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootflow_cros, 0);
+/* Test Android bootmeth */ +static int bootflow_android(struct unit_test_state *uts) +{
- if (!IS_ENABLED(CONFIG_BOOTMETH_ANDROID))
return -EAGAIN;
- ut_assertok(scan_mmc_android_bootdev(uts, "mmc7"));
- ut_assertok(run_command("bootflow list", 0));
- ut_assert_nextlinen("Showing all");
- ut_assert_nextlinen("Seq");
- ut_assert_nextlinen("---");
- ut_assert_nextlinen(" 0 extlinux");
- ut_assert_nextlinen(" 1 android ready mmc 0 mmc7.bootdev.whole ");
- ut_assert_nextlinen("---");
- ut_assert_skip_to_line("(2 bootflows, 2 valid)");
- ut_assert_console_end();
- return 0;
+} +BOOTSTD_TEST(bootflow_android, 0); diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index 58205066ec88..05e15830590c 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -11,6 +11,7 @@ import pytest import u_boot_utils # pylint: disable=E0611 from tests import fs_helper +from test_android import test_abootimg
def mkdir_cond(dirname): """Create a directory if it doesn't already exist @@ -423,6 +424,83 @@ def setup_cros_image(cons):
return fname
+def setup_android_image(cons):
- """Create a 20MB disk image with Android partitions"""
- Partition = collections.namedtuple('part', 'start,size,name')
- parts = {}
- disk_data = None
- def set_part_data(partnum, data):
"""Set the contents of a disk partition
This updates disk_data by putting data in the right place
Args:
partnum (int): Partition number to set
data (bytes): Data for that partition
"""
nonlocal disk_data
start = parts[partnum].start * sect_size
disk_data = disk_data[:start] + data + disk_data[start + len(data):]
- mmc_dev = 7
- fname = os.path.join(cons.config.source_dir, f'mmc{mmc_dev}.img')
- u_boot_utils.run_and_log(cons, 'qemu-img create %s 20M' % fname)
- u_boot_utils.run_and_log(cons, f'cgpt create {fname}')
- ptr = 40
- # Number of sectors in 1MB
- sect_size = 512
- sect_1mb = (1 << 20) // sect_size
- required_parts = [
{'num': 1, 'label':'misc', 'size': '1M'},
{'num': 2, 'label':'boot_a', 'size': '4M'},
{'num': 3, 'label':'boot_b', 'size': '4M'},
{'num': 4, 'label':'vendor_boot_a', 'size': '4M'},
{'num': 5, 'label':'vendor_boot_b', 'size': '4M'},
- ]
- for part in required_parts:
size_str = part['size']
if 'M' in size_str:
size = int(size_str[:-1]) * sect_1mb
else:
size = int(size_str)
u_boot_utils.run_and_log(
cons,
f"cgpt add -i {part['num']} -b {ptr} -s {size} -l {part['label']} -t basicdata {fname}")
ptr += size
- u_boot_utils.run_and_log(cons, f'cgpt boot -p {fname}')
- out = u_boot_utils.run_and_log(cons, f'cgpt show -q {fname}')
- # Create a dict (indexed by partition number) containing the above info
- for line in out.splitlines():
start, size, num, name = line.split(maxsplit=3)
parts[int(num)] = Partition(int(start), int(size), name)
- with open(fname, 'rb') as inf:
disk_data = inf.read()
- test_abootimg.AbootimgTestDiskImage(cons, 'bootv4.img', test_abootimg.boot_img_hex)
- boot_img = os.path.join(cons.config.result_dir, 'bootv4.img')
- with open(boot_img, 'rb') as inf:
set_part_data(2, inf.read())
- test_abootimg.AbootimgTestDiskImage(cons, 'vendor_boot.img', test_abootimg.vboot_img_hex)
- vendor_boot_img = os.path.join(cons.config.result_dir, 'vendor_boot.img')
- with open(vendor_boot_img, 'rb') as inf:
set_part_data(4, inf.read())
- with open(fname, 'wb') as outf:
outf.write(disk_data)
- print('wrote to {}'.format(fname))
- return fname
def setup_cedit_file(cons): infname = os.path.join(cons.config.source_dir, @@ -478,6 +556,7 @@ def test_ut_dm_init_bootstd(u_boot_console): setup_bootmenu_image(u_boot_console) setup_cedit_file(u_boot_console) setup_cros_image(u_boot_console)
setup_android_image(u_boot_console)
# Restart so that the new mmc1.img is picked up u_boot_console.restart_uboot()
-- 2.45.2
Reviewed-by: Julien Masson jmasson@baylibre.com