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
- Lines: 245
- Date:
2003-08-25 04:44:40.000000000 -0700
- Orig file:
linux-2.4.21/arch/x86_64/kernel/process.c
- Orig date:
2003-06-13 07:51:32.000000000 -0700
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(®s->rsp);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)