]> bbs.cooldavid.org Git - net-next-2.6.git/blob - arch/i386/kernel/reboot.c
[PATCH] Remove i386_ksyms.c, almost.
[net-next-2.6.git] / arch / i386 / kernel / reboot.c
1 /*
2  *  linux/arch/i386/kernel/reboot.c
3  */
4
5 #include <linux/config.h>
6 #include <linux/mm.h>
7 #include <linux/module.h>
8 #include <linux/delay.h>
9 #include <linux/init.h>
10 #include <linux/interrupt.h>
11 #include <linux/mc146818rtc.h>
12 #include <linux/efi.h>
13 #include <linux/dmi.h>
14 #include <asm/uaccess.h>
15 #include <asm/apic.h>
16 #include "mach_reboot.h"
17 #include <linux/reboot_fixups.h>
18
19 /*
20  * Power off function, if any
21  */
22 void (*pm_power_off)(void);
23 EXPORT_SYMBOL(pm_power_off);
24
25 static int reboot_mode;
26 static int reboot_thru_bios;
27
28 #ifdef CONFIG_SMP
29 int reboot_smp = 0;
30 static int reboot_cpu = -1;
31 /* shamelessly grabbed from lib/vsprintf.c for readability */
32 #define is_digit(c)     ((c) >= '0' && (c) <= '9')
33 #endif
34 static int __init reboot_setup(char *str)
35 {
36         while(1) {
37                 switch (*str) {
38                 case 'w': /* "warm" reboot (no memory testing etc) */
39                         reboot_mode = 0x1234;
40                         break;
41                 case 'c': /* "cold" reboot (with memory testing etc) */
42                         reboot_mode = 0x0;
43                         break;
44                 case 'b': /* "bios" reboot by jumping through the BIOS */
45                         reboot_thru_bios = 1;
46                         break;
47                 case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */
48                         reboot_thru_bios = 0;
49                         break;
50 #ifdef CONFIG_SMP
51                 case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
52                         reboot_smp = 1;
53                         if (is_digit(*(str+1))) {
54                                 reboot_cpu = (int) (*(str+1) - '0');
55                                 if (is_digit(*(str+2))) 
56                                         reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
57                         }
58                                 /* we will leave sorting out the final value 
59                                 when we are ready to reboot, since we might not
60                                 have set up boot_cpu_id or smp_num_cpu */
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  * Reboot options and system auto-detection code provided by
76  * Dell Inc. so their systems "just work". :-)
77  */
78
79 /*
80  * Some machines require the "reboot=b"  commandline option, this quirk makes that automatic.
81  */
82 static 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
91 /*
92  * Some machines require the "reboot=s"  commandline option, this quirk makes that automatic.
93  */
94 static int __init set_smp_reboot(struct dmi_system_id *d)
95 {
96 #ifdef CONFIG_SMP
97         if (!reboot_smp) {
98                 reboot_smp = 1;
99                 printk(KERN_INFO "%s series board detected. Selecting SMP-method for reboots.\n", d->ident);
100         }
101 #endif
102         return 0;
103 }
104
105 /*
106  * Some machines require the "reboot=b,s"  commandline option, this quirk makes that automatic.
107  */
108 static int __init set_smp_bios_reboot(struct dmi_system_id *d)
109 {
110         set_smp_reboot(d);
111         set_bios_reboot(d);
112         return 0;
113 }
114
115 static struct dmi_system_id __initdata reboot_dmi_table[] = {
116         {       /* Handle problems with rebooting on Dell 1300's */
117                 .callback = set_smp_bios_reboot,
118                 .ident = "Dell PowerEdge 1300",
119                 .matches = {
120                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
121                         DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
122                 },
123         },
124         {       /* Handle problems with rebooting on Dell 300's */
125                 .callback = set_bios_reboot,
126                 .ident = "Dell PowerEdge 300",
127                 .matches = {
128                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
129                         DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
130                 },
131         },
132         {       /* Handle problems with rebooting on Dell 2400's */
133                 .callback = set_bios_reboot,
134                 .ident = "Dell PowerEdge 2400",
135                 .matches = {
136                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
137                         DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
138                 },
139         },
140         { }
141 };
142
143 static int __init reboot_init(void)
144 {
145         dmi_check_system(reboot_dmi_table);
146         return 0;
147 }
148
149 core_initcall(reboot_init);
150
151 /* The following code and data reboots the machine by switching to real
152    mode and jumping to the BIOS reset entry point, as if the CPU has
153    really been reset.  The previous version asked the keyboard
154    controller to pulse the CPU reset line, which is more thorough, but
155    doesn't work with at least one type of 486 motherboard.  It is easy
156    to stop this code working; hence the copious comments. */
157
158 static unsigned long long
159 real_mode_gdt_entries [3] =
160 {
161         0x0000000000000000ULL,  /* Null descriptor */
162         0x00009a000000ffffULL,  /* 16-bit real-mode 64k code at 0x00000000 */
163         0x000092000100ffffULL   /* 16-bit real-mode 64k data at 0x00000100 */
164 };
165
166 static struct
167 {
168         unsigned short       size __attribute__ ((packed));
169         unsigned long long * base __attribute__ ((packed));
170 }
171 real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries },
172 real_mode_idt = { 0x3ff, NULL },
173 no_idt = { 0, NULL };
174
175
176 /* This is 16-bit protected mode code to disable paging and the cache,
177    switch to real mode and jump to the BIOS reset code.
178
179    The instruction that switches to real mode by writing to CR0 must be
180    followed immediately by a far jump instruction, which set CS to a
181    valid value for real mode, and flushes the prefetch queue to avoid
182    running instructions that have already been decoded in protected
183    mode.
184
185    Clears all the flags except ET, especially PG (paging), PE
186    (protected-mode enable) and TS (task switch for coprocessor state
187    save).  Flushes the TLB after paging has been disabled.  Sets CD and
188    NW, to disable the cache on a 486, and invalidates the cache.  This
189    is more like the state of a 486 after reset.  I don't know if
190    something else should be done for other chips.
191
192    More could be done here to set up the registers as if a CPU reset had
193    occurred; hopefully real BIOSs don't assume much. */
194
195 static unsigned char real_mode_switch [] =
196 {
197         0x66, 0x0f, 0x20, 0xc0,                 /*    movl  %cr0,%eax        */
198         0x66, 0x83, 0xe0, 0x11,                 /*    andl  $0x00000011,%eax */
199         0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,     /*    orl   $0x60000000,%eax */
200         0x66, 0x0f, 0x22, 0xc0,                 /*    movl  %eax,%cr0        */
201         0x66, 0x0f, 0x22, 0xd8,                 /*    movl  %eax,%cr3        */
202         0x66, 0x0f, 0x20, 0xc3,                 /*    movl  %cr0,%ebx        */
203         0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,       /*    andl  $0x60000000,%ebx */
204         0x74, 0x02,                             /*    jz    f                */
205         0x0f, 0x09,                             /*    wbinvd                 */
206         0x24, 0x10,                             /* f: andb  $0x10,al         */
207         0x66, 0x0f, 0x22, 0xc0                  /*    movl  %eax,%cr0        */
208 };
209 static unsigned char jump_to_bios [] =
210 {
211         0xea, 0x00, 0x00, 0xff, 0xff            /*    ljmp  $0xffff,$0x0000  */
212 };
213
214 /*
215  * Switch to real mode and then execute the code
216  * specified by the code and length parameters.
217  * We assume that length will aways be less that 100!
218  */
219 void machine_real_restart(unsigned char *code, int length)
220 {
221         unsigned long flags;
222
223         local_irq_disable();
224
225         /* Write zero to CMOS register number 0x0f, which the BIOS POST
226            routine will recognize as telling it to do a proper reboot.  (Well
227            that's what this book in front of me says -- it may only apply to
228            the Phoenix BIOS though, it's not clear).  At the same time,
229            disable NMIs by setting the top bit in the CMOS address register,
230            as we're about to do peculiar things to the CPU.  I'm not sure if
231            `outb_p' is needed instead of just `outb'.  Use it to be on the
232            safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
233          */
234
235         spin_lock_irqsave(&rtc_lock, flags);
236         CMOS_WRITE(0x00, 0x8f);
237         spin_unlock_irqrestore(&rtc_lock, flags);
238
239         /* Remap the kernel at virtual address zero, as well as offset zero
240            from the kernel segment.  This assumes the kernel segment starts at
241            virtual address PAGE_OFFSET. */
242
243         memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
244                 sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
245
246         /*
247          * Use `swapper_pg_dir' as our page directory.
248          */
249         load_cr3(swapper_pg_dir);
250
251         /* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
252            this on booting to tell it to "Bypass memory test (also warm
253            boot)".  This seems like a fairly standard thing that gets set by
254            REBOOT.COM programs, and the previous reset routine did this
255            too. */
256
257         *((unsigned short *)0x472) = reboot_mode;
258
259         /* For the switch to real mode, copy some code to low memory.  It has
260            to be in the first 64k because it is running in 16-bit mode, and it
261            has to have the same physical and virtual address, because it turns
262            off paging.  Copy it near the end of the first page, out of the way
263            of BIOS variables. */
264
265         memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),
266                 real_mode_switch, sizeof (real_mode_switch));
267         memcpy ((void *) (0x1000 - 100), code, length);
268
269         /* Set up the IDT for real mode. */
270
271         __asm__ __volatile__ ("lidt %0" : : "m" (real_mode_idt));
272
273         /* Set up a GDT from which we can load segment descriptors for real
274            mode.  The GDT is not used in real mode; it is just needed here to
275            prepare the descriptors. */
276
277         __asm__ __volatile__ ("lgdt %0" : : "m" (real_mode_gdt));
278
279         /* Load the data segment registers, and thus the descriptors ready for
280            real mode.  The base address of each segment is 0x100, 16 times the
281            selector value being loaded here.  This is so that the segment
282            registers don't have to be reloaded after switching to real mode:
283            the values are consistent for real mode operation already. */
284
285         __asm__ __volatile__ ("movl $0x0010,%%eax\n"
286                                 "\tmovl %%eax,%%ds\n"
287                                 "\tmovl %%eax,%%es\n"
288                                 "\tmovl %%eax,%%fs\n"
289                                 "\tmovl %%eax,%%gs\n"
290                                 "\tmovl %%eax,%%ss" : : : "eax");
291
292         /* Jump to the 16-bit code that we copied earlier.  It disables paging
293            and the cache, switches to real mode, and jumps to the BIOS reset
294            entry point. */
295
296         __asm__ __volatile__ ("ljmp $0x0008,%0"
297                                 :
298                                 : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100)));
299 }
300 #ifdef CONFIG_APM_MODULE
301 EXPORT_SYMBOL(machine_real_restart);
302 #endif
303
304 void machine_restart(char * __unused)
305 {
306 #ifdef CONFIG_SMP
307         int cpuid;
308         
309         cpuid = GET_APIC_ID(apic_read(APIC_ID));
310
311         if (reboot_smp) {
312
313                 /* check to see if reboot_cpu is valid 
314                    if its not, default to the BSP */
315                 if ((reboot_cpu == -1) ||  
316                       (reboot_cpu > (NR_CPUS -1))  || 
317                       !physid_isset(cpuid, phys_cpu_present_map))
318                         reboot_cpu = boot_cpu_physical_apicid;
319
320                 reboot_smp = 0;  /* use this as a flag to only go through this once*/
321                 /* re-run this function on the other CPUs
322                    it will fall though this section since we have 
323                    cleared reboot_smp, and do the reboot if it is the
324                    correct CPU, otherwise it halts. */
325                 if (reboot_cpu != cpuid)
326                         smp_call_function((void *)machine_restart , NULL, 1, 0);
327         }
328
329         /* if reboot_cpu is still -1, then we want a tradional reboot, 
330            and if we are not running on the reboot_cpu,, halt */
331         if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
332                 for (;;)
333                 __asm__ __volatile__ ("hlt");
334         }
335         /*
336          * Stop all CPUs and turn off local APICs and the IO-APIC, so
337          * other OSs see a clean IRQ state.
338          */
339         smp_send_stop();
340 #endif /* CONFIG_SMP */
341
342         lapic_shutdown();
343
344 #ifdef CONFIG_X86_IO_APIC
345         disable_IO_APIC();
346 #endif
347
348         if (!reboot_thru_bios) {
349                 if (efi_enabled) {
350                         efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL);
351                         __asm__ __volatile__("lidt %0": :"m" (no_idt));
352                         __asm__ __volatile__("int3");
353                 }
354                 /* rebooting needs to touch the page at absolute addr 0 */
355                 *((unsigned short *)__va(0x472)) = reboot_mode;
356                 for (;;) {
357                         mach_reboot_fixups(); /* for board specific fixups */
358                         mach_reboot();
359                         /* That didn't work - force a triple fault.. */
360                         __asm__ __volatile__("lidt %0": :"m" (no_idt));
361                         __asm__ __volatile__("int3");
362                 }
363         }
364         if (efi_enabled)
365                 efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
366
367         machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
368 }
369
370 EXPORT_SYMBOL(machine_restart);
371
372 void machine_halt(void)
373 {
374 }
375
376 EXPORT_SYMBOL(machine_halt);
377
378 void machine_power_off(void)
379 {
380         lapic_shutdown();
381
382         if (efi_enabled)
383                 efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
384         if (pm_power_off)
385                 pm_power_off();
386 }
387
388 EXPORT_SYMBOL(machine_power_off);
389