From 2fa4756d03a377dd0a6e943d2a16f4e2c9c97342 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:30:54 -0600 Subject: lib: Move string tests to the string module A few string tests were added to the print module by mistake. Move them. Signed-off-by: Simon Glass --- test/print_ut.c | 40 ---------------------------------------- test/str_ut.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 40 deletions(-) (limited to 'test') diff --git a/test/print_ut.c b/test/print_ut.c index 247011f2db..47a6ce5784 100644 --- a/test/print_ut.c +++ b/test/print_ut.c @@ -345,26 +345,6 @@ static int print_do_hex_dump(struct unit_test_state *uts) } PRINT_TEST(print_do_hex_dump, UT_TESTF_CONSOLE_REC); -static int print_itoa(struct unit_test_state *uts) -{ - ut_asserteq_str("123", simple_itoa(123)); - ut_asserteq_str("0", simple_itoa(0)); - ut_asserteq_str("2147483647", simple_itoa(0x7fffffff)); - ut_asserteq_str("4294967295", simple_itoa(0xffffffff)); - - /* Use #ifdef here to avoid a compiler warning on 32-bit machines */ -#ifdef CONFIG_PHYS_64BIT - if (sizeof(ulong) == 8) { - ut_asserteq_str("9223372036854775807", - simple_itoa((1UL << 63) - 1)); - ut_asserteq_str("18446744073709551615", simple_itoa(-1)); - } -#endif /* CONFIG_PHYS_64BIT */ - - return 0; -} -PRINT_TEST(print_itoa, 0); - static int snprint(struct unit_test_state *uts) { char buf[10] = "xxxxxxxxx"; @@ -391,26 +371,6 @@ static int snprint(struct unit_test_state *uts) } PRINT_TEST(snprint, 0); -static int print_xtoa(struct unit_test_state *uts) -{ - ut_asserteq_str("7f", simple_xtoa(127)); - ut_asserteq_str("00", simple_xtoa(0)); - ut_asserteq_str("7fffffff", simple_xtoa(0x7fffffff)); - ut_asserteq_str("ffffffff", simple_xtoa(0xffffffff)); - - /* Use #ifdef here to avoid a compiler warning on 32-bit machines */ -#ifdef CONFIG_PHYS_64BIT - if (sizeof(ulong) == 8) { - ut_asserteq_str("7fffffffffffffff", - simple_xtoa((1UL << 63) - 1)); - ut_asserteq_str("ffffffffffffffff", simple_xtoa(-1)); - } -#endif /* CONFIG_PHYS_64BIT */ - - return 0; -} -PRINT_TEST(print_xtoa, 0); - int do_ut_print(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct unit_test *tests = UNIT_TEST_SUITE_START(print_test); diff --git a/test/str_ut.c b/test/str_ut.c index d2840d5152..6c817f6f72 100644 --- a/test/str_ut.c +++ b/test/str_ut.c @@ -202,6 +202,46 @@ static int str_dectoul(struct unit_test_state *uts) } STR_TEST(str_dectoul, 0); +static int str_itoa(struct unit_test_state *uts) +{ + ut_asserteq_str("123", simple_itoa(123)); + ut_asserteq_str("0", simple_itoa(0)); + ut_asserteq_str("2147483647", simple_itoa(0x7fffffff)); + ut_asserteq_str("4294967295", simple_itoa(0xffffffff)); + + /* Use #ifdef here to avoid a compiler warning on 32-bit machines */ +#ifdef CONFIG_PHYS_64BIT + if (sizeof(ulong) == 8) { + ut_asserteq_str("9223372036854775807", + simple_itoa((1UL << 63) - 1)); + ut_asserteq_str("18446744073709551615", simple_itoa(-1)); + } +#endif /* CONFIG_PHYS_64BIT */ + + return 0; +} +STR_TEST(str_itoa, 0); + +static int str_xtoa(struct unit_test_state *uts) +{ + ut_asserteq_str("7f", simple_xtoa(127)); + ut_asserteq_str("00", simple_xtoa(0)); + ut_asserteq_str("7fffffff", simple_xtoa(0x7fffffff)); + ut_asserteq_str("ffffffff", simple_xtoa(0xffffffff)); + + /* Use #ifdef here to avoid a compiler warning on 32-bit machines */ +#ifdef CONFIG_PHYS_64BIT + if (sizeof(ulong) == 8) { + ut_asserteq_str("7fffffffffffffff", + simple_xtoa((1UL << 63) - 1)); + ut_asserteq_str("ffffffffffffffff", simple_xtoa(-1)); + } +#endif /* CONFIG_PHYS_64BIT */ + + return 0; +} +STR_TEST(str_xtoa, 0); + int do_ut_str(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct unit_test *tests = UNIT_TEST_SUITE_START(str_test); -- cgit v1.2.3 From 18436c74dce29a74e996d5932ba01e0cd3481326 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:30:55 -0600 Subject: test: Add tests for trailing_strtol() This function currently has no tests. Add some. Signed-off-by: Simon Glass --- include/vsprintf.h | 4 ++-- test/str_ut.c | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/include/vsprintf.h b/include/vsprintf.h index 532ef3650b..3d1f968df4 100644 --- a/include/vsprintf.h +++ b/include/vsprintf.h @@ -99,7 +99,7 @@ long long simple_strtoll(const char *cp, char **endp, unsigned int base); * For example, "abc123" would return 123. * * @str: String to exxamine - * Return: training number if found, else -1 + * Return: trailing number if found, else -1 */ long trailing_strtol(const char *str); @@ -114,7 +114,7 @@ long trailing_strtol(const char *str); * @str: String to exxamine * @end: Pointer to end of string to examine, or NULL to use the * whole string - * Return: training number if found, else -1 + * Return: trailing number if found, else -1 */ long trailing_strtoln(const char *str, const char *end); diff --git a/test/str_ut.c b/test/str_ut.c index 6c817f6f72..9674a59f2a 100644 --- a/test/str_ut.c +++ b/test/str_ut.c @@ -242,6 +242,25 @@ static int str_xtoa(struct unit_test_state *uts) } STR_TEST(str_xtoa, 0); +static int str_trailing(struct unit_test_state *uts) +{ + char str1[] = "abc123def"; + + ut_asserteq(-1, trailing_strtol("")); + ut_asserteq(-1, trailing_strtol("123")); + ut_asserteq(123, trailing_strtol("abc123")); + ut_asserteq(4, trailing_strtol("12c4")); + ut_asserteq(-1, trailing_strtol("abd")); + ut_asserteq(-1, trailing_strtol("abc123def")); + + ut_asserteq(-1, trailing_strtoln(str1, NULL)); + ut_asserteq(123, trailing_strtoln(str1, str1 + 6)); + ut_asserteq(-1, trailing_strtoln(str1, str1 + 9)); + + return 0; +} +STR_TEST(str_trailing, 0); + int do_ut_str(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { struct unit_test *tests = UNIT_TEST_SUITE_START(str_test); -- cgit v1.2.3 From d667a0d8f413d7278f912aa4e671bc56d28b25f2 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:30:57 -0600 Subject: lib: Fix a few bugs in trailing_strtoln() At present this has a minor bug in that it reads the byte before the start of the string, if it is empty. Also it doesn't handle a non-numeric prefix which is only one character long. Fix these bugs with a reworked implementation. Add a test for the second case. The first one is hard to test. Signed-off-by: Simon Glass --- include/vsprintf.h | 3 +++ lib/strto.c | 11 ++++++----- test/str_ut.c | 2 ++ 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'test') diff --git a/include/vsprintf.h b/include/vsprintf.h index d4bf3211da..5172ceedec 100644 --- a/include/vsprintf.h +++ b/include/vsprintf.h @@ -98,6 +98,9 @@ long long simple_strtoll(const char *cp, char **endp, unsigned int base); * Given a string this finds a trailing number on the string and returns it. * For example, "abc123" would return 123. * + * Note that this does not handle a string without a prefix. See dectoul() for + * that case. + * * @str: String to examine * Return: trailing number if found, else -1 */ diff --git a/lib/strto.c b/lib/strto.c index f191884376..b1d803a77d 100644 --- a/lib/strto.c +++ b/lib/strto.c @@ -189,11 +189,12 @@ long trailing_strtoln(const char *str, const char *end) if (!end) end = str + strlen(str); - if (isdigit(end[-1])) { - for (p = end - 1; p > str; p--) { - if (!isdigit(*p)) - return dectoul(p + 1, NULL); - } + p = end - 1; + if (p > str && isdigit(*p)) { + do { + if (!isdigit(p[-1])) + return dectoul(p, NULL); + } while (--p > str); } return -1; diff --git a/test/str_ut.c b/test/str_ut.c index 9674a59f2a..058b359437 100644 --- a/test/str_ut.c +++ b/test/str_ut.c @@ -257,6 +257,8 @@ static int str_trailing(struct unit_test_state *uts) ut_asserteq(123, trailing_strtoln(str1, str1 + 6)); ut_asserteq(-1, trailing_strtoln(str1, str1 + 9)); + ut_asserteq(3, trailing_strtol("a3")); + return 0; } STR_TEST(str_trailing, 0); -- cgit v1.2.3 From 8565efd509236dc7d4e766de39edae2cefb10057 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:30:58 -0600 Subject: lib: Add a way to find the postiion of a trailing number At present it is not possible to find out which part of the string is the number part and which is before it. Add a new variant which provides this feature, so we can separate the two in the caller. Signed-off-by: Simon Glass --- include/vsprintf.h | 18 ++++++++++++++++++ lib/strto.c | 14 ++++++++++++-- test/str_ut.c | 13 ++++++++++++- 3 files changed, 42 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/include/vsprintf.h b/include/vsprintf.h index 5172ceedec..e006af200f 100644 --- a/include/vsprintf.h +++ b/include/vsprintf.h @@ -121,6 +121,24 @@ long trailing_strtol(const char *str); */ long trailing_strtoln(const char *str, const char *end); +/** + * trailing_strtoln_end() - extract trailing integer from a fixed-length string + * + * Given a fixed-length string this finds a trailing number on the string + * and returns it. For example, "abc123" would return 123. Only the + * characters between @str and @end - 1 are examined. If @end is NULL, it is + * set to str + strlen(str). + * + * @str: String to examine + * @end: Pointer to end of string to examine, or NULL to use the + * whole string + * @endp: If non-NULL, this is set to point to the character where the + * number starts, e.g. for "mmc0" this would be point to the '0'; if no + * trailing number is found, it is set to the end of the string + * Return: training number if found, else -1 + */ +long trailing_strtoln_end(const char *str, const char *end, char const **endp); + /** * panic() - Print a message and reset/hang * diff --git a/lib/strto.c b/lib/strto.c index b1d803a77d..6462d4fddf 100644 --- a/lib/strto.c +++ b/lib/strto.c @@ -183,7 +183,7 @@ long long simple_strtoll(const char *cp, char **endp, unsigned int base) return simple_strtoull(cp, endp, base); } -long trailing_strtoln(const char *str, const char *end) +long trailing_strtoln_end(const char *str, const char *end, char const **endp) { const char *p; @@ -192,14 +192,24 @@ long trailing_strtoln(const char *str, const char *end) p = end - 1; if (p > str && isdigit(*p)) { do { - if (!isdigit(p[-1])) + if (!isdigit(p[-1])) { + if (endp) + *endp = p; return dectoul(p, NULL); + } } while (--p > str); } + if (endp) + *endp = end; return -1; } +long trailing_strtoln(const char *str, const char *end) +{ + return trailing_strtoln_end(str, end, NULL); +} + long trailing_strtol(const char *str) { return trailing_strtoln(str, NULL); diff --git a/test/str_ut.c b/test/str_ut.c index 058b359437..5a844347c2 100644 --- a/test/str_ut.c +++ b/test/str_ut.c @@ -244,7 +244,9 @@ STR_TEST(str_xtoa, 0); static int str_trailing(struct unit_test_state *uts) { - char str1[] = "abc123def"; + const char str1[] = "abc123def"; + const char str2[] = "abc123def456"; + const char *end; ut_asserteq(-1, trailing_strtol("")); ut_asserteq(-1, trailing_strtol("123")); @@ -259,6 +261,15 @@ static int str_trailing(struct unit_test_state *uts) ut_asserteq(3, trailing_strtol("a3")); + ut_asserteq(123, trailing_strtoln_end(str1, str1 + 6, &end)); + ut_asserteq(3, end - str1); + + ut_asserteq(-1, trailing_strtoln_end(str1, str1 + 7, &end)); + ut_asserteq(7, end - str1); + + ut_asserteq(456, trailing_strtoln_end(str2, NULL, &end)); + ut_asserteq(9, end - str2); + return 0; } STR_TEST(str_trailing, 0); -- cgit v1.2.3 From 6aa4fe39122a85ce1ef559139518fa5042406186 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:30:59 -0600 Subject: dm: core: Rename and fix uclass_get_by_name_len() It seems that namelen is more common in U-Boot. Rename this function to fit in better. Also fix a bug where it breaks the operation of uclass_get_by_name() and add a test. Signed-off-by: Simon Glass Reported-by: Patrick Delaunay Reported-by: Tim Harvey --- drivers/core/uclass.c | 7 ++++--- include/dm/uclass.h | 6 +++--- test/dm/core.c | 2 ++ 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'test') diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 2578803b7a..4b9b54f0f1 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -180,14 +180,15 @@ void uclass_set_priv(struct uclass *uc, void *priv) uc->priv_ = priv; } -enum uclass_id uclass_get_by_name_len(const char *name, int len) +enum uclass_id uclass_get_by_namelen(const char *name, int len) { int i; for (i = 0; i < UCLASS_COUNT; i++) { struct uclass_driver *uc_drv = lists_uclass_lookup(i); - if (uc_drv && !strncmp(uc_drv->name, name, len)) + if (uc_drv && !strncmp(uc_drv->name, name, len) && + strlen(uc_drv->name) == len) return i; } @@ -196,7 +197,7 @@ enum uclass_id uclass_get_by_name_len(const char *name, int len) enum uclass_id uclass_get_by_name(const char *name) { - return uclass_get_by_name_len(name, strlen(name)); + return uclass_get_by_namelen(name, strlen(name)); } int dev_get_uclass_index(struct udevice *dev, struct uclass **ucp) diff --git a/include/dm/uclass.h b/include/dm/uclass.h index aafe652288..f6c0110b06 100644 --- a/include/dm/uclass.h +++ b/include/dm/uclass.h @@ -173,13 +173,13 @@ int uclass_get(enum uclass_id key, struct uclass **ucp); const char *uclass_get_name(enum uclass_id id); /** - * uclass_get_by_name_len() - Look up a uclass by its partial driver name + * uclass_get_by_namelen() - Look up a uclass by its driver name * * @name: Name to look up - * @len: Length of the partial name + * @len: Length of @name (the uclass driver name must have the same length) * Return: the associated uclass ID, or UCLASS_INVALID if not found */ -enum uclass_id uclass_get_by_name_len(const char *name, int len); +enum uclass_id uclass_get_by_namelen(const char *name, int len); /** * uclass_get_by_name() - Look up a uclass by its driver name diff --git a/test/dm/core.c b/test/dm/core.c index 0ce0b3c4a2..2c73ecf54a 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -1161,6 +1161,8 @@ static int dm_test_uclass_names(struct unit_test_state *uts) ut_asserteq_str("test", uclass_get_name(UCLASS_TEST)); ut_asserteq(UCLASS_TEST, uclass_get_by_name("test")); + ut_asserteq(UCLASS_SPI, uclass_get_by_name("spi")); + return 0; } DM_TEST(dm_test_uclass_names, UT_TESTF_SCAN_PDATA); -- cgit v1.2.3 From 4e0710a2d007032c8a82ef3af45a0e6e9176a2a7 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:31:00 -0600 Subject: dm: core: Allow finding a uclass device by partial name In some cases two devices are related and the only way to tell is to check that the names partially patch. Add a way to check this without needing to create a new string for the comparison. Fix the comment for device_find_child_by_namelen() while we are here. Signed-off-by: Simon Glass --- drivers/core/uclass.c | 13 ++++++++++--- include/dm/device.h | 2 +- include/dm/uclass-internal.h | 16 ++++++++++++++++ test/dm/core.c | 15 +++++++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) (limited to 'test') diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c index 4b9b54f0f1..08d9ed82de 100644 --- a/drivers/core/uclass.c +++ b/drivers/core/uclass.c @@ -274,8 +274,8 @@ int uclass_find_next_device(struct udevice **devp) return 0; } -int uclass_find_device_by_name(enum uclass_id id, const char *name, - struct udevice **devp) +int uclass_find_device_by_namelen(enum uclass_id id, const char *name, int len, + struct udevice **devp) { struct uclass *uc; struct udevice *dev; @@ -289,7 +289,8 @@ int uclass_find_device_by_name(enum uclass_id id, const char *name, return ret; uclass_foreach_dev(dev, uc) { - if (!strcmp(dev->name, name)) { + if (!strncmp(dev->name, name, len) && + strlen(dev->name) == len) { *devp = dev; return 0; } @@ -298,6 +299,12 @@ int uclass_find_device_by_name(enum uclass_id id, const char *name, return -ENODEV; } +int uclass_find_device_by_name(enum uclass_id id, const char *name, + struct udevice **devp) +{ + return uclass_find_device_by_namelen(id, name, strlen(name), devp); +} + int uclass_find_next_free_seq(struct uclass *uc) { struct udevice *dev; diff --git a/include/dm/device.h b/include/dm/device.h index e0f86f5df9..b474888d02 100644 --- a/include/dm/device.h +++ b/include/dm/device.h @@ -799,7 +799,7 @@ int device_find_first_child_by_uclass(const struct udevice *parent, struct udevice **devp); /** - * device_find_child_by_name() - Find a child by device name + * device_find_child_by_namelen() - Find a child by device name * * @parent: Parent device to search * @name: Name to look for diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h index daf856c03c..3ddcdd2143 100644 --- a/include/dm/uclass-internal.h +++ b/include/dm/uclass-internal.h @@ -154,6 +154,22 @@ int uclass_find_first_device(enum uclass_id id, struct udevice **devp); */ int uclass_find_next_device(struct udevice **devp); +/** + * uclass_find_device_by_namelen() - Find uclass device based on ID and name + * + * This searches for a device with the exactly given name. + * + * The device is NOT probed, it is merely returned. + * + * @id: ID to look up + * @name: name of a device to find + * @len: Length of @name (the uclass driver name must have the same length) + * @devp: Returns pointer to device (the first one with the name) + * Return: 0 if OK, -ve on error + */ +int uclass_find_device_by_namelen(enum uclass_id id, const char *name, int len, + struct udevice **devp); + /** * uclass_find_device_by_name() - Find uclass device based on ID and name * diff --git a/test/dm/core.c b/test/dm/core.c index 2c73ecf54a..ebd504427d 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -1260,3 +1260,18 @@ static int dm_test_get_stats(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_get_stats, UT_TESTF_SCAN_FDT); + +/* Test uclass_find_device_by_name() */ +static int dm_test_uclass_find_device(struct unit_test_state *uts) +{ + struct udevice *dev; + + ut_assertok(uclass_find_device_by_name(UCLASS_I2C, "i2c@0", &dev)); + ut_asserteq(-ENODEV, + uclass_find_device_by_name(UCLASS_I2C, "i2c@0x", &dev)); + ut_assertok(uclass_find_device_by_namelen(UCLASS_I2C, "i2c@0x", 5, + &dev)); + + return 0; +} +DM_TEST(dm_test_uclass_find_device, UT_TESTF_SCAN_FDT); -- cgit v1.2.3 From 9bd2f62d12a53370822f0514ccc32e45209abc50 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:31:01 -0600 Subject: test: fastboot: Avoid using mmc1 The bootflow tests need to use an MMC with an associated backing file containing a filesystem. Update the fastboot tests to cope with this. Signed-off-by: Simon Glass --- test/dm/fastboot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test') diff --git a/test/dm/fastboot.c b/test/dm/fastboot.c index e7f8c362b8..758538d0e8 100644 --- a/test/dm/fastboot.c +++ b/test/dm/fastboot.c @@ -81,9 +81,9 @@ static int dm_test_fastboot_mmc_part(struct unit_test_state *uts) &part_info, response)); ut_asserteq(0, fastboot_mmc_get_part_info("0.0:0", &fb_dev_desc, &part_info, response)); - ut_asserteq(0, fastboot_mmc_get_part_info("1", &fb_dev_desc, + ut_asserteq(0, fastboot_mmc_get_part_info("2", &fb_dev_desc, &part_info, response)); - ut_asserteq(0, fastboot_mmc_get_part_info("1.0", &fb_dev_desc, + ut_asserteq(0, fastboot_mmc_get_part_info("2.0", &fb_dev_desc, &part_info, response)); ut_asserteq(1, fastboot_mmc_get_part_info(":1", &fb_dev_desc, &part_info, response)); -- cgit v1.2.3 From 026e2136f834feb19acc95efd61e6613f37234de Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:31:02 -0600 Subject: test: dm: Restart USB before assuming it is stopped Update the blk test to stop USB first, in case another test has started it. Signed-off-by: Simon Glass --- test/dm/blk.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'test') diff --git a/test/dm/blk.c b/test/dm/blk.c index 8556cc7159..85c3a3bd45 100644 --- a/test/dm/blk.c +++ b/test/dm/blk.c @@ -15,6 +15,9 @@ DECLARE_GLOBAL_DATA_PTR; +/* Allow resetting the USB-started flag */ +extern char usb_started; + /* Test that block devices can be created */ static int dm_test_blk_base(struct unit_test_state *uts) { @@ -66,8 +69,11 @@ static int dm_test_blk_usb(struct unit_test_state *uts) struct udevice *usb_dev, *dev; struct blk_desc *dev_desc; + usb_started = false; + /* Get a flash device */ state_set_skip_delays(true); + ut_assertok(usb_stop()); ut_assertok(usb_init()); ut_assertok(uclass_get_device(UCLASS_MASS_STORAGE, 0, &usb_dev)); ut_assertok(blk_get_device_by_str("usb", "0", &dev_desc)); -- cgit v1.2.3 From fb1451bec2a54046eeb541d77ba0e5eb55302d46 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:31:24 -0600 Subject: bootstd: Add tests for bootstd including all uclasses Add a set of combined tests for the bootdev, bootflow and bootmeth commands, along with associated functionality. Expand the sandbox console-recording limit so that these can work. These tests rely on a filesystem script which is not yet added to the Python tests. It is included here as a shell script. Signed-off-by: Simon Glass --- MAINTAINERS | 1 + arch/sandbox/dts/test.dts | 18 ++ configs/sandbox_defconfig | 3 +- configs/sandbox_flattree_defconfig | 3 +- include/test/suites.h | 2 + test/Makefile | 1 + test/boot/Makefile | 5 + test/boot/bootdev.c | 223 +++++++++++++++++++++ test/boot/bootflow.c | 400 +++++++++++++++++++++++++++++++++++++ test/boot/bootmeth.c | 122 +++++++++++ test/boot/bootstd_common.c | 35 ++++ test/boot/bootstd_common.h | 27 +++ test/cmd_ut.c | 7 + 13 files changed, 845 insertions(+), 2 deletions(-) create mode 100644 test/boot/Makefile create mode 100644 test/boot/bootdev.c create mode 100644 test/boot/bootflow.c create mode 100644 test/boot/bootmeth.c create mode 100644 test/boot/bootstd_common.c create mode 100644 test/boot/bootstd_common.h (limited to 'test') diff --git a/MAINTAINERS b/MAINTAINERS index 77a3408224..963ec91c89 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -708,6 +708,7 @@ F: include/bootflow.h F: include/bootmeth.h F: include/bootstd.h F: net/eth_bootdevice.c +F: test/boot/ BTRFS M: Marek Behun diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 5b38ee4a5f..a8a86bc715 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -74,6 +74,21 @@ }; }; + bootstd { + compatible = "u-boot,boot-std"; + + filename-prefixes = "/", "/boot/"; + bootdev-order = "mmc2", "mmc1"; + + syslinux { + compatible = "u-boot,distro-syslinux"; + }; + + efi { + compatible = "u-boot,distro-efi"; + }; + }; + reboot-mode0 { compatible = "reboot-mode-gpio"; gpios = <&gpio_c 0 GPIO_ACTIVE_HIGH>, <&gpio_c 1 GPIO_ACTIVE_HIGH>; @@ -891,10 +906,13 @@ non-removable; }; + /* This is used for the bootdev tests */ mmc1 { compatible = "sandbox,mmc"; + filename = "mmc1.img"; }; + /* This is used for the fastboot tests */ mmc0 { compatible = "sandbox,mmc"; }; diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 14d7af4db2..fe8ea4626d 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -28,7 +28,7 @@ CONFIG_AUTOBOOT_STOP_STR_CRYPT="$5$rounds=640000$HrpE65IkB8CM5nCL$BKT3QdF98Bo8fJ CONFIG_IMAGE_PRE_LOAD=y CONFIG_IMAGE_PRE_LOAD_SIG=y CONFIG_CONSOLE_RECORD=y -CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000 +CONFIG_CONSOLE_RECORD_OUT_SIZE=0x6000 CONFIG_PRE_CONSOLE_BUFFER=y CONFIG_LOG=y CONFIG_DISPLAY_BOARDINFO_LATE=y @@ -120,6 +120,7 @@ CONFIG_ENV_IS_IN_EXT4=y CONFIG_ENV_EXT4_INTERFACE="host" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0" CONFIG_ENV_IMPORT_FDT=y +# CONFIG_BOOTDEV_ETH is not set CONFIG_BOOTP_SEND_HOSTNAME=y CONFIG_NETCONSOLE=y CONFIG_IP_DEFRAG=y diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig index ded16af9f5..80a4be47eb 100644 --- a/configs/sandbox_flattree_defconfig +++ b/configs/sandbox_flattree_defconfig @@ -17,7 +17,7 @@ CONFIG_BOOTSTAGE_FDT=y CONFIG_BOOTSTAGE_STASH=y CONFIG_BOOTSTAGE_STASH_SIZE=0x4096 CONFIG_CONSOLE_RECORD=y -CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000 +CONFIG_CONSOLE_RECORD_OUT_SIZE=0x6000 CONFIG_DISPLAY_BOARDINFO_LATE=y CONFIG_CMD_CPU=y CONFIG_CMD_LICENSE=y @@ -72,6 +72,7 @@ CONFIG_ENV_IS_NOWHERE=y CONFIG_ENV_IS_IN_EXT4=y CONFIG_ENV_EXT4_INTERFACE="host" CONFIG_ENV_EXT4_DEVICE_AND_PART="0:0" +# CONFIG_BOOTDEV_ETH is not set CONFIG_BOOTP_SEND_HOSTNAME=y CONFIG_NETCONSOLE=y CONFIG_IP_DEFRAG=y diff --git a/include/test/suites.h b/include/test/suites.h index 6553a765c6..ee6858a802 100644 --- a/include/test/suites.h +++ b/include/test/suites.h @@ -29,6 +29,8 @@ int cmd_ut_category(const char *name, const char *prefix, int do_ut_addrmap(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); +int do_ut_bootstd(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]); int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); int do_ut_common(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); diff --git a/test/Makefile b/test/Makefile index b3b2902e2e..abd605a435 100644 --- a/test/Makefile +++ b/test/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_UT_TIME) += time_ut.o obj-y += ut.o ifeq ($(CONFIG_SPL_BUILD),) +obj-$(CONFIG_UNIT_TEST) += boot/ obj-$(CONFIG_UNIT_TEST) += common/ obj-$(CONFIG_UNIT_TEST) += lib/ obj-y += log/ diff --git a/test/boot/Makefile b/test/boot/Makefile new file mode 100644 index 0000000000..1730792b5f --- /dev/null +++ b/test/boot/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2021 Google LLC + +obj-$(CONFIG_BOOTSTD) += bootdev.o bootstd_common.o bootflow.o bootmeth.o diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c new file mode 100644 index 0000000000..1c2a79fb10 --- /dev/null +++ b/test/boot/bootdev.c @@ -0,0 +1,223 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for bootdev functions. All start with 'bootdev' + * + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bootstd_common.h" + +/* Allow reseting the USB-started flag */ +extern char usb_started; + +/* Check 'bootdev list' command */ +static int bootdev_test_cmd_list(struct unit_test_state *uts) +{ + int probed; + + console_record_reset_enable(); + for (probed = 0; probed < 2; probed++) { + int probe_ch = probed ? '+' : ' '; + + ut_assertok(run_command(probed ? "bootdev list -p" : + "bootdev list", 0)); + ut_assert_nextline("Seq Probed Status Uclass Name"); + ut_assert_nextlinen("---"); + ut_assert_nextline("%3x [ %c ] %6s %-8s %s", 0, probe_ch, "OK", + "mmc", "mmc2.bootdev"); + ut_assert_nextline("%3x [ %c ] %6s %-8s %s", 1, probe_ch, "OK", + "mmc", "mmc1.bootdev"); + ut_assert_nextline("%3x [ %c ] %6s %-8s %s", 2, probe_ch, "OK", + "mmc", "mmc0.bootdev"); + ut_assert_nextlinen("---"); + ut_assert_nextline("(3 bootdevs)"); + ut_assert_console_end(); + } + + return 0; +} +BOOTSTD_TEST(bootdev_test_cmd_list, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check 'bootdev select' and 'info' commands */ +static int bootdev_test_cmd_select(struct unit_test_state *uts) +{ + struct bootstd_priv *std; + + /* get access to the CLI's cur_bootdev */ + ut_assertok(bootstd_get_priv(&std)); + + console_record_reset_enable(); + ut_asserteq(1, run_command("bootdev info", 0)); + ut_assert_nextlinen("Please use"); + ut_assert_console_end(); + + /* select by sequence */ + ut_assertok(run_command("bootdev select 0", 0)); + ut_assert_console_end(); + + ut_assertok(run_command("bootdev info", 0)); + ut_assert_nextline("Name: mmc2.bootdev"); + ut_assert_nextline("Sequence: 0"); + ut_assert_nextline("Status: Probed"); + ut_assert_nextline("Uclass: mmc"); + ut_assert_nextline("Bootflows: 0 (0 valid)"); + ut_assert_console_end(); + + /* select by bootdev name */ + ut_assertok(run_command("bootdev select mmc1.bootdev", 0)); + ut_assert_console_end(); + ut_assertnonnull(std->cur_bootdev); + ut_asserteq_str("mmc1.bootdev", std->cur_bootdev->name); + + /* select by bootdev label*/ + ut_assertok(run_command("bootdev select mmc1", 0)); + ut_assert_console_end(); + ut_assertnonnull(std->cur_bootdev); + ut_asserteq_str("mmc1.bootdev", std->cur_bootdev->name); + + /* deselect */ + ut_assertok(run_command("bootdev select", 0)); + ut_assert_console_end(); + ut_assertnull(std->cur_bootdev); + + ut_asserteq(1, run_command("bootdev info", 0)); + ut_assert_nextlinen("Please use"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootdev_test_cmd_select, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check bootdev labels */ +static int bootdev_test_labels(struct unit_test_state *uts) +{ + struct udevice *dev, *media; + + ut_assertok(bootdev_find_by_label("mmc2", &dev)); + ut_asserteq(UCLASS_BOOTDEV, device_get_uclass_id(dev)); + media = dev_get_parent(dev); + ut_asserteq(UCLASS_MMC, device_get_uclass_id(media)); + ut_asserteq_str("mmc2", media->name); + + /* Check invalid uclass */ + ut_asserteq(-EINVAL, bootdev_find_by_label("fred0", &dev)); + + /* Check unknown sequence number */ + ut_asserteq(-ENOENT, bootdev_find_by_label("mmc6", &dev)); + + return 0; +} +BOOTSTD_TEST(bootdev_test_labels, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check bootdev ordering with the bootdev-order property */ +static int bootdev_test_order(struct unit_test_state *uts) +{ + struct bootflow_iter iter; + struct bootflow bflow; + + /* + * First try the order set by the bootdev-order property + * Like all sandbox unit tests this relies on the devicetree setting up + * the required devices: + * + * mmc0 - nothing connected + * mmc1 - connected to mmc1.img file + * mmc2 - nothing connected + */ + ut_assertok(env_set("boot_targets", NULL)); + ut_assertok(bootflow_scan_first(&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); + 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_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); + bootflow_iter_uninit(&iter); + + /* + * Now drop both orderings, to check the default (prioriy/sequence) + * ordering + */ + 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(&iter, 0, &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); + bootflow_iter_uninit(&iter); + + return 0; +} +BOOTSTD_TEST(bootdev_test_order, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check bootdev ordering with the uclass priority */ +static int bootdev_test_prio(struct unit_test_state *uts) +{ + struct bootdev_uc_plat *ucp; + struct bootflow_iter iter; + struct bootflow bflow; + struct udevice *blk; + + /* Start up USB which gives us three additional bootdevs */ + usb_started = false; + ut_assertok(run_command("usb start", 0)); + + ut_assertok(bootstd_test_drop_bootdev_order(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_asserteq(6, iter.num_devs); + ut_asserteq_str("mmc2.bootdev", iter.dev_order[0]->name); + ut_asserteq_str("usb_mass_storage.lun0.bootdev", + iter.dev_order[3]->name); + + ut_assertok(bootdev_get_sibling_blk(iter.dev_order[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; + + bootflow_iter_uninit(&iter); + ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_asserteq(6, 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); + + return 0; +} +BOOTSTD_TEST(bootdev_test_prio, UT_TESTF_DM | UT_TESTF_SCAN_FDT); diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c new file mode 100644 index 0000000000..1ebb789e97 --- /dev/null +++ b/test/boot/bootflow.c @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for bootdev functions. All start with 'bootdev' + * + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "bootstd_common.h" + +/* Check 'bootflow scan/list' commands */ +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_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(" 0 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf"); + ut_assert_nextlinen("---"); + ut_assert_nextline("(1 bootflow, 1 valid)"); + ut_assert_console_end(); + + ut_assertok(run_command("bootflow list", 0)); + ut_assert_nextline("Showing bootflows for bootdev 'mmc1.bootdev'"); + ut_assert_nextline("Seq Method State Uclass Part Name Filename"); + ut_assert_nextlinen("---"); + ut_assert_nextline(" 0 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf"); + ut_assert_nextlinen("---"); + ut_assert_nextline("(1 bootflow, 1 valid)"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootflow_cmd, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check 'bootflow scan' with a name / label / seq */ +static int bootflow_cmd_label(struct unit_test_state *uts) +{ + console_record_reset_enable(); + ut_assertok(run_command("bootflow scan -l mmc1", 0)); + ut_assert_nextline("Scanning for bootflows in bootdev 'mmc1.bootdev'"); + 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_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'"); + 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); + +/* Check 'bootflow scan/list' commands using all bootdevs */ +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 -l", 0)); + ut_assert_nextline("Scanning for bootflows in all bootdevs"); + 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("Scanning bootdev 'mmc0.bootdev':"); + ut_assert_nextline("No more bootdevs"); + ut_assert_nextlinen("---"); + ut_assert_nextline("(1 bootflow, 1 valid)"); + ut_assert_console_end(); + + ut_assertok(run_command("bootflow list", 0)); + ut_assert_nextline("Showing all bootflows"); + ut_assert_nextline("Seq Method State Uclass Part Name Filename"); + ut_assert_nextlinen("---"); + ut_assert_nextline(" 0 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf"); + ut_assert_nextlinen("---"); + ut_assert_nextline("(1 bootflow, 1 valid)"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootflow_cmd_glob, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check 'bootflow scan -e' */ +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 -ale", 0)); + ut_assert_nextline("Scanning for bootflows in all bootdevs"); + ut_assert_nextline("Seq Method State Uclass Part Name Filename"); + ut_assert_nextlinen("---"); + ut_assert_nextline("Scanning bootdev 'mmc2.bootdev':"); + ut_assert_nextline(" 0 syslinux media mmc 0 mmc2.bootdev.whole "); + ut_assert_nextline(" ** No partition found, err=-93"); + ut_assert_nextline(" 1 efi media mmc 0 mmc2.bootdev.whole "); + ut_assert_nextline(" ** No partition found, err=-93"); + + ut_assert_nextline("Scanning bootdev 'mmc1.bootdev':"); + ut_assert_nextline(" 2 syslinux media mmc 0 mmc1.bootdev.whole "); + ut_assert_nextline(" ** No partition found, err=-2"); + ut_assert_nextline(" 3 efi media mmc 0 mmc1.bootdev.whole "); + ut_assert_nextline(" ** No partition found, err=-2"); + ut_assert_nextline(" 4 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf"); + ut_assert_nextline(" 5 efi fs mmc 1 mmc1.bootdev.part_1 efi/boot/bootsbox.efi"); + + ut_assert_skip_to_line("Scanning bootdev 'mmc0.bootdev':"); + ut_assert_skip_to_line(" 3f efi media mmc 0 mmc0.bootdev.whole "); + ut_assert_nextline(" ** No partition found, err=-93"); + ut_assert_nextline("No more bootdevs"); + ut_assert_nextlinen("---"); + ut_assert_nextline("(64 bootflows, 1 valid)"); + ut_assert_console_end(); + + ut_assertok(run_command("bootflow list", 0)); + ut_assert_nextline("Showing all bootflows"); + ut_assert_nextline("Seq Method State Uclass Part Name Filename"); + ut_assert_nextlinen("---"); + ut_assert_nextline(" 0 syslinux media mmc 0 mmc2.bootdev.whole "); + ut_assert_nextline(" 1 efi media mmc 0 mmc2.bootdev.whole "); + ut_assert_skip_to_line(" 4 syslinux ready mmc 1 mmc1.bootdev.part_1 /extlinux/extlinux.conf"); + ut_assert_skip_to_line(" 3f efi media mmc 0 mmc0.bootdev.whole "); + ut_assert_nextlinen("---"); + ut_assert_nextline("(64 bootflows, 1 valid)"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootflow_cmd_scan_e, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check 'bootflow info' */ +static int bootflow_cmd_info(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", 0)); + ut_assert_console_end(); + ut_assertok(run_command("bootflow select 0", 0)); + ut_assert_console_end(); + ut_assertok(run_command("bootflow info", 0)); + ut_assert_nextline("Name: mmc1.bootdev.part_1"); + ut_assert_nextline("Device: mmc1.bootdev"); + ut_assert_nextline("Block dev: mmc1.blk"); + ut_assert_nextline("Method: syslinux"); + ut_assert_nextline("State: ready"); + ut_assert_nextline("Partition: 1"); + ut_assert_nextline("Subdir: (none)"); + ut_assert_nextline("Filename: /extlinux/extlinux.conf"); + ut_assert_nextlinen("Buffer: "); + ut_assert_nextline("Size: 253 (595 bytes)"); + ut_assert_nextline("Error: 0"); + ut_assert_console_end(); + + ut_assertok(run_command("bootflow info -d", 0)); + ut_assert_nextline("Name: mmc1.bootdev.part_1"); + ut_assert_skip_to_line("Error: 0"); + ut_assert_nextline("Contents:"); + ut_assert_nextline("%s", ""); + ut_assert_nextline("# extlinux.conf generated by appliance-creator"); + ut_assert_skip_to_line(" initrd /initramfs-5.3.7-301.fc31.armv7hl.img"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootflow_cmd_info, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check 'bootflow scan -b' to boot the first available bootdev */ +static int bootflow_scan_boot(struct unit_test_state *uts) +{ + console_record_reset_enable(); + ut_assertok(run_command("bootflow scan -b", 0)); + ut_assert_nextline( + "** Booting bootflow 'mmc1.bootdev.part_1' with syslinux"); + ut_assert_nextline("Ignoring unknown command: ui"); + + /* + * We expect it to get through to boot although sandbox always returns + * -EFAULT as it cannot actually boot the kernel + */ + ut_assert_skip_to_line("sandbox: continuing, as we cannot run Linux"); + ut_assert_nextline("Boot failed (err=-14)"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootflow_scan_boot, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check iterating through available bootflows */ +static int bootflow_iter(struct unit_test_state *uts) +{ + struct bootflow_iter iter; + struct bootflow bflow; + + bootstd_clear_glob(); + + /* The first device is mmc2.bootdev which has no media */ + ut_asserteq(-EPROTONOSUPPORT, + bootflow_scan_first(&iter, BOOTFLOWF_ALL, &bflow)); + ut_asserteq(2, iter.num_methods); + ut_asserteq(0, iter.cur_method); + ut_asserteq(0, iter.part); + ut_asserteq(0, iter.max_part); + ut_asserteq_str("syslinux", iter.method->name); + ut_asserteq(0, bflow.err); + + /* + * This shows MEDIA even though there is none, since int + * bootdev_find_in_blk() we call part_get_info() which returns + * -EPROTONOSUPPORT. Ideally it would return -EEOPNOTSUPP and we would + * know. + */ + ut_asserteq(BOOTFLOWST_MEDIA, bflow.state); + + ut_asserteq(-EPROTONOSUPPORT, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(2, iter.num_methods); + ut_asserteq(1, iter.cur_method); + ut_asserteq(0, iter.part); + ut_asserteq(0, iter.max_part); + ut_asserteq_str("efi", iter.method->name); + ut_asserteq(0, bflow.err); + ut_asserteq(BOOTFLOWST_MEDIA, bflow.state); + bootflow_free(&bflow); + + /* The next device is mmc1.bootdev - at first we use the whole device */ + ut_asserteq(-ENOENT, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(2, iter.num_methods); + ut_asserteq(0, iter.cur_method); + ut_asserteq(0, 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); + bootflow_free(&bflow); + + ut_asserteq(-ENOENT, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(2, iter.num_methods); + ut_asserteq(1, iter.cur_method); + ut_asserteq(0, iter.part); + ut_asserteq(0x1e, iter.max_part); + ut_asserteq_str("efi", iter.method->name); + ut_asserteq(0, bflow.err); + ut_asserteq(BOOTFLOWST_MEDIA, bflow.state); + bootflow_free(&bflow); + + /* Then more to partition 1 where we find something */ + ut_assertok(bootflow_scan_next(&iter, &bflow)); + ut_asserteq(2, iter.num_methods); + ut_asserteq(0, iter.cur_method); + ut_asserteq(1, iter.part); + ut_asserteq(0x1e, iter.max_part); + ut_asserteq_str("syslinux", iter.method->name); + ut_asserteq(0, bflow.err); + ut_asserteq(BOOTFLOWST_READY, bflow.state); + bootflow_free(&bflow); + + ut_asserteq(-ENOENT, bootflow_scan_next(&iter, &bflow)); + ut_asserteq(2, iter.num_methods); + ut_asserteq(1, iter.cur_method); + ut_asserteq(1, iter.part); + ut_asserteq(0x1e, iter.max_part); + ut_asserteq_str("efi", iter.method->name); + ut_asserteq(0, bflow.err); + 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)); + 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); + bootflow_free(&bflow); + + bootflow_iter_uninit(&iter); + + ut_assert_console_end(); + + return 0; +} +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 *bootstd, *dev; + + /* Add the EFI bootmgr driver */ + ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd)); + ut_assertok(device_bind_driver(bootstd, "bootmeth_efi_mgr", "bootmgr", + &dev)); + + /* Add the system bootdev that it uses */ + ut_assertok(device_bind_driver(bootstd, "system_bootdev", + "system-bootdev", &dev)); + + ut_assertok(bootstd_test_drop_bootdev_order(uts)); + + /* 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_assert_skip_to_line(" 1 bootmgr ready bootstd 0 "); + ut_assert_nextline("No more bootdevs"); + ut_assert_skip_to_line("(2 bootflows, 2 valid)"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootflow_system, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check disabling a bootmethod if it requests it */ +static int bootflow_iter_disable(struct unit_test_state *uts) +{ + struct udevice *bootstd, *dev; + struct bootflow_iter iter; + struct bootflow bflow; + int i; + + /* Add the EFI bootmgr driver */ + ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd)); + ut_assertok(device_bind_driver(bootstd, "bootmeth_sandbox", "sandbox", + &dev)); + + /* Add the system bootdev that it uses */ + ut_assertok(device_bind_driver(bootstd, "system_bootdev", + "system-bootdev", &dev)); + + ut_assertok(bootstd_test_drop_bootdev_order(uts)); + + bootstd_clear_glob(); + ut_assertok(run_command("bootflow scan -lb", 0)); + + /* Try to boot the bootmgr flow, which will fail */ + console_record_reset_enable(); + ut_assertok(bootflow_scan_first(&iter, 0, &bflow)); + ut_asserteq(3, iter.num_methods); + ut_asserteq_str("sandbox", iter.method->name); + ut_asserteq(-ENOTSUPP, bootflow_run_boot(&iter, &bflow)); + + ut_assert_skip_to_line("Boot method 'sandbox' failed and will not be retried"); + ut_assert_console_end(); + + /* Check that the sandbox bootmeth has been removed */ + ut_asserteq(2, iter.num_methods); + for (i = 0; i < iter.num_methods; i++) + ut_assert(strcmp("sandbox", iter.method_order[i]->name)); + + return 0; +} +BOOTSTD_TEST(bootflow_iter_disable, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check 'bootflow boot' to boot a selected bootflow */ +static int bootflow_cmd_boot(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", 0)); + ut_assert_console_end(); + ut_assertok(run_command("bootflow select 0", 0)); + ut_assert_console_end(); + ut_asserteq(1, run_command("bootflow boot", 0)); + ut_assert_nextline( + "** Booting bootflow 'mmc1.bootdev.part_1' with syslinux"); + ut_assert_nextline("Ignoring unknown command: ui"); + + /* + * We expect it to get through to boot although sandbox always returns + * -EFAULT as it cannot actually boot the kernel + */ + ut_assert_skip_to_line("sandbox: continuing, as we cannot run Linux"); + ut_assert_nextline("Boot failed (err=-14)"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootflow_cmd_boot, UT_TESTF_DM | UT_TESTF_SCAN_FDT); diff --git a/test/boot/bootmeth.c b/test/boot/bootmeth.c new file mode 100644 index 0000000000..07776c5368 --- /dev/null +++ b/test/boot/bootmeth.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for bootdev functions. All start with 'bootdev' + * + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include "bootstd_common.h" + +/* Check 'bootmeth list' command */ +static int bootmeth_cmd_list(struct unit_test_state *uts) +{ + console_record_reset_enable(); + ut_assertok(run_command("bootmeth list", 0)); + ut_assert_nextline("Order Seq Name Description"); + ut_assert_nextlinen("---"); + ut_assert_nextline(" 0 0 syslinux Syslinux boot from a block device"); + ut_assert_nextline(" 1 1 efi EFI boot from an .efi file"); + ut_assert_nextlinen("---"); + ut_assert_nextline("(2 bootmeths)"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootmeth_cmd_list, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check 'bootmeth order' command */ +static int bootmeth_cmd_order(struct unit_test_state *uts) +{ + /* Select just one bootmethod */ + console_record_reset_enable(); + ut_assertok(run_command("bootmeth order syslinux", 0)); + ut_assert_console_end(); + ut_assertnonnull(env_get("bootmeths")); + ut_asserteq_str("syslinux", env_get("bootmeths")); + + /* Only that one should be listed */ + ut_assertok(run_command("bootmeth list", 0)); + ut_assert_nextline("Order Seq Name Description"); + ut_assert_nextlinen("---"); + ut_assert_nextline(" 0 0 syslinux Syslinux boot from a block device"); + ut_assert_nextlinen("---"); + ut_assert_nextline("(1 bootmeth)"); + ut_assert_console_end(); + + /* Check the -a flag, efi should show as not in the order ("-") */ + ut_assertok(run_command("bootmeth list -a", 0)); + ut_assert_nextline("Order Seq Name Description"); + ut_assert_nextlinen("---"); + ut_assert_nextline(" 0 0 syslinux Syslinux boot from a block device"); + ut_assert_nextline(" - 1 efi EFI boot from an .efi file"); + ut_assert_nextlinen("---"); + ut_assert_nextline("(2 bootmeths)"); + ut_assert_console_end(); + + /* Check the -a flag with the reverse order */ + ut_assertok(run_command("bootmeth order \"efi syslinux\"", 0)); + ut_assert_console_end(); + ut_assertok(run_command("bootmeth list -a", 0)); + ut_assert_nextline("Order Seq Name Description"); + ut_assert_nextlinen("---"); + ut_assert_nextline(" 1 0 syslinux Syslinux boot from a block device"); + ut_assert_nextline(" 0 1 efi EFI boot from an .efi file"); + ut_assert_nextlinen("---"); + ut_assert_nextline("(2 bootmeths)"); + ut_assert_console_end(); + + /* Now reset the order to empty, which should show all of them again */ + ut_assertok(run_command("bootmeth order", 0)); + ut_assert_console_end(); + ut_assertnull(env_get("bootmeths")); + ut_assertok(run_command("bootmeth list", 0)); + ut_assert_skip_to_line("(2 bootmeths)"); + + /* Try reverse order */ + ut_assertok(run_command("bootmeth order \"efi syslinux\"", 0)); + ut_assert_console_end(); + ut_assertok(run_command("bootmeth list", 0)); + ut_assert_nextline("Order Seq Name Description"); + ut_assert_nextlinen("---"); + ut_assert_nextline(" 0 1 efi EFI boot from an .efi file"); + ut_assert_nextline(" 1 0 syslinux Syslinux boot from a block device"); + ut_assert_nextlinen("---"); + ut_assert_nextline("(2 bootmeths)"); + ut_assertnonnull(env_get("bootmeths")); + ut_asserteq_str("efi syslinux", env_get("bootmeths")); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootmeth_cmd_order, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check 'bootmeths' env var */ +static int bootmeth_env(struct unit_test_state *uts) +{ + struct bootstd_priv *std; + + ut_assertok(bootstd_get_priv(&std)); + + /* Select just one bootmethod */ + console_record_reset_enable(); + ut_assertok(env_set("bootmeths", "syslinux")); + ut_asserteq(1, std->bootmeth_count); + + /* Select an invalid bootmethod */ + ut_asserteq(1, run_command("setenv bootmeths fred", 0)); + ut_assert_nextline("Unknown bootmeth 'fred'"); + ut_assert_nextlinen("## Error inserting"); + ut_assert_console_end(); + + ut_assertok(env_set("bootmeths", "efi syslinux")); + ut_asserteq(2, std->bootmeth_count); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootmeth_env, UT_TESTF_DM | UT_TESTF_SCAN_FDT); diff --git a/test/boot/bootstd_common.c b/test/boot/bootstd_common.c new file mode 100644 index 0000000000..05347d8710 --- /dev/null +++ b/test/boot/bootstd_common.c @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test for bootdev functions. All start with 'bootdev' + * + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include "bootstd_common.h" + +int bootstd_test_drop_bootdev_order(struct unit_test_state *uts) +{ + struct bootstd_priv *priv; + struct udevice *bootstd; + + ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd)); + priv = dev_get_priv(bootstd); + priv->bootdev_order = NULL; + + 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); + const int n_ents = UNIT_TEST_SUITE_COUNT(bootstd_test); + + return cmd_ut_category("bootstd", "bootstd_test_", + tests, n_ents, argc, argv); +} diff --git a/test/boot/bootstd_common.h b/test/boot/bootstd_common.h new file mode 100644 index 0000000000..676ef0a57f --- /dev/null +++ b/test/boot/bootstd_common.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Common header file for bootdev, bootflow, bootmeth tests + * + * Copyright 2021 Google LLC + * Written by Simon Glass + */ + +#ifndef __bootstd_common_h +#define __bootstd_common_h + +/* Declare a new bootdev test */ +#define BOOTSTD_TEST(_name, _flags) \ + UNIT_TEST(_name, _flags, bootstd_test) + +struct unit_test_state; + +/** + * bootstd_test_drop_bootdev_order() - Remove the existing boot order + * + * Drop the boot order so that all bootdevs are used in their alias order + * + * @uts: Unit test state to use for ut_assert...() functions + */ +int bootstd_test_drop_bootdev_order(struct unit_test_state *uts); + +#endif diff --git a/test/cmd_ut.c b/test/cmd_ut.c index 90b260f72d..67a13ee32b 100644 --- a/test/cmd_ut.c +++ b/test/cmd_ut.c @@ -28,6 +28,10 @@ int cmd_ut_category(const char *name, const char *prefix, static struct cmd_tbl cmd_ut_sub[] = { U_BOOT_CMD_MKENT(all, CONFIG_SYS_MAXARGS, 1, do_ut_all, "", ""), +#ifdef CONFIG_BOOTSTD + U_BOOT_CMD_MKENT(bootstd, CONFIG_SYS_MAXARGS, 1, do_ut_bootstd, + "", ""), +#endif U_BOOT_CMD_MKENT(common, CONFIG_SYS_MAXARGS, 1, do_ut_common, "", ""), #if defined(CONFIG_UT_DM) U_BOOT_CMD_MKENT(dm, CONFIG_SYS_MAXARGS, 1, do_ut_dm, "", ""), @@ -115,6 +119,9 @@ static char ut_help_text[] = "ut bloblist - Test bloblist implementation\n" "ut compression - Test compressors and bootm decompression\n" #endif +#ifdef CONFIG_BOOTSTD + "ut bootstd - Test standard boot implementation\n" +#endif #ifdef CONFIG_UT_DM "ut dm [test-name]\n" #endif -- cgit v1.2.3 From fca20a5a6262f2a79f3dca65509510def40dc076 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sun, 24 Apr 2022 23:31:25 -0600 Subject: bootstd: Add setup for the bootflow tests We need to create a disk image with a partition table and a DOS-format filesystem containing a few files. Provide a fallback binary for CI since it does not seem able to detect the loopback partitions. Add this to a dm_init test so that it happens when needed. Signed-off-by: Simon Glass --- test/py/tests/bootstd/mmc1.img.xz | Bin 0 -> 4448 bytes test/py/tests/test_ut.py | 103 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 test/py/tests/bootstd/mmc1.img.xz (limited to 'test') diff --git a/test/py/tests/bootstd/mmc1.img.xz b/test/py/tests/bootstd/mmc1.img.xz new file mode 100644 index 0000000000..4e7f39b830 Binary files /dev/null and b/test/py/tests/bootstd/mmc1.img.xz differ diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index 01c2b3ffa1..35fb393c1f 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -1,9 +1,102 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. +import gzip +import os import os.path import pytest +import u_boot_utils + +def mkdir_cond(dirname): + """Create a directory if it doesn't already exist + + Args: + dirname: Name of directory to create + """ + if not os.path.exists(dirname): + os.mkdir(dirname) + +def setup_bootflow_image(u_boot_console): + """Create a 20MB disk image with a single FAT partition""" + cons = u_boot_console + fname = os.path.join(cons.config.source_dir, 'mmc1.img') + mnt = os.path.join(cons.config.persistent_data_dir, 'mnt') + mkdir_cond(mnt) + + 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=b'type=c') + + loop = None + mounted = False + complete = False + try: + out = u_boot_utils.run_and_log(cons, + 'sudo losetup --show -f -P %s' % fname) + loop = out.strip() + fatpart = '%sp1' % loop + u_boot_utils.run_and_log(cons, 'sudo mkfs.vfat %s' % fatpart) + u_boot_utils.run_and_log( + cons, 'sudo mount -o loop %s %s -o uid=%d,gid=%d' % + (fatpart, mnt, os.getuid(), os.getgid())) + mounted = True + + vmlinux = 'vmlinuz-5.3.7-301.fc31.armv7hl' + initrd = 'initramfs-5.3.7-301.fc31.armv7hl.img' + dtbdir = 'dtb-5.3.7-301.fc31.armv7hl' + script = '''# extlinux.conf generated by appliance-creator +ui menu.c32 +menu autoboot Welcome to Fedora-Workstation-armhfp-31-1.9. Automatic boot in # second{,s}. Press a key for options. +menu title Fedora-Workstation-armhfp-31-1.9 Boot Options. +menu hidden +timeout 20 +totaltimeout 600 + +label Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl) + kernel /%s + append ro root=UUID=9732b35b-4cd5-458b-9b91-80f7047e0b8a rhgb quiet LANG=en_US.UTF-8 cma=192MB cma=256MB + fdtdir /%s/ + initrd /%s''' % (vmlinux, dtbdir, initrd) + ext = os.path.join(mnt, 'extlinux') + mkdir_cond(ext) + + with open(os.path.join(ext, 'extlinux.conf'), 'w') as fd: + print(script, file=fd) + + inf = os.path.join(cons.config.persistent_data_dir, 'inf') + with open(inf, 'wb') as fd: + fd.write(gzip.compress(b'vmlinux')) + u_boot_utils.run_and_log(cons, 'mkimage -f auto -d %s %s' % + (inf, os.path.join(mnt, vmlinux))) + + with open(os.path.join(mnt, initrd), 'w') as fd: + print('initrd', file=fd) + + mkdir_cond(os.path.join(mnt, dtbdir)) + + dtb_file = os.path.join(mnt, '%s/sandbox.dtb' % dtbdir) + u_boot_utils.run_and_log( + cons, 'dtc -o %s' % dtb_file, stdin=b'/dts-v1/; / {};') + complete = True + except ValueError as exc: + print('Falled to create image, failing back to prepared copy: %s', + str(exc)) + finally: + if mounted: + u_boot_utils.run_and_log(cons, 'sudo umount %s' % mnt) + if loop: + u_boot_utils.run_and_log(cons, 'sudo losetup -d %s' % loop) + + if not complete: + # Use a prepared image since we cannot create one + infname = os.path.join(cons.config.source_dir, + 'test/py/tests/bootstd/mmc1.img.xz') + u_boot_utils.run_and_log( + cons, + ['sh', '-c', 'xz -dc %s >%s' % (infname, fname)]) + + @pytest.mark.buildconfigspec('ut_dm') def test_ut_dm_init(u_boot_console): """Initialize data for ut dm tests.""" @@ -21,6 +114,16 @@ def test_ut_dm_init(u_boot_console): with open(fn, 'wb') as fh: fh.write(data) +@pytest.mark.buildconfigspec('cmd_bootflow') +def test_ut_dm_init_bootstd(u_boot_console): + """Initialise data for bootflow tests""" + + setup_bootflow_image(u_boot_console) + + # Restart so that the new mmc1.img is picked up + u_boot_console.restart_uboot() + + def test_ut(u_boot_console, ut_subtest): """Execute a "ut" subtest. -- cgit v1.2.3