/* * Copyright (c) 2023 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #ifdef CONFIG_THREAD_STACK_MEM_MAPPED #define STACK_SIZE (CONFIG_MMU_PAGE_SIZE + CONFIG_TEST_EXTRA_STACK_SIZE) K_THREAD_STACK_DEFINE(mapped_thread_stack_area, STACK_SIZE); static struct k_thread mapped_thread_data; ZTEST_BMEM static char *mapped_stack_addr; ZTEST_BMEM static size_t mapped_stack_sz; /** * @brief To cause fault in guard pages. * * @param p1 0 if testing rear guard page, 1 if testing front guard page. * @param p2 Unused. * @param p3 Unused. */ void mapped_thread(void *p1, void *p2, void *p3) { bool is_front = p1 == NULL ? false : true; volatile char *ptr; ARG_UNUSED(p2); ARG_UNUSED(p3); TC_PRINT("Starts %s\n", __func__); TC_PRINT("Mapped stack %p size %zu\n", mapped_stack_addr, mapped_stack_sz); ptr = mapped_stack_addr; /* Figure out where to cause the stack fault. */ if (is_front) { /* Middle of front guard page. */ ptr -= CONFIG_MMU_PAGE_SIZE / 2; } else { /* Middle of rear guard page. */ ptr += mapped_stack_sz; ptr += CONFIG_MMU_PAGE_SIZE / 2; } TC_PRINT("Trying to cause stack fault at %p\n", ptr); *ptr = 0; TC_PRINT("Should have fault on guard page but not!\n"); ztest_test_fail(); } /** * @brief To create thread to fault on guard pages. * * @param is_front True if testing front guard page, false if testing rear guard page. * @param is_user True if creating a user thread, false if creating a kernel thread. */ void create_thread(bool is_front, bool is_user) { /* Start thread */ k_thread_create(&mapped_thread_data, mapped_thread_stack_area, STACK_SIZE, mapped_thread, is_front ? (void *)1 : (void *)0, NULL, NULL, K_PRIO_COOP(1), is_user ? K_USER : 0, K_FOREVER); zassert_true(mapped_thread_data.stack_info.mapped.addr != NULL); /* Grab the mapped stack object address and size so we can calculate * where to cause a stack fault. */ mapped_stack_addr = (void *)mapped_thread_data.stack_info.mapped.addr; mapped_stack_sz = mapped_thread_data.stack_info.mapped.sz; k_thread_start(&mapped_thread_data); /* Note that this sleep is required on SMP platforms where * that thread will execute asynchronously! */ k_sleep(K_MSEC(100)); k_thread_join(&mapped_thread_data, K_FOREVER); } #endif /* CONFIG_THREAD_STACK_MEM_MAPPED */ /** * @brief Test faulting on front guard page * * @ingroup kernel_memprotect_tests */ ZTEST(stackprot_mapped_stack, test_guard_page_front) { #ifdef CONFIG_THREAD_STACK_MEM_MAPPED create_thread(true, false); #else ztest_test_skip(); #endif } /** * @brief Test faulting on rear guard page * * @ingroup kernel_memprotect_tests */ ZTEST(stackprot_mapped_stack, test_guard_page_rear) { #ifdef CONFIG_THREAD_STACK_MEM_MAPPED create_thread(false, false); #else ztest_test_skip(); #endif } /** * @brief Test faulting on front guard page in user mode * * @ingroup kernel_memprotect_tests */ ZTEST(stackprot_mapped_stack, test_guard_page_front_user) { #ifdef CONFIG_THREAD_STACK_MEM_MAPPED create_thread(true, true); #else ztest_test_skip(); #endif } /** * @brief Test faulting on rear guard page in user mode * * @ingroup kernel_memprotect_tests */ ZTEST(stackprot_mapped_stack, test_guard_page_rear_user) { #ifdef CONFIG_THREAD_STACK_MEM_MAPPED create_thread(false, true); #else ztest_test_skip(); #endif } ZTEST_SUITE(stackprot_mapped_stack, NULL, NULL, NULL, NULL, NULL);