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