All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: U-Boot Mailing List <u-boot@lists.denx.de>
Cc: Simon Glass <sjg@chromium.org>, Bin Meng <bmeng.cn@gmail.com>
Subject: [PATCH 15/22] bloblist: Support resizing a blob
Date: Mon,  5 Jul 2021 16:32:53 -0600	[thread overview]
Message-ID: <20210705223300.2139971-14-sjg@chromium.org> (raw)
In-Reply-To: <20210705223300.2139971-1-sjg@chromium.org>

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 <sjg@chromium.org>
---

 common/bloblist.c  |  71 ++++++++++++++++-
 include/bloblist.h |  13 +++
 test/bloblist.c    | 192 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 274 insertions(+), 2 deletions(-)

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[])
 {
-- 
2.32.0.93.g670b81a890-goog


  parent reply	other threads:[~2021-07-05 22:36 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-07-05 22:32 [PATCH 00/22] Various fixes and enhancements Simon Glass
2021-07-05 22:32 ` [PATCH 01/22] dm: core: Add logging for DM_SEQ_ALIAS Simon Glass
2021-07-05 22:32 ` [PATCH 02/22] dm: Support lzma in the flashmap Simon Glass
2021-07-05 22:32 ` [PATCH 03/22] test: Allow CONFIG_SPL_LOAD_FIT to be disabled Simon Glass
2021-07-05 22:32 ` [PATCH 04/22] test: Add DM_DMA " Simon Glass
2021-07-05 22:32 ` [PATCH 05/22] test: Avoid a build error with SPL Simon Glass
2021-07-05 22:32 ` [PATCH 06/22] Makefile: Avoid rebuilding .dtb files each time Simon Glass
2021-07-05 22:32 ` [PATCH 07/22] sandbox: Support executables for more phases Simon Glass
2021-07-05 22:32 ` [PATCH 08/22] sandbox: Add work-around for SDL2 display Simon Glass
2021-07-22  6:00   ` Heinrich Schuchardt
2021-07-22 13:28     ` Simon Glass
2021-07-05 22:32 ` [PATCH 09/22] sandbox: Use hinting with the display Simon Glass
2021-07-05 22:32 ` [PATCH 10/22] sandbox: Adjust the bloblist default address Simon Glass
2021-07-05 22:32 ` [PATCH 11/22] cros_ec: Allow reading the battery-charge state Simon Glass
2021-07-05 22:32 ` [PATCH 12/22] cros_ec: Drop cros_ec_entering_mode() Simon Glass
2021-07-05 22:32 ` [PATCH 13/22] cros_ec: Support the full-size vboot context Simon Glass
2021-07-05 22:32 ` [PATCH 14/22] cros_ec: Use standard calls for recovery-request checking Simon Glass
2021-07-05 22:32 ` Simon Glass [this message]
2021-07-05 22:32 ` [PATCH 16/22] bloblist: Tidy up a few API comments Simon Glass
2021-07-05 22:32 ` [PATCH 17/22] bloblist: Correct condition in bloblist_addrec() Simon Glass
2021-07-05 22:32 ` [PATCH 18/22] image: Allow @ in node names when not using signatures Simon Glass
2021-07-17 20:40   ` Simon Glass
2021-07-05 22:32 ` [PATCH 19/22] spl: Provide more information on boot failure Simon Glass
2021-07-05 22:32 ` [PATCH 20/22] sandbox: mmc: Support fixed MMC devices Simon Glass
2021-07-06  1:12   ` Jaehoon Chung
2021-07-17 20:39   ` Simon Glass
2021-07-05 22:32 ` [PATCH 21/22] blk: Support iteration Simon Glass
2021-07-05 22:33 ` [PATCH 22/22] log: Allow padding of the function name Simon Glass
2021-07-17 20:39 ` Simon Glass
2021-07-17 20:39 ` [PATCH 21/22] blk: Support iteration Simon Glass
2021-07-17 20:39 ` [PATCH 19/22] spl: Provide more information on boot failure Simon Glass
2021-07-17 20:39 ` [PATCH 17/22] bloblist: Correct condition in bloblist_addrec() Simon Glass
2021-07-17 20:39 ` [PATCH 16/22] bloblist: Tidy up a few API comments Simon Glass
2021-07-17 20:39 ` [PATCH 15/22] bloblist: Support resizing a blob Simon Glass
2021-07-17 20:39 ` [PATCH 14/22] cros_ec: Use standard calls for recovery-request checking Simon Glass
2021-07-17 20:39 ` [PATCH 13/22] cros_ec: Support the full-size vboot context Simon Glass
2021-07-17 20:39 ` [PATCH 12/22] cros_ec: Drop cros_ec_entering_mode() Simon Glass
2021-07-17 20:39 ` [PATCH 11/22] cros_ec: Allow reading the battery-charge state Simon Glass
2021-07-17 20:39 ` [PATCH 10/22] sandbox: Adjust the bloblist default address Simon Glass
2021-07-17 20:39 ` [PATCH 09/22] sandbox: Use hinting with the display Simon Glass
2021-07-17 20:39 ` [PATCH 08/22] sandbox: Add work-around for SDL2 display Simon Glass
2021-07-17 20:39 ` [PATCH 07/22] sandbox: Support executables for more phases Simon Glass
2021-07-17 20:39 ` [PATCH 06/22] Makefile: Avoid rebuilding .dtb files each time Simon Glass
2021-07-18 13:34   ` Masahiro Yamada
2021-07-22  2:13     ` Simon Glass
2021-07-17 20:39 ` [PATCH 05/22] test: Avoid a build error with SPL Simon Glass
2021-07-17 20:39 ` [PATCH 04/22] test: Add DM_DMA to be disabled Simon Glass
2021-07-17 20:39 ` [PATCH 03/22] test: Allow CONFIG_SPL_LOAD_FIT " Simon Glass
2021-07-17 20:39 ` [PATCH 02/22] dm: Support lzma in the flashmap Simon Glass
2021-07-17 20:39 ` [PATCH 01/22] dm: core: Add logging for DM_SEQ_ALIAS Simon Glass

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210705223300.2139971-14-sjg@chromium.org \
    --to=sjg@chromium.org \
    --cc=bmeng.cn@gmail.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.