Add BIOS reboot function

Using the keyboard controller to trigger CPU reset does not work on some 486
machines. Add reboot routine based on linux/arch/x86/realmode/rm/reboot.S that
switches to the real mode and jumps into the BIOS reset entry point after
writing 0 to 0x472 to request a cold reboot. It seems the intention was already
there, given the 0x472 reference, but the proper implementation was missing.

For now, I only implemented the 32-bit version as handling 64-bit requires
more code to exit the Long Mode. Also, there is no code for setting the GDT/IDT.
However, as the code is expected to handle rebooting 486 machines only after
the two other mechanisms (0xcf9 and 0x64 respectively), this seems sufficient.

On my 486 DX4-120 system w/82C895+82C502A chipset it works about 9/10 times.

Also, make sure reboot() never returns.
This commit is contained in:
01e3 2022-07-21 10:37:54 -07:00
parent 6b998e82e7
commit cebdf67d2c
1 changed files with 42 additions and 1 deletions

View File

@ -71,10 +71,51 @@ void reboot(void)
outb(0xfe, 0x64);
usleep(150000);
#ifndef __x86_64__
if (efi_rs_table == NULL) {
// In last resort, (very) obsolete reboot method using BIOS
*((uint16_t *)0x472) = 0x1234;
*((uint16_t *)0x472) = 0; // Request cold reboot.
// Switch the CPU back to the real mode.
__asm__ __volatile__("\t"
"movl $16, %ecx\n\t"
"movl %ecx, %ds\n\t"
"movl %ecx, %es\n\t"
"movl %ecx, %fs\n\t"
"movl %ecx, %gs\n\t"
"movl %ecx, %ss\n\t"
"xorl %ecx, %ecx\n\t"
"movl %cr0, %edx\n\t"
"andl $0x00000011, %edx\n\t"
"orl $0x60000000, %edx\n\t"
"movl %edx, %cr0\n\t"
"movl %ecx, %cr3\n\t"
"movl %cr0, %edx\n\t"
"testl $0x60000000, %edx\n\t" // If no cache bits -> no wbinvd.
"jz 2f\n\t"
"wbinvd\n\t"
"2:\n\t"
"andb $0x10, %dl\n\t"
"movl %edx, %cr0\n\t"
// call BIOS reboot routine.
"ljmpw $0xf000, $0xfff0\n\t"
);
}
#endif
/**
* Make sure we won't return to the calling function in case all
* of the above methods failed.
*/
for (;;) {
__asm__ __volatile__("hlt");
}
}
void floppy_off()