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