Reboot

From OSDev.wiki
Revision as of 04:05, 30 September 2016 by Alyssa (talk | contribs) (Add note about UEFI options)
Jump to navigation Jump to search

There are several methods for rebooting, including

  1. ACPI Reset command
  2. load a 0-sized IDT and issue an interrupt (that'll triple fault and reset)
  3. Use the 8042 keyboard controller to pulse the CPU's RESET pin
  4. Use the ResetSystem runtime UEFI service, if available.

ACPI reset command

ACPI 2.0+ defines a "reset register" that can be used to reset the PC. According to the ACPI specification, all hardware must be reset after using this mechanism. In the FADT, there are several General Address Structures. Take a look at the FADT page for details. The FADT structure contains a generic address structure called ResetReg, followed by a byte called ResetValue. This is an optional feature and software must check support for it by checking if the FADT is version 2 or newer, and then testing if bit 10 of the Flags field in the FADT is set. After that, software can reset the system by writing the value in ResetValue into the area pointed to by ResetReg. ACPI says the ResetReg can only be located in I/O bus, PCI bus or memory-mapped. If it is in the I/O bus, simply do:

outportb(FADT->ResetReg->Address, FADT->ResetValue);

If it is memory-mapped, simply map the memory pointed by ResetReg->Address somewhere in the virtual address space, and write ResetValue there as an 8-bit operation.

TODO: Determine how PCI bus resets work.

Short code to do a 8042 reset

void reboot()
{
    uint8_t good = 0x02;
    while (good & 0x02)
        good = inb(0x64);
    outb(0x64, 0xFE);
    halt();
}


Annotated code for reboot()

/* keyboard interface IO port: data and control
   READ:   status port
   WRITE:  control register */
#define KBRD_INTRFC 0x64

/* keyboard interface bits */
#define KBRD_BIT_KDATA 0 /* keyboard data is in buffer (output buffer is empty) (bit 0) */
#define KBRD_BIT_UDATA 1 /* user data is in buffer (command buffer is empty) (bit 1) */

#define KBRD_IO 0x60 /* keyboard IO port */
#define KBRD_RESET 0xFE /* reset CPU command */

#define bit(n) (1<<(n)) /* Set bit n to 1 */

/* Check if bit n in flags is set */
#define check_flag(flags, n) ((flags) & bit(n))

void reboot()
{
    uint8_t temp;

    asm volatile ("cli"); /* disable all interrupts */

    /* Clear all keyboard buffers (output and command buffers) */
    do
    {
        temp = inb(KBRD_INTRFC); /* empty user data */
        if (check_flag(temp, KBRD_BIT_KDATA) != 0)
            inb(KBRD_IO); /* empty keyboard data */
    } while (check_flag(temp, KBRD_BIT_UDATA) != 0);

    outb(KBRD_INTRFC, KBRD_RESET); /* pulse CPU reset line */
loop:
    asm volatile ("hlt"); /* if that didn't work, halt the CPU */
    goto loop; /* if a NMI is received, halt again */
}