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_NIOS2)
38 	__asm__ volatile ("trap");
39 #elif defined(CONFIG_ARC)
40 	__asm__ volatile ("swi");
41 #else
42 	/* Triggers usage fault on ARM, illegal instruction on RISCV
43 	 * and xtensa
44 	 */
45 	{
46 		volatile long illegal = 0;
47 		((void(*)(void))&illegal)();
48 	}
49 #endif
50 }
51 
entry_oops(void)52 static void entry_oops(void)
53 {
54 	unsigned int key;
55 
56 	TC_PRINT("oops\n");
57 	expected_reason = K_ERR_KERNEL_OOPS;
58 
59 	key = irq_lock();
60 	k_oops();
61 	irq_unlock(key);
62 }
63 
entry_panic(void)64 static void entry_panic(void)
65 {
66 	unsigned int key;
67 
68 	TC_PRINT("panic\n");
69 	expected_reason = K_ERR_KERNEL_PANIC;
70 
71 	key = irq_lock();
72 	k_panic();
73 	irq_unlock(key);
74 }
75 
entry_zephyr_assert(void)76 static void entry_zephyr_assert(void)
77 {
78 	TC_PRINT("assert\n");
79 	expected_reason = K_ERR_KERNEL_PANIC;
80 
81 	__ASSERT(0, "intentionally failed assertion");
82 }
83 
entry_arbitrary_reason(void)84 static void entry_arbitrary_reason(void)
85 {
86 	unsigned int key;
87 
88 	TC_PRINT("arbitrary reason\n");
89 	expected_reason = INT_MAX;
90 
91 	key = irq_lock();
92 	z_except_reason(INT_MAX);
93 	irq_unlock(key);
94 }
95 
entry_arbitrary_reason_negative(void)96 static void entry_arbitrary_reason_negative(void)
97 {
98 	unsigned int key;
99 
100 	TC_PRINT("arbitrary reason (negative)\n");
101 	expected_reason = -2;
102 
103 	key = irq_lock();
104 	z_except_reason(-2);
105 	irq_unlock(key);
106 }
107 
108 typedef void (*exc_trigger_func_t)(void);
109 
110 static const exc_trigger_func_t exc_trigger_func[] = {
111 	entry_cpu_exception,
112 	entry_oops,
113 	entry_panic,
114 	entry_zephyr_assert,
115 	entry_arbitrary_reason,
116 	entry_arbitrary_reason_negative,
117 };
118 
119 /**
120  * @brief Test the kernel fatal error handling works correctly
121  * @details Manually trigger the crash with various ways and check
122  * that the kernel is handling that properly or not. Also the crash reason
123  * should match.
124  *
125  * @ingroup kernel_common_tests
126  */
ZTEST(fatal_no_mt,test_fatal)127 ZTEST(fatal_no_mt, test_fatal)
128 {
129 #ifdef VIA_TWISTER
130 #define EXC_TRIGGER_FUNC_IDX VIA_TWISTER
131 #else
132 #define EXC_TRIGGER_FUNC_IDX 0
133 #endif
134 	exc_trigger_func[EXC_TRIGGER_FUNC_IDX]();
135 
136 	ztest_test_fail();
137 	TC_END_REPORT(TC_FAIL);
138 }
139 
140 ZTEST_SUITE(fatal_no_mt, NULL, NULL, NULL, NULL, NULL);
141