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);
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;
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;
}
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[])
{