From f178bebf551a43445ba8f1e1a4c1638eff8eb612 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:45 -0600 Subject: sandbox: Support executables for more phases The SPL header has a function for obtaining the phase in capital letters, e.g. 'SPL'. Add one for lower-case also, as used by sandbox. Use this to generalise the sandbox logic for determining the filename of the next sandbox executable. This can provide support for VPL. Signed-off-by: Simon Glass --- include/os.h | 5 ++++- include/spl.h | 21 +++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/os.h b/include/os.h index bd1096eb8b3..7b20d606dd0 100644 --- a/include/os.h +++ b/include/os.h @@ -327,9 +327,12 @@ int os_jump_to_image(const void *dest, int size); * @fname: place to put full path to U-Boot * @maxlen: maximum size of @fname * @use_img: select the 'u-boot.img' file instead of the 'u-boot' ELF file + * @cur_prefix: prefix of current executable, e.g. "spl" or "tpl" + * @next_prefix: prefix of executable to find, e.g. "spl" or "" * Return: 0 if OK, -NOSPC if the filename is too large, -ENOENT if not found */ -int os_find_u_boot(char *fname, int maxlen, bool use_img); +int os_find_u_boot(char *fname, int maxlen, bool use_img, + const char *cur_prefix, const char *next_prefix); /** * os_spl_to_uboot() - Run U-Boot proper diff --git a/include/spl.h b/include/spl.h index c643943482d..d88fb79a676 100644 --- a/include/spl.h +++ b/include/spl.h @@ -176,6 +176,27 @@ static inline const char *spl_phase_name(enum u_boot_phase phase) } } +/** + * spl_phase_prefix() - Get the prefix of the current phase + * + * @phase: Phase to look up + * @return phase prefix ("spl", "tpl", etc.) + */ +static inline const char *spl_phase_prefix(enum u_boot_phase phase) +{ + switch (phase) { + case PHASE_TPL: + return "tpl"; + case PHASE_SPL: + return "spl"; + case PHASE_BOARD_F: + case PHASE_BOARD_R: + return ""; + default: + return "phase?"; + } +} + /* A string name for SPL or TPL */ #ifdef CONFIG_SPL_BUILD # ifdef CONFIG_TPL_BUILD -- cgit v1.3.1 From 201efb2bb0f7c4ae5f08f51b6f6b7cdfdba5b4f4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:49 -0600 Subject: cros_ec: Allow reading the battery-charge state Add a function to read this information from the EC. It is useful for determining whether the battery has enough charge to boot. Signed-off-by: Simon Glass --- drivers/misc/cros_ec.c | 17 +++++++++++++++++ include/cros_ec.h | 8 ++++++++ 2 files changed, 25 insertions(+) (limited to 'include') diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 7904d5cc72d..0818ef8ad6e 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -1661,6 +1661,23 @@ int cros_ec_get_switches(struct udevice *dev) return ret; } +int cros_ec_read_batt_charge(struct udevice *dev, uint *chargep) +{ + struct ec_params_charge_state req; + struct ec_response_charge_state resp; + int ret; + + req.cmd = CHARGE_STATE_CMD_GET_STATE; + ret = ec_command(dev, EC_CMD_CHARGE_STATE, 0, &req, sizeof(req), + &resp, sizeof(resp)); + if (ret) + return log_msg_ret("read", ret); + + *chargep = resp.get_state.batt_state_of_charge; + + return 0; +} + UCLASS_DRIVER(cros_ec) = { .id = UCLASS_CROS_EC, .name = "cros-ec", diff --git a/include/cros_ec.h b/include/cros_ec.h index 9396b4d2466..9dab6cdf9ba 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -652,4 +652,12 @@ int cros_ec_vstore_read(struct udevice *dev, int slot, uint8_t *data); int cros_ec_vstore_write(struct udevice *dev, int slot, const uint8_t *data, size_t size); +/** + * cros_ec_read_batt_charge() - Read the battery-charge state + * + * @dev: CROS-EC device + * @chargep: Return battery-charge state as a percentage + */ +int cros_ec_read_batt_charge(struct udevice *dev, uint *chargep); + #endif -- cgit v1.3.1 From 1e465eb6698e294e8fa9ed41165483b88062396a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:50 -0600 Subject: cros_ec: Drop cros_ec_entering_mode() This function is not needed anymore. Drop it. Signed-off-by: Simon Glass --- drivers/misc/cros_ec.c | 11 ----------- drivers/misc/cros_ec_sandbox.c | 3 --- include/cros_ec.h | 9 --------- 3 files changed, 23 deletions(-) (limited to 'include') diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 0818ef8ad6e..2a15094d20a 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -754,17 +754,6 @@ int cros_ec_flash_protect(struct udevice *dev, uint32_t set_mask, return 0; } -int cros_ec_entering_mode(struct udevice *dev, int mode) -{ - int rc; - - rc = ec_command(dev, EC_CMD_ENTERING_MODE, 0, &mode, sizeof(mode), - NULL, 0); - if (rc) - return -1; - return 0; -} - static int cros_ec_check_version(struct udevice *dev) { struct cros_ec_dev *cdev = dev_get_uclass_priv(dev); diff --git a/drivers/misc/cros_ec_sandbox.c b/drivers/misc/cros_ec_sandbox.c index beea47caa33..ab91f3fa67a 100644 --- a/drivers/misc/cros_ec_sandbox.c +++ b/drivers/misc/cros_ec_sandbox.c @@ -496,9 +496,6 @@ static int process_cmd(struct ec_state *ec, case EC_CMD_MKBP_STATE: len = cros_ec_keyscan(ec, resp_data); break; - case EC_CMD_ENTERING_MODE: - len = 0; - break; case EC_CMD_GET_NEXT_EVENT: { struct ec_response_get_next_event *resp = resp_data; diff --git a/include/cros_ec.h b/include/cros_ec.h index 9dab6cdf9ba..ef89deff762 100644 --- a/include/cros_ec.h +++ b/include/cros_ec.h @@ -198,15 +198,6 @@ int cros_ec_flash_protect(struct udevice *dev, uint32_t set_mask, uint32_t set_flags, struct ec_response_flash_protect *resp); -/** - * Notify EC of current boot mode - * - * @param dev CROS-EC device - * @param vboot_mode Verified boot mode - * @return 0 if ok, <0 on error - */ -int cros_ec_entering_mode(struct udevice *dev, int mode); - /** * Run internal tests on the cros_ec interface. * -- cgit v1.3.1 From 1fe59375498fb84cd9ab72cf1f7f89437cd24cf4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:53 -0600 Subject: bloblist: Support resizing a blob Sometimes a blob needs to expand, e.g. because it needs to hold more log data. Add support for this. Note that the bloblist must have sufficient spare space for this to work. Signed-off-by: Simon Glass --- common/bloblist.c | 71 +++++++++++++++++++- include/bloblist.h | 13 ++++ test/bloblist.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/common/bloblist.c b/common/bloblist.c index eab63e9ca51..bb49ecab92e 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -57,13 +57,22 @@ static struct bloblist_rec *bloblist_first_blob(struct bloblist_hdr *hdr) return (struct bloblist_rec *)((void *)hdr + hdr->hdr_size); } -static struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr, - struct bloblist_rec *rec) +static ulong bloblist_blob_end_ofs(struct bloblist_hdr *hdr, + struct bloblist_rec *rec) { ulong offset; offset = (void *)rec - (void *)hdr; offset += rec->hdr_size + ALIGN(rec->size, BLOBLIST_ALIGN); + + return offset; +} + +static struct bloblist_rec *bloblist_next_blob(struct bloblist_hdr *hdr, + struct bloblist_rec *rec) +{ + ulong offset = bloblist_blob_end_ofs(hdr, rec); + if (offset >= hdr->alloced) return NULL; return (struct bloblist_rec *)((void *)hdr + offset); @@ -215,6 +224,64 @@ int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp) return 0; } +static int bloblist_resize_rec(struct bloblist_hdr *hdr, + struct bloblist_rec *rec, + int new_size) +{ + int expand_by; /* Number of bytes to expand by (-ve to contract) */ + int new_alloced; /* New value for @hdr->alloced */ + ulong next_ofs; /* Offset of the record after @rec */ + + expand_by = ALIGN(new_size - rec->size, BLOBLIST_ALIGN); + new_alloced = ALIGN(hdr->alloced + expand_by, BLOBLIST_ALIGN); + if (new_size < 0) { + log(LOGC_BLOBLIST, LOGL_DEBUG, + "Attempt to shrink blob size below 0 (%x)\n", new_size); + return log_msg_ret("size", -EINVAL); + } + if (new_alloced > hdr->size) { + log(LOGC_BLOBLIST, LOGL_ERR, + "Failed to allocate %x bytes size=%x, need size=%x\n", + new_size, hdr->size, new_alloced); + return log_msg_ret("alloc", -ENOSPC); + } + + /* Move the following blobs up or down, if this is not the last */ + next_ofs = bloblist_blob_end_ofs(hdr, rec); + if (next_ofs != hdr->alloced) { + memmove((void *)hdr + next_ofs + expand_by, + (void *)hdr + next_ofs, new_alloced - next_ofs); + } + hdr->alloced = new_alloced; + + /* Zero the new part of the blob */ + if (expand_by > 0) { + memset((void *)rec + rec->hdr_size + rec->size, '\0', + new_size - rec->size); + } + + /* Update the size of this blob */ + rec->size = new_size; + + return 0; +} + +int bloblist_resize(uint tag, int new_size) +{ + struct bloblist_hdr *hdr = gd->bloblist; + struct bloblist_rec *rec; + int ret; + + rec = bloblist_findrec(tag); + if (!rec) + return log_msg_ret("find", -ENOENT); + ret = bloblist_resize_rec(hdr, rec, new_size); + if (ret) + return log_msg_ret("resize", ret); + + return 0; +} + static u32 bloblist_calc_chksum(struct bloblist_hdr *hdr) { struct bloblist_rec *rec; diff --git a/include/bloblist.h b/include/bloblist.h index 964b974fdaf..b659d2bc93d 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -179,6 +179,19 @@ void *bloblist_ensure(uint tag, int size); */ int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp); +/** + * bloblist_resize() - resize a blob + * + * Any blobs above this one are relocated up or down. The resized blob remains + * in the same place. + * + * @tag: Tag to add (enum bloblist_tag_t) + * @new_size: New size of the blob (>0 to expand, <0 to contract) + * @return 0 if OK, -ENOSPC if the bloblist does not have enough space, -ENOENT + * if the tag is not found + */ +int bloblist_resize(uint tag, int new_size); + /** * bloblist_new() - Create a new, empty bloblist of a given size * diff --git a/test/bloblist.c b/test/bloblist.c index d876b639184..345eb181fff 100644 --- a/test/bloblist.c +++ b/test/bloblist.c @@ -33,6 +33,9 @@ enum { ERASE_BYTE = '\xff', }; +static const char test1_str[] = "the eyes are open"; +static const char test2_str[] = "the mouth moves"; + static struct bloblist_hdr *clear_bloblist(void) { struct bloblist_hdr *hdr; @@ -384,6 +387,195 @@ static int bloblist_test_reloc(struct unit_test_state *uts) } BLOBLIST_TEST(bloblist_test_reloc, 0); +/* Test expansion of a blob */ +static int bloblist_test_grow(struct unit_test_state *uts) +{ + const uint small_size = 0x20; + void *blob1, *blob2, *blob1_new; + struct bloblist_hdr *hdr; + void *ptr; + + ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE); + hdr = ptr; + memset(hdr, ERASE_BYTE, TEST_BLOBLIST_SIZE); + + /* Create two blobs */ + ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0)); + blob1 = bloblist_add(TEST_TAG, small_size, 0); + ut_assertnonnull(blob1); + ut_assertok(check_zero(blob1, small_size)); + strcpy(blob1, test1_str); + + blob2 = bloblist_add(TEST_TAG2, small_size, 0); + ut_assertnonnull(blob2); + strcpy(blob2, test2_str); + + ut_asserteq(sizeof(struct bloblist_hdr) + + sizeof(struct bloblist_rec) * 2 + small_size * 2, + hdr->alloced); + + /* Resize the first one */ + ut_assertok(bloblist_resize(TEST_TAG, small_size + 4)); + + /* The first one should not have moved, just got larger */ + blob1_new = bloblist_find(TEST_TAG, small_size + 4); + ut_asserteq_ptr(blob1, blob1_new); + + /* The new space should be zeroed */ + ut_assertok(check_zero(blob1 + small_size, 4)); + + /* The second one should have moved */ + blob2 = bloblist_find(TEST_TAG2, small_size); + ut_assertnonnull(blob2); + ut_asserteq_str(test2_str, blob2); + + /* The header should have more bytes in use */ + hdr = ptr; + ut_asserteq(sizeof(struct bloblist_hdr) + + sizeof(struct bloblist_rec) * 2 + small_size * 2 + + BLOBLIST_ALIGN, + hdr->alloced); + + return 0; +} +BLOBLIST_TEST(bloblist_test_grow, 0); + +/* Test shrinking of a blob */ +static int bloblist_test_shrink(struct unit_test_state *uts) +{ + const uint small_size = 0x20; + void *blob1, *blob2, *blob1_new; + struct bloblist_hdr *hdr; + int new_size; + void *ptr; + + ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE); + + /* Create two blobs */ + ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0)); + blob1 = bloblist_add(TEST_TAG, small_size, 0); + ut_assertnonnull(blob1); + strcpy(blob1, test1_str); + + blob2 = bloblist_add(TEST_TAG2, small_size, 0); + ut_assertnonnull(blob2); + strcpy(blob2, test2_str); + + hdr = ptr; + ut_asserteq(sizeof(struct bloblist_hdr) + + sizeof(struct bloblist_rec) * 2 + small_size * 2, + hdr->alloced); + + /* Resize the first one */ + new_size = small_size - BLOBLIST_ALIGN - 4; + ut_assertok(bloblist_resize(TEST_TAG, new_size)); + + /* The first one should not have moved, just got smaller */ + blob1_new = bloblist_find(TEST_TAG, new_size); + ut_asserteq_ptr(blob1, blob1_new); + + /* The second one should have moved */ + blob2 = bloblist_find(TEST_TAG2, small_size); + ut_assertnonnull(blob2); + ut_asserteq_str(test2_str, blob2); + + /* The header should have fewer bytes in use */ + hdr = ptr; + ut_asserteq(sizeof(struct bloblist_hdr) + + sizeof(struct bloblist_rec) * 2 + small_size * 2 - + BLOBLIST_ALIGN, + hdr->alloced); + + return 0; +} +BLOBLIST_TEST(bloblist_test_shrink, 0); + +/* Test failing to adjust a blob size */ +static int bloblist_test_resize_fail(struct unit_test_state *uts) +{ + const uint small_size = 0x20; + struct bloblist_hdr *hdr; + void *blob1, *blob2; + int new_size; + void *ptr; + + ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE); + + /* Create two blobs */ + ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0)); + blob1 = bloblist_add(TEST_TAG, small_size, 0); + ut_assertnonnull(blob1); + + blob2 = bloblist_add(TEST_TAG2, small_size, 0); + ut_assertnonnull(blob2); + + hdr = ptr; + ut_asserteq(sizeof(struct bloblist_hdr) + + sizeof(struct bloblist_rec) * 2 + small_size * 2, + hdr->alloced); + + /* Resize the first one, to check the boundary conditions */ + ut_asserteq(-EINVAL, bloblist_resize(TEST_TAG, -1)); + + new_size = small_size + (hdr->size - hdr->alloced); + ut_asserteq(-ENOSPC, bloblist_resize(TEST_TAG, new_size + 1)); + ut_assertok(bloblist_resize(TEST_TAG, new_size)); + + return 0; +} +BLOBLIST_TEST(bloblist_test_resize_fail, 0); + +/* Test expanding the last blob in a bloblist */ +static int bloblist_test_resize_last(struct unit_test_state *uts) +{ + const uint small_size = 0x20; + struct bloblist_hdr *hdr; + void *blob1, *blob2, *blob2_new; + int alloced_val; + void *ptr; + + ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE); + memset(ptr, ERASE_BYTE, TEST_BLOBLIST_SIZE); + hdr = ptr; + + /* Create two blobs */ + ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0)); + blob1 = bloblist_add(TEST_TAG, small_size, 0); + ut_assertnonnull(blob1); + + blob2 = bloblist_add(TEST_TAG2, small_size, 0); + ut_assertnonnull(blob2); + + /* Check the byte after the last blob */ + alloced_val = sizeof(struct bloblist_hdr) + + sizeof(struct bloblist_rec) * 2 + small_size * 2; + ut_asserteq(alloced_val, hdr->alloced); + ut_asserteq_ptr((void *)hdr + alloced_val, blob2 + small_size); + ut_asserteq((u8)ERASE_BYTE, *((u8 *)hdr + hdr->alloced)); + + /* Resize the second one, checking nothing changes */ + ut_asserteq(0, bloblist_resize(TEST_TAG2, small_size + 4)); + + blob2_new = bloblist_find(TEST_TAG2, small_size + 4); + ut_asserteq_ptr(blob2, blob2_new); + + /* + * the new blob should encompass the byte we checked now, so it should + * be zeroed. This zeroing should affect only the four new bytes added + * to the blob. + */ + ut_asserteq(0, *((u8 *)hdr + alloced_val)); + ut_asserteq((u8)ERASE_BYTE, *((u8 *)hdr + alloced_val + 4)); + + /* Check that the new top of the allocated blobs has not been touched */ + alloced_val += BLOBLIST_ALIGN; + ut_asserteq(alloced_val, hdr->alloced); + ut_asserteq((u8)ERASE_BYTE, *((u8 *)hdr + hdr->alloced)); + + return 0; +} +BLOBLIST_TEST(bloblist_test_resize_last, 0); + int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { -- cgit v1.3.1 From faff554292824037c4f098020ddbc8d979900415 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:54 -0600 Subject: bloblist: Tidy up a few API comments Some comments for struct bloblist_hdr are a bit ambiguous. Update them to clarify the meaning more precisely. Also document bloblist_get_stats() properly. Signed-off-by: Simon Glass --- include/bloblist.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/bloblist.h b/include/bloblist.h index b659d2bc93d..9f007c7a94d 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -64,10 +64,10 @@ enum bloblist_tag_t { * first bloblist_rec starts at this offset from the start of the header * @flags: Space for BLOBLISTF_... flags (none yet) * @magic: BLOBLIST_MAGIC - * @size: Total size of all records (non-zero if valid) including this header. + * @size: Total size of the bloblist (non-zero if valid) including this header. * The bloblist extends for this many bytes from the start of this header. - * @alloced: Total size allocated for this bloblist. When adding new records, - * the bloblist can grow up to this size. This starts out as + * When adding new records, the bloblist can grow up to this size. + * @alloced: Total size allocated so far for this bloblist. This starts out as * sizeof(bloblist_hdr) since we need at least that much space to store a * valid bloblist * @spare: Spare space (for future use) @@ -230,6 +230,10 @@ int bloblist_finish(void); * bloblist_get_stats() - Get information about the bloblist * * This returns useful information about the bloblist + * + * @basep: Returns base address of bloblist + * @sizep: Returns the number of bytes used in the bloblist + * @allocedp: Returns the total space allocated to the bloblist */ void bloblist_get_stats(ulong *basep, ulong *sizep, ulong *allocedp); -- cgit v1.3.1 From 7d84fbb57312ac0224dc67860f4d0306a3bb3f81 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:57 -0600 Subject: spl: Provide more information on boot failure If SPL fails to boot, try to provide an error code to indicate what is wrong. For example, if a uclass is missing, this can return -EPFNOSUPPORT (-96) which provides useful information. Add a helper for accessing the image-loader name so we can drop the use of #ifdefs in this code. Put this feature behind a CONFIG_SHOW_ERRORS option to avoid increasing the code size. Signed-off-by: Simon Glass --- common/spl/Kconfig | 10 ++++++++++ common/spl/spl.c | 48 ++++++++++++++++++++++++++++++++---------------- include/spl.h | 10 ++++++++++ 3 files changed, 52 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 2df3e5d8690..c0183521d20 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -91,6 +91,16 @@ config SPL_SYS_REPORT_STACK_F_USAGE occurrence of non 0xaa bytes. This default implementation works for stacks growing down only. +config SPL_SHOW_ERRORS + bool "Show more information when something goes wrong" + help + This enabled more verbose error messages and checking when something + goes wrong in SPL. For example, it shows the error code when U-Boot + cannot be located. This can help to diagnose the problem and figure + out a fix, particularly during development. + + This adds a small amount to SPL code size, perhaps 100 bytes. + menu "PowerPC and LayerScape SPL Boot options" config SPL_NAND_BOOT diff --git a/common/spl/spl.c b/common/spl/spl.c index eba77cace6d..3b96f2fc310 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -593,32 +593,42 @@ static int spl_load_image(struct spl_image_info *spl_image, * @spl_image: Place to put the image details if successful * @spl_boot_list: List of boot devices to try * @count: Number of elements in spl_boot_list - * @return 0 if OK, -ve on error + * @return 0 if OK, -ENODEV if there were no boot devices + * if CONFIG_SHOW_ERRORS is enabled, returns -ENXIO if there were + * devices but none worked */ static int boot_from_devices(struct spl_image_info *spl_image, u32 spl_boot_list[], int count) { + int ret = -ENODEV; int i; for (i = 0; i < count && spl_boot_list[i] != BOOT_DEVICE_NONE; i++) { struct spl_image_loader *loader; - - loader = spl_ll_find_loader(spl_boot_list[i]); -#if defined(CONFIG_SPL_SERIAL_SUPPORT) \ - && defined(CONFIG_SPL_LIBCOMMON_SUPPORT) \ - && !defined(CONFIG_SILENT_CONSOLE) - if (loader) - printf("Trying to boot from %s\n", loader->name); - else - puts(SPL_TPL_PROMPT "Unsupported Boot Device!\n"); -#endif + int bootdev = spl_boot_list[i]; + + if (CONFIG_IS_ENABLED(SHOW_ERRORS)) + ret = -ENXIO; + loader = spl_ll_find_loader(bootdev); + if (CONFIG_IS_ENABLED(SERIAL_SUPPORT) && + CONFIG_IS_ENABLED(LIBCOMMON_SUPPORT) && + !IS_ENABLED(CONFIG_SILENT_CONSOLE)) { + if (loader) + printf("Trying to boot from %s\n", + spl_loader_name(loader)); + else if (CONFIG_IS_ENABLED(SHOW_ERRORS)) + printf(SPL_TPL_PROMPT + "Unsupported Boot Device %d\n", bootdev); + else + puts(SPL_TPL_PROMPT "Unsupported Boot Device!\n"); + } if (loader && !spl_load_image(spl_image, loader)) { - spl_image->boot_device = spl_boot_list[i]; + spl_image->boot_device = bootdev; return 0; } } - return -ENODEV; + return ret; } #if defined(CONFIG_SPL_FRAMEWORK_BOARD_INIT_F) @@ -710,9 +720,15 @@ void board_init_r(gd_t *dummy1, ulong dummy2) spl_image.boot_device = BOOT_DEVICE_NONE; board_boot_order(spl_boot_list); - if (boot_from_devices(&spl_image, spl_boot_list, - ARRAY_SIZE(spl_boot_list))) { - puts(SPL_TPL_PROMPT "failed to boot from all boot devices\n"); + ret = boot_from_devices(&spl_image, spl_boot_list, + ARRAY_SIZE(spl_boot_list)); + if (ret) { + if (CONFIG_IS_ENABLED(SHOW_ERRORS) && + CONFIG_IS_ENABLED(LIBCOMMON_SUPPORT)) + printf(SPL_TPL_PROMPT "failed to boot from all boot devices (err=%d)\n", + ret); + else + puts(SPL_TPL_PROMPT "failed to boot from all boot devices\n"); hang(); } diff --git a/include/spl.h b/include/spl.h index d88fb79a676..74a19394520 100644 --- a/include/spl.h +++ b/include/spl.h @@ -505,6 +505,16 @@ struct spl_image_loader { struct spl_boot_device *bootdev); }; +/* Helper function for accessing the name */ +static inline const char *spl_loader_name(const struct spl_image_loader *loader) +{ +#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT + return loader->name; +#else + return NULL; +#endif +} + /* Declare an SPL image loader */ #define SPL_LOAD_IMAGE(__name) \ ll_entry_declare(struct spl_image_loader, __name, spl_image_loader) -- cgit v1.3.1 From 96f37b092fdbb604e43c313265995d72ff1a82fe Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:59 -0600 Subject: blk: Support iteration It is useful to be able to iterate over block devices. Typically there are fixed and removable devices. For security reasons it is sometimes useful to ignore removable devices since they are under user control. Add iterators which support selecting the block-device type. Signed-off-by: Simon Glass --- drivers/block/blk-uclass.c | 49 ++++++++++++++++++++++++++++++++++++++++ include/blk.h | 56 ++++++++++++++++++++++++++++++++++++++++++++++ test/dm/blk.c | 55 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 160 insertions(+) (limited to 'include') diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index dfc0d469702..83682dcc181 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -540,6 +540,55 @@ int blk_next_free_devnum(enum if_type if_type) return ret + 1; } +static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags) +{ + const struct blk_desc *desc = dev_get_uclass_plat(dev); + enum blk_flag_t flags; + + flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED; + + return flags & req_flags ? 0 : 1; +} + +int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp) +{ + int ret; + + for (ret = uclass_first_device_err(UCLASS_BLK, devp); + !ret; + ret = uclass_next_device_err(devp)) { + if (!blk_flags_check(*devp, flags)) + return 0; + } + + return -ENODEV; +} + +int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp) +{ + int ret; + + for (ret = uclass_next_device_err(devp); + !ret; + ret = uclass_next_device_err(devp)) { + if (!blk_flags_check(*devp, flags)) + return 0; + } + + return -ENODEV; +} + +int blk_count_devices(enum blk_flag_t flag) +{ + struct udevice *dev; + int count = 0; + + blk_foreach_probe(flag, dev) + count++; + + return count; +} + static int blk_claim_devnum(enum if_type if_type, int devnum) { struct udevice *dev; diff --git a/include/blk.h b/include/blk.h index c4401b00253..19bab081c2c 100644 --- a/include/blk.h +++ b/include/blk.h @@ -19,6 +19,8 @@ typedef ulong lbaint_t; #define LBAF "%" LBAFlength "x" #define LBAFU "%" LBAFlength "u" +struct udevice; + /* Interface types: */ enum if_type { IF_TYPE_UNKNOWN = 0, @@ -683,4 +685,58 @@ const char *blk_get_if_type_name(enum if_type if_type); int blk_common_cmd(int argc, char *const argv[], enum if_type if_type, int *cur_devnump); +enum blk_flag_t { + BLKF_FIXED = 1 << 0, + BLKF_REMOVABLE = 1 << 1, + BLKF_BOTH = BLKF_FIXED | BLKF_REMOVABLE, +}; + +/** + * blk_first_device_err() - Get the first block device + * + * The device returned is probed if necessary, and ready for use + * + * @flags: Indicates type of device to return + * @devp: Returns pointer to the first device in that uclass, or NULL if none + * @return 0 if found, -ENODEV if not found, other -ve on error + */ +int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp); + +/** + * blk_next_device_err() - Get the next block device + * + * The device returned is probed if necessary, and ready for use + * + * @flags: Indicates type of device to return + * @devp: On entry, pointer to device to lookup. On exit, returns pointer + * to the next device in the uclass if no error occurred, or -ENODEV if + * there is no next device. + * @return 0 if found, -ENODEV if not found, other -ve on error + */ +int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp); + +/** + * blk_foreach_probe() - Helper function to iteration through block devices + * + * This creates a for() loop which works through the available devices in + * a uclass in order from start to end. Devices are probed if necessary, + * and ready for use. + * + * @flags: Indicates type of device to return + * @dev: struct udevice * to hold the current device. Set to NULL when there + * are no more devices. + */ +#define blk_foreach_probe(flags, pos) \ + for (int _ret = blk_first_device_err(flags, &(pos)); \ + !_ret && pos; \ + _ret = blk_next_device_err(flags, &(pos))) + +/** + * blk_count_devices() - count the number of devices of a particular type + * + * @flags: Indicates type of device to find + * @return number of devices matching those flags + */ +int blk_count_devices(enum blk_flag_t flag); + #endif diff --git a/test/dm/blk.c b/test/dm/blk.c index b7f4304e9e9..deccf05289b 100644 --- a/test/dm/blk.c +++ b/test/dm/blk.c @@ -162,3 +162,58 @@ static int dm_test_blk_get_from_parent(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_blk_get_from_parent, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); + +/* Test iteration through block devices */ +static int dm_test_blk_iter(struct unit_test_state *uts) +{ + struct udevice *dev; + int i; + + /* + * See sandbox test.dts - it has: + * + * mmc0 - removable + * mmc1 - removable + * mmc2 - fixed + */ + ut_assertok(blk_first_device_err(BLKF_FIXED, &dev)); + ut_asserteq_str("mmc2.blk", dev->name); + ut_asserteq(-ENODEV, blk_next_device_err(BLKF_FIXED, &dev)); + + ut_assertok(blk_first_device_err(BLKF_REMOVABLE, &dev)); + ut_asserteq_str("mmc1.blk", dev->name); + ut_assertok(blk_next_device_err(BLKF_REMOVABLE, &dev)); + ut_asserteq_str("mmc0.blk", dev->name); + ut_asserteq(-ENODEV, blk_next_device_err(BLKF_REMOVABLE, &dev)); + + ut_assertok(blk_first_device_err(BLKF_BOTH, &dev)); + ut_asserteq_str("mmc2.blk", dev->name); + ut_assertok(blk_next_device_err(BLKF_BOTH, &dev)); + ut_asserteq_str("mmc1.blk", dev->name); + ut_assertok(blk_next_device_err(BLKF_BOTH, &dev)); + ut_asserteq_str("mmc0.blk", dev->name); + ut_asserteq(-ENODEV, blk_next_device_err(BLKF_FIXED, &dev)); + + ut_asserteq(1, blk_count_devices(BLKF_FIXED)); + ut_asserteq(2, blk_count_devices(BLKF_REMOVABLE)); + ut_asserteq(3, blk_count_devices(BLKF_BOTH)); + + i = 0; + blk_foreach_probe(BLKF_FIXED, dev) + ut_asserteq_str((i++, "mmc2.blk"), dev->name); + ut_asserteq(1, i); + + i = 0; + blk_foreach_probe(BLKF_REMOVABLE, dev) + ut_asserteq_str(i++ ? "mmc0.blk" : "mmc1.blk", dev->name); + ut_asserteq(2, i); + + i = 0; + blk_foreach_probe(BLKF_BOTH, dev) + ut_asserteq_str((++i == 1 ? "mmc2.blk" : i == 2 ? + "mmc1.blk" : "mmc0.blk"), dev->name); + ut_asserteq(3, i); + + return 0; +} +DM_TEST(dm_test_blk_iter, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); -- cgit v1.3.1