try multiple reset methods

. fixes reboot-hang under vbox
	. makes experience nicer under vmware
	. taken from netbsd reset code
This commit is contained in:
Ben Gras 2012-02-20 18:58:17 +01:00
parent a953da6e10
commit ca47635d0a
5 changed files with 71 additions and 3 deletions

View 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;
}

View 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;

View 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) );

View 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

View 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));