patch-2.4.22 linux-2.4.22/arch/x86_64/kernel/process.c

Next file: linux-2.4.22/arch/x86_64/kernel/setup.c
Previous file: linux-2.4.22/arch/x86_64/kernel/pci-pc.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/arch/x86_64/kernel/process.c linux-2.4.22/arch/x86_64/kernel/process.c
@@ -9,7 +9,7 @@
  *  X86-64 port
  *	Andi Kleen.
  * 
- *  $Id: process.c,v 1.64 2003/03/31 15:11:26 ak Exp $
+ *  $Id: process.c,v 1.70 2003/06/09 05:18:21 ak Exp $
  */
 
 /*
@@ -54,6 +54,7 @@
 #include <asm/prctl.h>
 #include <asm/kdebug.h>
 #include <asm/proto.h>
+#include <asm/apic.h>
 
 #include <linux/irq.h>
 
@@ -159,34 +160,37 @@
 __setup("idle=", idle_setup);
 
 static long no_idt[3];
-static int reboot_mode;
-
-#ifdef CONFIG_SMP
-int reboot_smp = 0;
-static int reboot_cpu = -1;
-#endif
+static enum { 
+	BOOT_BIOS = 'b',
+	BOOT_TRIPLE = 't', 
+	BOOT_KBD = 'k',
+} reboot_type = BOOT_KBD;
+static int reboot_mode = 0; 
+
+/* reboot=b[ios] | t[riple] | k[bd] [, [w]arm | [c]old]
+   bios	  Use the CPU reboto vector for warm reset
+   warm   Don't set the cold reboot flag
+   cold   Set the cold reboto flag
+   triple Force a triple fault (init)
+   kbd    Use the keyboard controller. cold reset (default)
+ */ 
 static int __init reboot_setup(char *str)
 {
-	while(1) {
+	for (;;) {
 		switch (*str) {
-		case 'w': /* "warm" reboot (no memory testing etc) */
+		case 'w': 
 			reboot_mode = 0x1234;
 			break;
-		case 'c': /* "cold" reboot (with memory testing etc) */
-			reboot_mode = 0x0;
+
+		case 'c':
+			reboot_mode = 0;
 			break;
-#ifdef CONFIG_SMP
-		case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
-			reboot_smp = 1;
-			if (isdigit(str[1]))
-				sscanf(str+1, "%d", &reboot_cpu);		
-			else if (!strncmp(str,"smp",3))
-				sscanf(str+3, "%d", &reboot_cpu); 
-			/* we will leave sorting out the final value 
-			   when we are ready to reboot, since we might not
- 			   have set up boot_cpu_id or smp_num_cpu */
+
+		case 't':
+		case 'b':
+		case 'k':
+			reboot_type = *str;
 			break;
-#endif
 		}
 		if((str = strchr(str,',')) != NULL)
 			str++;
@@ -195,9 +199,34 @@
 	}
 	return 1;
 }
-
 __setup("reboot=", reboot_setup);
 
+/* overwrites random kernel memory. Should not be kernel .text */
+#define WARMBOOT_TRAMP 0x1000UL
+
+static void reboot_warm(void)
+{
+	extern unsigned char warm_reboot[], warm_reboot_end[];
+	printk("warm reboot\n");
+
+	__cli(); 
+		
+	/* restore identity mapping */
+	init_level4_pgt[0] = __pml4(__pa(level3_ident_pgt) | 7); 
+	__flush_tlb_all(); 
+
+	memcpy(__va(WARMBOOT_TRAMP), warm_reboot, warm_reboot_end - warm_reboot); 
+
+	asm volatile( "   pushq $0\n" 		/* ss */
+		     "   pushq $0x2000\n" 	/* rsp */
+	             "   pushfq\n"		/* eflags */
+		     "   pushq %[cs]\n"
+		     "   pushq %[target]\n"
+		     "   iretq" :: 
+		      [cs] "i" (__KERNEL_COMPAT32_CS), 
+		      [target] "b" (WARMBOOT_TRAMP));
+}
+
 static inline void kb_wait(void)
 {
 	int i;
@@ -207,60 +236,76 @@
 			break;
 }
 
-void machine_restart(char * __unused)
+
+#ifdef CONFIG_SMP
+static void smp_halt(void)
 {
-#if CONFIG_SMP
-	int cpuid;
+	int cpuid = safe_smp_processor_id(); 
+	static int first_entry = 1;
 	
-	cpuid = GET_APIC_ID(apic_read(APIC_ID));
+	if (first_entry) { 
+		first_entry = 0;
+		smp_call_function((void *)machine_restart, NULL, 1, 0);		
+	}
 
-	if (reboot_smp) {
+	smp_stop_cpu(); 
 
-		/* check to see if reboot_cpu is valid 
-		   if its not, default to the BSP */
-		if ((reboot_cpu == -1) ||  
-		      (reboot_cpu > (NR_CPUS -1))  || 
-		      !(phys_cpu_present_map & (1<<cpuid))) 
-			reboot_cpu = boot_cpu_id;
-
-		reboot_smp = 0;  /* use this as a flag to only go through this once*/
-		/* re-run this function on the other CPUs
-		   it will fall though this section since we have 
-		   cleared reboot_smp, and do the reboot if it is the
-		   correct CPU, otherwise it halts. */
-		if (reboot_cpu != cpuid)
-			smp_call_function((void *)machine_restart , NULL, 1, 0);
-	}
-
-	/* if reboot_cpu is still -1, then we want a tradional reboot, 
-	   and if we are not running on the reboot_cpu,, halt */
-	if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
+	/* AP calling this. Just halt */
+	if (cpuid != boot_cpu_id) { 
 		for (;;)
-		__asm__ __volatile__ ("hlt");
+			asm("hlt");
 	}
-	/*
-	 * Stop all CPUs and turn off local APICs and the IO-APIC, so
-	 * other OSs see a clean IRQ state.
-	 */
-		smp_send_stop();
+
+	/* Wait for all other CPUs to have run smp_stop_cpu */
+	while (cpu_online_map) 
+		rep_nop(); 
+}
+#endif
+
+void machine_restart(char * __unused)
+{
+	int i;
+
+#if CONFIG_SMP
+	smp_halt();
+#endif
+	__cli();
+
+#ifndef CONFIG_SMP
+	disable_local_APIC();
 #endif
 	disable_IO_APIC();
-	/* Could do reset through the northbridge of the Hammer here. */
 
-	/* rebooting needs to touch the page at absolute addr 0 */
+	__sti();
+
+	/* Tell the BIOS if we want cold or warm reboot */
 	*((unsigned short *)__va(0x472)) = reboot_mode;
+
 	for (;;) {
-		int i;
-		/* First fondle with the keyboard controller. */ 
+		/* Could also try the reset bit in the Hammer NB */
+		switch (reboot_type) { 
+		case BOOT_BIOS:
+			reboot_warm();
+
+		case BOOT_KBD:
+			/* force cold reboot to reinit all hardware*/
 		for (i=0; i<100; i++) {
 			kb_wait();
 			udelay(50);
 			outb(0xfe,0x64);         /* pulse reset low */
 			udelay(50);
 		}
-		/* That didn't work - force a triple fault.. */
+			
+		case BOOT_TRIPLE: 
+			/* force cold reboot to reinit all hardware*/
+			*((unsigned short *)__va(0x472)) = 0;
+
 		__asm__ __volatile__("lidt %0": :"m" (no_idt));
 		__asm__ __volatile__("int3");
+
+			reboot_type = BOOT_KBD;
+			break;
+		}      
 	}
 }
 
@@ -277,7 +322,7 @@
 extern int printk_address(unsigned long); 
 
 /* Prints also some state that isn't saved in the pt_regs */ 
-void show_regs(struct pt_regs * regs)
+void __show_regs(struct pt_regs * regs)
 {
 	unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L, fs, gs, shadowgs;
 	unsigned int fsindex,gsindex;
@@ -318,7 +363,11 @@
 	       fs,fsindex,gs,gsindex,shadowgs); 
 	printk("CS:  %04x DS: %04x ES: %04x CR0: %016lx\n", cs, ds, es, cr0); 
 	printk("CR2: %016lx CR3: %016lx CR4: %016lx\n", cr2, cr3, cr4);
+}
 
+void show_regs(struct pt_regs * regs)
+{
+	__show_regs(regs);
 	show_trace(&regs->rsp);
 }
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)