From ce824b5e41f690d4845d898e436f27a3c542142a Mon Sep 17 00:00:00 2001 From: Jakub Dabek Date: Tue, 23 Jan 2024 11:02:11 +0100 Subject: [PATCH 1/3] boot_test: change call of boot tests Boot tests were dependent on ipc. Change to run theme as part of zephyr boot process. Calls to zephyr api were deprecated and would not build with current zephyr version. Update the call. Signed-off-by: Jakub Dabek --- src/ipc/ipc4/handler.c | 10 ---------- zephyr/boot_test.c | 8 ++++++++ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c index e6696aee910c..08fa27e90658 100644 --- a/src/ipc/ipc4/handler.c +++ b/src/ipc/ipc4/handler.c @@ -1539,14 +1539,4 @@ void ipc_cmd(struct ipc_cmd_hdr *_hdr) ipc4_send_reply(&reply); } - -#if CONFIG_SOF_BOOT_TEST - /* - * When the first FW_GEN IPC has been processed we are in a stable - * running state, now if a test causes an exception, we have a good - * chance of capturing it. - */ - if (target == SOF_IPC4_MESSAGE_TARGET_FW_GEN_MSG) - TEST_RUN_ONCE(ztest_run_test_suite, sof_boot); -#endif } diff --git a/zephyr/boot_test.c b/zephyr/boot_test.c index bd1b22a95062..4cbbfa597d8b 100644 --- a/zephyr/boot_test.c +++ b/zephyr/boot_test.c @@ -4,9 +4,17 @@ */ #include +#include #include LOG_MODULE_REGISTER(sof_boot_test, LOG_LEVEL_DBG); ZTEST_SUITE(sof_boot, NULL, NULL, NULL, NULL, NULL); + +void sys_run_boot_tests(void) +{ + ztest_run_all(NULL, false, 1, 1); +} +SYS_INIT(sys_run_boot_tests, APPLICATION, 99); + From 13ba1b7704045cddf83a4876098dca4137e7de08 Mon Sep 17 00:00:00 2001 From: Jakub Dabek Date: Tue, 23 Jan 2024 11:27:15 +0100 Subject: [PATCH 2/3] vmh_tests: remove current vmh test implementation Remove current tests for vmh api. To be replaced by new implementation. Old implementation is not parametrized and only checks one scenario: create heap and allocate on it. New implementation will cover multiple heap creation, multiple allocations, checking allocated memory for physical page allocation among other scenarios. Remove whole implementation since there is no code reuse. Signed-off-by: Jakub Dabek --- zephyr/test/vmh.c | 75 +---------------------------------------------- 1 file changed, 1 insertion(+), 74 deletions(-) diff --git a/zephyr/test/vmh.c b/zephyr/test/vmh.c index 038413607ce3..0ac6311f3d88 100644 --- a/zephyr/test/vmh.c +++ b/zephyr/test/vmh.c @@ -17,81 +17,8 @@ LOG_MODULE_DECLARE(sof_boot_test, CONFIG_SOF_LOG_LEVEL); -#define ALLOC_SIZE1 1616 -#define ALLOC_SIZE2 26 - -static int vmh_test_single(bool span) -{ - struct vmh_heap *h = vmh_init_heap(NULL, MEM_REG_ATTR_CORE_HEAP, 0, span); - - if (!h) - return -EINVAL; - - char *buf = vmh_alloc(h, ALLOC_SIZE1); - int ret1; - - if (buf) { - buf[0] = 0; - buf[ALLOC_SIZE1 - 1] = 15; - - ret1 = vmh_free(h, buf); - if (ret1 < 0) - goto out; - } else if (span) { - ret1 = -ENOMEM; - LOG_ERR("Failed to allocate %u in contiguous mode", ALLOC_SIZE1); - goto out; - } else { - LOG_WRN("Ignoring failure to allocate %u in non-contiguous mode", - ALLOC_SIZE1); - } - - buf = vmh_alloc(h, ALLOC_SIZE2); - - if (!buf) { - ret1 = -ENOMEM; - LOG_ERR("Failed to allocate %u", ALLOC_SIZE2); - goto out; - } - - buf[0] = 0; - buf[ALLOC_SIZE2 - 1] = 15; - - ret1 = vmh_free(h, buf); - if (ret1 < 0) - LOG_ERR("Free error %d", ret1); - -out: - int ret2 = vmh_free_heap(h); - - if (ret2 < 0) - LOG_ERR("Free heap error %d", ret2); - - if (!ret1) - ret1 = ret2; - - return ret1; -} - -static int vmh_test(void) -{ - int ret = vmh_test_single(false); - - if (ret < 0) { - LOG_ERR("Non-contiguous test error %d", ret); - return ret; - } - - ret = vmh_test_single(true); - if (ret < 0) - LOG_ERR("Contiguous test error %d", ret); - - return ret; -} ZTEST(sof_boot, virtual_memory_heap) { - int ret = vmh_test(); - - TEST_CHECK_RET(ret, "virtual_memory_heap"); + TEST_CHECK_RET(true, "virtual_memory_heap"); } From 64bcd7500b78b7588f126910fe15357c5e519fcd Mon Sep 17 00:00:00 2001 From: Jakub Dabek Date: Tue, 23 Jan 2024 11:46:41 +0100 Subject: [PATCH 3/3] vmh_tests: Add set of parametrized tests and test suit Add enhanced vmh testing. Add tests for: heap creation, heap creation with config, multiple allocation tests for each heap mode. Signed-off-by: Jakub Dabek --- zephyr/test/vmh.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) diff --git a/zephyr/test/vmh.c b/zephyr/test/vmh.c index 0ac6311f3d88..c7d3d1882cc6 100644 --- a/zephyr/test/vmh.c +++ b/zephyr/test/vmh.c @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -17,8 +18,263 @@ LOG_MODULE_DECLARE(sof_boot_test, CONFIG_SOF_LOG_LEVEL); +/* Test creating and freeing a virtual memory heap */ +static void test_vmh_init_and_free_heap(int memory_region_attribute, + struct vmh_heap_config *config, + int core_id, + bool allocating_continuously, + bool expect_success) +{ + struct vmh_heap *heap = vmh_init_heap(config, memory_region_attribute, + core_id, allocating_continuously); + if (expect_success) { + zassert_not_null(heap, + "Heap initialization expected to succeed but failed"); + } + else + zassert_is_null(heap, "Heap initialization expected to fail but succeeded"); + + if (heap) { + int ret = vmh_free_heap(heap); + + zassert_equal(ret, 0, "Failed to free heap"); + } +} + +/* Test for vmh_alloc and vmh_free */ +static void test_vmh_alloc_free_no_check(struct vmh_heap *heap, + uint32_t alloc_size, + bool expect_success) +{ + void *ptr = vmh_alloc(heap, alloc_size); + + if (expect_success) + zassert_not_null(ptr, "Allocation expected to succeed but failed"); + else + zassert_is_null(ptr, "Allocation expected to fail but succeeded"); + + if (ptr) { + int ret = vmh_free(heap, ptr); + + zassert_equal(ret, 0, "Failed to free allocated memory"); + } +} + +static void verify_memory_content(void *ptr, uint32_t alloc_size) +{ + + /* Calculate check positions end and middle if applicable */ + uint8_t *end_ptr = (uint8_t *)ptr + alloc_size - sizeof(uint32_t); + uint8_t *middle_ptr = (uint8_t *)ptr + (alloc_size / 2); + uint8_t test_value = 0xAA; + int test_write_size = 1; + + /* Write test pattern to the allocated memory beginning middle and end */ + memset(ptr, test_value, test_write_size); + memset(middle_ptr, test_value, test_write_size); + memset(end_ptr, test_value, test_write_size); + + /* Verify the written test pattern at all points */ + zassert_equal(*((uint8_t *)ptr), test_value, + "Memory content verification failed at the start"); + zassert_equal(*end_ptr, test_value, + "Memory content verification failed at the end"); + zassert_equal(*middle_ptr, test_value, + "Memory content verification failed in the middle"); +} + +/* Test function for vmh_alloc and vmh_free with memory read/write */ +static void test_vmh_alloc_free_check(struct vmh_heap *heap, + uint32_t alloc_size, + bool expect_success) +{ + void *ptr = vmh_alloc(heap, alloc_size); + + if (expect_success) + zassert_not_null(ptr, "Allocation expected to succeed but failed"); + else { + zassert_is_null(ptr, "Allocation expected to fail but succeeded"); + return; + } + + if (ptr) + verify_memory_content(ptr, alloc_size); + + int ret = vmh_free(heap, ptr); + + zassert_equal(ret, 0, "Failed to free allocated memory"); +} + +/* Test function for multiple allocations on the same heap with read/write */ +static void test_vmh_multiple_allocs(struct vmh_heap *heap, int num_allocs, + uint32_t min_alloc_size, + uint32_t max_alloc_size) +{ + void *ptrs[num_allocs]; + uint32_t alloc_size; + bool success; + int ret; + + /* Perform multiple allocations */ + for (int i = 0; i < num_allocs; i++) { + /* Generate a random allocation size between min_alloc_size and max_alloc_size */ + alloc_size = min_alloc_size + + k_cycle_get_32() % (max_alloc_size - min_alloc_size + 1); + + ptrs[i] = vmh_alloc(heap, alloc_size); + + if (!ptrs[i]) + LOG_INF("Test allocation failed for size: %d", alloc_size); + + zassert_true(ptrs[i] != NULL, + "Allocation of size %u expected to succeed but failed", + alloc_size); + + if (ptrs[i]) + verify_memory_content(ptrs[i], alloc_size); + } + + for (int i = 0; i < num_allocs; i++) { + if (ptrs[i]) { + ret = vmh_free(heap, ptrs[i]); + zassert_equal(ret, 0, "Failed to free allocated memory"); + } + } +} + +/* Test case for multiple allocations */ +static void test_vmh_alloc_multiple_times(bool allocating_continuously) +{ + struct vmh_heap *heap = + vmh_init_heap(NULL, MEM_REG_ATTR_CORE_HEAP, 0, allocating_continuously); + + zassert_not_null(heap, "Heap initialization failed"); + + /* Test multiple allocations with small sizes */ + test_vmh_multiple_allocs(heap, 16, 4, 8); + test_vmh_multiple_allocs(heap, 64, 4, 8); + test_vmh_multiple_allocs(heap, 16, 4, 1024); + test_vmh_multiple_allocs(heap, 64, 4, 1024); + if (allocating_continuously) { + test_vmh_multiple_allocs(heap, 16, 1024, 4096); + test_vmh_multiple_allocs(heap, 16, 4096, 8192); + } + + /* Clean up the heap after testing */ + int ret = vmh_free_heap(heap); + + zassert_equal(ret, 0, "Failed to free heap after multiple allocations"); +} + +/* Test case for vmh_alloc and vmh_free */ +static void test_vmh_alloc_free(bool allocating_continuously) +{ + struct vmh_heap *heap = + vmh_init_heap(NULL, MEM_REG_ATTR_CORE_HEAP, 0, allocating_continuously); + + zassert_not_null(heap, "Heap initialization failed"); + + test_vmh_alloc_free_no_check(heap, 512, true); + test_vmh_alloc_free_no_check(heap, 1024, true); + test_vmh_alloc_free_no_check(heap, sizeof(int), true); + test_vmh_alloc_free_no_check(heap, 0, false); + + test_vmh_alloc_free_check(heap, 512, true); + test_vmh_alloc_free_check(heap, 1024, true); + test_vmh_alloc_free_check(heap, sizeof(int), true); + test_vmh_alloc_free_check(heap, 0, false); + + int ret = vmh_free_heap(heap); + + zassert_equal(ret, 0, "Failed to free heap"); + + /* Could add tests with configs for heaps*/ +} + +/* Test case for vmh_alloc and vmh_free with and without config */ +static void test_heap_creation(void) +{ + test_vmh_init_and_free_heap(MEM_REG_ATTR_CORE_HEAP, NULL, 0, false, true); + + /* Try to setup with pre defined heap config */ + struct vmh_heap_config config = {0}; + + config.block_bundles_table[0].block_size = 8; + + config.block_bundles_table[0].number_of_blocks = 1024; + + config.block_bundles_table[1].block_size = 16; + + config.block_bundles_table[1].number_of_blocks = 512; + + test_vmh_init_and_free_heap(MEM_REG_ATTR_CORE_HEAP, &config, 0, false, true); +} + +/* Test case for alloc/free on configured heap */ +static void test_alloc_on_configured_heap(bool allocating_continuously) +{ + + /* Try to setup with pre defined heap config */ + struct vmh_heap_config config = {0}; + + config.block_bundles_table[0].block_size = 32; + + config.block_bundles_table[0].number_of_blocks = 256; + + /* Create continuous allocation heap for success test */ + struct vmh_heap *heap = + vmh_init_heap(&config, MEM_REG_ATTR_CORE_HEAP, 0, allocating_continuously); + + /* Will succeed on continuous and fail with single block alloc */ + test_vmh_alloc_free_check(heap, 512, allocating_continuously); + + int ret = vmh_free_heap(heap); + + zassert_equal(ret, 0, "Failed to free heap"); +} + +/* Test cases for initializing heaps on all available regions */ +static void test_vmh_init_all_heaps(void) +{ + int num_regions = CONFIG_MP_MAX_NUM_CPUS + VIRTUAL_REGION_COUNT; + int i; + const struct sys_mm_drv_region *virtual_memory_region = + sys_mm_drv_query_memory_regions(); + + /* Test initializing all types of heaps */ + for (i = 0; i < num_regions; i++) { + + /* Zeroed size symbolizes end of regions table */ + if (!virtual_memory_region[i].size) + break; + + struct vmh_heap *heap = vmh_init_heap(NULL, virtual_memory_region[i].attr, + i, true); + + zassert_not_null(heap, "Heap initialization expected to succeed but failed"); + + /* Test if it fails when heap already exists */ + test_vmh_init_and_free_heap(virtual_memory_region[i].attr, NULL, i, true, + false); + + if (heap) { + int ret = vmh_free_heap(heap); + + zassert_equal(ret, 0, "Failed to free heap"); + } + } +} ZTEST(sof_boot, virtual_memory_heap) { + test_heap_creation(); + test_vmh_init_all_heaps(); + test_alloc_on_configured_heap(true); + test_alloc_on_configured_heap(false); + test_vmh_alloc_free(true); + test_vmh_alloc_free(false); + test_vmh_alloc_multiple_times(true); + test_vmh_alloc_multiple_times(false); + TEST_CHECK_RET(true, "virtual_memory_heap"); }