From 964588513d593f2d88b1dd07fde1031bc2aafbd1 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 9 Jan 2026 18:50:05 +0200 Subject: [PATCH 1/2] zephyr: userspace_helper: add user_access_to_mailbox() Add helper function to make memory regions needed for sof/mailbox.h available to a user thread. Signed-off-by: Kai Vehmanen --- zephyr/include/rtos/userspace_helper.h | 8 +++++ zephyr/lib/userspace_helper.c | 46 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/zephyr/include/rtos/userspace_helper.h b/zephyr/include/rtos/userspace_helper.h index a09280077a64..f1363189e31b 100644 --- a/zephyr/include/rtos/userspace_helper.h +++ b/zephyr/include/rtos/userspace_helper.h @@ -91,4 +91,12 @@ int user_stack_free(void *p_stack); */ void module_driver_heap_remove(struct k_heap *mod_drv_heap); +/** + * Add access to mailbox.h interface to a user-space thread. + * + * @param domain memory domain to add the mailbox partitions to + * @param thread_id user-space thread for which access is added + */ +int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id); + #endif /* __ZEPHYR_LIB_USERSPACE_HELPER_H__ */ diff --git a/zephyr/lib/userspace_helper.c b/zephyr/lib/userspace_helper.c index 817e381bc3db..9bf84138ee4e 100644 --- a/zephyr/lib/userspace_helper.c +++ b/zephyr/lib/userspace_helper.c @@ -18,6 +18,7 @@ #include #include #include +#include #define MODULE_DRIVER_HEAP_CACHED CONFIG_SOF_ZEPHYR_HEAP_CACHED @@ -82,6 +83,46 @@ int user_memory_init_shared(k_tid_t thread_id, struct processing_module *mod) return k_mem_domain_add_thread(comp_dom, thread_id); } +int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id) +{ + struct k_mem_partition mem_partition; + int ret; + + /* + * Start with mailbox_swregs. This is aligned with mailbox.h + * implementation with uncached addressed used for register I/O. + */ + mem_partition.start = + (uintptr_t)sys_cache_uncached_ptr_get((void __sparse_cache *)MAILBOX_SW_REG_BASE); + + BUILD_ASSERT(MAILBOX_SW_REG_SIZE == CONFIG_MMU_PAGE_SIZE); + mem_partition.size = CONFIG_MMU_PAGE_SIZE; + mem_partition.attr = K_MEM_PARTITION_P_RW_U_RW; + + ret = k_mem_domain_add_partition(domain, &mem_partition); + if (ret < 0) + return ret; + +#ifndef CONFIG_IPC_MAJOR_4 + /* + * Next mailbox_stream (not available in IPC4). Stream access is cached, + * so different mapping this time. + */ + mem_partition.start = + (uintptr_t)sys_cache_cached_ptr_get((void *)SRAM_STREAM_BASE); + BUILD_ASSERT(MAILBOX_STREAM_SIZE == CONFIG_MMU_PAGE_SIZE); + /* size and attr the same as for mailbox_swregs */ + + ret = k_mem_domain_add_partition(domain, &mem_partition); + if (ret < 0) + return ret; +#endif + + k_mem_domain_add_thread(domain, thread_id); + + return 0; +} + #else /* CONFIG_USERSPACE */ void *user_stack_allocate(size_t stack_size, uint32_t options) @@ -102,4 +143,9 @@ int user_stack_free(void *p_stack) void module_driver_heap_remove(struct k_heap *mod_drv_heap) { } +int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id) +{ + return 0; +} + #endif /* CONFIG_USERSPACE */ From 619ee219deda3dbdbed7b29d75626edc9cd5c20e Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Fri, 9 Jan 2026 18:52:50 +0200 Subject: [PATCH 2/2] zephyr: test: userspace: add test_mailbox for sof/mailbox.h Add a user-space test for sof/mailbox.h interface usage. The test covers current usage of mailbox by SOF audio pipeline code. Signed-off-by: Kai Vehmanen --- zephyr/test/CMakeLists.txt | 4 + zephyr/test/userspace/README.md | 2 + zephyr/test/userspace/test_mailbox.c | 123 +++++++++++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 zephyr/test/userspace/test_mailbox.c diff --git a/zephyr/test/CMakeLists.txt b/zephyr/test/CMakeLists.txt index 0479014ed526..c0fabc414109 100644 --- a/zephyr/test/CMakeLists.txt +++ b/zephyr/test/CMakeLists.txt @@ -15,3 +15,7 @@ if (CONFIG_SOF_BOOT_TEST_STANDALONE AND CONFIG_SOF_USERSPACE_INTERFACE_DMA) zephyr_library_sources(userspace/test_intel_ssp_dai.c) endif() endif() + +if (CONFIG_SOF_BOOT_TEST_STANDALONE AND CONFIG_USERSPACE) + zephyr_library_sources(userspace/test_mailbox.c) +endif() diff --git a/zephyr/test/userspace/README.md b/zephyr/test/userspace/README.md index 46119f3753db..703a264ef430 100644 --- a/zephyr/test/userspace/README.md +++ b/zephyr/test/userspace/README.md @@ -12,6 +12,8 @@ Available tests: - Test Zephyr DAI interface, together with SOF DMA wrapper from a user thread. Mimics the call flows done in sof/src/audio/dai-zephyr.c. Use cavstool.py as host runner. +- test_mailbox.c + - Test use of sof/mailbox.h interface from a Zephyr user thread. Building for Intel Panther Lake: ./scripts/xtensa-build-zephyr.py --cmake-args=-DCONFIG_SOF_BOOT_TEST_STANDALONE=y \ diff --git a/zephyr/test/userspace/test_mailbox.c b/zephyr/test/userspace/test_mailbox.c new file mode 100644 index 000000000000..44ff458b661c --- /dev/null +++ b/zephyr/test/userspace/test_mailbox.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright(c) 2026 Intel Corporation. + */ + +/* + * Test case for sof/mailbox.h interface use from a Zephyr user + * thread. + */ + +#include +#include +#include + +#include +#include +#include +#include + +#include /* mailbox definitions */ + +LOG_MODULE_DECLARE(sof_boot_test, LOG_LEVEL_DBG); + +#define USER_STACKSIZE 2048 + +static struct k_thread user_thread; +static K_THREAD_STACK_DEFINE(user_stack, USER_STACKSIZE); + +static void mailbox_write_to_pipeline_regs(void) +{ + unsigned int offset = + offsetof(struct ipc4_fw_registers, pipeline_regs); + struct ipc4_pipeline_registers pipe_reg; + + pipe_reg.stream_start_offset = (uint64_t)-1; + pipe_reg.stream_end_offset = (uint64_t)-1; + + LOG_INF("Write to IPC4 pipeline regs at offset %u", offset); + + mailbox_sw_regs_write(offset, &pipe_reg, sizeof(pipe_reg)); +} + +/* + * the "stream" mailbox not available on targets using IPC4 + * layout for shared memory between host and DSP + */ +#ifdef CONFIG_IPC_MAJOR_4 +static void mailbox_write_to_stream_posn(void) +{ +} +#else +static void mailbox_write_to_stream_posn(void) +{ + struct sof_ipc_stream_posn posn; + size_t offset = 0; /* first stream position slot */ + + LOG_INF("Write to IPC4 stream#0 position info offset %u size %u.", + offset, sizeof(posn)); + + mailbox_stream_write(offset, &posn, sizeof(posn)); +} +#endif + +static void mailbox_test_thread(void *p1, void *p2, void *p3) +{ + zassert_true(k_is_user_context(), "isn't user"); + + LOG_INF("SOF thread %s (%s)", + k_is_user_context() ? "UserSpace!" : "privileged mode.", + CONFIG_BOARD_TARGET); + + mailbox_write_to_pipeline_regs(); + mailbox_write_to_stream_posn(); +} + +static void mailbox_test(void) +{ + struct k_mem_domain domain; + int ret = k_mem_domain_init(&domain, 0, NULL); + + zassert_equal(ret, 0); + + k_thread_create(&user_thread, user_stack, USER_STACKSIZE, + mailbox_test_thread, NULL, NULL, NULL, + -1, K_USER, K_FOREVER); + + LOG_INF("set up user access to mailbox"); + + ret = user_access_to_mailbox(&domain, &user_thread); + zassert_equal(ret, 0); + + k_thread_start(&user_thread); + + LOG_INF("user started, waiting in kernel until test complete"); + + k_thread_join(&user_thread, K_FOREVER); +} + +ZTEST(userspace_mailbox, mailbox_test) +{ + /* first test from kernel */ + mailbox_write_to_pipeline_regs(); + mailbox_write_to_stream_posn(); + + /* then full test in userspace */ + mailbox_test(); + + ztest_test_pass(); +} + +ZTEST_SUITE(userspace_mailbox, NULL, NULL, NULL, NULL, NULL); + +/** + * SOF main has booted up and IPC handling is stopped. + * Run test suites with ztest_run_all. + */ +static int run_tests(void) +{ + ztest_run_test_suite(userspace_mailbox, false, 1, 1, NULL); + return 0; +} + +SYS_INIT(run_tests, APPLICATION, 99);