1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/tc_util.h>
10 #include <zephyr/kernel_structs.h>
11 #include <kernel_internal.h>
12 #include <assert.h>
13 
14 static ZTEST_DMEM volatile int expected_reason = -1;
15 
k_sys_fatal_error_handler(unsigned int reason,const struct arch_esf * pEsf)16 void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf)
17 {
18 	int rv = TC_PASS;
19 
20 	TC_PRINT("Caught system error -- reason %d\n", reason);
21 	if (reason != expected_reason) {
22 		TC_PRINT("Unexpected reason (exp: %d)\n", expected_reason);
23 		rv = TC_FAIL;
24 	}
25 	TC_END_RESULT_CUSTOM(rv, "test_fatal");
26 	TC_END_REPORT(rv);
27 	arch_system_halt(reason);
28 }
29 
entry_cpu_exception(void)30 static void entry_cpu_exception(void)
31 {
32 	expected_reason = K_ERR_CPU_EXCEPTION;
33 
34 	TC_PRINT("cpu exception\n");
35 #if defined(CONFIG_X86)
36 	__asm__ volatile ("ud2");
37 #elif defined(CONFIG_ARC)
38 	__asm__ volatile ("swi");
39 #else
40 	/* Triggers usage fault on ARM, illegal instruction on RISCV
41 	 * and xtensa
42 	 */
43 	{
44 		volatile long illegal = 0;
45 		((void(*)(void))&illegal)();
46 	}
47 #endif
48 }
49 
entry_oops(void)50 static void entry_oops(void)
51 {
52 	unsigned int key;
53 
54 	TC_PRINT("oops\n");
55 	expected_reason = K_ERR_KERNEL_OOPS;
56 
57 	key = irq_lock();
58 	k_oops();
59 	irq_unlock(key);
60 }
61 
entry_panic(void)62 static void entry_panic(void)
63 {
64 	unsigned int key;
65 
66 	TC_PRINT("panic\n");
67 	expected_reason = K_ERR_KERNEL_PANIC;
68 
69 	key = irq_lock();
70 	k_panic();
71 	irq_unlock(key);
72 }
73 
entry_zephyr_assert(void)74 static void entry_zephyr_assert(void)
75 {
76 	TC_PRINT("assert\n");
77 	expected_reason = K_ERR_KERNEL_PANIC;
78 
79 	__ASSERT(0, "intentionally failed assertion");
80 }
81 
entry_arbitrary_reason(void)82 static void entry_arbitrary_reason(void)
83 {
84 	unsigned int key;
85 
86 	TC_PRINT("arbitrary reason\n");
87 	expected_reason = INT_MAX;
88 
89 	key = irq_lock();
90 	z_except_reason(INT_MAX);
91 	irq_unlock(key);
92 }
93 
entry_arbitrary_reason_negative(void)94 static void entry_arbitrary_reason_negative(void)
95 {
96 	unsigned int key;
97 
98 	TC_PRINT("arbitrary reason (negative)\n");
99 	expected_reason = -2;
100 
101 	key = irq_lock();
102 	z_except_reason(-2);
103 	irq_unlock(key);
104 }
105 
106 typedef void (*exc_trigger_func_t)(void);
107 
108 static const exc_trigger_func_t exc_trigger_func[] = {
109 	entry_cpu_exception,
110 	entry_oops,
111 	entry_panic,
112 	entry_zephyr_assert,
113 	entry_arbitrary_reason,
114 	entry_arbitrary_reason_negative,
115 };
116 
117 /**
118  * @brief Verify the kernel fatal error handling works correctly
119  * @details Manually trigger the crash with various ways and check
120  * that the kernel is handling that properly or not. Also the crash reason
121  * should match.
122  *
123  * @ingroup kernel_fatal_tests
124  */
ZTEST(fatal_no_mt,test_fatal_no_mt)125 ZTEST(fatal_no_mt, test_fatal_no_mt)
126 {
127 #ifdef VIA_TWISTER
128 #define EXC_TRIGGER_FUNC_IDX VIA_TWISTER
129 #else
130 #define EXC_TRIGGER_FUNC_IDX 0
131 #endif
132 	exc_trigger_func[EXC_TRIGGER_FUNC_IDX]();
133 
134 	ztest_test_fail();
135 	TC_END_REPORT(TC_FAIL);
136 }
137 
138 ZTEST_SUITE(fatal_no_mt, NULL, NULL, NULL, NULL, NULL);
139