From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-20.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 61DBAC07E99 for ; Mon, 5 Jul 2021 22:36:19 +0000 (UTC) Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D74656103E for ; Mon, 5 Jul 2021 22:36:18 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D74656103E Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=chromium.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 11C7982C6C; Tue, 6 Jul 2021 00:34:26 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (1024-bit key; unprotected) header.d=chromium.org header.i=@chromium.org header.b="DI1XO66z"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 6698582C1C; Tue, 6 Jul 2021 00:33:43 +0200 (CEST) Received: from mail-ot1-x330.google.com (mail-ot1-x330.google.com [IPv6:2607:f8b0:4864:20::330]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 84C5382A29 for ; Tue, 6 Jul 2021 00:33:25 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=chromium.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=sjg@chromium.org Received: by mail-ot1-x330.google.com with SMTP id r4-20020a0568301204b029047d1030ef5cso12792254otp.12 for ; Mon, 05 Jul 2021 15:33:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=fu4y558FRmG54tx0tXI7N1KEWHvw8kXX1hc0nB89MH0=; b=DI1XO66zMBx9Yc0bnkQAhOgctxmc6bNU6r4D05zCnHyVG6qZY/AIlFLPxf+qxylA0R U2VFnK6BKPBYkizMuXwkllJ92vbE8LxXm7vPO7EEpWwBTfbiAYcMZVtQJpKVfkrmhkhY X3j7XRqQ5zEZbLR66Wkbv17E6cbus/GSZq7Tg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=fu4y558FRmG54tx0tXI7N1KEWHvw8kXX1hc0nB89MH0=; b=GoTFvmSb9EfXaxZG6ZovGytUp62WcegcRytI2AiPybojVKp7FIF9zCXNUgENPhRWLF xxt33P4DVP0tb7qjsPs9B4rbCmX50o3OX1toE/0k4ZwQ4h0HIJZDNK25vKa3ybcn67ec YR0Iwh7wG02qAbV+u9GMpSgR4GkAWt/RnzVOXswlf+rR7JwxRwkpwedWEZKY/jtnC7qD fPff7BeUSJHFcXfd3QLXw/IIvDI5BFkT9jH6pc/xr9O7BXJqNKKeXzf20LzDGSNExIcj xZ0nMVfoDoRy68QJ/DDNqvq5sDbxYNwh9QU7Pz0tAm2f/kcHOJtC7/cJl8mSOwp3Xra9 LXXg== X-Gm-Message-State: AOAM531rQ7/xtY3s8LIlW35GPMn8eJ5D8oiUsqD4S+rRgtf5EN4SORWR 5UaJX0HwP4jhtFJGntHO6kCb46S3FRnhOj9E X-Google-Smtp-Source: ABdhPJzErE7EFIDIdneXAmsLNfhi6DFdB1YaEIWWfxGpv1zFmpSoqB8Eg0b4nclU6HOH2NysRB/osQ== X-Received: by 2002:a05:6830:241d:: with SMTP id j29mr12796748ots.371.1625524403952; Mon, 05 Jul 2021 15:33:23 -0700 (PDT) Received: from kiwi.bld.corp.google.com (c-67-190-101-114.hsd1.co.comcast.net. [67.190.101.114]) by smtp.gmail.com with ESMTPSA id u22sm1434938oie.26.2021.07.05.15.33.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 05 Jul 2021 15:33:23 -0700 (PDT) From: Simon Glass To: U-Boot Mailing List Cc: Simon Glass , Bin Meng Subject: [PATCH 15/22] bloblist: Support resizing a blob Date: Mon, 5 Jul 2021 16:32:53 -0600 Message-Id: <20210705223300.2139971-14-sjg@chromium.org> X-Mailer: git-send-email 2.32.0.93.g670b81a890-goog In-Reply-To: <20210705223300.2139971-1-sjg@chromium.org> References: <20210705223300.2139971-1-sjg@chromium.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean 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(-) 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