Jan Dabros has uploaded this change for review.

View Change

tests: Add lib/bootmem-test test case

Signed-off-by: Jan Dabros <jsd@semihalf.com>
Change-Id: Ic1e539061ee5051d4158712a8a981a475ea7458a
---
M tests/lib/Makefile.inc
A tests/lib/bootmem-test.c
A tests/lib/bootmem-test.ld
3 files changed, 296 insertions(+), 0 deletions(-)

git pull ssh://review.coreboot.org:29418/coreboot refs/changes/10/43510/1
diff --git a/tests/lib/Makefile.inc b/tests/lib/Makefile.inc
index dae406a..69e3fd4 100644
--- a/tests/lib/Makefile.inc
+++ b/tests/lib/Makefile.inc
@@ -4,6 +4,7 @@
tests-y += b64_decode-test
tests-y += hexstrtobin-test
tests-y += memrange-test
+tests-y += bootmem-test

string-test-srcs += tests/lib/string-test.c
string-test-srcs += src/lib/string.c
@@ -19,3 +20,10 @@
memrange-test-srcs += src/lib/memrange.c
memrange-test-srcs += tests/stubs/console.c
memrange-test-srcs += tests/mocks/device/device_util.c
+
+bootmem-test-srcs += tests/lib/bootmem-test.c
+bootmem-test-srcs += src/lib/bootmem.c
+bootmem-test-srcs += src/lib/memrange.c
+bootmem-test-srcs += tests/stubs/console.c
+bootmem-test-srcs += tests/mocks/device/device_util.c
+bootmem-test-cflags += -Wl,--script=tests/lib/bootmem-test.ld
diff --git a/tests/lib/bootmem-test.c b/tests/lib/bootmem-test.c
new file mode 100644
index 0000000..8082720
--- /dev/null
+++ b/tests/lib/bootmem-test.c
@@ -0,0 +1,272 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <tests/test.h>
+#include <stdlib.h>
+
+#include <bootmem.h>
+#include <commonlib/coreboot_tables.h>
+#include <device/device.h>
+#include <device/resource.h>
+#include <memrange.h>
+#include <symbols.h>
+
+/* Stubs defined to satisfy linker dependencies */
+void cbmem_add_bootmem(void)
+{
+}
+
+void bootmem_arch_add_ranges(void)
+{
+}
+
+struct bootmem_ranges_t {
+ uint64_t start;
+ uint64_t size;
+ uint32_t type;
+};
+
+struct bootmem_ranges_t *os_ranges;
+struct bootmem_ranges_t *ranges;
+
+/* See tests/lib/bootmem-test.ld for boundaries definitions */
+extern u8 _ramstage_size[];
+#define PROGRAM_START ((uintptr_t)_program)
+#define RAMSTAGE_SIZE ((uintptr_t)_ramstage_size)
+#define CACHEABLE_START PROGRAM_START
+#define CACHEABLE_SIZE (1ULL << 32)
+#define CACHEABLE_END (CACHEABLE_START + CACHEABLE_SIZE)
+#define RESERVED_START (1ULL << 32)
+#define RESERVED_SIZE 0x100000
+#define RESERVED_END (RESERVED_START + RESERVED_SIZE)
+#define FIRST (RESERVED_END - CACHEABLE_START)
+
+/* Note that second region overlaps first */
+struct resource res_mock[] = {
+ { .base = CACHEABLE_START, .size = CACHEABLE_SIZE, .next = &res_mock[1],
+ .flags = IORESOURCE_CACHEABLE | IORESOURCE_MEM },
+ { .base = RESERVED_START, .size = RESERVED_SIZE, .next = NULL,
+ .flags = IORESOURCE_RESERVE | IORESOURCE_MEM }
+};
+
+/* Device simulating RAM */
+struct device mem_device_mock = {
+ .enabled = 1,
+ .resource_list = res_mock,
+ .next = NULL
+};
+
+/* Simplified version for the purpose of tests */
+static uint32_t bootmem_to_lb_tag(const enum bootmem_type tag)
+{
+ switch (tag) {
+ case BM_MEM_RAM:
+ return LB_MEM_RAM;
+ case BM_MEM_RESERVED:
+ return LB_MEM_RESERVED;
+ default:
+ return LB_MEM_RESERVED;
+ }
+}
+
+/* Bootmem layout for bootmem tests
+ *
+ * Regions marked with asteriks (***) are not visible for OS
+ *
+ * +-------+----CACHEABLE_MEMORY---------+-+ <-0x10000000
+ * | | ***PROGRAM*** | |
+ * | +-----------------------------+ | <-0x10040000
+ * | | ***STACK*** | |
+ * | +-----------------------------+ | <-0x10041000
+ * | |
+ * | |
+ * | |
+ * | +-------RESERVED_MEMORY-------+ | <-0x100000000
+ * | | | |
+ * | | | |
+ * | | | |
+ * | +-----------------------------+ | <-0x100100000
+ * | |
+ * | |
+ * +---------------------------------------+ <-0x110000000
+ *
+ */
+static int test_basic_setup(void **state)
+{
+ os_ranges = (struct bootmem_ranges_t *)malloc(3 * sizeof(*os_ranges));
+
+ if (!os_ranges)
+ return -1;
+
+ os_ranges[0].start = CACHEABLE_START;
+ os_ranges[0].size = RESERVED_START - CACHEABLE_START;
+ os_ranges[0].type = BM_MEM_RAM;
+
+ os_ranges[1].start = RESERVED_START;
+ os_ranges[1].size = RESERVED_SIZE;
+ os_ranges[1].type = BM_MEM_RESERVED;
+
+ os_ranges[2].start = RESERVED_END;
+ os_ranges[2].size = CACHEABLE_END - RESERVED_END;
+ os_ranges[2].type = BM_MEM_RAM;
+
+ return 0;
+}
+
+static int test_basic_teardown(void **state)
+{
+ free(os_ranges);
+
+ return 0;
+}
+
+/* This test need to be run first, in order to use bootmem library API */
+static void test_bootmem_write_mem_table(void **state)
+{
+ int i;
+ struct lb_memory *lb_mem;
+
+ will_return_always(search_global_resources, &mem_device_mock);
+
+ /* Allocate space for 5 lb_mem entries to be safe */
+ lb_mem = malloc(sizeof(*lb_mem) + 5 * sizeof(struct lb_memory_range));
+
+ bootmem_write_memory_table(lb_mem);
+
+ /* There should be only three entries visible in coreboot table */
+ assert_int_equal(lb_mem->size, 3 * sizeof(struct lb_memory_range));
+
+ for (i = 0; i < lb_mem->size / sizeof(struct lb_memory_range); i++) {
+ assert_int_equal(unpack_lb64(lb_mem->map[i].start), os_ranges[i].start);
+ assert_int_equal(unpack_lb64(lb_mem->map[i].size), os_ranges[i].size);
+ assert_int_equal(lb_mem->map[i].type, bootmem_to_lb_tag(os_ranges[i].type));
+ }
+
+ free(lb_mem);
+}
+
+int os_bootmem_walk_cnt;
+int bootmem_walk_cnt;
+
+static bool verify_os_bootmem_walk(const struct range_entry *r, void *arg)
+{
+ assert_int_equal(range_entry_base(r), os_ranges[os_bootmem_walk_cnt].start);
+ assert_int_equal(range_entry_size(r), os_ranges[os_bootmem_walk_cnt].size);
+ assert_int_equal(range_entry_tag(r), os_ranges[os_bootmem_walk_cnt].type);
+
+ os_bootmem_walk_cnt++;
+
+ return true;
+}
+
+static bool verify_bootmem_walk(const struct range_entry *r, void *arg)
+{
+ assert_int_equal(range_entry_base(r), ranges[bootmem_walk_cnt].start);
+ assert_int_equal(range_entry_size(r), ranges[bootmem_walk_cnt].size);
+ assert_int_equal(range_entry_tag(r), ranges[bootmem_walk_cnt].type);
+
+ bootmem_walk_cnt++;
+
+ return true;
+}
+
+static int test_bootmem_walk_setup(void **state)
+{
+ if (test_basic_setup(state) < 0)
+ return -1;
+
+ /* program and stack regions should be merged since they are neighbors */
+ ranges = (struct bootmem_ranges_t *)malloc(4 * sizeof(*os_ranges));
+
+ ranges[0].start = PROGRAM_START;
+ ranges[0].size = RAMSTAGE_SIZE;
+ ranges[0].type = BM_MEM_RAMSTAGE;
+
+ ranges[1].start = CACHEABLE_START + RAMSTAGE_SIZE;
+ ranges[1].size = RESERVED_START - ranges[1].start;
+ ranges[1].type = BM_MEM_RAM;
+
+ ranges[2].start = RESERVED_START;
+ ranges[2].size = RESERVED_SIZE;
+ ranges[2].type = BM_MEM_RESERVED;
+
+ ranges[3].start = RESERVED_END;
+ ranges[3].size = CACHEABLE_END - RESERVED_END;
+ ranges[3].type = BM_MEM_RAM;
+
+ os_bootmem_walk_cnt = 0;
+ bootmem_walk_cnt = 0;
+
+ return 0;
+}
+
+static int test_bootmem_walk_teardown(void **state)
+{
+ test_basic_teardown(state);
+
+ free(ranges);
+
+ return 0;
+}
+
+static void test_bootmem_walk(void **state)
+{
+ bootmem_walk_os_mem(verify_os_bootmem_walk, NULL);
+ bootmem_walk(verify_bootmem_walk, NULL);
+
+ assert_int_equal(os_bootmem_walk_cnt, 3);
+ assert_int_equal(bootmem_walk_cnt, 4);
+}
+
+static void test_bootmem_region_targets_type(void **state)
+{
+ int ret;
+
+ ret = bootmem_region_targets_type(PROGRAM_START, RAMSTAGE_SIZE, BM_MEM_RAMSTAGE);
+ assert_int_equal(ret, 1);
+
+ /* Below range covers two differently tagged regions */
+ ret = bootmem_region_targets_type(PROGRAM_START, RAMSTAGE_SIZE, BM_MEM_RAMSTAGE + 1);
+ assert_int_equal(ret, 0);
+}
+
+static void test_bootmem_allocate_buffer(void **state)
+{
+ void *buf;
+
+ /* All allocated buffers should be below 32bit boundary */
+ buf = bootmem_allocate_buffer((1ULL << 32));
+ assert_null(buf);
+
+ /* Try too big size for our BM_MEM_RAM range below 32bit boundary */
+ buf = bootmem_allocate_buffer(RESERVED_START - PROGRAM_START);
+ assert_null(buf);
+
+ /* Two working cases */
+ buf = bootmem_allocate_buffer(0xE0000000);
+ assert_non_null(buf);
+ assert_in_range((uintptr_t)buf, CACHEABLE_START + RAMSTAGE_SIZE, RESERVED_START);
+
+ buf = bootmem_allocate_buffer(0xF000000);
+ assert_non_null(buf);
+ assert_in_range((uintptr_t)buf, CACHEABLE_START + RAMSTAGE_SIZE, RESERVED_START);
+
+ /* Run out of memory for new allocations */
+ buf = bootmem_allocate_buffer(0x1000000);
+ assert_null(buf);
+}
+
+int main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(test_bootmem_write_mem_table,
+ test_basic_setup,
+ test_basic_teardown),
+ cmocka_unit_test_setup_teardown(test_bootmem_walk,
+ test_bootmem_walk_setup,
+ test_bootmem_walk_teardown),
+ cmocka_unit_test(test_bootmem_allocate_buffer),
+ cmocka_unit_test(test_bootmem_region_targets_type)
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff --git a/tests/lib/bootmem-test.ld b/tests/lib/bootmem-test.ld
new file mode 100644
index 0000000..eefef63
--- /dev/null
+++ b/tests/lib/bootmem-test.ld
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+/*
+ * Below values needs to be in sync with tests/lib/bootmem-test.c code,
+ * since there are some assumptions about overlapping regions, neighboring
+ * ones etc.
+ */
+SECTIONS {
+ _program = 0x10000000;
+ _eprogram = _program + 0x40000;
+ _stack = _eprogram;
+ _estack = _stack + 0x1000;
+ _ramstage_size = _estack - _program;
+}
+/* Below instruction is just for the default script not being overwritten by this helper */
+INSERT AFTER .rodata;

To view, visit change 43510. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: coreboot
Gerrit-Branch: master
Gerrit-Change-Id: Ic1e539061ee5051d4158712a8a981a475ea7458a
Gerrit-Change-Number: 43510
Gerrit-PatchSet: 1
Gerrit-Owner: Jan Dabros <jsd@semihalf.com>
Gerrit-MessageType: newchange