1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #include "mos/misc/power.h" |
4 | |
5 | #include <mos/interrupt/ipi.h> |
6 | #include <mos/lib/structures/list.h> |
7 | #include <mos/misc/cmdline.h> |
8 | #include <mos/misc/panic.h> |
9 | #include <mos/misc/setup.h> |
10 | #include <mos/platform/platform.h> |
11 | #include <mos/syslog/printk.h> |
12 | #include <mos_stdio.h> |
13 | |
14 | // stack smashing protector |
15 | u64 __stack_chk_guard = 0; |
16 | |
17 | [[noreturn]] void __stack_chk_fail(void) |
18 | { |
19 | mos_panic("Stack smashing detected!" ); |
20 | } |
21 | |
22 | void __stack_chk_fail_local(void) |
23 | { |
24 | __stack_chk_fail(); |
25 | } |
26 | |
27 | static kmsg_handler_t *kwarn_handler = NULL; |
28 | static bool poweroff_on_panic = false; |
29 | |
30 | MOS_EARLY_SETUP("poweroff_on_panic" , setup_poweroff_on_panic) |
31 | { |
32 | poweroff_on_panic = cmdline_string_truthiness(arg, default_value: true); |
33 | return true; |
34 | } |
35 | |
36 | void kwarn_handler_set(kmsg_handler_t *handler) |
37 | { |
38 | pr_warn("installing a new warning handler..." ); |
39 | kwarn_handler = handler; |
40 | } |
41 | |
42 | void kwarn_handler_remove(void) |
43 | { |
44 | pr_warn("removing warning handler..." ); |
45 | if (!kwarn_handler) |
46 | mos_warn("no previous warning handler installed" ); |
47 | kwarn_handler = NULL; |
48 | } |
49 | |
50 | extern const panic_point_t __MOS_PANIC_LIST_START[], __MOS_PANIC_LIST_END[]; |
51 | extern const panic_hook_t __MOS_PANIC_HOOKS_START[], __MOS_PANIC_HOOKS_END[]; |
52 | |
53 | static const panic_point_t *find_panic_point(ptr_t ip) |
54 | { |
55 | const panic_point_t *point = NULL; |
56 | for (const panic_point_t *p = __MOS_PANIC_LIST_START; p < __MOS_PANIC_LIST_END; p++) |
57 | { |
58 | if (p->ip == ip) |
59 | { |
60 | point = p; |
61 | break; |
62 | } |
63 | } |
64 | return point; |
65 | } |
66 | |
67 | void try_handle_kernel_panics(ptr_t ip) |
68 | { |
69 | const panic_point_t *point = find_panic_point(ip); |
70 | if (!point) |
71 | { |
72 | pr_dwarn(panic, "no panic point found for " PTR_FMT, ip); |
73 | return; |
74 | } |
75 | try_handle_kernel_panics_at(point); |
76 | } |
77 | |
78 | void try_handle_kernel_panics_at(const panic_point_t *point) |
79 | { |
80 | platform_interrupt_disable(); |
81 | |
82 | if (!once()) |
83 | { |
84 | pr_fatal("recursive panic detected, aborting..." ); |
85 | pr_info("" ); |
86 | if (unlikely(poweroff_on_panic)) |
87 | { |
88 | pr_emerg("Powering off..." ); |
89 | power_shutdown(); |
90 | } |
91 | |
92 | while (true) |
93 | ; |
94 | } |
95 | |
96 | if (printk_unquiet()) |
97 | pr_info("quiet mode disabled" ); // was quiet |
98 | |
99 | pr_emerg("" ); |
100 | pr_fatal("!!!!!!!!!!!!!!!!!!!!!!!!" ); |
101 | pr_fatal("!!!!! KERNEL PANIC !!!!!" ); |
102 | pr_fatal("!!!!!!!!!!!!!!!!!!!!!!!!" ); |
103 | pr_emerg("" ); |
104 | pr_emerg("file: %s:%llu" , point->file, point->line); |
105 | pr_emerg("function: %s" , point->func); |
106 | if (point->ip) |
107 | pr_emerg("instruction: %ps (" PTR_FMT ")" , (void *) point->ip, point->ip); |
108 | else |
109 | pr_emerg("instruction: see backtrace" ); |
110 | pr_emerg("" ); |
111 | |
112 | pr_cont("\n" ); |
113 | |
114 | if (point->ip == 0) |
115 | { |
116 | // inline panic point |
117 | pr_emph("Current stack trace:" ); |
118 | platform_dump_current_stack(); |
119 | } |
120 | else |
121 | { |
122 | if (current_cpu->interrupt_regs) |
123 | { |
124 | pr_emph("Register states before interrupt:" ); |
125 | platform_dump_regs(current_cpu->interrupt_regs); |
126 | pr_cont("\n" ); |
127 | pr_emph("Stack trace before interrupt" ); |
128 | platform_dump_stack(current_cpu->interrupt_regs); |
129 | pr_cont("\n" ); |
130 | } |
131 | else |
132 | { |
133 | pr_emph("No interrupt context available" ); |
134 | } |
135 | } |
136 | |
137 | pr_cont("\n" ); |
138 | |
139 | for (const panic_hook_t *hook = __MOS_PANIC_HOOKS_START; hook < __MOS_PANIC_HOOKS_END; hook++) |
140 | { |
141 | if (hook->enabled && !*hook->enabled) |
142 | continue; |
143 | |
144 | pr_dinfo2(panic, "invoking panic hook '%s' at %ps" , hook->name, (void *) hook); |
145 | hook->hook(); |
146 | } |
147 | |
148 | ipi_send_all(type: IPI_TYPE_HALT); |
149 | |
150 | if (unlikely(poweroff_on_panic)) |
151 | { |
152 | pr_emerg("Powering off..." ); |
153 | power_shutdown(); |
154 | } |
155 | |
156 | pr_emerg("Halting..." ); |
157 | platform_halt_cpu(); |
158 | |
159 | while (1) |
160 | ; |
161 | } |
162 | |
163 | void mos_kwarn(const char *func, u32 line, const char *fmt, ...) |
164 | { |
165 | va_list args; |
166 | if (kwarn_handler) |
167 | { |
168 | va_start(args, fmt); |
169 | kwarn_handler(func, line, fmt, args); |
170 | va_end(args); |
171 | return; |
172 | } |
173 | |
174 | char message[MOS_PRINTK_BUFFER_SIZE]; |
175 | va_start(args, fmt); |
176 | vsnprintf(buf: message, MOS_PRINTK_BUFFER_SIZE, format: fmt, args); |
177 | va_end(args); |
178 | |
179 | lprintk(loglevel: MOS_LOG_WARN, format: "\n%s" , message); |
180 | lprintk(loglevel: MOS_LOG_WARN, format: " in function: %s (line %u)\n" , func, line); |
181 | } |
182 | |