From f093f8649c794866f5793f132f93c95335aea817 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:41 -0600 Subject: test: Allow CONFIG_SPL_LOAD_FIT to be disabled At present if this is not enabled on a sandbox build, the build fails. Add a condition to avoid this. Signed-off-by: Simon Glass --- test/Makefile | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test') diff --git a/test/Makefile b/test/Makefile index a26e915e050..117839e5847 100644 --- a/test/Makefile +++ b/test/Makefile @@ -3,7 +3,9 @@ # (C) Copyright 2012 The Chromium Authors obj-y += test-main.o +ifdef CONFIG_SPL_LOAD_FIT obj-$(CONFIG_SANDBOX) += image/ +endif ifneq ($(CONFIG_$(SPL_)BLOBLIST),) obj-$(CONFIG_$(SPL_)CMDLINE) += bloblist.o -- cgit v1.3.1 From bf8188e4aa442a9fcd6b5332d177ec76a8faae65 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:42 -0600 Subject: test: Add DM_DMA to be disabled At present if DM_DMA is disabled on a sandbox build, the build fails. Make the test conditional. Signed-off-by: Simon Glass --- test/dm/core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test') diff --git a/test/dm/core.c b/test/dm/core.c index 2210345dd14..0492698997c 100644 --- a/test/dm/core.c +++ b/test/dm/core.c @@ -1171,6 +1171,7 @@ static int dm_test_all_have_seq(struct unit_test_state *uts) } DM_TEST(dm_test_all_have_seq, UT_TESTF_SCAN_PDATA); +#if CONFIG_IS_ENABLED(DM_DMA) static int dm_test_dma_offset(struct unit_test_state *uts) { struct udevice *dev; @@ -1200,3 +1201,4 @@ static int dm_test_dma_offset(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_dma_offset, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT); +#endif -- cgit v1.3.1 From 719d286475d2df1f1d8f4413659893934f38de7d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:43 -0600 Subject: test: Avoid a build error with SPL At present this fails to build chromeos_sandbox due to a rebase error in dm_test_pre_run(). Fix it. Signed-off-by: Simon Glass --- test/test-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test') diff --git a/test/test-main.c b/test/test-main.c index 7afe8741cf9..3cdf6849c57 100644 --- a/test/test-main.c +++ b/test/test-main.c @@ -45,7 +45,7 @@ static int dm_test_pre_run(struct unit_test_state *uts) uts->force_fail_alloc = false; uts->skip_post_probe = false; gd->dm_root = NULL; - if (IS_ENABLED(CONFIG_UT_DM) && !CONFIG_IS_ENABLED(OF_PLATDATA)) + if (CONFIG_IS_ENABLED(UT_DM) && !CONFIG_IS_ENABLED(OF_PLATDATA)) memset(dm_testdrv_op_count, '\0', sizeof(dm_testdrv_op_count)); arch_reset_for_test(); -- cgit v1.3.1 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 --- arch/sandbox/cpu/os.c | 63 +++++++++++++++++++----------------------- arch/sandbox/cpu/spl.c | 16 ++++++++++- arch/sandbox/include/asm/spl.h | 13 +++++++++ include/os.h | 5 +++- include/spl.h | 21 ++++++++++++++ test/image/spl_load.c | 6 +++- 6 files changed, 86 insertions(+), 38 deletions(-) (limited to 'test') diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index 0d21827e1b7..a8aa9def27f 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -783,12 +783,14 @@ int os_jump_to_image(const void *dest, int size) return os_jump_to_file(fname, true); } -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) { struct sandbox_state *state = state_get_current(); const char *progname = state->argv[0]; int len = strlen(progname); - const char *suffix; + char subdir[10]; + char *suffix; char *p; int fd; @@ -798,45 +800,36 @@ int os_find_u_boot(char *fname, int maxlen, bool use_img) strcpy(fname, progname); suffix = fname + len - 4; - /* If we are TPL, boot to SPL */ - if (!strcmp(suffix, "-tpl")) { - fname[len - 3] = 's'; - fd = os_open(fname, O_RDONLY); - if (fd >= 0) { - close(fd); - return 0; - } - - /* Look for 'u-boot-spl' in the spl/ directory */ - p = strstr(fname, "/spl/"); - if (p) { - p[1] = 's'; - fd = os_open(fname, O_RDONLY); - if (fd >= 0) { - close(fd); - return 0; - } - } - return -ENOENT; - } + /* Change the existing suffix to the new one */ + if (*suffix != '-') + return -EINVAL; - /* Look for 'u-boot' in the same directory as 'u-boot-spl' */ - if (!strcmp(suffix, "-spl")) { - fname[len - 4] = '\0'; - fd = os_open(fname, O_RDONLY); - if (fd >= 0) { - close(fd); - return 0; - } + if (*next_prefix) + strcpy(suffix + 1, next_prefix); /* e.g. "-tpl" to "-spl" */ + else + *suffix = '\0'; /* e.g. "-spl" to "" */ + fd = os_open(fname, O_RDONLY); + if (fd >= 0) { + close(fd); + return 0; } - /* Look for 'u-boot' in the parent directory of spl/ */ - p = strstr(fname, "spl/"); + /* + * We didn't find it, so try looking for 'u-boot-xxx' in the xxx/ + * directory. Replace the old dirname with the new one. + */ + snprintf(subdir, sizeof(subdir), "/%s/", cur_prefix); + p = strstr(fname, subdir); if (p) { - /* Remove the "spl" characters */ - memmove(p, p + 4, strlen(p + 4) + 1); + if (*next_prefix) + /* e.g. ".../tpl/u-boot-spl" to "../spl/u-boot-spl" */ + memcpy(p + 1, next_prefix, strlen(next_prefix)); + else + /* e.g. ".../spl/u-boot" to ".../u-boot" */ + strcpy(p, p + 1 + strlen(cur_prefix)); if (use_img) strcat(p, ".img"); + fd = os_open(fname, O_RDONLY); if (fd >= 0) { close(fd); diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index f82b0d3de16..650bdb0a701 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -17,6 +17,20 @@ DECLARE_GLOBAL_DATA_PTR; +int sandbox_find_next_phase(char *fname, int maxlen, bool use_img) +{ + const char *cur_prefix, *next_prefix; + int ret; + + cur_prefix = spl_phase_prefix(spl_phase()); + next_prefix = spl_phase_prefix(spl_next_phase()); + ret = os_find_u_boot(fname, maxlen, use_img, cur_prefix, next_prefix); + if (ret) + return log_msg_ret("find", ret); + + return 0; +} + /* SPL / TPL init function */ void board_init_f(ulong flag) { @@ -37,7 +51,7 @@ static int spl_board_load_image(struct spl_image_info *spl_image, char fname[256]; int ret; - ret = os_find_u_boot(fname, sizeof(fname), false); + ret = sandbox_find_next_phase(fname, sizeof(fname), false); if (ret) { printf("(%s not found, error %d)\n", fname, ret); return ret; diff --git a/arch/sandbox/include/asm/spl.h b/arch/sandbox/include/asm/spl.h index 51e9d95d557..d25dc7c82a0 100644 --- a/arch/sandbox/include/asm/spl.h +++ b/arch/sandbox/include/asm/spl.h @@ -12,4 +12,17 @@ enum { BOOT_DEVICE_BOARD, }; +/** + * sandbox_find_next_phase() - Find the next phase of U-Boot + * + * This function is intended to be called from within sandbox SPL. It uses + * a few rules to find the filename of the next U-Boot phase. See also + * os_find_u_boot(). + * + * @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 + */ +int sandbox_find_next_phase(char *fname, int maxlen, bool use_img); + #endif 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 diff --git a/test/image/spl_load.c b/test/image/spl_load.c index 851603ddd75..e7cabf5680c 100644 --- a/test/image/spl_load.c +++ b/test/image/spl_load.c @@ -56,6 +56,7 @@ struct image_header *spl_get_load_buffer(ssize_t offset, size_t size) static int spl_test_load(struct unit_test_state *uts) { + const char *cur_prefix, *next_prefix; struct spl_image_info image; struct image_header *header; struct text_ctx text_ctx; @@ -68,7 +69,10 @@ static int spl_test_load(struct unit_test_state *uts) load.bl_len = 512; load.read = read_fit_image; - ret = os_find_u_boot(fname, sizeof(fname), true); + cur_prefix = spl_phase_prefix(spl_phase()); + next_prefix = spl_phase_prefix(spl_next_phase()); + ret = os_find_u_boot(fname, sizeof(fname), true, cur_prefix, + next_prefix); if (ret) { printf("(%s not found, error %d)\n", fname, ret); return ret; -- 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 'test') 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 1f618d528e234d2b7b0047750284dd531f5d718f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:32:55 -0600 Subject: bloblist: Correct condition in bloblist_addrec() It is possible to add a blob that ends at the end of the bloblist, but at present this is not supported. Fix it and add a regression test for this case. Signed-off-by: Simon Glass --- common/bloblist.c | 2 +- test/bloblist.c | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) (limited to 'test') diff --git a/common/bloblist.c b/common/bloblist.c index bb49ecab92e..1290fff8504 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -118,7 +118,7 @@ static int bloblist_addrec(uint tag, int size, int align, /* Calculate the new allocated total */ new_alloced = data_start + ALIGN(size, align); - if (new_alloced >= hdr->size) { + if (new_alloced > hdr->size) { log(LOGC_BLOBLIST, LOGL_ERR, "Failed to allocate %x bytes size=%x, need size=%x\n", size, hdr->size, new_alloced); diff --git a/test/bloblist.c b/test/bloblist.c index 345eb181fff..4104e6a92f6 100644 --- a/test/bloblist.c +++ b/test/bloblist.c @@ -576,6 +576,29 @@ static int bloblist_test_resize_last(struct unit_test_state *uts) } BLOBLIST_TEST(bloblist_test_resize_last, 0); +/* Check a completely full bloblist */ +static int bloblist_test_blob_maxsize(struct unit_test_state *uts) +{ + void *ptr; + int size; + + /* At the start there should be no records */ + clear_bloblist(); + ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0)); + + /* Add a blob that takes up all space */ + size = TEST_BLOBLIST_SIZE - sizeof(struct bloblist_hdr) - + sizeof(struct bloblist_rec); + ptr = bloblist_add(TEST_TAG, size, 0); + ut_assertnonnull(ptr); + + ptr = bloblist_add(TEST_TAG, size + 1, 0); + ut_assertnull(ptr); + + return 0; +} +BLOBLIST_TEST(bloblist_test_blob_maxsize, 0); + int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { -- 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 'test') 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 From 72fa1ad8d9fe58153ca72e3886b8d846299e8fff Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 5 Jul 2021 16:33:00 -0600 Subject: log: Allow padding of the function name At present when function names are logged, the output is a little hard to read since every function is a different length. Add a way to pad the names so that the log messages line up vertically. This doesn't work if the function name is very long, but it makes a big difference in most cases. Use 20 characters as a default since this covers the vast majority of functions. Signed-off-by: Simon Glass --- common/Kconfig | 8 ++++++++ common/log_console.c | 2 +- test/log/log_test.c | 16 +++++++++------- 3 files changed, 18 insertions(+), 8 deletions(-) (limited to 'test') diff --git a/common/Kconfig b/common/Kconfig index 1f0c3663af0..2ab20a6c85b 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -322,6 +322,14 @@ config LOGF_FUNC Show the function name in log messages by default. This value can be overridden using the 'log format' command. +config LOGF_FUNC_PAD + int "Number of characters to use for function" + default 20 + help + Sets the field width to use when showing the function. Set this to + a larger value if you have lots of long function names, and want + things to line up. + config LOG_SYSLOG bool "Log output to syslog server" depends on NET diff --git a/common/log_console.c b/common/log_console.c index 3f6177499ef..f1dcc04b97c 100644 --- a/common/log_console.c +++ b/common/log_console.c @@ -38,7 +38,7 @@ static int log_console_emit(struct log_device *ldev, struct log_rec *rec) if (fmt & BIT(LOGF_LINE)) printf("%d-", rec->line); if (fmt & BIT(LOGF_FUNC)) - printf("%s()", rec->func); + printf("%*s()", CONFIG_LOGF_FUNC_PAD, rec->func); } if (fmt & BIT(LOGF_MSG)) printf("%s%s", add_space ? " " : "", rec->msg); diff --git a/test/log/log_test.c b/test/log/log_test.c index f1e67509c17..db7170f3042 100644 --- a/test/log/log_test.c +++ b/test/log/log_test.c @@ -62,9 +62,9 @@ static int do_check_log_entries(struct unit_test_state *uts, int flags, int min, for (i = min; i <= max; i++) { if (flags & EXPECT_LOG) - ut_assert_nextline("do_log_run() log %d", i); + ut_assert_nextline(" do_log_run() log %d", i); if (flags & EXPECT_DIRECT) - ut_assert_nextline("func() _log %d", i); + ut_assert_nextline(" func() _log %d", i); if (flags & EXPECT_DEBUG) { ut_assert_nextline("log %d", i); ut_assert_nextline("_log %d", i); @@ -72,11 +72,12 @@ static int do_check_log_entries(struct unit_test_state *uts, int flags, int min, } if (flags & EXPECT_EXTRA) for (; i <= LOGL_MAX ; i++) - ut_assert_nextline("func() _log %d", i); + ut_assert_nextline(" func() _log %d", i); for (i = LOGL_FIRST; i < LOGL_COUNT; i++) { if (flags & EXPECT_FORCE) - ut_assert_nextline("func() _log force %d", i); + ut_assert_nextline(" func() _log force %d", + i); if (flags & EXPECT_DEBUG) ut_assert_nextline("_log force %d", i); } @@ -277,7 +278,8 @@ int do_log_test_helpers(struct unit_test_state *uts) log_io("level %d\n", LOGL_DEBUG_IO); for (i = LOGL_EMERG; i <= _LOG_MAX_LEVEL; i++) - ut_assert_nextline("%s() level %d", __func__, i); + ut_assert_nextline("%*s() level %d", CONFIG_LOGF_FUNC_PAD, + __func__, i); ut_assert_console_end(); return 0; } @@ -297,14 +299,14 @@ int do_log_test_disable(struct unit_test_state *uts) { ut_assertok(console_record_reset_enable()); log_err("default\n"); - ut_assert_nextline("%s() default", __func__); + ut_assert_nextline("%*s() default", CONFIG_LOGF_FUNC_PAD, __func__); ut_assertok(log_device_set_enable(LOG_GET_DRIVER(console), false)); log_err("disabled\n"); ut_assertok(log_device_set_enable(LOG_GET_DRIVER(console), true)); log_err("enabled\n"); - ut_assert_nextline("%s() enabled", __func__); + ut_assert_nextline("%*s() enabled", CONFIG_LOGF_FUNC_PAD, __func__); ut_assert_console_end(); return 0; } -- cgit v1.3.1