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 OptiPlex 745",
119 .matches = {
120 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
121 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
122 DMI_MATCH(DMI_BOARD_NAME, "0WF810"),
123 },
124 },
125 {
126 .callback = set_bios_reboot,
127 .ident = "Dell PowerEdge 2400",
128 .matches = {
129 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
130 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
131 },
132 },
133 {
134 .callback = set_bios_reboot,
135 .ident = "HP Compaq Laptop",
136 .matches = {
137 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
138 DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
139 },
140 },
141 { }
142};
143
144static int __init reboot_init(void)
145{
146 dmi_check_system(reboot_dmi_table);
147 return 0;
148}
149
150core_initcall(reboot_init);
151
152
153
154
155
156
157
158
159static unsigned long long
160real_mode_gdt_entries [3] =
161{
162 0x0000000000000000ULL,
163 0x00009a000000ffffULL,
164 0x000092000100ffffULL
165};
166
167static struct Xgt_desc_struct
168real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, (long)real_mode_gdt_entries },
169real_mode_idt = { 0x3ff, 0 },
170no_idt = { 0, 0 };
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192static unsigned char real_mode_switch [] =
193{
194 0x66, 0x0f, 0x20, 0xc0,
195 0x66, 0x83, 0xe0, 0x11,
196 0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,
197 0x66, 0x0f, 0x22, 0xc0,
198 0x66, 0x0f, 0x22, 0xd8,
199 0x66, 0x0f, 0x20, 0xc3,
200 0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,
201 0x74, 0x02,
202 0x0f, 0x09,
203 0x24, 0x10,
204 0x66, 0x0f, 0x22, 0xc0
205};
206static unsigned char jump_to_bios [] =
207{
208 0xea, 0x00, 0x00, 0xff, 0xff
209};
210
211
212
213
214
215
216void machine_real_restart(unsigned char *code, int length)
217{
218 local_irq_disable();
219
220
221
222
223
224
225
226
227
228
229
230 spin_lock(&rtc_lock);
231 CMOS_WRITE(0x00, 0x8f);
232 spin_unlock(&rtc_lock);
233
234
235
236
237
238 memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
239 sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
240
241
242
243
244 load_cr3(swapper_pg_dir);
245
246
247
248
249
250
251
252 *((unsigned short *)0x472) = reboot_mode;
253
254
255
256
257
258
259
260 memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),
261 real_mode_switch, sizeof (real_mode_switch));
262 memcpy ((void *) (0x1000 - 100), code, length);
263
264
265
266 load_idt(&real_mode_idt);
267
268
269
270
271
272 load_gdt(&real_mode_gdt);
273
274
275
276
277
278
279
280 __asm__ __volatile__ ("movl $0x0010,%%eax\n"
281 "\tmovl %%eax,%%ds\n"
282 "\tmovl %%eax,%%es\n"
283 "\tmovl %%eax,%%fs\n"
284 "\tmovl %%eax,%%gs\n"
285 "\tmovl %%eax,%%ss" : : : "eax");
286
287
288
289
290
291 __asm__ __volatile__ ("ljmp $0x0008,%0"
292 :
293 : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100)));
294}
295#ifdef CONFIG_APM_MODULE
296EXPORT_SYMBOL(machine_real_restart);
297#endif
298
299static void native_machine_shutdown(void)
300{
301#ifdef CONFIG_SMP
302 int reboot_cpu_id;
303
304
305 reboot_cpu_id = 0;
306
307
308 if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) &&
309 cpu_isset(reboot_cpu, cpu_online_map)) {
310 reboot_cpu_id = reboot_cpu;
311 }
312
313
314 if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
315 reboot_cpu_id = smp_processor_id();
316 }
317
318
319 set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
320
321
322
323
324
325 smp_send_stop();
326#endif
327
328 lapic_shutdown();
329
330#ifdef CONFIG_X86_IO_APIC
331 disable_IO_APIC();
332#endif
333}
334
335void __attribute__((weak)) mach_reboot_fixups(void)
336{
337}
338
339static void native_machine_emergency_restart(void)
340{
341 if (!reboot_thru_bios) {
342 if (efi_enabled) {
343 efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL);
344 load_idt(&no_idt);
345 __asm__ __volatile__("int3");
346 }
347
348 *((unsigned short *)__va(0x472)) = reboot_mode;
349 for (;;) {
350 mach_reboot_fixups();
351 mach_reboot();
352
353 load_idt(&no_idt);
354 __asm__ __volatile__("int3");
355 }
356 }
357 if (efi_enabled)
358 efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
359
360 machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
361}
362
363static void native_machine_restart(char * __unused)
364{
365 machine_shutdown();
366 machine_emergency_restart();
367}
368
369static void native_machine_halt(void)
370{
371}
372
373static void native_machine_power_off(void)
374{
375 if (pm_power_off) {
376 machine_shutdown();
377 pm_power_off();
378 }
379}
380
381
382struct machine_ops machine_ops = {
383 .power_off = native_machine_power_off,
384 .shutdown = native_machine_shutdown,
385 .emergency_restart = native_machine_emergency_restart,
386 .restart = native_machine_restart,
387 .halt = native_machine_halt,
388};
389
390void machine_power_off(void)
391{
392 machine_ops.power_off();
393}
394
395void machine_shutdown(void)
396{
397 machine_ops.shutdown();
398}
399
400void machine_emergency_restart(void)
401{
402 machine_ops.emergency_restart();
403}
404
405void machine_restart(char *cmd)
406{
407 machine_ops.restart(cmd);
408}
409
410void machine_halt(void)
411{
412 machine_ops.halt();
413}
414