1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <zephyr/arch/cpu.h>
9 #include <cmsis_core.h>
10 #include <zephyr/kernel_structs.h>
11 #include <zephyr/sys/barrier.h>
12 #include <offsets_short_arch.h>
13 #include <ksched.h>
14
15 #if !defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) && \
16 !defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
17 #error "Unsupported architecture"
18 #endif
19
20 #if defined(CONFIG_USERSPACE)
21
22 #define PRIORITY 0
23 #define DB_VAL 0xDEADBEEF
24
25 static struct k_thread user_thread;
26 static K_THREAD_STACK_DEFINE(user_thread_stack, 1024);
27
28 #include <zephyr/internal/syscall_handler.h>
29 #include "test_syscalls.h"
30
z_impl_test_arm_user_syscall(void)31 void z_impl_test_arm_user_syscall(void)
32 {
33 /* User thread system call
34 *
35 * Verify the following
36 * - mode variable indicates PRIV mode
37 * - the PSP is inside the thread's privileged stack
38 * - PSPLIM register guards the privileged stack
39 * - MSPLIM register still guards the interrupt stack
40 */
41 zassert_true((arch_current_thread()->arch.mode & CONTROL_nPRIV_Msk) == 0,
42 "mode variable not set to PRIV mode in system call\n");
43
44 zassert_false(arch_is_user_context(),
45 "arch_is_user_context() indicates nPRIV\n");
46
47 zassert_true(
48 ((__get_PSP() >= arch_current_thread()->arch.priv_stack_start) &&
49 (__get_PSP() < (arch_current_thread()->arch.priv_stack_start +
50 CONFIG_PRIVILEGED_STACK_SIZE))),
51 "Process SP outside thread privileged stack limits\n");
52
53 #if defined(CONFIG_BUILTIN_STACK_GUARD)
54 zassert_true(__get_PSPLIM() == arch_current_thread()->arch.priv_stack_start,
55 "PSPLIM not guarding the thread's privileged stack\n");
56 zassert_true(__get_MSPLIM() == (uint32_t)z_interrupt_stacks,
57 "MSPLIM not guarding the interrupt stack\n");
58 #endif
59 }
60
z_vrfy_test_arm_user_syscall(void)61 static inline void z_vrfy_test_arm_user_syscall(void)
62 {
63 z_impl_test_arm_user_syscall();
64 }
65 #include <zephyr/syscalls/test_arm_user_syscall_mrsh.c>
66
67
arm_isr_handler(const void * args)68 void arm_isr_handler(const void *args)
69 {
70 ARG_UNUSED(args);
71
72 /* Interrupt triggered while running a user thread
73 *
74 * Verify the following
75 * - mode variable indicates nPRIV mode
76 * - the PSP is inside the thread's default (user) stack
77 * - PSPLIM register is not set (applies on the second ISR call)
78 * - MSPLIM register still guards the interrupt stack
79 */
80
81 zassert_true((arch_current_thread()->arch.mode & CONTROL_nPRIV_Msk) != 0,
82 "mode variable not set to nPRIV mode for user thread\n");
83
84 zassert_false(arch_is_user_context(),
85 "arch_is_user_context() indicates nPRIV in ISR\n");
86
87 zassert_true(
88 ((__get_PSP() >= arch_current_thread()->stack_info.start) &&
89 (__get_PSP() < (arch_current_thread()->stack_info.start +
90 arch_current_thread()->stack_info.size))),
91 "Process SP outside thread stack limits\n");
92
93 static int first_call = 1;
94
95 if (first_call == 1) {
96 first_call = 0;
97
98 /* Trigger thread yield() manually */
99 (void)irq_lock();
100 z_move_thread_to_end_of_prio_q(arch_current_thread());
101 SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
102 irq_unlock(0);
103
104 } else if (first_call == 0) {
105 #if defined(CONFIG_BUILTIN_STACK_GUARD)
106 /* Second ISR run occurs after thread context-switch.
107 * We expect PSPLIM to be clear at this point.
108 */
109 zassert_true(__get_PSPLIM() == 0,
110 "PSPLIM not clear\n");
111 zassert_true(__get_MSPLIM() == (uint32_t)z_interrupt_stacks,
112 "MSPLIM not guarding the interrupt stack\n");
113 #endif
114 NVIC_DisableIRQ((uint32_t)args);
115 }
116 }
117
user_thread_entry(void * p1,void * p2,void * p3)118 static void user_thread_entry(void *p1, void *p2, void *p3)
119 {
120 ARG_UNUSED(p2);
121 ARG_UNUSED(p3);
122
123 uint32_t irq_line = POINTER_TO_INT(p1);
124 /* User Thread */
125 #if !defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
126 ARG_UNUSED(irq_line);
127 #endif
128 /* Trigger a system call to switch to supervisor thread
129 * mode and verify the thread state during system calls.
130 */
131 test_arm_user_syscall();
132
133 #if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
134
135 /*
136 * Trigger an ISR to switch to handler mode, to inspect
137 * the kernel structs and verify the thread state.
138 */
139 TC_PRINT("USR Thread: IRQ Line: %u\n", (uint32_t)irq_line);
140
141 NVIC->STIR = irq_line;
142 barrier_dsync_fence_full();
143 barrier_isync_fence_full();
144
145 /* ISR is set to cause thread to context-switch -out and -in again.
146 * We inspect for a second time, to verlfy the status, after
147 * the user thread is switch back in.
148 */
149 NVIC->STIR = irq_line;
150 barrier_dsync_fence_full();
151 barrier_isync_fence_full();
152 #endif
153 }
154
ZTEST(arm_thread_swap,test_arm_syscalls)155 ZTEST(arm_thread_swap, test_arm_syscalls)
156 {
157 int i = 0;
158
159 /* Supervisor Thread (ztest thread)
160 *
161 * Verify the following:
162 * - the "mode" variable indicates PRIV mode
163 * - arch_is_user_context() is negative
164 * - the PSP is inside the default thread stack
165 * - PSPLIM register guards the default stack
166 * - MSPLIM register guards the interrupt stack
167 */
168 zassert_true((arch_current_thread()->arch.mode & CONTROL_nPRIV_Msk) == 0,
169 "mode variable not set to PRIV mode for supervisor thread\n");
170
171 zassert_false(arch_is_user_context(),
172 "arch_is_user_context() indicates nPRIV\n");
173
174 zassert_true(
175 ((__get_PSP() >= arch_current_thread()->stack_info.start) &&
176 (__get_PSP() < (arch_current_thread()->stack_info.start +
177 arch_current_thread()->stack_info.size))),
178 "Process SP outside thread stack limits\n");
179
180 #if defined(CONFIG_BUILTIN_STACK_GUARD)
181 zassert_true(__get_PSPLIM() == arch_current_thread()->stack_info.start,
182 "PSPLIM not guarding the default stack\n");
183 zassert_true(__get_MSPLIM() == (uint32_t)z_interrupt_stacks,
184 "MSPLIM not guarding the interrupt stack\n");
185 #endif
186
187 #if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE)
188 for (i = CONFIG_NUM_IRQS - 1; i >= 0; i--) {
189 if (NVIC_GetEnableIRQ(i) == 0) {
190 /*
191 * Interrupts configured statically with IRQ_CONNECT(.)
192 * are automatically enabled. NVIC_GetEnableIRQ()
193 * returning false, here, implies that the IRQ line is
194 * either not implemented or it is not enabled, thus,
195 * currently not in use by Zephyr.
196 */
197
198 /* Set the NVIC line to pending. */
199 NVIC_SetPendingIRQ(i);
200
201 if (NVIC_GetPendingIRQ(i)) {
202 /* If the NVIC line is pending, it is
203 * guaranteed that it is implemented.
204 */
205 break;
206 }
207 }
208 }
209
210 zassert_true(i >= 0,
211 "No available IRQ line to use in the test\n");
212
213 TC_PRINT("Available IRQ line: %u\n", i);
214
215 arch_irq_connect_dynamic(i, 0 /* highest priority */,
216 arm_isr_handler,
217 (uint32_t *)i,
218 0);
219
220 NVIC_ClearPendingIRQ(i);
221 NVIC_EnableIRQ(i);
222
223 /* Allow the user thread to trigger an interrupt;
224 * this is *ONLY* done for testing purposes, here,
225 * i.e. to allow the inspection of the thread state
226 * while running in user mode.
227 */
228 SCB->CCR |= SCB_CCR_USERSETMPEND_Msk;
229 #endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE*/
230
231 /* Create and switch to a user thread, passing
232 * as argument the IRQ line to used in the test.
233 */
234 k_thread_create(&user_thread,
235 user_thread_stack,
236 K_THREAD_STACK_SIZEOF(user_thread_stack),
237 user_thread_entry,
238 (uint32_t *)i, NULL, NULL,
239 K_PRIO_COOP(PRIORITY), K_USER,
240 K_NO_WAIT);
241 }
242
z_impl_test_arm_cpu_write_reg(void)243 void z_impl_test_arm_cpu_write_reg(void)
244 {
245 /* User thread CPU write registers system call for testing
246 *
247 * Verify the following
248 * - Write 0xDEADBEEF values during system call into registers
249 * - In main test we will read that registers to verify
250 * that all of them were scrubbed and do not contain any sensitive data
251 */
252
253 /* Part below is made to test that kernel scrubs CPU registers
254 * after returning from the system call
255 */
256 TC_PRINT("Writing 0xDEADBEEF values into registers\n");
257 __asm__ volatile (
258 "ldr r0, =0xDEADBEEF;\n\t"
259 "ldr r1, =0xDEADBEEF;\n\t"
260 "ldr r2, =0xDEADBEEF;\n\t"
261 "ldr r3, =0xDEADBEEF;\n\t"
262 );
263 TC_PRINT("Exit from system call\n");
264 }
265
z_vrfy_test_arm_cpu_write_reg(void)266 static inline void z_vrfy_test_arm_cpu_write_reg(void)
267 {
268 z_impl_test_arm_cpu_write_reg();
269 }
270 #include <zephyr/syscalls/test_arm_cpu_write_reg_mrsh.c>
271
272 /**
273 * @brief Test CPU scrubs registers after system call
274 *
275 * @details - Call from user mode a syscall test_arm_cpu_write_reg(),
276 * the system call function writes into registers 0xDEADBEEF value
277 * - Then in main test function below check registers values,
278 * if no 0xDEADBEEF value detected, that means CPU scrubbed registers
279 * before exit from the system call.
280 *
281 * @ingroup kernel_memprotect_tests
282 */
ZTEST_USER(arm_thread_swap,test_syscall_cpu_scrubs_regs)283 ZTEST_USER(arm_thread_swap, test_syscall_cpu_scrubs_regs)
284 {
285 uint32_t arm_reg_val[4];
286
287 test_arm_cpu_write_reg();
288
289 __asm__ volatile ("mov %0, r0" : "=r"(arm_reg_val[0]));
290 __asm__ volatile ("mov %0, r1" : "=r"(arm_reg_val[1]));
291 __asm__ volatile ("mov %0, r2" : "=r"(arm_reg_val[2]));
292 __asm__ volatile ("mov %0, r3" : "=r"(arm_reg_val[3]));
293
294 for (int i = 0; i < 4; i++) {
295 zassert_not_equal(arm_reg_val[i], DB_VAL,
296 "register value is 0xDEADBEEF, "
297 "not scrubbed after system call.");
298 }
299 }
300 #else
ZTEST_USER(arm_thread_swap,test_syscall_cpu_scrubs_regs)301 ZTEST_USER(arm_thread_swap, test_syscall_cpu_scrubs_regs)
302 {
303 ztest_test_skip();
304 }
305
ZTEST(arm_thread_swap,test_arm_syscalls)306 ZTEST(arm_thread_swap, test_arm_syscalls)
307 {
308 ztest_test_skip();
309 }
310
311 #endif /* CONFIG_USERSPACE */
312 /**
313 * @}
314 */
315