1 /*
2  * Copyright (c) 2019 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <kernel.h>
8 
9 #include <kernel_internal.h>
10 #include <kernel_structs.h>
11 #include <sys/__assert.h>
12 #include <arch/cpu.h>
13 #include <logging/log_ctrl.h>
14 #include <logging/log.h>
15 #include <fatal.h>
16 #include <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; /* LCOV_EXCL_LINE */
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 
get_cpu(void)85 static inline int get_cpu(void)
86 {
87 #if defined(CONFIG_SMP)
88 	return arch_curr_cpu()->id;
89 #else
90 	return 0;
91 #endif
92 }
93 
z_fatal_error(unsigned int reason,const z_arch_esf_t * esf)94 void z_fatal_error(unsigned int reason, const z_arch_esf_t *esf)
95 {
96 	/* We can't allow this code to be preempted, but don't need to
97 	 * synchronize between CPUs, so an arch-layer lock is
98 	 * appropriate.
99 	 */
100 	unsigned int key = arch_irq_lock();
101 	struct k_thread *thread = IS_ENABLED(CONFIG_MULTITHREADING) ?
102 			k_current_get() : NULL;
103 
104 	/* twister looks for the "ZEPHYR FATAL ERROR" string, don't
105 	 * change it without also updating twister
106 	 */
107 	LOG_ERR(">>> ZEPHYR FATAL ERROR %d: %s on CPU %d", reason,
108 		reason_to_str(reason), get_cpu());
109 
110 	/* FIXME: This doesn't seem to work as expected on all arches.
111 	 * Need a reliable way to determine whether the fault happened when
112 	 * an IRQ or exception was being handled, or thread context.
113 	 *
114 	 * See #17656
115 	 */
116 #if defined(CONFIG_ARCH_HAS_NESTED_EXCEPTION_DETECTION)
117 	if ((esf != NULL) && arch_is_in_nested_exception(esf)) {
118 		LOG_ERR("Fault during interrupt handling\n");
119 	}
120 #endif
121 
122 	LOG_ERR("Current thread: %p (%s)", thread,
123 		log_strdup(thread_name_get(thread)));
124 
125 	coredump(reason, esf, thread);
126 
127 	k_sys_fatal_error_handler(reason, esf);
128 
129 	/* If the system fatal error handler returns, then kill the faulting
130 	 * thread; a policy decision was made not to hang the system.
131 	 *
132 	 * Policy for fatal errors in ISRs: unconditionally panic.
133 	 *
134 	 * There is one exception to this policy: a stack sentinel
135 	 * check may be performed (on behalf of the current thread)
136 	 * during ISR exit, but in this case the thread should be
137 	 * aborted.
138 	 *
139 	 * Note that k_thread_abort() returns on some architectures but
140 	 * not others; e.g. on ARC, x86_64, Xtensa with ASM2, ARM
141 	 */
142 	if (!IS_ENABLED(CONFIG_TEST)) {
143 		__ASSERT(reason != K_ERR_KERNEL_PANIC,
144 			 "Attempted to recover from a kernel panic condition");
145 		/* FIXME: #17656 */
146 #if defined(CONFIG_ARCH_HAS_NESTED_EXCEPTION_DETECTION)
147 		if ((esf != NULL) && arch_is_in_nested_exception(esf)) {
148 #if defined(CONFIG_STACK_SENTINEL)
149 			if (reason != K_ERR_STACK_CHK_FAIL) {
150 				__ASSERT(0,
151 				 "Attempted to recover from a fatal error in ISR");
152 			 }
153 #endif /* CONFIG_STACK_SENTINEL */
154 		}
155 #endif /* CONFIG_ARCH_HAS_NESTED_EXCEPTION_DETECTION */
156 	} else {
157 		/* Test mode */
158 #if defined(CONFIG_ARCH_HAS_NESTED_EXCEPTION_DETECTION)
159 		if ((esf != NULL) && arch_is_in_nested_exception(esf)) {
160 			/* Abort the thread only on STACK Sentinel check fail. */
161 #if defined(CONFIG_STACK_SENTINEL)
162 			if (reason != K_ERR_STACK_CHK_FAIL) {
163 				arch_irq_unlock(key);
164 				return;
165 			}
166 #else
167 			arch_irq_unlock(key);
168 			return;
169 #endif /* CONFIG_STACK_SENTINEL */
170 		} else {
171 			/* Abort the thread only if the fault is not due to
172 			 * a spurious ISR handler triggered.
173 			 */
174 			if (reason == K_ERR_SPURIOUS_IRQ) {
175 				arch_irq_unlock(key);
176 				return;
177 			}
178 		}
179 #endif /*CONFIG_ARCH_HAS_NESTED_EXCEPTION_DETECTION */
180 	}
181 
182 	arch_irq_unlock(key);
183 
184 	if (IS_ENABLED(CONFIG_MULTITHREADING)) {
185 		k_thread_abort(thread);
186 	}
187 }
188