1 /*
2 * Copyright (c) 2023 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/kernel/thread_stack.h>
10
11 #ifdef CONFIG_THREAD_STACK_MEM_MAPPED
12
13 #define STACK_SIZE (CONFIG_MMU_PAGE_SIZE + CONFIG_TEST_EXTRA_STACK_SIZE)
14
15 K_THREAD_STACK_DEFINE(mapped_thread_stack_area, STACK_SIZE);
16 static struct k_thread mapped_thread_data;
17
18 ZTEST_BMEM static char *mapped_stack_addr;
19 ZTEST_BMEM static size_t mapped_stack_sz;
20
21 /**
22 * @brief To cause fault in guard pages.
23 *
24 * @param p1 0 if testing rear guard page, 1 if testing front guard page.
25 * @param p2 Unused.
26 * @param p3 Unused.
27 */
mapped_thread(void * p1,void * p2,void * p3)28 void mapped_thread(void *p1, void *p2, void *p3)
29 {
30 bool is_front = p1 == NULL ? false : true;
31 volatile char *ptr;
32
33 ARG_UNUSED(p2);
34 ARG_UNUSED(p3);
35
36 TC_PRINT("Starts %s\n", __func__);
37 TC_PRINT("Mapped stack %p size %zu\n", mapped_stack_addr, mapped_stack_sz);
38
39 ptr = mapped_stack_addr;
40
41 /* Figure out where to cause the stack fault. */
42 if (is_front) {
43 /* Middle of front guard page. */
44 ptr -= CONFIG_MMU_PAGE_SIZE / 2;
45 } else {
46 /* Middle of rear guard page. */
47 ptr += mapped_stack_sz;
48 ptr += CONFIG_MMU_PAGE_SIZE / 2;
49 }
50
51 TC_PRINT("Trying to cause stack fault at %p\n", ptr);
52
53 *ptr = 0;
54
55 TC_PRINT("Should have fault on guard page but not!\n");
56 ztest_test_fail();
57 }
58
59 /**
60 * @brief To create thread to fault on guard pages.
61 *
62 * @param is_front True if testing front guard page, false if testing rear guard page.
63 * @param is_user True if creating a user thread, false if creating a kernel thread.
64 */
create_thread(bool is_front,bool is_user)65 void create_thread(bool is_front, bool is_user)
66 {
67 /* Start thread */
68 k_thread_create(&mapped_thread_data, mapped_thread_stack_area, STACK_SIZE,
69 mapped_thread,
70 is_front ? (void *)1 : (void *)0,
71 NULL, NULL,
72 K_PRIO_COOP(1), is_user ? K_USER : 0, K_FOREVER);
73
74 zassert_true(mapped_thread_data.stack_info.mapped.addr != NULL);
75
76 /* Grab the mapped stack object address and size so we can calculate
77 * where to cause a stack fault.
78 */
79 mapped_stack_addr = (void *)mapped_thread_data.stack_info.mapped.addr;
80 mapped_stack_sz = mapped_thread_data.stack_info.mapped.sz;
81
82 k_thread_start(&mapped_thread_data);
83
84 /* Note that this sleep is required on SMP platforms where
85 * that thread will execute asynchronously!
86 */
87 k_sleep(K_MSEC(100));
88
89 k_thread_join(&mapped_thread_data, K_FOREVER);
90 }
91
92 #endif /* CONFIG_THREAD_STACK_MEM_MAPPED */
93
94 /**
95 * @brief Test faulting on front guard page
96 *
97 * @ingroup kernel_memprotect_tests
98 */
ZTEST(stackprot_mapped_stack,test_guard_page_front)99 ZTEST(stackprot_mapped_stack, test_guard_page_front)
100 {
101 #ifdef CONFIG_THREAD_STACK_MEM_MAPPED
102 create_thread(true, false);
103 #else
104 ztest_test_skip();
105 #endif
106 }
107
108 /**
109 * @brief Test faulting on rear guard page
110 *
111 * @ingroup kernel_memprotect_tests
112 */
ZTEST(stackprot_mapped_stack,test_guard_page_rear)113 ZTEST(stackprot_mapped_stack, test_guard_page_rear)
114 {
115 #ifdef CONFIG_THREAD_STACK_MEM_MAPPED
116 create_thread(false, false);
117 #else
118 ztest_test_skip();
119 #endif
120 }
121
122 /**
123 * @brief Test faulting on front guard page in user mode
124 *
125 * @ingroup kernel_memprotect_tests
126 */
ZTEST(stackprot_mapped_stack,test_guard_page_front_user)127 ZTEST(stackprot_mapped_stack, test_guard_page_front_user)
128 {
129 #ifdef CONFIG_THREAD_STACK_MEM_MAPPED
130 create_thread(true, true);
131 #else
132 ztest_test_skip();
133 #endif
134 }
135
136 /**
137 * @brief Test faulting on rear guard page in user mode
138 *
139 * @ingroup kernel_memprotect_tests
140 */
ZTEST(stackprot_mapped_stack,test_guard_page_rear_user)141 ZTEST(stackprot_mapped_stack, test_guard_page_rear_user)
142 {
143 #ifdef CONFIG_THREAD_STACK_MEM_MAPPED
144 create_thread(false, true);
145 #else
146 ztest_test_skip();
147 #endif
148 }
149
150
151 ZTEST_SUITE(stackprot_mapped_stack, NULL, NULL, NULL, NULL, NULL);
152