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