Reboot: Difference between revisions

[unchecked revision][unchecked revision]
Content deleted Content added
Cleanup, still needs more work
m Bot: Replace deprecated source tag with syntaxhighlight
 
(16 intermediate revisions by 9 users not shown)
Line 1:
There are several methods for rebooting, including
 
# ACPI Reset command
# load a 0-sized IDT and issue an interrupt (that'll triple fault and reset)
# Use the 8042 keyboard controller to pulse the CPU's RESET pin
# Use the ResetSystem runtime [[UEFI]] service, if available.
# Far jump to the reset vector (0xFFFF:0000)/ Triple fault
 
== 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#GenericAddressStructure|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:
<sourcesyntaxhighlight lang="c">
outportb(FADT->ResetReg.Address, FADT->ResetValue);
</syntaxhighlight>
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. Like:
<syntaxhighlight lang="c">
vmm_map(FADT->ResetReg.Address, 1); // Map 1 byte
uint8_t *reg = (uint8_t *)((uintptr_t)FADT->ResetReg.Address);
*reg = FADT->ResetValue;
</syntaxhighlight>
 
But if it is on the PCI Configuration Space, you need to write ResetValue as a byte on:
* Segment: 0
* Bus: 0
* Slot: (address >> 32) & 0xFFFF
* Function: (address >> 16) & 0xFFFF
* Offset: address & 0xFFFF
That operation in C looks like:
<syntaxhighlight lang="c">
pci_writeb(0, 0, (FADT->ResetReg.Address >> 32) & 0xFFFF, (FADT->ResetReg.Address >> 16) & 0xFFFF, FADT->ResetReg.Address & 0xFFFF, FADT->ResetValue);
</syntaxhighlight>
 
== Short code to do a 8042 reset ==
<sourcesyntaxhighlight lang="c">
void reboot()
{
unsigned charuint8_t good = 0x02;
while ((good & 0x02) != 0)
good = inportinb(0x64);
outportoutb(0x64, 0xFE);
frzhalt();
}
</syntaxhighlight>
</source>
 
 
==Annotated code for reboot()==
<source lang="c">
typedef unsigned char uchar;
typedef uchar byte;
 
== Annotated code for reboot() ==
<syntaxhighlight lang="c">
/* keyboard interface IO port: data and control
READ: status port
Line 41 ⟶ 65:
void reboot()
{
byteuint8_t temp;
 
asm volatile ("CLIcli"); /* disable all interrupts */
 
/* Clear all keyboard buffers (output and command buffers) */
Line 54 ⟶ 78:
 
outb(KBRD_INTRFC, KBRD_RESET); /* pulse CPU reset line */
loop:
asm volatile ("HLThlt"); /* if that didn't work, halt the CPU */
goto loop; /* if a NMI is received, halt again */
}
</syntaxhighlight>
</source>
== Far jump to the reset vector/Triple fault ==
 
Probably the easiest way.
<syntaxhighlight lang="asm">
JMP 0xFFFF:0
</syntaxhighlight>
It'll far jump to the reset vector if you're in real mode, and triple faults if you're in protected mode and removed/haven't setup the gpf handler before.
[[Category:Power management]]