From 4c1497e77661eea47d3dbb9bee029532cc0da198 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 19 Sep 2020 18:49:29 -0600 Subject: [PATCH] bloblist: Allow custom alignment for blobs Some blobs need a larger alignment than the default. For example, ACPI tables often start at a 4KB boundary. Add support for this. Update the size of the test blob to allow these larger records. Signed-off-by: Simon Glass --- arch/x86/cpu/intel_common/acpi.c | 2 +- arch/x86/cpu/intel_common/intel_opregion.c | 2 +- common/bloblist.c | 32 ++++++++++------- include/bloblist.h | 6 ++-- test/bloblist.c | 42 +++++++++++++++++----- 5 files changed, 59 insertions(+), 25 deletions(-) diff --git a/arch/x86/cpu/intel_common/acpi.c b/arch/x86/cpu/intel_common/acpi.c index a4d5fbd38a..4496bbfd99 100644 --- a/arch/x86/cpu/intel_common/acpi.c +++ b/arch/x86/cpu/intel_common/acpi.c @@ -198,7 +198,7 @@ int southbridge_inject_dsdt(const struct udevice *dev, struct acpi_ctx *ctx) struct acpi_global_nvs *gnvs; int ret; - ret = bloblist_ensure_size(BLOBLISTT_ACPI_GNVS, sizeof(*gnvs), + ret = bloblist_ensure_size(BLOBLISTT_ACPI_GNVS, sizeof(*gnvs), 0, (void **)&gnvs); if (ret) return log_msg_ret("bloblist", ret); diff --git a/arch/x86/cpu/intel_common/intel_opregion.c b/arch/x86/cpu/intel_common/intel_opregion.c index 4e6c64d9aa..c95ae04992 100644 --- a/arch/x86/cpu/intel_common/intel_opregion.c +++ b/arch/x86/cpu/intel_common/intel_opregion.c @@ -108,7 +108,7 @@ int intel_gma_init_igd_opregion(struct udevice *dev, struct optionrom_vbt *ext_vbt; ret = bloblist_ensure_size(BLOBLISTT_INTEL_VBT, - vbt->hdr_vbt_size, + vbt->hdr_vbt_size, 0, (void **)&ext_vbt); if (ret) { log_err("GMA: Unable to add Ext VBT to bloblist\n"); diff --git a/common/bloblist.c b/common/bloblist.c index 173f28d8ec..33b5862380 100644 --- a/common/bloblist.c +++ b/common/bloblist.c @@ -83,18 +83,25 @@ static struct bloblist_rec *bloblist_findrec(uint tag) return NULL; } -static int bloblist_addrec(uint tag, int size, struct bloblist_rec **recp) +static int bloblist_addrec(uint tag, int size, int align, + struct bloblist_rec **recp) { struct bloblist_hdr *hdr = gd->bloblist; struct bloblist_rec *rec; int data_start, new_alloced; + if (!align) + align = BLOBLIST_ALIGN; + /* Figure out where the new data will start */ - data_start = hdr->alloced + sizeof(*rec); - data_start = ALIGN(data_start, BLOBLIST_ALIGN); + data_start = map_to_sysmem(hdr) + hdr->alloced + sizeof(*rec); + + /* Align the address and then calculate the offset from ->alloced */ + data_start = ALIGN(data_start, align) - map_to_sysmem(hdr); /* Calculate the new allocated total */ - new_alloced = data_start + ALIGN(size, BLOBLIST_ALIGN); + new_alloced = data_start + ALIGN(size, align); + if (new_alloced >= hdr->size) { log(LOGC_BLOBLIST, LOGL_ERR, "Failed to allocate %x bytes size=%x, need size=%x\n", @@ -117,7 +124,8 @@ static int bloblist_addrec(uint tag, int size, struct bloblist_rec **recp) return 0; } -static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size) +static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size, + int align) { struct bloblist_rec *rec; @@ -130,7 +138,7 @@ static int bloblist_ensurerec(uint tag, struct bloblist_rec **recp, int size) } else { int ret; - ret = bloblist_addrec(tag, size, &rec); + ret = bloblist_addrec(tag, size, align, &rec); if (ret) return ret; } @@ -152,22 +160,22 @@ void *bloblist_find(uint tag, int size) return (void *)rec + rec->hdr_size; } -void *bloblist_add(uint tag, int size) +void *bloblist_add(uint tag, int size, int align) { struct bloblist_rec *rec; - if (bloblist_addrec(tag, size, &rec)) + if (bloblist_addrec(tag, size, align, &rec)) return NULL; return (void *)rec + rec->hdr_size; } -int bloblist_ensure_size(uint tag, int size, void **blobp) +int bloblist_ensure_size(uint tag, int size, int align, void **blobp) { struct bloblist_rec *rec; int ret; - ret = bloblist_ensurerec(tag, &rec, size); + ret = bloblist_ensurerec(tag, &rec, size, align); if (ret) return ret; *blobp = (void *)rec + rec->hdr_size; @@ -179,7 +187,7 @@ void *bloblist_ensure(uint tag, int size) { struct bloblist_rec *rec; - if (bloblist_ensurerec(tag, &rec, size)) + if (bloblist_ensurerec(tag, &rec, size, 0)) return NULL; return (void *)rec + rec->hdr_size; @@ -190,7 +198,7 @@ int bloblist_ensure_size_ret(uint tag, int *sizep, void **blobp) struct bloblist_rec *rec; int ret; - ret = bloblist_ensurerec(tag, &rec, *sizep); + ret = bloblist_ensurerec(tag, &rec, *sizep, 0); if (ret == -ESPIPE) *sizep = rec->size; else if (ret) diff --git a/include/bloblist.h b/include/bloblist.h index 6c37cd2a63..965d8e9a29 100644 --- a/include/bloblist.h +++ b/include/bloblist.h @@ -132,10 +132,11 @@ void *bloblist_find(uint tag, int size); * * @tag: Tag to add (enum bloblist_tag_t) * @size: Size of the blob + * @align: Alignment of the blob (in bytes), 0 for default * @return pointer to the newly added block, or NULL if there is not enough * space for the blob */ -void *bloblist_add(uint tag, int size); +void *bloblist_add(uint tag, int size, int align); /** * bloblist_ensure_size() - Find or add a blob @@ -145,10 +146,11 @@ void *bloblist_add(uint tag, int size); * @tag: Tag to add (enum bloblist_tag_t) * @size: Size of the blob * @blobp: Returns a pointer to blob on success + * @align: Alignment of the blob (in bytes), 0 for default * @return 0 if OK, -ENOSPC if it is missing and could not be added due to lack * of space, or -ESPIPE it exists but has the wrong size */ -int bloblist_ensure_size(uint tag, int size, void **blobp); +int bloblist_ensure_size(uint tag, int size, int align, void **blobp); /** * bloblist_ensure() - Find or add a blob diff --git a/test/bloblist.c b/test/bloblist.c index 6853523764..0bb9e2d81e 100644 --- a/test/bloblist.c +++ b/test/bloblist.c @@ -25,10 +25,10 @@ enum { TEST_SIZE = 10, TEST_SIZE2 = 20, - TEST_SIZE_LARGE = 0xe0, + TEST_SIZE_LARGE = 0x3e0, TEST_ADDR = CONFIG_BLOBLIST_ADDR, - TEST_BLOBLIST_SIZE = 0x100, + TEST_BLOBLIST_SIZE = 0x400, ERASE_BYTE = '\xff', }; @@ -100,7 +100,7 @@ static int bloblist_test_blob(struct unit_test_state *uts) ut_asserteq(map_to_sysmem(hdr), TEST_ADDR); /* Add a record and check that we can find it */ - data = bloblist_add(TEST_TAG, TEST_SIZE); + data = bloblist_add(TEST_TAG, TEST_SIZE, 0); rec = (void *)(hdr + 1); ut_asserteq_addr(rec + 1, data); data = bloblist_find(TEST_TAG, TEST_SIZE); @@ -206,10 +206,10 @@ static int bloblist_test_checksum(struct unit_test_state *uts) hdr->chksum--; /* Make sure the checksum changes when we add blobs */ - data = bloblist_add(TEST_TAG, TEST_SIZE); + data = bloblist_add(TEST_TAG, TEST_SIZE, 0); ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE)); - data2 = bloblist_add(TEST_TAG2, TEST_SIZE2); + data2 = bloblist_add(TEST_TAG2, TEST_SIZE2, 0); ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE)); ut_assertok(bloblist_finish()); @@ -255,9 +255,9 @@ static int bloblist_test_cmd_info(struct unit_test_state *uts) console_record_reset(); run_command("bloblist info", 0); ut_assert_nextline("base: %lx", (ulong)map_to_sysmem(hdr)); - ut_assert_nextline("size: 100 256 Bytes"); + ut_assert_nextline("size: 400 1 KiB"); ut_assert_nextline("alloced: 70 112 Bytes"); - ut_assert_nextline("free: 90 144 Bytes"); + ut_assert_nextline("free: 390 912 Bytes"); ut_assert_console_end(); gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD); @@ -298,6 +298,8 @@ BLOBLIST_TEST(bloblist_test_cmd_list, 0); static int bloblist_test_align(struct unit_test_state *uts) { struct bloblist_hdr *hdr; + ulong addr; + char *data; int i; /* At the start there should be no records */ @@ -305,14 +307,14 @@ static int bloblist_test_align(struct unit_test_state *uts) ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0)); ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE)); - /* Check the alignment */ + /* Check the default alignment */ for (i = 0; i < 3; i++) { int size = i * 3; ulong addr; char *data; int j; - data = bloblist_add(i, size); + data = bloblist_add(i, size, 0); ut_assertnonnull(data); addr = map_to_sysmem(data); ut_asserteq(0, addr & (BLOBLIST_ALIGN - 1)); @@ -324,6 +326,28 @@ static int bloblist_test_align(struct unit_test_state *uts) ut_asserteq(ERASE_BYTE, data[j]); } + /* Check larger alignment */ + for (i = 0; i < 3; i++) { + int align = 32 << i; + + data = bloblist_add(3 + i, i * 4, align); + ut_assertnonnull(data); + addr = map_to_sysmem(data); + ut_asserteq(0, addr & (align - 1)); + } + + /* Check alignment with an bloblist starting on a smaller alignment */ + hdr = map_sysmem(TEST_ADDR + BLOBLIST_ALIGN, TEST_BLOBLIST_SIZE); + memset(hdr, ERASE_BYTE, TEST_BLOBLIST_SIZE); + memset(hdr, '\0', sizeof(*hdr)); + ut_assertok(bloblist_new(TEST_ADDR + BLOBLIST_ALIGN, TEST_BLOBLIST_SIZE, + 0)); + + data = bloblist_add(1, 5, BLOBLIST_ALIGN * 2); + ut_assertnonnull(data); + addr = map_to_sysmem(data); + ut_asserteq(0, addr & (BLOBLIST_ALIGN * 2 - 1)); + return 0; } BLOBLIST_TEST(bloblist_test_align, 0);