1
2
3
4
5#include <linux/mm.h>
6#include <linux/module.h>
7#include <linux/delay.h>
8#include <linux/init.h>
9#include <linux/interrupt.h>
10#include <linux/mc146818rtc.h>
11#include <linux/efi.h>
12#include <linux/dmi.h>
13#include <linux/ctype.h>
14#include <linux/pm.h>
15#include <linux/reboot.h>
16#include <asm/uaccess.h>
17#include <asm/apic.h>
18#include <asm/desc.h>
19#include "mach_reboot.h"
20#include <asm/reboot_fixups.h>
21#include <asm/reboot.h>
22
23
24
25
26void (*pm_power_off)(void);
27EXPORT_SYMBOL(pm_power_off);
28
29static int reboot_mode;
30static int reboot_thru_bios;
31
32#ifdef CONFIG_SMP
33static int reboot_cpu = -1;
34#endif
35static int __init reboot_setup(char *str)
36{
37 while(1) {
38 switch (*str) {
39 case 'w':
40 reboot_mode = 0x1234;
41 break;
42 case 'c':
43 reboot_mode = 0x0;
44 break;
45 case 'b':
46 reboot_thru_bios = 1;
47 break;
48 case 'h':
49 reboot_thru_bios = 0;
50 break;
51#ifdef CONFIG_SMP
52 case 's':
53 if (isdigit(*(str+1))) {
54 reboot_cpu = (int) (*(str+1) - '0');
55 if (isdigit(*(str+2)))
56 reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
57 }
58
59
60
61 break;
62#endif
63 }
64 if((str = strchr(str,',')) != NULL)
65 str++;
66 else
67 break;
68 }
69 return 1;
70}
71
72__setup("reboot=", reboot_setup);
73
74
75
76
77
78
79
80
81
82static int __init set_bios_reboot(struct dmi_system_id *d)
83{
84 if (!reboot_thru_bios) {
85 reboot_thru_bios = 1;
86 printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
87 }
88 return 0;
89}
90
91static struct dmi_system_id __initdata reboot_dmi_table[] = {
92 {
93 .callback = set_bios_reboot,
94 .ident = "Dell E520",
95 .matches = {
96 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
97 DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
98 },
99 },
100 {
101 .callback = set_bios_reboot,
102 .ident = "Dell PowerEdge 1300",
103 .matches = {
104 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
105 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
106 },
107 },
108 {
109 .callback = set_bios_reboot,
110 .ident = "Dell PowerEdge 300",
111 .matches = {
112 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
113 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
114 },
115 },
116 {
117 .callback = set_bios_reboot,
118 .ident = "Dell PowerEdge 2400",
119 .matches = {
120 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
121 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
122 },
123 },
124 {
125 .callback = set_bios_reboot,
126 .ident = "HP Compaq Laptop",
127 .matches = {
128 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
129 DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
130 },
131 },
132 { }
133};
134
135static int __init reboot_init(void)
136{
137 dmi_check_system(reboot_dmi_table);
138 return 0;
139}
140
141core_initcall(reboot_init);
142
143
144
145
146
147
148
149
150static unsigned long long
151real_mode_gdt_entries [3] =
152{
153 0x0000000000000000ULL,
154 0x00009a000000ffffULL,
155 0x000092000100ffffULL
156};
157
158static struct Xgt_desc_struct
159real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries },
160real_mode_idt = { 0x3ff, 0 },
161no_idt = { 0, 0 };
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183static unsigned char real_mode_switch [] =
184{
185 0x66, 0x0f, 0x20, 0xc0,
186 0x66, 0x83, 0xe0, 0x11,
187 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,
188 0x66, 0x0f, 0x22, 0xc0,
189 0x66, 0x0f, 0x22, 0xd8,
190 0x66, 0x0f, 0x20, 0xc3,
191 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,
192 0x74, 0x02,
193 0x0f, 0x09,
194 0x24, 0x10,
195 0x66, 0x0f, 0x22, 0xc0
196};
197static unsigned char jump_to_bios [] =
198{
199 0xea, 0x00, 0x00, 0xff, 0xff
200};
201
202
203
204
205
206
207void machine_real_restart(unsigned char *code, int length)
208{
209 local_irq_disable();
210
211
212
213
214
215
216
217
218
219
220
221 spin_lock(&rtc_lock);
222 CMOS_WRITE(0x00, 0x8f);
223 spin_unlock(&rtc_lock);
224
225
226
227
228
229 memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
230 sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
231
232
233
234
235 load_cr3(swapper_pg_dir);
236
237
238
239
240
241
242
243 *((unsigned short *)0x472) = reboot_mode;
244
245
246
247
248
249
250
251 memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),
252 real_mode_switch, sizeof (real_mode_switch));
253 memcpy ((void *) (0x1000 - 100), code, length);
254
255
256
257 load_idt(&real_mode_idt);
258
259
260
261
262
263 load_gdt(&real_mode_gdt);
264
265
266
267
268
269
270
271 __asm__ __volatile__ ("movl $0x0010,%%eax\n"
272 "\tmovl %%eax,%%ds\n"
273 "\tmovl %%eax,%%es\n"
274 "\tmovl %%eax,%%fs\n"
275 "\tmovl %%eax,%%gs\n"
276 "\tmovl %%eax,%%ss" : : : "eax");
277
278
279
280
281
282 __asm__ __volatile__ ("ljmp $0x0008,%0"
283 :
284 : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100)));
285}
286#ifdef CONFIG_APM_MODULE
287EXPORT_SYMBOL(machine_real_restart);
288#endif
289
290static void native_machine_shutdown(void)
291{
292#ifdef CONFIG_SMP
293 int reboot_cpu_id;
294
295
296 reboot_cpu_id = 0;
297
298
299 if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) &&
300 cpu_isset(reboot_cpu, cpu_online_map)) {
301 reboot_cpu_id = reboot_cpu;
302 }
303
304
305 if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
306 reboot_cpu_id = smp_processor_id();
307 }
308
309
310 set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
311
312
313
314
315
316 smp_send_stop();
317#endif
318
319 lapic_shutdown();
320
321#ifdef CONFIG_X86_IO_APIC
322 disable_IO_APIC();
323#endif
324}
325
326void __attribute__((weak)) mach_reboot_fixups(void)
327{
328}
329
330static void native_machine_emergency_restart(void)
331{
332 if (!reboot_thru_bios) {
333 if (efi_enabled) {
334 efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL);
335 load_idt(&no_idt);
336 __asm__ __volatile__("int3");
337 }
338
339 *((unsigned short *)__va(0x472)) = reboot_mode;
340 for (;;) {
341 mach_reboot_fixups();
342 mach_reboot();
343
344 load_idt(&no_idt);
345 __asm__ __volatile__("int3");
346 }
347 }
348 if (efi_enabled)
349 efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
350
351 machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
352}
353
354static void native_machine_restart(char * __unused)
355{
356 machine_shutdown();
357 machine_emergency_restart();
358}
359
360static void native_machine_halt(void)
361{
362}
363
364static void native_machine_power_off(void)
365{
366 if (pm_power_off) {
367 machine_shutdown();
368 pm_power_off();
369 }
370}
371
372
373struct machine_ops machine_ops = {
374 .power_off = native_machine_power_off,
375 .shutdown = native_machine_shutdown,
376 .emergency_restart = native_machine_emergency_restart,
377 .restart = native_machine_restart,
378 .halt = native_machine_halt,
379};
380
381void machine_power_off(void)
382{
383 machine_ops.power_off();
384}
385
386void machine_shutdown(void)
387{
388 machine_ops.shutdown();
389}
390
391void machine_emergency_restart(void)
392{
393 machine_ops.emergency_restart();
394}
395
396void machine_restart(char *cmd)
397{
398 machine_ops.restart(cmd);
399}
400
401void machine_halt(void)
402{
403 machine_ops.halt();
404}
405