acpi shutdown in virtualbox

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
poby
Posts: 24
Joined: Wed Sep 21, 2016 9:39 am

acpi shutdown in virtualbox

Post by poby »

I am running a custom os in virtualbox and have parsed the ACPI, FACP, DSDT etc tables to get the PM1a_CNT and SLP_TYPa values. These seem to be correct. However when I try to do an ACPI shutdown with:

Code: Select all

xor eax, eax
mov edx, [PM1a_CNT]
mov ax, [SLP_TYPa]
or ax, (1 shl 13)
out dx, ax 
Nothing happens. PM1a_CNT is 0x4004 and SLP_TYPa is 0, which seems reasonable compared to other values I have seen elsewhere. I also check PM1b_CNT which is zero so I don't bother with it.

Is there an issue or trick with virtualbox to get it working?

Also, when trying to acpi shutdown from the virtualbox menu, it says it's not supported in this guest.

Has anyone successfully implemented acpi shutdown in their os running under virtualbox?
mariuszp
Member
Member
Posts: 587
Joined: Sat Oct 16, 2010 3:38 pm

Re: acpi shutdown in virtualbox

Post by mariuszp »

poby wrote:I am running a custom os in virtualbox and have parsed the ACPI, FACP, DSDT etc tables to get the PM1a_CNT and SLP_TYPa values. These seem to be correct. However when I try to do an ACPI shutdown with:

Code: Select all

xor eax, eax
mov edx, [PM1a_CNT]
mov ax, [SLP_TYPa]
or ax, (1 shl 13)
out dx, ax 
Nothing happens. PM1a_CNT is 0x4004 and SLP_TYPa is 0, which seems reasonable compared to other values I have seen elsewhere. I also check PM1b_CNT which is zero so I don't bother with it.

Is there an issue or trick with virtualbox to get it working?

Also, when trying to acpi shutdown from the virtualbox menu, it says it's not supported in this guest.

Has anyone successfully implemented acpi shutdown in their os running under virtualbox?
Mine works, but i use ACPICA instead of implementing it manually
User avatar
BrightLight
Member
Member
Posts: 901
Joined: Sat Dec 27, 2014 9:11 am
Location: Maadi, Cairo, Egypt
Contact:

Re: acpi shutdown in virtualbox

Post by BrightLight »

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.
You know your OS is advanced when you stop using the Intel programming guide as a reference.
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: acpi shutdown in virtualbox

Post by jnc100 »

Yes, for VirtualBox you can write (((5 & 7) << 10) | (1 << 13)) to io port 0x4004 as a 16-bit write.

However, any code which scans the dsdt/ssdt for _S5 and a package object is very fragile. There is nothing to specify that _S5 has to be a data object. It can just as easily be a method _S5() which returns the actual package object.

In addition, you are expected to execute _PTS(5) and then _GTS(5) before doing the write to PM1a/b_CNT.

All-in-all, attempting to do it without a proper AML interpreter (e.g. ACPICA) will result in a system that luckily happens to work on some systems but will likely cause many issues on others.

Regards,
John.
poby
Posts: 24
Joined: Wed Sep 21, 2016 9:39 am

Re: acpi shutdown in virtualbox

Post by poby »

Huge thanks to you guys! Got it working now. I wish the wiki was updated with this sort of info.

I'm doing a brute force scan through the DSDT to find the "_S5_" string as I've heard there's only one in there. But I might look into programming an AML parser if, as seems likely, I might want to use other values later. All in assembly :) Because (it's fun) | (I'm a masochist)
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: acpi shutdown in virtualbox

Post by SpyderTL »

poby wrote:Also, when trying to acpi shutdown from the virtualbox menu, it says it's not supported in this guest.

Has anyone successfully implemented acpi shutdown in their os running under virtualbox?
You can set the system power to the _S5_ state any time you want by using the "shortcut" that you are using now.

However, if you want the system to respond to the user pressing the power (or sleep) button, or if you want to know when the user of a laptop closes the lid, then you will need a full AML interpreter, because the code to notify the system which of these events you want to receive is written in AML, and it is located in the ACPI tables. This is why the shutdown button in VirtualBox does not currently work in your OS, because you haven't notified the system that your OS supports receiving shutdown events.

Congrats on the working shutdown, by the way. This is the same method I'm currently using, and getting a physical machine to shut itself off is one of my proudest osdev moments. :)
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
poby
Posts: 24
Joined: Wed Sep 21, 2016 9:39 am

Re: acpi shutdown in virtualbox

Post by poby »

I assume _PTS and _GTS are in the DSDT, but I'm having trouble finding any information about them. The spec is so long and frankly more than a little overwhelming, it would be great to get a brief synopsis of what these methods do and the record format.
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: acpi shutdown in virtualbox

Post by SpyderTL »

I found a pretty good summary here: http://www.advogato.org/article/913.html

PTS and GTS are functions provided by the system, written in AML, that you can (should) execute whenever the OS decides to put the system to sleep. Your AML interpreter (that you write) simply executes the code in these two functions.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
Post Reply