diff options
| author | Tom Rini <[email protected]> | 2023-01-24 14:04:14 -0500 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2023-01-24 14:04:14 -0500 |
| commit | 4e1ab2065e21e48a3087144ab826f12cfb797a65 (patch) | |
| tree | 1dc9e793258c5a4a1be4d5e6d554f7f1a82450f3 /test/boot | |
| parent | dd31cd58b02729807934cb699b164b1f8736620f (diff) | |
| parent | 3891c68ef50eda38d78c95ecd03aed030aa6bb53 (diff) | |
Merge branch '2023-01-24-bootstd-allow-migration-from-distro_bootcmd-script'
To quote the author:
So far, standard boot does not replicate all the of the functionality
of the distro_bootcmd scripts. In particular it lacks some bootdevs and
some of the bootmeths are incomplete.
Also there is currently no internal mechanism to enumerate buses in order
to discover bootdevs, e.g. with USB.
This series addresses these shortcomings:
- Adds the concept of a 'bootdev hunter' to enumerate buses, etc. in an
effort to find bootdevs of a certain priority
- Adds bootdevs for SCSI, IDE, NVMe, virtio, SPI flash
- Handles PXE and DHCP properly
- Supports reading the device tree with EFI and reading scripts from the
network
It also tidies up label processing, so it is possible to use:
bootflow scan mmc2
to scan just one MMC device (with BOOTSTD_FULL).
As before this implementation still relies on CONFIG_CMDLINE being
enabled, mostly for the network stack. Further work would be required to
disentangle that.
Quite a few tests are added but there are some gaps:
- SPI flash bootdev
- EFI FDT loading
Note that SATA works via SCSI (CONFIG_SCSI_AHCI) and does not use
driver model. Only pogo_v4 seems to be affected. Probably all thats is
needed is to call bootdev_setup_sibling_blk() in the Marvell SATA driver.
Also, while it would be possible to init MMC in a bootdev hunter, there is
no point since U-Boot always inits MMC on startup, if present.
With this series it should be possible to migrate boards to standard boot
by removing the inclusion of config_distro_bootcmd.h and instead adding
a suitable value for boot_targets to the environment, e.g.:
boot_targets=mmc1 mmc0 nvme scsi usb pxe dhcp spi
Thus it is possible to boot automatically without scripts and boards can
use a text-based environment instead of the config.h files.
To demonstrate this, rockpro64-rk3399 is migrated to standard boot in this
series. Full migration could probably be automated using a script, similar
in concept to moveconfig:
- obtain the board environment via 'make u-boot-initial-env'
- get the value of "boot_targets"
- drop config_distro_bootcmd.h from the config.h file
- rebuild again to get the environment without distro scripts
- write the environment (adding boot_targets) to board.env
- remove CONFIG_EXTRA_ENV_SETTINGS from the config.h file
Diffstat (limited to 'test/boot')
| -rw-r--r-- | test/boot/bootdev.c | 563 | ||||
| -rw-r--r-- | test/boot/bootflow.c | 138 | ||||
| -rw-r--r-- | test/boot/bootstd_common.c | 19 | ||||
| -rw-r--r-- | test/boot/bootstd_common.h | 13 |
4 files changed, 671 insertions, 62 deletions
diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index 1c2a79fb108..ef5215bbcec 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -102,22 +102,89 @@ BOOTSTD_TEST(bootdev_test_cmd_select, UT_TESTF_DM | UT_TESTF_SCAN_FDT); static int bootdev_test_labels(struct unit_test_state *uts) { struct udevice *dev, *media; + int mflags = 0; - ut_assertok(bootdev_find_by_label("mmc2", &dev)); + ut_assertok(bootdev_find_by_label("mmc2", &dev, &mflags)); ut_asserteq(UCLASS_BOOTDEV, device_get_uclass_id(dev)); + ut_asserteq(0, mflags); media = dev_get_parent(dev); ut_asserteq(UCLASS_MMC, device_get_uclass_id(media)); ut_asserteq_str("mmc2", media->name); + /* Check method flags */ + ut_assertok(bootdev_find_by_label("pxe", &dev, &mflags)); + ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY, + mflags); + ut_assertok(bootdev_find_by_label("dhcp", &dev, &mflags)); + ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_DHCP_ONLY, + mflags); + /* Check invalid uclass */ - ut_asserteq(-EINVAL, bootdev_find_by_label("fred0", &dev)); + ut_asserteq(-EINVAL, bootdev_find_by_label("fred0", &dev, &mflags)); /* Check unknown sequence number */ - ut_asserteq(-ENOENT, bootdev_find_by_label("mmc6", &dev)); + ut_asserteq(-ENOENT, bootdev_find_by_label("mmc6", &dev, &mflags)); return 0; } -BOOTSTD_TEST(bootdev_test_labels, UT_TESTF_DM | UT_TESTF_SCAN_FDT); +BOOTSTD_TEST(bootdev_test_labels, UT_TESTF_DM | UT_TESTF_SCAN_FDT | + UT_TESTF_ETH_BOOTDEV); + +/* Check bootdev_find_by_any() */ +static int bootdev_test_any(struct unit_test_state *uts) +{ + struct udevice *dev, *media; + int mflags; + + /* + * with ethernet enabled we have 8 devices ahead of the mmc ones: + * + * ut_assertok(run_command("bootdev list", 0)); + * Seq Probed Status Uclass Name + * --- ------ ------ -------- ------------------ + * 0 [ + ] OK ethernet [email protected] + * 1 [ ] OK ethernet [email protected] + * 2 [ ] OK ethernet sbe5.bootdev + * 3 [ ] OK ethernet [email protected] + * 4 [ ] OK ethernet phy-test-eth.bootdev + * 5 [ ] OK ethernet dsa-test-eth.bootdev + * 6 [ ] OK ethernet [email protected] + * 7 [ ] OK ethernet [email protected] + * 8 [ ] OK mmc mmc2.bootdev + * 9 [ + ] OK mmc mmc1.bootdev + * a [ ] OK mmc mmc0.bootdev + */ + console_record_reset_enable(); + ut_assertok(bootdev_find_by_any("8", &dev, &mflags)); + ut_asserteq(UCLASS_BOOTDEV, device_get_uclass_id(dev)); + ut_asserteq(BOOTFLOW_METHF_SINGLE_DEV, mflags); + media = dev_get_parent(dev); + ut_asserteq(UCLASS_MMC, device_get_uclass_id(media)); + ut_asserteq_str("mmc2", media->name); + ut_assert_console_end(); + + /* there should not be this many bootdevs */ + ut_asserteq(-ENODEV, bootdev_find_by_any("50", &dev, &mflags)); + ut_assert_nextline("Cannot find '50' (err=-19)"); + ut_assert_console_end(); + + /* Check method flags */ + ut_assertok(bootdev_find_by_any("pxe", &dev, &mflags)); + ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY, + mflags); + + /* Check invalid uclass */ + mflags = 123; + ut_asserteq(-EINVAL, bootdev_find_by_any("fred0", &dev, &mflags)); + ut_assert_nextline("Unknown uclass 'fred0' in label"); + ut_assert_nextline("Cannot find bootdev 'fred0' (err=-22)"); + ut_asserteq(123, mflags); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootdev_test_any, UT_TESTF_DM | UT_TESTF_SCAN_FDT | + UT_TESTF_ETH_BOOTDEV); /* Check bootdev ordering with the bootdev-order property */ static int bootdev_test_order(struct unit_test_state *uts) @@ -135,20 +202,31 @@ static int bootdev_test_order(struct unit_test_state *uts) * mmc2 - nothing connected */ ut_assertok(env_set("boot_targets", NULL)); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); ut_asserteq(2, iter.num_devs); - ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); - ut_asserteq_str("mmc1.bootdev", iter.dev_order[1]->name); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); + ut_asserteq_str("mmc1.bootdev", iter.dev_used[1]->name); bootflow_iter_uninit(&iter); /* Use the environment variable to override it */ ut_assertok(env_set("boot_targets", "mmc1 mmc2")); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); ut_asserteq(2, iter.num_devs); - ut_asserteq_str("mmc1.bootdev", iter.dev_order[0]->name); - ut_asserteq_str("mmc2.bootdev", iter.dev_order[1]->name); + ut_asserteq_str("mmc1.bootdev", iter.dev_used[0]->name); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[1]->name); bootflow_iter_uninit(&iter); + return 0; +} +BOOTSTD_TEST(bootdev_test_order, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check default bootdev ordering */ +static int bootdev_test_order_default(struct unit_test_state *uts) +{ + struct bootflow_iter iter; + struct bootflow bflow; + /* * Now drop both orderings, to check the default (prioriy/sequence) * ordering @@ -156,31 +234,19 @@ static int bootdev_test_order(struct unit_test_state *uts) ut_assertok(env_set("boot_targets", NULL)); ut_assertok(bootstd_test_drop_bootdev_order(uts)); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); - ut_asserteq(3, iter.num_devs); - ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); - ut_asserteq_str("mmc1.bootdev", iter.dev_order[1]->name); - ut_asserteq_str("mmc0.bootdev", iter.dev_order[2]->name); - - /* - * Check that adding aliases for the bootdevs works. We just fake it by - * setting the sequence numbers directly. - */ - iter.dev_order[0]->seq_ = 0; - iter.dev_order[1]->seq_ = 3; - iter.dev_order[2]->seq_ = 2; - bootflow_iter_uninit(&iter); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); + ut_asserteq(2, iter.num_devs); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); + ut_asserteq_str("mmc1.bootdev", iter.dev_used[1]->name); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); ut_asserteq(3, iter.num_devs); - ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); - ut_asserteq_str("mmc0.bootdev", iter.dev_order[1]->name); - ut_asserteq_str("mmc1.bootdev", iter.dev_order[2]->name); + ut_asserteq_str("mmc0.bootdev", iter.dev_used[2]->name); bootflow_iter_uninit(&iter); return 0; } -BOOTSTD_TEST(bootdev_test_order, UT_TESTF_DM | UT_TESTF_SCAN_FDT); +BOOTSTD_TEST(bootdev_test_order_default, UT_TESTF_DM | UT_TESTF_SCAN_FDT); /* Check bootdev ordering with the uclass priority */ static int bootdev_test_prio(struct unit_test_state *uts) @@ -190,6 +256,11 @@ static int bootdev_test_prio(struct unit_test_state *uts) struct bootflow bflow; struct udevice *blk; + test_set_skip_delays(true); + + /* disable ethernet since the hunter will run dhcp */ + test_set_eth_enable(false); + /* Start up USB which gives us three additional bootdevs */ usb_started = false; ut_assertok(run_command("usb start", 0)); @@ -198,26 +269,440 @@ static int bootdev_test_prio(struct unit_test_state *uts) /* 3 MMC and 3 USB bootdevs: MMC should come before USB */ console_record_reset_enable(); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); ut_asserteq(6, iter.num_devs); - ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[0]->name); ut_asserteq_str("usb_mass_storage.lun0.bootdev", - iter.dev_order[3]->name); + iter.dev_used[3]->name); - ut_assertok(bootdev_get_sibling_blk(iter.dev_order[3], &blk)); + ut_assertok(bootdev_get_sibling_blk(iter.dev_used[3], &blk)); ut_asserteq_str("usb_mass_storage.lun0", blk->name); /* adjust the priority of the first USB bootdev to the highest */ - ucp = dev_get_uclass_plat(iter.dev_order[3]); - ucp->prio = 1; + ucp = dev_get_uclass_plat(iter.dev_used[3]); + ucp->prio = BOOTDEVP_1_PRE_SCAN; + /* try again but enable hunting, which brings in SCSI */ bootflow_iter_uninit(&iter); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); - ut_asserteq(6, iter.num_devs); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, BOOTFLOWF_HUNT, + &bflow)); + ut_asserteq(-ENODEV, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(7, iter.num_devs); ut_asserteq_str("usb_mass_storage.lun0.bootdev", - iter.dev_order[0]->name); - ut_asserteq_str("mmc2.bootdev", iter.dev_order[1]->name); + iter.dev_used[0]->name); + ut_asserteq_str("mmc2.bootdev", iter.dev_used[1]->name); return 0; } BOOTSTD_TEST(bootdev_test_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check listing hunters */ +static int bootdev_test_hunter(struct unit_test_state *uts) +{ + struct bootstd_priv *std; + + test_set_skip_delays(true); + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + console_record_reset_enable(); + bootdev_list_hunters(std); + ut_assert_nextline("Prio Used Uclass Hunter"); + ut_assert_nextlinen("----"); + ut_assert_nextline(" 6 ethernet eth_bootdev"); + ut_assert_nextline(" 1 simple_bus (none)"); + ut_assert_nextline(" 5 ide ide_bootdev"); + ut_assert_nextline(" 2 mmc mmc_bootdev"); + ut_assert_nextline(" 4 nvme nvme_bootdev"); + ut_assert_nextline(" 4 scsi scsi_bootdev"); + ut_assert_nextline(" 4 spi_flash sf_bootdev"); + ut_assert_nextline(" 5 usb usb_bootdev"); + ut_assert_nextline(" 4 virtio virtio_bootdev"); + ut_assert_nextline("(total hunters: 9)"); + ut_assert_console_end(); + + ut_assertok(bootdev_hunt("usb1", false)); + ut_assert_nextline( + "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); + ut_assert_console_end(); + + /* USB is sixth in the list, so bit 7 */ + ut_asserteq(BIT(7), std->hunters_used); + + return 0; +} +BOOTSTD_TEST(bootdev_test_hunter, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check 'bootdev hunt' command */ +static int bootdev_test_cmd_hunt(struct unit_test_state *uts) +{ + struct bootstd_priv *std; + + test_set_skip_delays(true); + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + console_record_reset_enable(); + ut_assertok(run_command("bootdev hunt -l", 0)); + ut_assert_nextline("Prio Used Uclass Hunter"); + ut_assert_nextlinen("----"); + ut_assert_nextline(" 6 ethernet eth_bootdev"); + ut_assert_skip_to_line("(total hunters: 9)"); + ut_assert_console_end(); + + /* Use the MMC hunter and see that it updates */ + ut_assertok(run_command("bootdev hunt mmc", 0)); + ut_assertok(run_command("bootdev hunt -l", 0)); + ut_assert_skip_to_line(" 5 ide ide_bootdev"); + ut_assert_nextline(" 2 * mmc mmc_bootdev"); + ut_assert_skip_to_line("(total hunters: 9)"); + ut_assert_console_end(); + + /* Scan all hunters */ + test_set_eth_enable(false); + test_set_skip_delays(true); + ut_assertok(run_command("bootdev hunt", 0)); + ut_assert_nextline("Hunting with: ethernet"); + + /* This is the extension feature which has no uclass at present */ + ut_assert_nextline("Hunting with: simple_bus"); + ut_assert_nextline("Found 2 extension board(s)."); + ut_assert_nextline("Hunting with: ide"); + ut_assert_nextline("Bus 0: not available "); + + /* mmc hunter has already been used so should not run again */ + + ut_assert_nextline("Hunting with: nvme"); + ut_assert_nextline("Hunting with: scsi"); + ut_assert_nextline("scanning bus for devices..."); + ut_assert_skip_to_line("Hunting with: spi_flash"); + ut_assert_nextline("Hunting with: usb"); + ut_assert_nextline( + "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); + ut_assert_nextline("Hunting with: virtio"); + ut_assert_console_end(); + + /* List available hunters */ + ut_assertok(run_command("bootdev hunt -l", 0)); + ut_assert_nextlinen("Prio"); + ut_assert_nextlinen("----"); + ut_assert_nextline(" 6 * ethernet eth_bootdev"); + ut_assert_nextline(" 1 * simple_bus (none)"); + ut_assert_nextline(" 5 * ide ide_bootdev"); + ut_assert_nextline(" 2 * mmc mmc_bootdev"); + ut_assert_nextline(" 4 * nvme nvme_bootdev"); + ut_assert_nextline(" 4 * scsi scsi_bootdev"); + ut_assert_nextline(" 4 * spi_flash sf_bootdev"); + ut_assert_nextline(" 5 * usb usb_bootdev"); + ut_assert_nextline(" 4 * virtio virtio_bootdev"); + ut_assert_nextline("(total hunters: 9)"); + ut_assert_console_end(); + + ut_asserteq(GENMASK(MAX_HUNTER, 0), std->hunters_used); + + return 0; +} +BOOTSTD_TEST(bootdev_test_cmd_hunt, UT_TESTF_DM | UT_TESTF_SCAN_FDT | + UT_TESTF_ETH_BOOTDEV); + +/* Check searching for bootdevs using the hunters */ +static int bootdev_test_hunt_scan(struct unit_test_state *uts) +{ + struct bootflow_iter iter; + struct bootstd_priv *std; + struct bootflow bflow; + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + ut_assertok(bootstd_test_drop_bootdev_order(uts)); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, + BOOTFLOWF_SHOW | BOOTFLOWF_HUNT | + BOOTFLOWF_SKIP_GLOBAL, &bflow)); + ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used); + + return 0; +} +BOOTSTD_TEST(bootdev_test_hunt_scan, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check that only bootable partitions are processed */ +static int bootdev_test_bootable(struct unit_test_state *uts) +{ + struct bootflow_iter iter; + struct bootflow bflow; + struct udevice *blk; + + memset(&iter, '\0', sizeof(iter)); + memset(&bflow, '\0', sizeof(bflow)); + iter.part = 0; + ut_assertok(uclass_get_device_by_name(UCLASS_BLK, "mmc1.blk", &blk)); + iter.dev = blk; + ut_assertok(device_find_next_child(&iter.dev)); + uclass_first_device(UCLASS_BOOTMETH, &bflow.method); + + /* + * initially we don't have any knowledge of which partitions are + * bootable, but mmc1 has two partitions, with the first one being + * bootable + */ + iter.part = 2; + ut_asserteq(-EINVAL, bootdev_find_in_blk(iter.dev, blk, &iter, &bflow)); + ut_asserteq(0, iter.first_bootable); + + /* scan with part == 0 to get the partition info */ + iter.part = 0; + ut_asserteq(-ENOENT, bootdev_find_in_blk(iter.dev, blk, &iter, &bflow)); + ut_asserteq(1, iter.first_bootable); + + /* now it will refuse to use non-bootable partitions */ + iter.part = 2; + ut_asserteq(-EINVAL, bootdev_find_in_blk(iter.dev, blk, &iter, &bflow)); + + return 0; +} +BOOTSTD_TEST(bootdev_test_bootable, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check hunting for bootdev of a particular priority */ +static int bootdev_test_hunt_prio(struct unit_test_state *uts) +{ + test_set_skip_delays(true); + + console_record_reset_enable(); + ut_assertok(bootdev_hunt_prio(BOOTDEVP_4_SCAN_FAST, false)); + ut_assert_nextline("scanning bus for devices..."); + ut_assert_skip_to_line(" Type: Hard Disk"); + ut_assert_nextlinen(" Capacity:"); + ut_assert_console_end(); + + /* now try a different priority, verbosely */ + ut_assertok(bootdev_hunt_prio(BOOTDEVP_5_SCAN_SLOW, true)); + ut_assert_nextline("Hunting with: ide"); + ut_assert_nextline("Bus 0: not available "); + ut_assert_nextline("Hunting with: usb"); + ut_assert_nextline( + "Bus usb@1: scanning bus usb@1 for devices... 5 USB Device(s) found"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootdev_test_hunt_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check hunting for bootdevs with a particular label */ +static int bootdev_test_hunt_label(struct unit_test_state *uts) +{ + struct udevice *dev, *old; + struct bootstd_priv *std; + int mflags; + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + /* scan an unknown uclass */ + console_record_reset_enable(); + old = (void *)&mflags; /* arbitrary pointer to check against dev */ + dev = old; + mflags = 123; + ut_asserteq(-EINVAL, + bootdev_hunt_and_find_by_label("fred", &dev, &mflags)); + ut_assert_nextline("Unknown uclass 'fred' in label"); + ut_asserteq_ptr(old, dev); + ut_asserteq(123, mflags); + ut_assert_console_end(); + ut_asserteq(0, std->hunters_used); + + /* scan an invalid mmc controllers */ + ut_asserteq(-ENOENT, + bootdev_hunt_and_find_by_label("mmc4", &dev, &mflags)); + ut_asserteq_ptr(old, dev); + ut_asserteq(123, mflags); + ut_assert_nextline("Unknown seq 4 for label 'mmc4'"); + ut_assert_console_end(); + + ut_assertok(bootstd_test_check_mmc_hunter(uts)); + + /* scan for a particular mmc controller */ + ut_assertok(bootdev_hunt_and_find_by_label("mmc1", &dev, &mflags)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc1.bootdev", dev->name); + ut_asserteq(0, mflags); + ut_assert_console_end(); + + /* scan all of usb */ + test_set_skip_delays(true); + ut_assertok(bootdev_hunt_and_find_by_label("usb", &dev, &mflags)); + ut_assertnonnull(dev); + ut_asserteq_str("usb_mass_storage.lun0.bootdev", dev->name); + ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS, mflags); + ut_assert_nextlinen("Bus usb@1: scanning bus usb@1"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootdev_test_hunt_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check iterating to the next label in a list */ +static int bootdev_test_next_label(struct unit_test_state *uts) +{ + const char *const labels[] = {"mmc0", "scsi", "dhcp", "pxe", NULL}; + struct bootflow_iter iter; + struct bootstd_priv *std; + struct bootflow bflow; + struct udevice *dev; + int mflags; + + test_set_eth_enable(false); + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + memset(&iter, '\0', sizeof(iter)); + memset(&bflow, '\0', sizeof(bflow)); + iter.part = 0; + uclass_first_device(UCLASS_BOOTMETH, &bflow.method); + iter.cur_label = -1; + iter.labels = labels; + + dev = NULL; + mflags = 123; + ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); + console_record_reset_enable(); + ut_assert_console_end(); + ut_assertnonnull(dev); + ut_asserteq_str("mmc0.bootdev", dev->name); + ut_asserteq(0, mflags); + + ut_assertok(bootstd_test_check_mmc_hunter(uts)); + + ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); + ut_assert_nextline("scanning bus for devices..."); + ut_assert_skip_to_line( + " Capacity: 1.9 MB = 0.0 GB (4095 x 512)"); + ut_assert_console_end(); + ut_assertnonnull(dev); + ut_asserteq_str("scsi.id0lun0.bootdev", dev->name); + ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS, mflags); + + /* SCSI is sixth in the list, so bit 5 */ + ut_asserteq(BIT(MMC_HUNTER) | BIT(5), std->hunters_used); + + ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); + ut_assert_console_end(); + ut_assertnonnull(dev); + ut_asserteq_str("[email protected]", dev->name); + ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_DHCP_ONLY, + mflags); + + /* dhcp: Ethernet is first so bit 0 */ + ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used); + + ut_assertok(bootdev_next_label(&iter, &dev, &mflags)); + ut_assert_console_end(); + ut_assertnonnull(dev); + ut_asserteq_str("[email protected]", dev->name); + ut_asserteq(BOOTFLOW_METHF_SINGLE_UCLASS | BOOTFLOW_METHF_PXE_ONLY, + mflags); + + /* pxe: Ethernet is first so bit 0 */ + ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used); + + mflags = 123; + ut_asserteq(-ENODEV, bootdev_next_label(&iter, &dev, &mflags)); + ut_asserteq(123, mflags); + ut_assert_console_end(); + + /* no change */ + ut_asserteq(BIT(MMC_HUNTER) | BIT(5) | BIT(0), std->hunters_used); + + return 0; +} +BOOTSTD_TEST(bootdev_test_next_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT | + UT_TESTF_ETH_BOOTDEV | UT_TESTF_SF_BOOTDEV); + + +/* Check iterating to the next prioirty in a list */ +static int bootdev_test_next_prio(struct unit_test_state *uts) +{ + struct bootflow_iter iter; + struct bootstd_priv *std; + struct bootflow bflow; + struct udevice *dev; + int ret; + + test_set_eth_enable(false); + test_set_skip_delays(true); + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + memset(&iter, '\0', sizeof(iter)); + memset(&bflow, '\0', sizeof(bflow)); + iter.part = 0; + uclass_first_device(UCLASS_BOOTMETH, &bflow.method); + iter.cur_prio = 0; + iter.flags = BOOTFLOWF_SHOW; + + dev = NULL; + console_record_reset_enable(); + ut_assertok(bootdev_next_prio(&iter, &dev)); + ut_assertnonnull(dev); + ut_asserteq_str("mmc2.bootdev", dev->name); + + /* hunt flag not set, so this should not use any hunters */ + ut_asserteq(0, std->hunters_used); + ut_assert_console_end(); + + /* now try again with hunting enabled */ + iter.flags = BOOTFLOWF_SHOW | BOOTFLOWF_HUNT; + iter.cur_prio = 0; + iter.part = 0; + + ut_assertok(bootdev_next_prio(&iter, &dev)); + ut_asserteq_str("mmc2.bootdev", dev->name); + ut_assert_nextline("Hunting with: simple_bus"); + ut_assert_nextline("Found 2 extension board(s)."); + ut_assert_nextline("Hunting with: mmc"); + ut_assert_console_end(); + + ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used); + + ut_assertok(bootdev_next_prio(&iter, &dev)); + ut_asserteq_str("mmc1.bootdev", dev->name); + + ut_assertok(bootdev_next_prio(&iter, &dev)); + ut_asserteq_str("mmc0.bootdev", dev->name); + ut_assert_console_end(); + + ut_assertok(bootdev_next_prio(&iter, &dev)); + ut_asserteq_str("[email protected]", dev->name); + ut_assert_skip_to_line("Hunting with: spi_flash"); + + /* + * this scans all bootdevs of priority BOOTDEVP_4_SCAN_FAST before it + * starts looking at the devices, so we se virtio as well + */ + ut_assert_nextline("Hunting with: virtio"); + ut_assert_nextlinen("SF: Detected m25p16"); + + ut_assertok(bootdev_next_prio(&iter, &dev)); + ut_asserteq_str("[email protected]", dev->name); + ut_assert_nextlinen("SF: Detected m25p16"); + ut_assert_console_end(); + + /* keep going until there are no more bootdevs */ + do { + ret = bootdev_next_prio(&iter, &dev); + } while (!ret); + ut_asserteq(-ENODEV, ret); + ut_assertnull(dev); + ut_asserteq(GENMASK(MAX_HUNTER, 0), std->hunters_used); + + ut_assert_skip_to_line("Hunting with: ethernet"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootdev_test_next_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT | + UT_TESTF_SF_BOOTDEV); diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 5b76cd3ab14..b9284fc464a 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -51,11 +51,14 @@ static int bootflow_cmd(struct unit_test_state *uts) console_record_reset_enable(); ut_assertok(run_command("bootdev select 1", 0)); ut_assert_console_end(); - ut_assertok(run_command("bootflow scan -l", 0)); + ut_assertok(run_command("bootflow scan -lH", 0)); ut_assert_nextline("Scanning for bootflows in bootdev 'mmc1.bootdev'"); ut_assert_nextline("Seq Method State Uclass Part Name Filename"); ut_assert_nextlinen("---"); + ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':"); + ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':"); ut_assert_nextline(" 0 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf"); + ut_assert_nextline("No more bootdevs"); ut_assert_nextlinen("---"); ut_assert_nextline("(1 bootflow, 1 valid)"); ut_assert_console_end(); @@ -73,28 +76,53 @@ static int bootflow_cmd(struct unit_test_state *uts) } BOOTSTD_TEST(bootflow_cmd, UT_TESTF_DM | UT_TESTF_SCAN_FDT); -/* Check 'bootflow scan' with a name / label / seq */ +/* Check 'bootflow scan' with a label / seq */ static int bootflow_cmd_label(struct unit_test_state *uts) { + test_set_eth_enable(false); + console_record_reset_enable(); - ut_assertok(run_command("bootflow scan -l mmc1", 0)); - ut_assert_nextline("Scanning for bootflows in bootdev 'mmc1.bootdev'"); + ut_assertok(run_command("bootflow scan -lH mmc1", 0)); + ut_assert_nextline("Scanning for bootflows with label 'mmc1'"); ut_assert_skip_to_line("(1 bootflow, 1 valid)"); ut_assert_console_end(); - ut_assertok(run_command("bootflow scan -l mmc0.bootdev", 0)); - ut_assert_nextline("Scanning for bootflows in bootdev 'mmc0.bootdev'"); + ut_assertok(run_command("bootflow scan -lH 0", 0)); + ut_assert_nextline("Scanning for bootflows with label '0'"); ut_assert_skip_to_line("(0 bootflows, 0 valid)"); ut_assert_console_end(); - ut_assertok(run_command("bootflow scan -l 0", 0)); - ut_assert_nextline("Scanning for bootflows in bootdev 'mmc2.bootdev'"); + /* + * with ethernet enabled we have 8 devices ahead of the mmc ones: + * + * ut_assertok(run_command("bootdev list", 0)); + * Seq Probed Status Uclass Name + * --- ------ ------ -------- ------------------ + * 0 [ + ] OK ethernet [email protected] + * 1 [ ] OK ethernet [email protected] + * 2 [ ] OK ethernet sbe5.bootdev + * 3 [ ] OK ethernet [email protected] + * 4 [ ] OK ethernet phy-test-eth.bootdev + * 5 [ ] OK ethernet dsa-test-eth.bootdev + * 6 [ ] OK ethernet [email protected] + * 7 [ ] OK ethernet [email protected] + * 8 [ ] OK mmc mmc2.bootdev + * 9 [ + ] OK mmc mmc1.bootdev + * a [ ] OK mmc mmc0.bootdev + */ + ut_assertok(run_command("bootflow scan -lH 9", 0)); + ut_assert_nextline("Scanning for bootflows with label '9'"); + ut_assert_skip_to_line("(1 bootflow, 1 valid)"); + + ut_assertok(run_command("bootflow scan -lH 0", 0)); + ut_assert_nextline("Scanning for bootflows with label '0'"); ut_assert_skip_to_line("(0 bootflows, 0 valid)"); ut_assert_console_end(); return 0; } -BOOTSTD_TEST(bootflow_cmd_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT); +BOOTSTD_TEST(bootflow_cmd_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT | + UT_TESTF_ETH_BOOTDEV); /* Check 'bootflow scan/list' commands using all bootdevs */ static int bootflow_cmd_glob(struct unit_test_state *uts) @@ -102,7 +130,7 @@ static int bootflow_cmd_glob(struct unit_test_state *uts) ut_assertok(bootstd_test_drop_bootdev_order(uts)); console_record_reset_enable(); - ut_assertok(run_command("bootflow scan -lG", 0)); + ut_assertok(run_command("bootflow scan -lGH", 0)); ut_assert_nextline("Scanning for bootflows in all bootdevs"); ut_assert_nextline("Seq Method State Uclass Part Name Filename"); ut_assert_nextlinen("---"); @@ -134,7 +162,7 @@ static int bootflow_cmd_scan_e(struct unit_test_state *uts) ut_assertok(bootstd_test_drop_bootdev_order(uts)); console_record_reset_enable(); - ut_assertok(run_command("bootflow scan -aleG", 0)); + ut_assertok(run_command("bootflow scan -aleGH", 0)); ut_assert_nextline("Scanning for bootflows in all bootdevs"); ut_assert_nextline("Seq Method State Uclass Part Name Filename"); ut_assert_nextlinen("---"); @@ -199,6 +227,7 @@ static int bootflow_cmd_info(struct unit_test_state *uts) ut_assert_nextline("Size: 253 (595 bytes)"); ut_assert_nextline("OS: Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)"); ut_assert_nextline("Logo: (none)"); + ut_assert_nextline("FDT: <NULL>"); ut_assert_nextline("Error: 0"); ut_assert_console_end(); @@ -247,7 +276,8 @@ static int bootflow_iter(struct unit_test_state *uts) /* The first device is mmc2.bootdev which has no media */ ut_asserteq(-EPROTONOSUPPORT, - bootflow_scan_first(&iter, BOOTFLOWF_ALL | BOOTFLOWF_SKIP_GLOBAL, &bflow)); + bootflow_scan_first(NULL, NULL, &iter, + BOOTFLOWF_ALL | BOOTFLOWF_SKIP_GLOBAL, &bflow)); ut_asserteq(2, iter.num_methods); ut_asserteq(0, iter.cur_method); ut_asserteq(0, iter.part); @@ -315,8 +345,8 @@ 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(-EINVAL, bootflow_scan_next(&iter, &bflow)); ut_asserteq(2, iter.num_methods); ut_asserteq(0, iter.cur_method); ut_asserteq(2, iter.part); @@ -338,22 +368,24 @@ BOOTSTD_TEST(bootflow_iter, UT_TESTF_DM | UT_TESTF_SCAN_FDT); /* Check using the system bootdev */ static int bootflow_system(struct unit_test_state *uts) { - struct udevice *dev; + struct udevice *bootstd, *dev; if (!IS_ENABLED(CONFIG_CMD_BOOTEFI_BOOTMGR)) return -EAGAIN; - ut_assertok(uclass_get_device_by_name(UCLASS_BOOTMETH, "efi_mgr", - &dev)); + ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd)); + ut_assertok(device_bind(bootstd, DM_DRIVER_GET(bootmeth_efi_mgr), + "efi_mgr", 0, ofnode_null(), &dev)); + ut_assertok(device_probe(dev)); sandbox_set_fake_efi_mgr_dev(dev, true); /* We should get a single 'bootmgr' method right at the end */ bootstd_clear_glob(); console_record_reset_enable(); - ut_assertok(run_command("bootflow scan -l", 0)); + ut_assertok(run_command("bootflow scan -lH", 0)); ut_assert_skip_to_line( " 0 efi_mgr ready (none) 0 <NULL> <NULL>"); ut_assert_skip_to_line("No more bootdevs"); - ut_assert_skip_to_line("(5 bootflows, 5 valid)"); + ut_assert_skip_to_line("(2 bootflows, 2 valid)"); ut_assert_console_end(); return 0; @@ -380,11 +412,11 @@ static int bootflow_iter_disable(struct unit_test_state *uts) bootstd_clear_glob(); console_record_reset_enable(); ut_assertok(inject_response(uts)); - ut_assertok(run_command("bootflow scan -lb", 0)); + ut_assertok(run_command("bootflow scan -lbH", 0)); /* Try to boot the bootmgr flow, which will fail */ console_record_reset_enable(); - ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow)); ut_asserteq(3, iter.num_methods); ut_asserteq_str("sandbox", iter.method->name); ut_assertok(inject_response(uts)); @@ -416,7 +448,7 @@ static int bootflow_scan_glob_bootmeth(struct unit_test_state *uts) */ console_record_reset_enable(); ut_assertok(bootmeth_set_order("efi firmware0")); - ut_assertok(run_command("bootflow scan -lG", 0)); + ut_assertok(run_command("bootflow scan -lGH", 0)); ut_assert_nextline("Scanning for bootflows in all bootdevs"); ut_assert_nextline( "Seq Method State Uclass Part Name Filename"); @@ -425,7 +457,7 @@ static int bootflow_scan_glob_bootmeth(struct unit_test_state *uts) ut_assert_nextline("(0 bootflows, 0 valid)"); ut_assert_console_end(); - ut_assertok(run_command("bootflow scan -l", 0)); + ut_assertok(run_command("bootflow scan -lH", 0)); ut_assert_nextline("Scanning for bootflows in all bootdevs"); ut_assert_nextline( "Seq Method State Uclass Part Name Filename"); @@ -531,6 +563,66 @@ static int bootflow_cmd_menu(struct unit_test_state *uts) } BOOTSTD_TEST(bootflow_cmd_menu, UT_TESTF_DM | UT_TESTF_SCAN_FDT); +/* Check searching for a single bootdev using the hunters */ +static int bootflow_cmd_hunt_single(struct unit_test_state *uts) +{ + struct bootstd_priv *std; + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + ut_assertok(bootstd_test_drop_bootdev_order(uts)); + + console_record_reset_enable(); + ut_assertok(run_command("bootflow scan -l mmc1", 0)); + ut_assert_nextline("Scanning for bootflows with label 'mmc1'"); + ut_assert_skip_to_line("(1 bootflow, 1 valid)"); + ut_assert_console_end(); + + /* check that the hunter was used */ + ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used); + + return 0; +} +BOOTSTD_TEST(bootflow_cmd_hunt_single, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check searching for a uclass label using the hunters */ +static int bootflow_cmd_hunt_label(struct unit_test_state *uts) +{ + struct bootstd_priv *std; + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + test_set_skip_delays(true); + test_set_eth_enable(false); + ut_assertok(bootstd_test_drop_bootdev_order(uts)); + + console_record_reset_enable(); + ut_assertok(run_command("bootflow scan -l mmc", 0)); + + /* check that the hunter was used */ + ut_asserteq(BIT(MMC_HUNTER) | BIT(1), std->hunters_used); + + /* check that we got the mmc1 bootflow */ + ut_assert_nextline("Scanning for bootflows with label 'mmc'"); + ut_assert_nextlinen("Seq"); + ut_assert_nextlinen("---"); + ut_assert_nextline("Hunting with: simple_bus"); + ut_assert_nextline("Found 2 extension board(s)."); + ut_assert_nextline("Hunting with: mmc"); + ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':"); + ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':"); + ut_assert_nextline( + " 0 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf"); + ut_assert_nextline("Scanning bootdev 'mmc0.bootdev':"); + ut_assert_skip_to_line("(1 bootflow, 1 valid)"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootflow_cmd_hunt_label, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + /** * check_font() - Check that the font size for an item matches expectations * diff --git a/test/boot/bootstd_common.c b/test/boot/bootstd_common.c index 7a40836507a..e71a2975c53 100644 --- a/test/boot/bootstd_common.c +++ b/test/boot/bootstd_common.c @@ -7,6 +7,7 @@ */ #include <common.h> +#include <bootdev.h> #include <bootstd.h> #include <dm.h> #include <memalign.h> @@ -67,6 +68,24 @@ int bootstd_test_drop_bootdev_order(struct unit_test_state *uts) return 0; } +int bootstd_test_check_mmc_hunter(struct unit_test_state *uts) +{ + struct bootdev_hunter *start, *mmc; + struct bootstd_priv *std; + uint seq; + + /* get access to the used hunters */ + ut_assertok(bootstd_get_priv(&std)); + + /* check that the hunter was used */ + start = ll_entry_start(struct bootdev_hunter, bootdev_hunter); + mmc = BOOTDEV_HUNTER_GET(mmc_bootdev_hunter); + seq = mmc - start; + ut_asserteq(BIT(seq), std->hunters_used); + + return 0; +} + int do_ut_bootstd(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct unit_test *tests = UNIT_TEST_SUITE_START(bootstd_test); diff --git a/test/boot/bootstd_common.h b/test/boot/bootstd_common.h index c5e0fd1ceab..136a79b5178 100644 --- a/test/boot/bootstd_common.h +++ b/test/boot/bootstd_common.h @@ -20,6 +20,11 @@ #define TEST_VERSION "U-Boot v2022.04-local2" #define TEST_VERNUM 0x00010002 +enum { + MAX_HUNTER = 8, + MMC_HUNTER = 3, /* ID of MMC hunter */ +}; + struct unit_test_state; /** @@ -40,4 +45,12 @@ int bootstd_test_drop_bootdev_order(struct unit_test_state *uts); */ int bootstd_setup_for_tests(void); +/** + * bootstd_test_check_mmc_hunter() - Check that the mmc bootdev hunter was used + * + * @uts: Unit test state to use for ut_assert...() functions + * Returns: 0 if OK (used), other value on error (not used) + */ +int bootstd_test_check_mmc_hunter(struct unit_test_state *uts); + #endif |
