1/*
2 *  linux/arch/i386/kernel/reboot.c
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 * Power off function, if any
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': /* "warm" reboot (no memory testing etc) */
40			reboot_mode = 0x1234;
41			break;
42		case 'c': /* "cold" reboot (with memory testing etc) */
43			reboot_mode = 0x0;
44			break;
45		case 'b': /* "bios" reboot by jumping through the BIOS */
46			reboot_thru_bios = 1;
47			break;
48		case 'h': /* "hard" reboot by toggling RESET and/or crashing the CPU */
49			reboot_thru_bios = 0;
50			break;
51#ifdef CONFIG_SMP
52		case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
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				/* 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 */
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	{	/* Handle problems with rebooting on Dell E520's */
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	{	/* Handle problems with rebooting on Dell 1300's */
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	{	/* Handle problems with rebooting on Dell 300's */
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	{	/* Handle problems with rebooting on Dell 2400's */
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	{	/* Handle problems with rebooting on HP laptops */
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/* The following code and data reboots the machine by switching to real
144   mode and jumping to the BIOS reset entry point, as if the CPU has
145   really been reset.  The previous version asked the keyboard
146   controller to pulse the CPU reset line, which is more thorough, but
147   doesn't work with at least one type of 486 motherboard.  It is easy
148   to stop this code working; hence the copious comments. */
149
150static unsigned long long
151real_mode_gdt_entries [3] =
152{
153	0x0000000000000000ULL,	/* Null descriptor */
154	0x00009a000000ffffULL,	/* 16-bit real-mode 64k code at 0x00000000 */
155	0x000092000100ffffULL	/* 16-bit real-mode 64k data at 0x00000100 */
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/* This is 16-bit protected mode code to disable paging and the cache,
165   switch to real mode and jump to the BIOS reset code.
166
167   The instruction that switches to real mode by writing to CR0 must be
168   followed immediately by a far jump instruction, which set CS to a
169   valid value for real mode, and flushes the prefetch queue to avoid
170   running instructions that have already been decoded in protected
171   mode.
172
173   Clears all the flags except ET, especially PG (paging), PE
174   (protected-mode enable) and TS (task switch for coprocessor state
175   save).  Flushes the TLB after paging has been disabled.  Sets CD and
176   NW, to disable the cache on a 486, and invalidates the cache.  This
177   is more like the state of a 486 after reset.  I don't know if
178   something else should be done for other chips.
179
180   More could be done here to set up the registers as if a CPU reset had
181   occurred; hopefully real BIOSs don't assume much. */
182
183static unsigned char real_mode_switch [] =
184{
185	0x66, 0x0f, 0x20, 0xc0,			/*    movl  %cr0,%eax        */
186	0x66, 0x83, 0xe0, 0x11,			/*    andl  $0x00000011,%eax */
187	0x66, 0x0d, 0x00, 0x00, 0x00, 0x60,	/*    orl   $0x60000000,%eax */
188	0x66, 0x0f, 0x22, 0xc0,			/*    movl  %eax,%cr0        */
189	0x66, 0x0f, 0x22, 0xd8,			/*    movl  %eax,%cr3        */
190	0x66, 0x0f, 0x20, 0xc3,			/*    movl  %cr0,%ebx        */
191	0x66, 0x81, 0xe3, 0x00, 0x00, 0x00, 0x60,	/*    andl  $0x60000000,%ebx */
192	0x74, 0x02,				/*    jz    f                */
193	0x0f, 0x09,				/*    wbinvd                 */
194	0x24, 0x10,				/* f: andb  $0x10,al         */
195	0x66, 0x0f, 0x22, 0xc0			/*    movl  %eax,%cr0        */
196};
197static unsigned char jump_to_bios [] =
198{
199	0xea, 0x00, 0x00, 0xff, 0xff		/*    ljmp  $0xffff,$0x0000  */
200};
201
202/*
203 * Switch to real mode and then execute the code
204 * specified by the code and length parameters.
205 * We assume that length will aways be less that 100!
206 */
207void machine_real_restart(unsigned char *code, int length)
208{
209	local_irq_disable();
210
211	/* Write zero to CMOS register number 0x0f, which the BIOS POST
212	   routine will recognize as telling it to do a proper reboot.  (Well
213	   that's what this book in front of me says -- it may only apply to
214	   the Phoenix BIOS though, it's not clear).  At the same time,
215	   disable NMIs by setting the top bit in the CMOS address register,
216	   as we're about to do peculiar things to the CPU.  I'm not sure if
217	   `outb_p' is needed instead of just `outb'.  Use it to be on the
218	   safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
219	 */
220
221	spin_lock(&rtc_lock);
222	CMOS_WRITE(0x00, 0x8f);
223	spin_unlock(&rtc_lock);
224
225	/* Remap the kernel at virtual address zero, as well as offset zero
226	   from the kernel segment.  This assumes the kernel segment starts at
227	   virtual address PAGE_OFFSET. */
228
229	memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
230		sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS);
231
232	/*
233	 * Use `swapper_pg_dir' as our page directory.
234	 */
235	load_cr3(swapper_pg_dir);
236
237	/* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
238	   this on booting to tell it to "Bypass memory test (also warm
239	   boot)".  This seems like a fairly standard thing that gets set by
240	   REBOOT.COM programs, and the previous reset routine did this
241	   too. */
242
243	*((unsigned short *)0x472) = reboot_mode;
244
245	/* For the switch to real mode, copy some code to low memory.  It has
246	   to be in the first 64k because it is running in 16-bit mode, and it
247	   has to have the same physical and virtual address, because it turns
248	   off paging.  Copy it near the end of the first page, out of the way
249	   of BIOS variables. */
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	/* Set up the IDT for real mode. */
256
257	load_idt(&real_mode_idt);
258
259	/* Set up a GDT from which we can load segment descriptors for real
260	   mode.  The GDT is not used in real mode; it is just needed here to
261	   prepare the descriptors. */
262
263	load_gdt(&real_mode_gdt);
264
265	/* Load the data segment registers, and thus the descriptors ready for
266	   real mode.  The base address of each segment is 0x100, 16 times the
267	   selector value being loaded here.  This is so that the segment
268	   registers don't have to be reloaded after switching to real mode:
269	   the values are consistent for real mode operation already. */
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	/* Jump to the 16-bit code that we copied earlier.  It disables paging
279	   and the cache, switches to real mode, and jumps to the BIOS reset
280	   entry point. */
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	/* The boot cpu is always logical cpu 0 */
296	reboot_cpu_id = 0;
297
298	/* See if there has been given a command line override */
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	/* Make certain the cpu I'm rebooting on is online */
305	if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
306		reboot_cpu_id = smp_processor_id();
307	}
308
309	/* Make certain I only run on the appropriate processor */
310	set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
311
312	/* O.K. Now that I'm on the appropriate processor, stop
313	 * all of the others, and disable their local APICs.
314	 */
315
316	smp_send_stop();
317#endif /* CONFIG_SMP */
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		/* rebooting needs to touch the page at absolute addr 0 */
339		*((unsigned short *)__va(0x472)) = reboot_mode;
340		for (;;) {
341			mach_reboot_fixups(); /* for board specific fixups */
342			mach_reboot();
343			/* That didn't work - force a triple fault.. */
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