]> Zhao Yanbai Git Server - minix.git/commitdiff
try multiple reset methods
authorBen Gras <ben@minix3.org>
Mon, 20 Feb 2012 17:58:17 +0000 (18:58 +0100)
committerBen Gras <ben@minix3.org>
Mon, 20 Feb 2012 22:54:28 +0000 (23:54 +0100)
. fixes reboot-hang under vbox
. makes experience nicer under vmware
. taken from netbsd reset code

kernel/arch/i386/arch_clock.c
kernel/arch/i386/arch_system.c
kernel/arch/i386/include/arch_proto.h
kernel/arch/i386/klib.S
kernel/proto.h

index 4af6b35ae43a6faaaba48c68e6700b9ec5d3f363..7ac9ae2f70f4848816d7e6f306c0cb3b7f133e3f 100644 (file)
@@ -364,3 +364,13 @@ PUBLIC short cpu_load(void)
        *last_idle = *current_idle;
        return load;
 }
+
+PUBLIC void busy_delay_ms(int ms)
+{
+       u64_t cycles = ms_2_cpu_time(ms), tsc0, tsc, tsc1;
+       read_tsc_64(&tsc0);
+       tsc1 = tsc0 + cycles;
+       do { read_tsc_64(&tsc); } while(tsc < tsc1);
+       return;
+}
+
index 8cc0ab11a7823e89f3d136b5950f13bcb5992abe..a1ddfa4c1f4b5a4ef194acbc29689cd71885dd53 100644 (file)
@@ -63,6 +63,62 @@ PUBLIC __dead void arch_monitor(void)
        monitor();
 }
 
+#define     KBCMDP          4       /* kbd controller port (O) */
+#define      KBC_PULSE0     0xfe    /* pulse output bit 0 */
+#define      IO_KBD          0x060           /* 8042 Keyboard */
+
+void
+reset(void)
+{
+        uint8_t b;
+        /*
+         * The keyboard controller has 4 random output pins, one of which is
+         * connected to the RESET pin on the CPU in many PCs.  We tell the
+         * keyboard controller to pulse this line a couple of times.
+         */
+        outb(IO_KBD + KBCMDP, KBC_PULSE0);
+        busy_delay_ms(100);
+        outb(IO_KBD + KBCMDP, KBC_PULSE0);
+        busy_delay_ms(100);
+
+        /*
+         * Attempt to force a reset via the Reset Control register at
+         * I/O port 0xcf9.  Bit 2 forces a system reset when it
+         * transitions from 0 to 1.  Bit 1 selects the type of reset
+         * to attempt: 0 selects a "soft" reset, and 1 selects a
+         * "hard" reset.  We try a "hard" reset.  The first write sets
+         * bit 1 to select a "hard" reset and clears bit 2.  The
+         * second write forces a 0 -> 1 transition in bit 2 to trigger
+         * a reset.
+         */
+        outb(0xcf9, 0x2);
+        outb(0xcf9, 0x6);
+        busy_delay_ms(500);  /* wait 0.5 sec to see if that did it */
+
+        /*
+         * Attempt to force a reset via the Fast A20 and Init register
+         * at I/O port 0x92.  Bit 1 serves as an alternate A20 gate.
+         * Bit 0 asserts INIT# when set to 1.  We are careful to only
+         * preserve bit 1 while setting bit 0.  We also must clear bit
+         * 0 before setting it if it isn't already clear.
+         */
+        b = inb(0x92);
+        if (b != 0xff) {
+                if ((b & 0x1) != 0)
+                        outb(0x92, b & 0xfe);
+                outb(0x92, b | 0x1);
+                busy_delay_ms(500);  /* wait 0.5 sec to see if that did it */
+        }
+
+       /* Triple fault */
+       x86_triplefault();
+
+       /* Give up on resetting */
+       while(1) {
+               ;
+       }
+}
+
 PRIVATE __dead void arch_bios_poweroff(void)
 {
        u32_t cr0;
index 215724e16f03cf2d5a583d982ffc0b134936ed18..f97466fa34eec5d3fb0ca32281af1b5c9c1da9fc 100644 (file)
@@ -75,6 +75,7 @@ _PROTOTYPE( void exception, (struct exception_frame * frame));
 /* klib386.s */
 _PROTOTYPE( __dead void monitor, (void)                                 );
 _PROTOTYPE( __dead void reset, (void)                                   );
+_PROTOTYPE( __dead void x86_triplefault, (void)                         );
 _PROTOTYPE( void int86, (void)                                         );
 _PROTOTYPE( reg_t read_cr0, (void)                                     );
 _PROTOTYPE( reg_t read_cr2, (void)                                     );
index 5f7bcfbb32089397268779a012209957f83135b6..a46f9e99d6af682f897cc98ac8b8a107fca73dd1 100644 (file)
@@ -499,13 +499,13 @@ ENTRY(mem_rdw)
 
 
 /*===========================================================================*/
-/*                             reset                                        */
+/*                             x86_triplefault                              */
 /*===========================================================================*/
 /*
- * PUBLIC void reset(); 
+ * PUBLIC void x86_triplefault(); 
  * Reset the system by loading IDT with offset 0 and interrupting. 
  */
-ENTRY(reset)
+ENTRY(x86_triplefault)
        lidt    idt_zero
        int     $3      /* anything goes, the 386 will not like it */
 .data
index b38e2c30d6bc44e693a8ae40361c940f8a903eaa..abe52df3d240bdd4ea51874ec1a8a3dc425572ba 100644 (file)
@@ -230,6 +230,7 @@ _PROTOTYPE(void disable_fpu_exception, (void));
 _PROTOTYPE(void release_fpu, (struct proc * p));
 _PROTOTYPE(void arch_pause,(void));
 _PROTOTYPE(short cpu_load, (void));
+_PROTOTYPE(void busy_delay_ms, (int ms));
 
 /* utility.c */
 _PROTOTYPE( void cpu_print_freq, (unsigned cpu));