diff --git a/app/debug_overlay.conf b/app/debug_overlay.conf index 439af1b67ea0..86cc10c745fe 100644 --- a/app/debug_overlay.conf +++ b/app/debug_overlay.conf @@ -1,6 +1,9 @@ CONFIG_DEBUG=y CONFIG_ASSERT=y +CONFIG_ZTEST=y +CONFIG_SOF_BOOT_TEST=y + # Following options can be enabled additionally, # but will incur a higher runtime cost, so are thus # disabled by default. diff --git a/app/src/main.c b/app/src/main.c index 7a622556b1ae..0f5c1f84fe0e 100644 --- a/app/src/main.c +++ b/app/src/main.c @@ -20,7 +20,7 @@ int sof_main(int argc, char *argv[]); * TODO: Here comes SOF initialization */ -int main(void) +static int sof_app_main(void) { int ret; @@ -49,3 +49,16 @@ int main(void) #endif return 0; } + +#if CONFIG_ZTEST +void test_main(void) +{ + sof_app_main(); + k_sleep(K_FOREVER); +} +#else +int main(void) +{ + return sof_app_main(); +} +#endif diff --git a/src/include/sof/boot_test.h b/src/include/sof/boot_test.h new file mode 100644 index 000000000000..965eec06a6a9 --- /dev/null +++ b/src/include/sof/boot_test.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + */ + +#ifndef __SOF_BOOT_TEST_H__ +#define __SOF_BOOT_TEST_H__ + +#include + +#define TEST_RUN_ONCE(fn, ...) do { \ + static bool once; \ + if (!once) { \ + once = true; \ + fn(__VA_ARGS__); \ + } \ +} while (0) + +#define TEST_CHECK_RET(ret, testname) do { \ + if ((ret) < 0) { \ + LOG_ERR(testname " failed: %d", (ret)); \ + ztest_test_fail(); \ + } else { \ + ztest_test_pass(); \ + } \ +} while (0) + +#endif diff --git a/src/ipc/ipc4/handler.c b/src/ipc/ipc4/handler.c index 1d92879b32d6..52b7f039a788 100644 --- a/src/ipc/ipc4/handler.c +++ b/src/ipc/ipc4/handler.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,11 @@ #include #include +#if CONFIG_SOF_BOOT_TEST +/* CONFIG_SOF_BOOT_TEST depends on Zephyr */ +#include +#endif + #include #include #include @@ -1527,4 +1533,14 @@ 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/CMakeLists.txt b/zephyr/CMakeLists.txt index b4d729bada78..ccba83b4ab82 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -129,7 +129,7 @@ endmacro() add_subdirectory(../src/init/ init_unused_install/) add_subdirectory(../src/ipc/ ipc_unused_install/) - +add_subdirectory(test/) # Old way below: all .c files added by this giant CMake file. @@ -810,6 +810,10 @@ zephyr_library_sources_ifdef(CONFIG_DW_DMA ${SOF_DRIVERS_PATH}/dw/dma.c ) +zephyr_library_sources_ifdef(CONFIG_SOF_BOOT_TEST + boot_test.c +) + zephyr_library_link_libraries(SOF) target_link_libraries(SOF INTERFACE zephyr_interface) diff --git a/zephyr/Kconfig b/zephyr/Kconfig index ea8c1d6e809f..3d9a0b841231 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -67,4 +67,14 @@ config CROSS_CORE_STREAM can be processed on different cores, however, each stream is processed entirely on single core. +config SOF_BOOT_TEST + bool "enable SOF run-time testing" + depends on ZTEST + help + Run tests during boot. This enables an SOF boot-time self-test. When + enabled, the resulting image will run a number of self-tests when the + first global IPC command is received, i.e. when SOF is completely + initialized. After that SOF will continue running and be usable as + usual. + endif diff --git a/zephyr/boot_test.c b/zephyr/boot_test.c new file mode 100644 index 000000000000..bd1b22a95062 --- /dev/null +++ b/zephyr/boot_test.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2023 Intel Corporation. All rights reserved. + */ + +#include + +#include + +LOG_MODULE_REGISTER(sof_boot_test, LOG_LEVEL_DBG); + +ZTEST_SUITE(sof_boot, NULL, NULL, NULL, NULL, NULL); diff --git a/zephyr/test/CMakeLists.txt b/zephyr/test/CMakeLists.txt new file mode 100644 index 000000000000..e0718b8e0754 --- /dev/null +++ b/zephyr/test/CMakeLists.txt @@ -0,0 +1,5 @@ +if (CONFIG_ACE_VERSION_1_5) + zephyr_library_sources_ifdef(CONFIG_SOF_BOOT_TEST + vmh.c + ) +endif() diff --git a/zephyr/test/vmh.c b/zephyr/test/vmh.c new file mode 100644 index 000000000000..038413607ce3 --- /dev/null +++ b/zephyr/test/vmh.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2023 Intel Corporation. All rights reserved. + * + * Author: Guennadi Liakhovetski + */ + +#include +#include + +#include +#include +#include + +#include +#include + +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"); +}