It's most likely you followed the Wiki on how to do an ACPI shutdown, didn't you?
The information on there is inaccurate, and I had similar problems until I read the relevant parts of the ACPI specification. Maybe someone could help me fix the Wiki entry on shutdown?
Anyway, the Wiki doesn't mention that the sleep objects may be in the SSDT and not nescessarily the DSDT (although on VirtualBox, it is in the DSDT.) The DSDT/SSDT as already mentioned on the Wiki is AML-encoded. The system shutdown really is the _S5_ sleep state, encoded in the _S5_ package object. You can scan the DSDT/SSDT for "_S5_" (without a null terminator) followed by the byte value 0x12 (which really is the AML opcode for package.) An AML package is a collection of other data. In the case of _S5_, the package contains 4 integers. The first integer is the SLP_TYPa value, and the second is the SLP_TYPb value. The integers may be bytes, words, DWORDs or QWORDs, although in the case of _S5_ they will always be bytes. In a pointer to the start of the _S5_ package, add 7 and read a byte from there and increment the pointer. If it is 0x0A (AML opcode for byte prefix), then the byte it now points to is the SLP_TYPa value. If not, take the read byte as the SLP_TYPa value. Repeat with the already-incremented pointer, but for the SLP_TYPb value. Ignore the remaining two values; they are reserved. AND both SLP_TYPa and SLP_TYPb values by 7 to clear all bits except the lowest three.
Now, the Wiki says you OUT the SLP_TYPa/b to the PM1a/b control block I/O ports. What the Wiki doesn't mention is that you have to shift them to the left by 10 bits. In general, after you've acquired the sleep values, you shut down like this:
Code: Select all
uint16_t tmp = inw(fadt->pm1a_control_block);
outw(fadt->pm1a_control_block, tmp | (uint16_t)slp_typa << 10) | 0x2000);
if(fadt->pm1b_control_block == 0)
{
panic("Shutdown failed...");
}
tmp = inw(fadt->pm1b_control_block);
outw(fadt->pm1b_control_block, tmp | (uint16_t)slp_typb << 10) | 0x2000);
Something you shouldn't depend on: on VirtualBox, the SLP_TYPa value is 5, and there is a byte prefix opcode before the byte value 5.
EDIT:
I've just noticed you mention the ACPI shutdown menu item on VirtualBox says unsupported on the guest. This means you have not even enabled ACPI. Do something like this:
Code: Select all
outb(fadt->sci_command, fadt->acpi_enable);
And put a short delay, then check if bit 0 of PM1a_CONTROL_BLOCK sets. If it doesn't set after a short delay (maybe a few milliseconds?), then you should fail and consider the firmware to be not responding. A shutdown won't work without enabling the ACPI firmware.
Oh, and that shutdown menu really generates a SCI IRQ, and you'll need an IRQ handler for that too and a complete AML interpreter.
My homemade ACPI DSDT/SSDT scanner and sleep/shutdown code.