*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;
+}
+
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;
/* 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) );
/*===========================================================================*/
-/* 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
_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));