diff options
Diffstat (limited to 'kernel/panic.c')
-rw-r--r-- | kernel/panic.c | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/kernel/panic.c b/kernel/panic.c new file mode 100644 index 000000000000..0fa3f3a66fb6 --- /dev/null +++ b/kernel/panic.c | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * linux/kernel/panic.c | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This function is used through-out the kernel (including mm and fs) | ||
9 | * to indicate a major problem. | ||
10 | */ | ||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/reboot.h> | ||
16 | #include <linux/notifier.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/sysrq.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/nmi.h> | ||
21 | |||
22 | int panic_timeout; | ||
23 | int panic_on_oops; | ||
24 | int tainted; | ||
25 | |||
26 | EXPORT_SYMBOL(panic_timeout); | ||
27 | |||
28 | struct notifier_block *panic_notifier_list; | ||
29 | |||
30 | EXPORT_SYMBOL(panic_notifier_list); | ||
31 | |||
32 | static int __init panic_setup(char *str) | ||
33 | { | ||
34 | panic_timeout = simple_strtoul(str, NULL, 0); | ||
35 | return 1; | ||
36 | } | ||
37 | __setup("panic=", panic_setup); | ||
38 | |||
39 | static long no_blink(long time) | ||
40 | { | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | /* Returns how long it waited in ms */ | ||
45 | long (*panic_blink)(long time); | ||
46 | EXPORT_SYMBOL(panic_blink); | ||
47 | |||
48 | /** | ||
49 | * panic - halt the system | ||
50 | * @fmt: The text string to print | ||
51 | * | ||
52 | * Display a message, then perform cleanups. | ||
53 | * | ||
54 | * This function never returns. | ||
55 | */ | ||
56 | |||
57 | NORET_TYPE void panic(const char * fmt, ...) | ||
58 | { | ||
59 | long i; | ||
60 | static char buf[1024]; | ||
61 | va_list args; | ||
62 | #if defined(CONFIG_ARCH_S390) | ||
63 | unsigned long caller = (unsigned long) __builtin_return_address(0); | ||
64 | #endif | ||
65 | |||
66 | bust_spinlocks(1); | ||
67 | va_start(args, fmt); | ||
68 | vsnprintf(buf, sizeof(buf), fmt, args); | ||
69 | va_end(args); | ||
70 | printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf); | ||
71 | bust_spinlocks(0); | ||
72 | |||
73 | #ifdef CONFIG_SMP | ||
74 | smp_send_stop(); | ||
75 | #endif | ||
76 | |||
77 | notifier_call_chain(&panic_notifier_list, 0, buf); | ||
78 | |||
79 | if (!panic_blink) | ||
80 | panic_blink = no_blink; | ||
81 | |||
82 | if (panic_timeout > 0) | ||
83 | { | ||
84 | /* | ||
85 | * Delay timeout seconds before rebooting the machine. | ||
86 | * We can't use the "normal" timers since we just panicked.. | ||
87 | */ | ||
88 | printk(KERN_EMERG "Rebooting in %d seconds..",panic_timeout); | ||
89 | for (i = 0; i < panic_timeout*1000; ) { | ||
90 | touch_nmi_watchdog(); | ||
91 | i += panic_blink(i); | ||
92 | mdelay(1); | ||
93 | i++; | ||
94 | } | ||
95 | /* | ||
96 | * Should we run the reboot notifier. For the moment Im | ||
97 | * choosing not too. It might crash, be corrupt or do | ||
98 | * more harm than good for other reasons. | ||
99 | */ | ||
100 | machine_restart(NULL); | ||
101 | } | ||
102 | #ifdef __sparc__ | ||
103 | { | ||
104 | extern int stop_a_enabled; | ||
105 | /* Make sure the user can actually press L1-A */ | ||
106 | stop_a_enabled = 1; | ||
107 | printk(KERN_EMERG "Press L1-A to return to the boot prom\n"); | ||
108 | } | ||
109 | #endif | ||
110 | #if defined(CONFIG_ARCH_S390) | ||
111 | disabled_wait(caller); | ||
112 | #endif | ||
113 | local_irq_enable(); | ||
114 | for (i = 0;;) { | ||
115 | i += panic_blink(i); | ||
116 | mdelay(1); | ||
117 | i++; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | EXPORT_SYMBOL(panic); | ||
122 | |||
123 | /** | ||
124 | * print_tainted - return a string to represent the kernel taint state. | ||
125 | * | ||
126 | * 'P' - Proprietary module has been loaded. | ||
127 | * 'F' - Module has been forcibly loaded. | ||
128 | * 'S' - SMP with CPUs not designed for SMP. | ||
129 | * 'R' - User forced a module unload. | ||
130 | * 'M' - Machine had a machine check experience. | ||
131 | * 'B' - System has hit bad_page. | ||
132 | * | ||
133 | * The string is overwritten by the next call to print_taint(). | ||
134 | */ | ||
135 | |||
136 | const char *print_tainted(void) | ||
137 | { | ||
138 | static char buf[20]; | ||
139 | if (tainted) { | ||
140 | snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c", | ||
141 | tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G', | ||
142 | tainted & TAINT_FORCED_MODULE ? 'F' : ' ', | ||
143 | tainted & TAINT_UNSAFE_SMP ? 'S' : ' ', | ||
144 | tainted & TAINT_FORCED_RMMOD ? 'R' : ' ', | ||
145 | tainted & TAINT_MACHINE_CHECK ? 'M' : ' ', | ||
146 | tainted & TAINT_BAD_PAGE ? 'B' : ' '); | ||
147 | } | ||
148 | else | ||
149 | snprintf(buf, sizeof(buf), "Not tainted"); | ||
150 | return(buf); | ||
151 | } | ||
152 | |||
153 | void add_taint(unsigned flag) | ||
154 | { | ||
155 | tainted |= flag; | ||
156 | } | ||
157 | EXPORT_SYMBOL(add_taint); | ||