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
15u64 __stack_chk_guard = 0;
16
17[[noreturn]] void __stack_chk_fail(void)
18{
19 mos_panic("Stack smashing detected!");
20}
21
22void __stack_chk_fail_local(void)
23{
24 __stack_chk_fail();
25}
26
27static kmsg_handler_t *kwarn_handler = NULL;
28static bool poweroff_on_panic = false;
29
30MOS_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
36void kwarn_handler_set(kmsg_handler_t *handler)
37{
38 pr_warn("installing a new warning handler...");
39 kwarn_handler = handler;
40}
41
42void 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
50extern const panic_point_t __MOS_PANIC_LIST_START[], __MOS_PANIC_LIST_END[];
51extern const panic_hook_t __MOS_PANIC_HOOKS_START[], __MOS_PANIC_HOOKS_END[];
52
53static 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
67void 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
78void 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
163void 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