[PATCH] i386: inline assembler: cleanup and encapsulate descriptor and task register...
[linux-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 <asm/desc.h>
17 #include "mach_reboot.h"
18 #include <linux/reboot_fixups.h>
19
20 /*
21  * Power off function, if any
22  */
23 void (*pm_power_off)(void);
24 EXPORT_SYMBOL(pm_power_off);
25
26 static int reboot_mode;
27 static int reboot_thru_bios;
28
29 #ifdef CONFIG_SMP
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                         if (is_digit(*(str+1))) {
53                                 reboot_cpu = (int) (*(str+1) - '0');
54                                 if (is_digit(*(str+2))) 
55                                         reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0');
56                         }
57                                 /* we will leave sorting out the final value 
58                                 when we are ready to reboot, since we might not
59                                 have set up boot_cpu_id or smp_num_cpu */
60                         break;
61 #endif
62                 }
63                 if((str = strchr(str,',')) != NULL)
64                         str++;
65                 else
66                         break;
67         }
68         return 1;
69 }
70
71 __setup("reboot=", reboot_setup);
72
73 /*
74  * Reboot options and system auto-detection code provided by
75  * Dell Inc. so their systems "just work". :-)
76  */
77
78 /*
79  * Some machines require the "reboot=b"  commandline option, this quirk makes that automatic.
80  */
81 static int __init set_bios_reboot(struct dmi_system_id *d)
82 {
83         if (!reboot_thru_bios) {
84                 reboot_thru_bios = 1;
85                 printk(KERN_INFO "%s series board detected. Selecting BIOS-method for reboots.\n", d->ident);
86         }
87         return 0;
88 }
89
90 static struct dmi_system_id __initdata reboot_dmi_table[] = {
91         {       /* Handle problems with rebooting on Dell 1300's */
92                 .callback = set_bios_reboot,
93                 .ident = "Dell PowerEdge 1300",
94                 .matches = {
95                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
96                         DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
97                 },
98         },
99         {       /* Handle problems with rebooting on Dell 300's */
100                 .callback = set_bios_reboot,
101                 .ident = "Dell PowerEdge 300",
102                 .matches = {
103                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
104                         DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
105                 },
106         },
107         {       /* Handle problems with rebooting on Dell 2400's */
108                 .callback = set_bios_reboot,
109                 .ident = "Dell PowerEdge 2400",
110                 .matches = {
111                         DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
112                         DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
113                 },
114         },
115         { }
116 };
117
118 static int __init reboot_init(void)
119 {
120         dmi_check_system(reboot_dmi_table);
121         return 0;
122 }
123
124 core_initcall(reboot_init);
125
126 /* The following code and data reboots the machine by switching to real
127    mode and jumping to the BIOS reset entry point, as if the CPU has
128    really been reset.  The previous version asked the keyboard
129    controller to pulse the CPU reset line, which is more thorough, but
130    doesn't work with at least one type of 486 motherboard.  It is easy
131    to stop this code working; hence the copious comments. */
132
133 static unsigned long long
134 real_mode_gdt_entries [3] =
135 {
136         0x0000000000000000ULL,  /* Null descriptor */
137         0x00009a000000ffffULL,  /* 16-bit real-mode 64k code at 0x00000000 */
138         0x000092000100ffffULL   /* 16-bit real-mode 64k data at 0x00000100 */
139 };
140
141 static struct
142 {
143         unsigned short       size __attribute__ ((packed));
144         unsigned long long * base __attribute__ ((packed));
145 }
146 real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries },
147 real_mode_idt = { 0x3ff, NULL },
148 no_idt = { 0, NULL };
149
150
151 /* This is 16-bit protected mode code to disable paging and the cache,
152    switch to real mode and jump to the BIOS reset code.
153
154    The instruction that switches to real mode by writing to CR0 must be
155    followed immediately by a far jump instruction, which set CS to a
156    valid value for real mode, and flushes the prefetch queue to avoid
157    running instructions that have already been decoded in protected
158    mode.
159
160    Clears all the flags except ET, especially PG (paging), PE
161    (protected-mode enable) and TS (task switch for coprocessor state
162    save).  Flushes the TLB after paging has been disabled.  Sets CD and
163    NW, to disable the cache on a 486, and invalidates the cache.  This
164    is more like the state of a 486 after reset.  I don't know if
165    something else should be done for other chips.
166
167    More could be done here to set up the registers as if a CPU reset had
168    occurred; hopefully real BIOSs don't assume much. */
169
170 static unsigned char real_mode_switch [] =
171 {
172         0x66, 0x0f, 0x20, 0xc0,                 /*    movl  %cr0,%eax        */
173         0x66, 0x83, 0xe0, 0x11,                 /*    andl  $0x00000011,%eax */
174         0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,     /*    orl   $0x60000000,%eax */
175         0x66, 0x0f, 0x22, 0xc0,                 /*    movl  %eax,%cr0        */
176         0x66, 0x0f, 0x22, 0xd8,                 /*    movl  %eax,%cr3        */
177         0x66, 0x0f, 0x20, 0xc3,                 /*    movl  %cr0,%ebx        */
178         0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,       /*    andl  $0x60000000,%ebx */
179         0x74, 0x02,                             /*    jz    f                */
180         0x0f, 0x09,                             /*    wbinvd                 */
181         0x24, 0x10,                             /* f: andb  $0x10,al         */
182         0x66, 0x0f, 0x22, 0xc0                  /*    movl  %eax,%cr0        */
183 };
184 static unsigned char jump_to_bios [] =
185 {
186         0xea, 0x00, 0x00, 0xff, 0xff            /*    ljmp  $0xffff,$0x0000  */
187 };
188
189 /*
190  * Switch to real mode and then execute the code
191  * specified by the code and length parameters.
192  * We assume that length will aways be less that 100!
193  */
194 void machine_real_restart(unsigned char *code, int length)
195 {
196         unsigned long flags;
197
198         local_irq_disable();
199
200         /* Write zero to CMOS register number 0x0f, which the BIOS POST
201            routine will recognize as telling it to do a proper reboot.  (Well
202            that's what this book in front of me says -- it may only apply to
203            the Phoenix BIOS though, it's not clear).  At the same time,
204            disable NMIs by setting the top bit in the CMOS address register,
205            as we're about to do peculiar things to the CPU.  I'm not sure if
206            `outb_p' is needed instead of just `outb'.  Use it to be on the
207            safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
208          */
209
210         spin_lock_irqsave(&rtc_lock, flags);
211         CMOS_WRITE(0x00, 0x8f);
212         spin_unlock_irqrestore(&rtc_lock, flags);
213
214         /* Remap the kernel at virtual address zero, as well as offset zero
215            from the kernel segment.  This assumes the kernel segment starts at
216            virtual address PAGE_OFFSET. */
217
218         memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
219                 sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
220
221         /*
222          * Use `swapper_pg_dir' as our page directory.
223          */
224         load_cr3(swapper_pg_dir);
225
226         /* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
227            this on booting to tell it to "Bypass memory test (also warm
228            boot)".  This seems like a fairly standard thing that gets set by
229            REBOOT.COM programs, and the previous reset routine did this
230            too. */
231
232         *((unsigned short *)0x472) = reboot_mode;
233
234         /* For the switch to real mode, copy some code to low memory.  It has
235            to be in the first 64k because it is running in 16-bit mode, and it
236            has to have the same physical and virtual address, because it turns
237            off paging.  Copy it near the end of the first page, out of the way
238            of BIOS variables. */
239
240         memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100),
241                 real_mode_switch, sizeof (real_mode_switch));
242         memcpy ((void *) (0x1000 - 100), code, length);
243
244         /* Set up the IDT for real mode. */
245
246         load_idt(&real_mode_idt);
247
248         /* Set up a GDT from which we can load segment descriptors for real
249            mode.  The GDT is not used in real mode; it is just needed here to
250            prepare the descriptors. */
251
252         load_gdt(&real_mode_gdt);
253
254         /* Load the data segment registers, and thus the descriptors ready for
255            real mode.  The base address of each segment is 0x100, 16 times the
256            selector value being loaded here.  This is so that the segment
257            registers don't have to be reloaded after switching to real mode:
258            the values are consistent for real mode operation already. */
259
260         __asm__ __volatile__ ("movl $0x0010,%%eax\n"
261                                 "\tmovl %%eax,%%ds\n"
262                                 "\tmovl %%eax,%%es\n"
263                                 "\tmovl %%eax,%%fs\n"
264                                 "\tmovl %%eax,%%gs\n"
265                                 "\tmovl %%eax,%%ss" : : : "eax");
266
267         /* Jump to the 16-bit code that we copied earlier.  It disables paging
268            and the cache, switches to real mode, and jumps to the BIOS reset
269            entry point. */
270
271         __asm__ __volatile__ ("ljmp $0x0008,%0"
272                                 :
273                                 : "i" ((void *) (0x1000 - sizeof (real_mode_switch) - 100)));
274 }
275 #ifdef CONFIG_APM_MODULE
276 EXPORT_SYMBOL(machine_real_restart);
277 #endif
278
279 void machine_shutdown(void)
280 {
281 #ifdef CONFIG_SMP
282         int reboot_cpu_id;
283
284         /* The boot cpu is always logical cpu 0 */
285         reboot_cpu_id = 0;
286
287         /* See if there has been given a command line override */
288         if ((reboot_cpu != -1) && (reboot_cpu < NR_CPUS) &&
289                 cpu_isset(reboot_cpu, cpu_online_map)) {
290                 reboot_cpu_id = reboot_cpu;
291         }
292
293         /* Make certain the cpu I'm rebooting on is online */
294         if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
295                 reboot_cpu_id = smp_processor_id();
296         }
297
298         /* Make certain I only run on the appropriate processor */
299         set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
300
301         /* O.K. Now that I'm on the appropriate processor, stop
302          * all of the others, and disable their local APICs.
303          */
304
305         smp_send_stop();
306 #endif /* CONFIG_SMP */
307
308         lapic_shutdown();
309
310 #ifdef CONFIG_X86_IO_APIC
311         disable_IO_APIC();
312 #endif
313 }
314
315 void machine_emergency_restart(void)
316 {
317         if (!reboot_thru_bios) {
318                 if (efi_enabled) {
319                         efi.reset_system(EFI_RESET_COLD, EFI_SUCCESS, 0, NULL);
320                         load_idt(&no_idt);
321                         __asm__ __volatile__("int3");
322                 }
323                 /* rebooting needs to touch the page at absolute addr 0 */
324                 *((unsigned short *)__va(0x472)) = reboot_mode;
325                 for (;;) {
326                         mach_reboot_fixups(); /* for board specific fixups */
327                         mach_reboot();
328                         /* That didn't work - force a triple fault.. */
329                         load_idt(&no_idt);
330                         __asm__ __volatile__("int3");
331                 }
332         }
333         if (efi_enabled)
334                 efi.reset_system(EFI_RESET_WARM, EFI_SUCCESS, 0, NULL);
335
336         machine_real_restart(jump_to_bios, sizeof(jump_to_bios));
337 }
338
339 void machine_restart(char * __unused)
340 {
341         machine_shutdown();
342         machine_emergency_restart();
343 }
344
345 void machine_halt(void)
346 {
347 }
348
349 void machine_power_off(void)
350 {
351         machine_shutdown();
352
353         if (pm_power_off)
354                 pm_power_off();
355 }
356
357