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