u-boot/test/bloblist.c
Simon Glass 751b7c7963 bloblist: Tidy up the data alignment
The intention which bloblists is that each blob's data is aligned in
memory. At present it is only the headers that are aligned.

Update the code to correct this and add a little more documentation.

Signed-off-by: Simon Glass <sjg@chromium.org>
2020-10-06 09:07:54 -06:00

341 lines
9.3 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2018, Google Inc. All rights reserved.
*/
#include <common.h>
#include <bloblist.h>
#include <log.h>
#include <mapmem.h>
#include <asm/state.h>
#include <test/suites.h>
#include <test/test.h>
#include <test/ut.h>
DECLARE_GLOBAL_DATA_PTR;
/* Declare a new compression test */
#define BLOBLIST_TEST(_name, _flags) \
UNIT_TEST(_name, _flags, bloblist_test)
enum {
TEST_TAG = 1,
TEST_TAG2 = 2,
TEST_TAG_MISSING = 3,
TEST_SIZE = 10,
TEST_SIZE2 = 20,
TEST_SIZE_LARGE = 0xe0,
TEST_ADDR = CONFIG_BLOBLIST_ADDR,
TEST_BLOBLIST_SIZE = 0x100,
ERASE_BYTE = '\xff',
};
static struct bloblist_hdr *clear_bloblist(void)
{
struct bloblist_hdr *hdr;
/*
* Clear out any existing bloblist so we have a clean slate. Zero the
* header so that existing records are removed, but set everything else
* to 0xff for testing purposes.
*/
hdr = map_sysmem(CONFIG_BLOBLIST_ADDR, TEST_BLOBLIST_SIZE);
memset(hdr, ERASE_BYTE, TEST_BLOBLIST_SIZE);
memset(hdr, '\0', sizeof(*hdr));
return hdr;
}
static int check_zero(void *data, int size)
{
u8 *ptr;
int i;
for (ptr = data, i = 0; i < size; i++, ptr++) {
if (*ptr)
return -EINVAL;
}
return 0;
}
static int bloblist_test_init(struct unit_test_state *uts)
{
struct bloblist_hdr *hdr;
hdr = clear_bloblist();
ut_asserteq(-ENOENT, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
hdr->version++;
ut_asserteq(-EPROTONOSUPPORT, bloblist_check(TEST_ADDR,
TEST_BLOBLIST_SIZE));
ut_asserteq(-ENOSPC, bloblist_new(TEST_ADDR, 0x10, 0));
ut_asserteq(-EFAULT, bloblist_new(1, TEST_BLOBLIST_SIZE, 0));
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
ut_assertok(bloblist_finish());
ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
hdr->flags++;
ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
return 1;
}
BLOBLIST_TEST(bloblist_test_init, 0);
static int bloblist_test_blob(struct unit_test_state *uts)
{
struct bloblist_hdr *hdr;
struct bloblist_rec *rec, *rec2;
char *data;
/* At the start there should be no records */
hdr = clear_bloblist();
ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
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);
rec = (void *)(hdr + 1);
ut_asserteq_addr(rec + 1, data);
data = bloblist_find(TEST_TAG, TEST_SIZE);
ut_asserteq_addr(rec + 1, data);
/* Check the data is zeroed */
ut_assertok(check_zero(data, TEST_SIZE));
/* Check the 'ensure' method */
ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
ut_assertnull(bloblist_ensure(TEST_TAG, TEST_SIZE2));
rec2 = (struct bloblist_rec *)(data + ALIGN(TEST_SIZE, BLOBLIST_ALIGN));
ut_assertok(check_zero(data, TEST_SIZE));
/* Check for a non-existent record */
ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
ut_asserteq_addr(rec2 + 1, bloblist_ensure(TEST_TAG2, TEST_SIZE2));
ut_assertnull(bloblist_find(TEST_TAG_MISSING, 0));
return 0;
}
BLOBLIST_TEST(bloblist_test_blob, 0);
/* Check bloblist_ensure_size_ret() */
static int bloblist_test_blob_ensure(struct unit_test_state *uts)
{
void *data, *data2;
int size;
/* At the start there should be no records */
clear_bloblist();
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
/* Test with an empty bloblist */
size = TEST_SIZE;
ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data));
ut_asserteq(TEST_SIZE, size);
ut_assertok(check_zero(data, TEST_SIZE));
/* Check that we get the same thing again */
ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data2));
ut_asserteq(TEST_SIZE, size);
ut_asserteq_addr(data, data2);
/* Check that the size remains the same */
size = TEST_SIZE2;
ut_assertok(bloblist_ensure_size_ret(TEST_TAG, &size, &data));
ut_asserteq(TEST_SIZE, size);
/* Check running out of space */
size = TEST_SIZE_LARGE;
ut_asserteq(-ENOSPC, bloblist_ensure_size_ret(TEST_TAG2, &size, &data));
return 0;
}
BLOBLIST_TEST(bloblist_test_blob_ensure, 0);
static int bloblist_test_bad_blob(struct unit_test_state *uts)
{
struct bloblist_hdr *hdr;
void *data;
hdr = clear_bloblist();
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
data = hdr + 1;
data += sizeof(struct bloblist_rec);
ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
ut_asserteq_addr(data, bloblist_ensure(TEST_TAG, TEST_SIZE));
return 0;
}
BLOBLIST_TEST(bloblist_test_bad_blob, 0);
static int bloblist_test_checksum(struct unit_test_state *uts)
{
struct bloblist_hdr *hdr;
char *data, *data2;
hdr = clear_bloblist();
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
ut_assertok(bloblist_finish());
ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
/*
* Now change things amd make sure that the checksum notices. We cannot
* change the size or alloced fields, since that will crash the code.
* It has to rely on these being correct.
*/
hdr->flags--;
ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
hdr->flags++;
hdr->size--;
ut_asserteq(-EFBIG, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
hdr->size++;
hdr->spare++;
ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
hdr->spare--;
hdr->chksum++;
ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
hdr->chksum--;
/* Make sure the checksum changes when we add blobs */
data = bloblist_add(TEST_TAG, TEST_SIZE);
ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
data2 = bloblist_add(TEST_TAG2, TEST_SIZE2);
ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
ut_assertok(bloblist_finish());
/* It should also change if we change the data */
ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
*data += 1;
ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
*data -= 1;
ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
*data2 += 1;
ut_asserteq(-EIO, bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
*data2 -= 1;
/*
* Changing data outside the range of valid data should not affect
* the checksum.
*/
ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
data[TEST_SIZE]++;
data2[TEST_SIZE2]++;
ut_assertok(bloblist_check(TEST_ADDR, TEST_BLOBLIST_SIZE));
return 0;
}
BLOBLIST_TEST(bloblist_test_checksum, 0);
/* Test the 'bloblist info' command */
static int bloblist_test_cmd_info(struct unit_test_state *uts)
{
struct sandbox_state *state = state_get_current();
struct bloblist_hdr *hdr;
char *data, *data2;
hdr = clear_bloblist();
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
data = bloblist_ensure(TEST_TAG, TEST_SIZE);
data2 = bloblist_ensure(TEST_TAG2, TEST_SIZE2);
console_record_reset_enable();
if (!state->show_test_output)
gd->flags |= GD_FLG_SILENT;
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("alloced: 70 112 Bytes");
ut_assert_nextline("free: 90 144 Bytes");
ut_assert_console_end();
gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
return 0;
}
BLOBLIST_TEST(bloblist_test_cmd_info, 0);
/* Test the 'bloblist list' command */
static int bloblist_test_cmd_list(struct unit_test_state *uts)
{
struct sandbox_state *state = state_get_current();
struct bloblist_hdr *hdr;
char *data, *data2;
hdr = clear_bloblist();
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
data = bloblist_ensure(TEST_TAG, TEST_SIZE);
data2 = bloblist_ensure(TEST_TAG2, TEST_SIZE2);
console_record_reset_enable();
if (!state->show_test_output)
gd->flags |= GD_FLG_SILENT;
console_record_reset();
run_command("bloblist list", 0);
ut_assert_nextline("Address Size Tag Name");
ut_assert_nextline("%08lx %8x 1 EC host event",
(ulong)map_to_sysmem(data), TEST_SIZE);
ut_assert_nextline("%08lx %8x 2 SPL hand-off",
(ulong)map_to_sysmem(data2), TEST_SIZE2);
ut_assert_console_end();
gd->flags &= ~(GD_FLG_SILENT | GD_FLG_RECORD);
return 0;
}
BLOBLIST_TEST(bloblist_test_cmd_list, 0);
/* Test alignment of bloblist blobs */
static int bloblist_test_align(struct unit_test_state *uts)
{
struct bloblist_hdr *hdr;
int i;
/* At the start there should be no records */
hdr = clear_bloblist();
ut_assertok(bloblist_new(TEST_ADDR, TEST_BLOBLIST_SIZE, 0));
ut_assertnull(bloblist_find(TEST_TAG, TEST_BLOBLIST_SIZE));
/* Check the alignment */
for (i = 0; i < 3; i++) {
int size = i * 3;
ulong addr;
char *data;
int j;
data = bloblist_add(i, size);
ut_assertnonnull(data);
addr = map_to_sysmem(data);
ut_asserteq(0, addr & (BLOBLIST_ALIGN - 1));
/* Only the bytes in the blob data should be zeroed */
for (j = 0; j < size; j++)
ut_asserteq(0, data[j]);
for (; j < BLOBLIST_ALIGN; j++)
ut_asserteq(ERASE_BYTE, data[j]);
}
return 0;
}
BLOBLIST_TEST(bloblist_test_align, 0);
int do_ut_bloblist(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
struct unit_test *tests = ll_entry_start(struct unit_test,
bloblist_test);
const int n_ents = ll_entry_count(struct unit_test, bloblist_test);
return cmd_ut_category("bloblist", "bloblist_test_",
tests, n_ents, argc, argv);
}