1 /*
2  * Copyright (c) 2020 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/irq_offload.h>
8 #include <zephyr/internal/syscall_handler.h>
9 
10 #include <zephyr/ztest.h>
11 #include <zephyr/ztest_error_hook.h>
12 
13 #define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
14 #define THREAD_TEST_PRIORITY 5
15 
16 static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
17 static struct k_thread tdata;
18 
19 static ZTEST_BMEM int case_type;
20 
21 /* A semaphore using inside irq_offload */
22 extern struct k_sem offload_sem;
23 
24 /* test case type */
25 enum {
26 	ZTEST_CATCH_FATAL_ACCESS,
27 	ZTEST_CATCH_FATAL_ILLEAGAL_INSTRUCTION,
28 	ZTEST_CATCH_FATAL_DIVIDE_ZERO,
29 	ZTEST_CATCH_FATAL_K_PANIC,
30 	ZTEST_CATCH_FATAL_K_OOPS,
31 	ZTEST_CATCH_FATAL_IN_ISR,
32 	ZTEST_CATCH_ASSERT_FAIL,
33 	ZTEST_CATCH_ASSERT_IN_ISR,
34 	ZTEST_CATCH_USER_FATAL_K_OOPS,
35 	ZTEST_ERROR_MAX
36 } error_case_type;
37 
38 
trigger_assert_fail(void * a)39 static void trigger_assert_fail(void *a)
40 {
41 	/* trigger an assert fail condition */
42 	__ASSERT(a != NULL, "parameter a should not be NULL!");
43 }
44 
45 /*
46  * Do not optimize to prevent GCC from generating invalid
47  * opcode exception instruction instead of real instruction.
48  */
trigger_fault_illegal_instruction(void)49 __no_optimization static void trigger_fault_illegal_instruction(void)
50 {
51 	void *a = NULL;
52 
53 	/* execute an illegal instruction */
54 	((void(*)(void))&a)();
55 #ifdef CONFIG_RX
56 	/*
57 	 * Intentionally execute an illegal instruction by calling a NULL pointer.
58 	 * Optimization is disabled to avoid GCC internal error during DWARF frame generation.
59 	 * __builtin_unreachable() hints to the compiler that control flow never returns here,
60 	 * which prevents faulty CFA emission on RX targets.
61 	 */
62 	__builtin_unreachable();
63 #endif
64 }
65 
66 /*
67  * Do not optimize to prevent GCC from generating invalid
68  * opcode exception instruction instead of real instruction.
69  */
trigger_fault_access(void)70 __no_optimization static void trigger_fault_access(void)
71 {
72 #if defined(CONFIG_SOC_ARC_IOT) || defined(CONFIG_SOC_FAMILY_NSIM_ARC_CLASSIC) || \
73 	defined(CONFIG_SOC_FAMILY_NSIM_ARC_V) || defined(CONFIG_SOC_EMSK)
74 	/* For iotdk, em_starterkit and ARC/nSIM, nSIM simulates full address space of
75 	 * memory, iotdk has eflash at 0x0 address, em_starterkit has ICCM at 0x0 address,
76 	 * access to 0x0 address doesn't generate any exception. So we access to 0XFFFFFFFF
77 	 * address instead to trigger exception. See issue #31419.
78 	 */
79 	void *a = (void *)0xFFFFFFFF;
80 #elif defined(CONFIG_CPU_CORTEX_M) || defined(CONFIG_CPU_AARCH32_CORTEX_R) || \
81 	defined(CONFIG_CPU_AARCH64_CORTEX_R)
82 	/* As this test case only runs when User Mode is enabled,
83 	 * accessing _current always triggers a memory access fault,
84 	 * and is guaranteed not to trigger SecureFault exceptions.
85 	 */
86 	void *a = (void *)_current;
87 #else
88 	/* For most arch which support userspace, dereferencing NULL
89 	 * pointer will be caught by exception.
90 	 *
91 	 * Note: this is not applicable for ARM Cortex-M:
92 	 * In Cortex-M, nPRIV read access to address 0x0 is generally allowed,
93 	 * provided that it is "mapped" e.g. when CONFIG_FLASH_BASE_ADDRESS is
94 	 * 0x0. So, de-referencing NULL pointer is not guaranteed to trigger an
95 	 * exception.
96 	 */
97 	void *a = (void *)NULL;
98 #endif
99 	/* access an illegal address */
100 	volatile int b = *((int *)a);
101 
102 	printk("b is %d\n", b);
103 }
104 
105 
106 /*
107  * Do not optimize the divide instruction. GCC will generate invalid
108  * opcode exception instruction instead of real divide instruction.
109  */
trigger_fault_divide_zero(void)110 __no_optimization static void trigger_fault_divide_zero(void)
111 {
112 	int a = 1;
113 	int b = 0;
114 
115 	/* divide by zero */
116 	a = a / b;
117 	printk("a is %d\n", a);
118 
119 /*
120  * While no optimization is enabled, some QEMU such as QEMU cortex a53
121  * series, QEMU mps2 and mps3 series and QEMU ARC series boards will not
122  * trigger an exception for divide zero. They might need to enable the divide
123  * zero exception. We only skip the QEMU board here, this means this
124  * test will still apply on the physical board.
125  * For the Cortex-M0, M0+, M23 (CONFIG_ARMV6_M_ARMV8_M_BASELINE)
126  * which does not include a divide instruction, the test is skipped,
127  * and there will be no hardware exception for that.
128  * For ARMv8-R, divide by zero trapping is not supported in hardware.
129  */
130 #if (defined(CONFIG_SOC_SERIES_MPS2) && defined(CONFIG_QEMU_TARGET)) || \
131 	(defined(CONFIG_SOC_SERIES_MPS3) && defined(CONFIG_QEMU_TARGET)) || \
132 	defined(CONFIG_BOARD_QEMU_CORTEX_A53) || defined(CONFIG_SOC_QEMU_ARC) || \
133 	defined(CONFIG_SOC_CORTEX_R8_VIRTUAL) || \
134 	defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) || \
135 	defined(CONFIG_BOARD_QEMU_CORTEX_R5) || \
136 	defined(CONFIG_ARMV8_R) || defined(CONFIG_AARCH32_ARMV8_R) || \
137 	defined(CONFIG_BOARD_FVP_BASE_REVC_2XAEM) || \
138 	defined(CONFIG_SOC_NSIM_EM11D)
139 	ztest_test_skip();
140 #endif
141 }
142 
trigger_fault_oops(void)143 static void trigger_fault_oops(void)
144 {
145 	k_oops();
146 }
147 
trigger_fault_panic(void)148 static void trigger_fault_panic(void)
149 {
150 	k_panic();
151 }
152 
release_offload_sem(void)153 static void release_offload_sem(void)
154 {
155 	/* Semaphore used inside irq_offload needs to be
156 	 * released after an assert or a fault has happened.
157 	 */
158 	k_sem_give(&offload_sem);
159 }
160 
161 /* This is the fatal error hook that allows you to do actions after
162  * the fatal error has occurred. This is optional; you can choose
163  * to define the hook yourself. If not, the program will use the
164  * default one.
165  */
ztest_post_fatal_error_hook(unsigned int reason,const struct arch_esf * pEsf)166 void ztest_post_fatal_error_hook(unsigned int reason,
167 		const struct arch_esf *pEsf)
168 {
169 	switch (case_type) {
170 	case ZTEST_CATCH_FATAL_ACCESS:
171 	case ZTEST_CATCH_FATAL_ILLEAGAL_INSTRUCTION:
172 	case ZTEST_CATCH_FATAL_DIVIDE_ZERO:
173 	case ZTEST_CATCH_FATAL_K_PANIC:
174 	case ZTEST_CATCH_FATAL_K_OOPS:
175 	case ZTEST_CATCH_USER_FATAL_K_OOPS:
176 		zassert_true(true);
177 		break;
178 
179 	/* Unfortunately, the case of trigger a fatal error
180 	 * inside ISR context still cannot be dealt with,
181 	 * So please don't use it this way.
182 	 */
183 	case ZTEST_CATCH_FATAL_IN_ISR:
184 		zassert_true(false);
185 		break;
186 	default:
187 		zassert_true(false);
188 		break;
189 	}
190 }
191 
192 /* This is the assert fail post hook that allows you to do actions after
193  * the assert fail happened. This is optional, you can choose to define
194  * the hook yourself. If not, the program will use the default one.
195  */
ztest_post_assert_fail_hook(void)196 void ztest_post_assert_fail_hook(void)
197 {
198 	switch (case_type) {
199 	case ZTEST_CATCH_ASSERT_FAIL:
200 		ztest_test_pass();
201 		break;
202 	case ZTEST_CATCH_ASSERT_IN_ISR:
203 		release_offload_sem();
204 		ztest_test_pass();
205 		break;
206 
207 	default:
208 		ztest_test_fail();
209 		break;
210 	}
211 }
212 
tThread_entry(void * p1,void * p2,void * p3)213 static void tThread_entry(void *p1, void *p2, void *p3)
214 {
215 	ARG_UNUSED(p2);
216 	ARG_UNUSED(p3);
217 
218 	int sub_type = *(int *)p1;
219 
220 	printk("case type is %d\n", case_type);
221 
222 	ztest_set_fault_valid(false);
223 
224 	switch (sub_type) {
225 	case ZTEST_CATCH_FATAL_ACCESS:
226 		ztest_set_fault_valid(true);
227 		trigger_fault_access();
228 		break;
229 	case ZTEST_CATCH_FATAL_ILLEAGAL_INSTRUCTION:
230 		ztest_set_fault_valid(true);
231 		trigger_fault_illegal_instruction();
232 		break;
233 	case ZTEST_CATCH_FATAL_DIVIDE_ZERO:
234 		ztest_set_fault_valid(true);
235 		trigger_fault_divide_zero();
236 		break;
237 	case ZTEST_CATCH_FATAL_K_PANIC:
238 		ztest_set_fault_valid(true);
239 		trigger_fault_panic();
240 		break;
241 	case ZTEST_CATCH_FATAL_K_OOPS:
242 		ztest_set_fault_valid(true);
243 		trigger_fault_oops();
244 		break;
245 
246 	default:
247 		break;
248 	}
249 
250 	/* should not reach here */
251 	ztest_test_fail();
252 }
253 
run_trigger_thread(int i)254 static int run_trigger_thread(int i)
255 {
256 	int ret;
257 	uint32_t perm = K_INHERIT_PERMS;
258 
259 	case_type = i;
260 
261 	if (k_is_user_context()) {
262 		perm = perm | K_USER;
263 	}
264 
265 	k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
266 			tThread_entry,
267 			(void *)&case_type, NULL, NULL,
268 			K_PRIO_PREEMPT(THREAD_TEST_PRIORITY),
269 			perm, K_NO_WAIT);
270 
271 	ret = k_thread_join(tid, K_FOREVER);
272 
273 	return ret;
274 }
275 
276 /**
277  * @brief Test if a fatal error can be caught
278  *
279  * @details Valid a fatal error we triggered in thread context works.
280  * If the fatal error happened and the program enter assert_post_handler,
281  * that means fatal error triggered as expected.
282  */
ZTEST_USER(error_hook_tests,test_catch_fatal_error)283 ZTEST_USER(error_hook_tests, test_catch_fatal_error)
284 {
285 #if defined(CONFIG_USERSPACE)
286 	run_trigger_thread(ZTEST_CATCH_FATAL_ACCESS);
287 	run_trigger_thread(ZTEST_CATCH_FATAL_ILLEAGAL_INSTRUCTION);
288 #if !defined(CONFIG_RISCV)
289 	/*
290 	 * Because RISC-V Arch doesn't trigger exception for division-by-zero,
291 	 * this test couldn't support RISC-V.
292 	 * (RISC-V ISA Manual v2.2, Ch6.2 Division Operation)
293 	 */
294 	run_trigger_thread(ZTEST_CATCH_FATAL_DIVIDE_ZERO);
295 #endif
296 #endif
297 	run_trigger_thread(ZTEST_CATCH_FATAL_K_PANIC);
298 	run_trigger_thread(ZTEST_CATCH_FATAL_K_OOPS);
299 }
300 
301 /**
302  * @brief Test if catching an assert works
303  *
304  * @details Valid the assert in thread context works or not. If the assert
305  * fail happened and the program enter assert_post_handler, that means
306  * assert works as expected.
307  */
ZTEST_USER(error_hook_tests,test_catch_assert_fail)308 ZTEST_USER(error_hook_tests, test_catch_assert_fail)
309 {
310 	case_type = ZTEST_CATCH_ASSERT_FAIL;
311 
312 	printk("1\n");
313 	ztest_set_assert_valid(false);
314 
315 	printk("2\n");
316 	ztest_set_assert_valid(true);
317 
318 	printk("3\n");
319 	trigger_assert_fail(NULL);
320 
321 	printk("4\n");
322 	ztest_test_fail();
323 }
324 
325 /* a handler using by irq_offload  */
tIsr_assert(const void * p)326 static void tIsr_assert(const void *p)
327 {
328 	ztest_set_assert_valid(true);
329 	trigger_assert_fail(NULL);
330 }
331 
332 /**
333  * @brief Test if an assert fail works in ISR context
334  *
335  * @details Valid the assert in ISR context works or not. If the assert
336  * fail happened and the program enter assert_post_handler, that means
337  * assert works as expected.
338  */
ZTEST(error_hook_tests,test_catch_assert_in_isr)339 ZTEST(error_hook_tests, test_catch_assert_in_isr)
340 {
341 	case_type = ZTEST_CATCH_ASSERT_IN_ISR;
342 	irq_offload(tIsr_assert, NULL);
343 }
344 
345 
346 #if defined(CONFIG_USERSPACE)
trigger_z_oops(void)347 static void trigger_z_oops(void)
348 {
349 	/* Set up a dummy syscall frame, pointing to a valid area in memory. */
350 	_current->syscall_frame = _image_ram_start;
351 
352 	K_OOPS(true);
353 }
354 
355 /**
356  * @brief Test if a z_oops can be catched
357  *
358  * @details Valid a z_oops we triggered in thread context works.
359  * If the z_oops happened and the program enter our handler,
360  * that means z_oops triggered as expected. This test only for
361  * userspace.
362  */
ZTEST(error_hook_tests,test_catch_z_oops)363 ZTEST(error_hook_tests, test_catch_z_oops)
364 {
365 	case_type = ZTEST_CATCH_USER_FATAL_K_OOPS;
366 
367 	ztest_set_fault_valid(true);
368 	trigger_z_oops();
369 }
370 #endif
371 
372 
error_hook_tests_setup(void)373 static void *error_hook_tests_setup(void)
374 {
375 #if defined(CONFIG_USERSPACE)
376 	k_thread_access_grant(k_current_get(), &tdata, &tstack);
377 #endif
378 	return NULL;
379 }
380 ZTEST_SUITE(error_hook_tests, NULL, error_hook_tests_setup, NULL, NULL, NULL);
381 
fail_assume_in_setup_setup(void)382 static void *fail_assume_in_setup_setup(void)
383 {
384 	/* Fail the assume, will skip all the tests */
385 	zassume_true(false);
386 	return NULL;
387 }
388 
389 ZTEST_SUITE(fail_assume_in_setup, NULL, fail_assume_in_setup_setup, NULL, NULL, NULL);
390 
391 ZTEST_EXPECT_SKIP(fail_assume_in_setup, test_to_skip0);
ZTEST(fail_assume_in_setup,test_to_skip0)392 ZTEST(fail_assume_in_setup, test_to_skip0)
393 {
394 	/* This test should never be run */
395 	ztest_test_fail();
396 }
397 
398 ZTEST_EXPECT_SKIP(fail_assume_in_setup, test_to_skip1);
ZTEST(fail_assume_in_setup,test_to_skip1)399 ZTEST(fail_assume_in_setup, test_to_skip1)
400 {
401 	/* This test should never be run */
402 	ztest_test_fail();
403 }
404 
fail_assume_in_before_before(void * unused)405 static void fail_assume_in_before_before(void *unused)
406 {
407 	ARG_UNUSED(unused);
408 	zassume_true(false);
409 }
410 
411 ZTEST_SUITE(fail_assume_in_before, NULL, NULL, fail_assume_in_before_before, NULL, NULL);
412 
413 ZTEST_EXPECT_SKIP(fail_assume_in_before, test_to_skip0);
ZTEST(fail_assume_in_before,test_to_skip0)414 ZTEST(fail_assume_in_before, test_to_skip0)
415 {
416 	/* This test should never be run */
417 	ztest_test_fail();
418 }
419 
420 ZTEST_EXPECT_SKIP(fail_assume_in_before, test_to_skip1);
ZTEST(fail_assume_in_before,test_to_skip1)421 ZTEST(fail_assume_in_before, test_to_skip1)
422 {
423 	/* This test should never be run */
424 	ztest_test_fail();
425 }
426 
427 ZTEST_SUITE(fail_assume_in_test, NULL, NULL, NULL, NULL, NULL);
428 
429 ZTEST_EXPECT_SKIP(fail_assume_in_test, test_to_skip);
ZTEST(fail_assume_in_test,test_to_skip)430 ZTEST(fail_assume_in_test, test_to_skip)
431 {
432 	zassume_true(false);
433 	ztest_test_fail();
434 }
435 
test_main(void)436 void test_main(void)
437 {
438 	ztest_run_test_suites(NULL, false, 1, 1);
439 	/* Can't run ztest_verify_all_test_suites_ran() since some tests are
440 	 * skipped by design.
441 	 */
442 }
443