diff --git a/common/Kconfig b/common/Kconfig index d8982ba377..45535e3501 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -697,6 +697,16 @@ config BLOBLIST_ADDR Sets the address of the bloblist, set up by the first part of U-Boot which runs. Subsequent U-Boot stages typically use the same address. +config BLOBLIST_SIZE_RELOC + hex "Size of bloblist after relocation" + depends on BLOBLIST + default BLOBLIST_SIZE + help + Sets the size of the bloblist in bytes after relocation. Since U-Boot + has a lot more memory available then, it is possible to use a larger + size than the one set up by SPL. This bloblist is set up during the + relocation process. + endmenu source "common/spl/Kconfig" diff --git a/common/bloblist.c b/common/bloblist.c index 33b5862380..e32f551e27 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -317,6 +317,15 @@ void bloblist_show_list(void) } } +void bloblist_reloc(void *to, uint to_size, void *from, uint from_size) +{ + struct bloblist_hdr *hdr; + + memcpy(to, from, from_size); + hdr = to; + hdr->size = to_size; +} + int bloblist_init(void) { bool expected; @@ -327,6 +336,8 @@ int bloblist_init(void) * that runs */ expected = !u_boot_first_phase(); + if (spl_prev_phase() == PHASE_TPL && !IS_ENABLED(CONFIG_TPL_BLOBLIST)) + expected = false; if (expected) ret = bloblist_check(CONFIG_BLOBLIST_ADDR, CONFIG_BLOBLIST_SIZE); diff --git a/common/board_f.c b/common/board_f.c index ae3001bed1..4327a43a33 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -568,9 +568,10 @@ static int reserve_bloblist(void) { #ifdef CONFIG_BLOBLIST /* Align to a 4KB boundary for easier reading of addresses */ - gd->start_addr_sp = ALIGN_DOWN(gd->start_addr_sp - CONFIG_BLOBLIST_SIZE, - 0x1000); - gd->new_bloblist = map_sysmem(gd->start_addr_sp, CONFIG_BLOBLIST_SIZE); + gd->start_addr_sp = ALIGN_DOWN(gd->start_addr_sp - + CONFIG_BLOBLIST_SIZE_RELOC, 0x1000); + gd->new_bloblist = map_sysmem(gd->start_addr_sp, + CONFIG_BLOBLIST_SIZE_RELOC); #endif return 0; @@ -658,7 +659,8 @@ static int reloc_bloblist(void) debug("Copying bloblist from %p to %p, size %x\n", gd->bloblist, gd->new_bloblist, size); - memcpy(gd->new_bloblist, gd->bloblist, size); + bloblist_reloc(gd->new_bloblist, CONFIG_BLOBLIST_SIZE_RELOC, + gd->bloblist, size); gd->bloblist = gd->new_bloblist; } #endif diff --git a/include/bloblist.h b/include/bloblist.h index 8cdce61187..964b974fda 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -242,6 +242,16 @@ void bloblist_show_list(void); */ const char *bloblist_tag_name(enum bloblist_tag_t tag); +/** + * bloblist_reloc() - Relocate the bloblist and optionally resize it + * + * @to: Pointer to new bloblist location (must not overlap old location) + * @to:size: New size for bloblist (must be larger than from_size) + * @from: Pointer to bloblist to relocate + * @from_size: Size of bloblist to relocate + */ +void bloblist_reloc(void *to, uint to_size, void *from, uint from_size); + /** * bloblist_init() - Init the bloblist system with a single bloblist * diff --git a/test/bloblist.c b/test/bloblist.c index 900299dd68..85a6c39680 100644 --- a/test/bloblist.c +++ b/test/bloblist.c @@ -347,6 +347,42 @@ static int bloblist_test_align(struct unit_test_state *uts) } BLOBLIST_TEST(bloblist_test_align, 0); +/* Test relocation of a bloblist */ +static int bloblist_test_reloc(struct unit_test_state *uts) +{ + const uint large_size = TEST_BLOBLIST_SIZE; + const uint small_size = 0x20; + void *old_ptr, *new_ptr; + void *blob1, *blob2; + ulong new_addr; + ulong new_size; + + ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0)); + old_ptr = map_sysmem(TEST_ADDR, TEST_BLOBLIST_SIZE); + + /* Add one blob and then one that won't fit */ + blob1 = bloblist_add(TEST_TAG, small_size, 0); + ut_assertnonnull(blob1); + blob2 = bloblist_add(TEST_TAG2, large_size, 0); + ut_assertnull(blob2); + + /* Relocate the bloblist somewhere else, a bit larger */ + new_addr = TEST_ADDR + TEST_BLOBLIST_SIZE; + new_size = TEST_BLOBLIST_SIZE + 0x100; + new_ptr = map_sysmem(new_addr, TEST_BLOBLIST_SIZE); + bloblist_reloc(new_ptr, new_size, old_ptr, TEST_BLOBLIST_SIZE); + gd->bloblist = new_ptr; + + /* Check the old blob is there and that we can now add the bigger one */ + ut_assertnonnull(bloblist_find(TEST_TAG, small_size)); + ut_assertnull(bloblist_find(TEST_TAG2, small_size)); + blob2 = bloblist_add(TEST_TAG2, large_size, 0); + ut_assertnonnull(blob2); + + return 0; +} +BLOBLIST_TEST(bloblist_test_reloc, 0); + int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) {