1 /*
2 * Copyright (c) 2019 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8
9 #include <kernel_internal.h>
10 #include <zephyr/kernel_structs.h>
11 #include <zephyr/sys/__assert.h>
12 #include <zephyr/arch/cpu.h>
13 #include <zephyr/logging/log_ctrl.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/fatal.h>
16 #include <zephyr/debug/coredump.h>
17
18 LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
19
20 /* LCOV_EXCL_START */
arch_system_halt(unsigned int reason)21 FUNC_NORETURN __weak void arch_system_halt(unsigned int reason)
22 {
23 ARG_UNUSED(reason);
24
25 /* TODO: What's the best way to totally halt the system if SMP
26 * is enabled?
27 */
28
29 (void)arch_irq_lock();
30 for (;;) {
31 /* Spin endlessly */
32 }
33 }
34 /* LCOV_EXCL_STOP */
35
36 /* LCOV_EXCL_START */
k_sys_fatal_error_handler(unsigned int reason,const z_arch_esf_t * esf)37 __weak void k_sys_fatal_error_handler(unsigned int reason,
38 const z_arch_esf_t *esf)
39 {
40 ARG_UNUSED(esf);
41
42 LOG_PANIC();
43 LOG_ERR("Halting system");
44 arch_system_halt(reason);
45 CODE_UNREACHABLE;
46 }
47 /* LCOV_EXCL_STOP */
48
thread_name_get(struct k_thread * thread)49 static const char *thread_name_get(struct k_thread *thread)
50 {
51 const char *thread_name = (thread != NULL) ? k_thread_name_get(thread) : NULL;
52
53 if ((thread_name == NULL) || (thread_name[0] == '\0')) {
54 thread_name = "unknown";
55 }
56
57 return thread_name;
58 }
59
reason_to_str(unsigned int reason)60 static const char *reason_to_str(unsigned int reason)
61 {
62 switch (reason) {
63 case K_ERR_CPU_EXCEPTION:
64 return "CPU exception";
65 case K_ERR_SPURIOUS_IRQ:
66 return "Unhandled interrupt";
67 case K_ERR_STACK_CHK_FAIL:
68 return "Stack overflow";
69 case K_ERR_KERNEL_OOPS:
70 return "Kernel oops";
71 case K_ERR_KERNEL_PANIC:
72 return "Kernel panic";
73 default:
74 return "Unknown error";
75 }
76 }
77
78 /* LCOV_EXCL_START */
k_fatal_halt(unsigned int reason)79 FUNC_NORETURN void k_fatal_halt(unsigned int reason)
80 {
81 arch_system_halt(reason);
82 }
83 /* LCOV_EXCL_STOP */
84
z_fatal_error(unsigned int reason,const z_arch_esf_t * esf)85 void z_fatal_error(unsigned int reason, const z_arch_esf_t *esf)
86 {
87 /* We can't allow this code to be preempted, but don't need to
88 * synchronize between CPUs, so an arch-layer lock is
89 * appropriate.
90 */
91 unsigned int key = arch_irq_lock();
92 struct k_thread *thread = IS_ENABLED(CONFIG_MULTITHREADING) ?
93 _current : NULL;
94
95 /* twister looks for the "ZEPHYR FATAL ERROR" string, don't
96 * change it without also updating twister
97 */
98 LOG_ERR(">>> ZEPHYR FATAL ERROR %d: %s on CPU %d", reason,
99 reason_to_str(reason), _current_cpu->id);
100
101 /* FIXME: This doesn't seem to work as expected on all arches.
102 * Need a reliable way to determine whether the fault happened when
103 * an IRQ or exception was being handled, or thread context.
104 *
105 * See #17656
106 */
107 #if defined(CONFIG_ARCH_HAS_NESTED_EXCEPTION_DETECTION)
108 if ((esf != NULL) && arch_is_in_nested_exception(esf)) {
109 LOG_ERR("Fault during interrupt handling\n");
110 }
111 #endif
112
113 LOG_ERR("Current thread: %p (%s)", thread,
114 thread_name_get(thread));
115
116 coredump(reason, esf, thread);
117
118 k_sys_fatal_error_handler(reason, esf);
119
120 /* If the system fatal error handler returns, then kill the faulting
121 * thread; a policy decision was made not to hang the system.
122 *
123 * Policy for fatal errors in ISRs: unconditionally panic.
124 *
125 * There is one exception to this policy: a stack sentinel
126 * check may be performed (on behalf of the current thread)
127 * during ISR exit, but in this case the thread should be
128 * aborted.
129 *
130 * Note that k_thread_abort() returns on some architectures but
131 * not others; e.g. on ARC, x86_64, Xtensa with ASM2, ARM
132 */
133 if (!IS_ENABLED(CONFIG_TEST)) {
134 __ASSERT(reason != K_ERR_KERNEL_PANIC,
135 "Attempted to recover from a kernel panic condition");
136 /* FIXME: #17656 */
137 #if defined(CONFIG_ARCH_HAS_NESTED_EXCEPTION_DETECTION)
138 if ((esf != NULL) && arch_is_in_nested_exception(esf)) {
139 #if defined(CONFIG_STACK_SENTINEL)
140 if (reason != K_ERR_STACK_CHK_FAIL) {
141 __ASSERT(0,
142 "Attempted to recover from a fatal error in ISR");
143 }
144 #endif /* CONFIG_STACK_SENTINEL */
145 }
146 #endif /* CONFIG_ARCH_HAS_NESTED_EXCEPTION_DETECTION */
147 } else {
148 /* Test mode */
149 #if defined(CONFIG_ARCH_HAS_NESTED_EXCEPTION_DETECTION)
150 if ((esf != NULL) && arch_is_in_nested_exception(esf)) {
151 /* Abort the thread only on STACK Sentinel check fail. */
152 #if defined(CONFIG_STACK_SENTINEL)
153 if (reason != K_ERR_STACK_CHK_FAIL) {
154 arch_irq_unlock(key);
155 return;
156 }
157 #else
158 arch_irq_unlock(key);
159 return;
160 #endif /* CONFIG_STACK_SENTINEL */
161 } else {
162 /* Abort the thread only if the fault is not due to
163 * a spurious ISR handler triggered.
164 */
165 if (reason == K_ERR_SPURIOUS_IRQ) {
166 arch_irq_unlock(key);
167 return;
168 }
169 }
170 #endif /*CONFIG_ARCH_HAS_NESTED_EXCEPTION_DETECTION */
171 }
172
173 arch_irq_unlock(key);
174
175 if (IS_ENABLED(CONFIG_MULTITHREADING)) {
176 k_thread_abort(thread);
177 }
178 }
179