Advanced Configuration and Power Interface (ACPI) is a specification which defines platform-independent interfaces for hardware discovery, configuration, power management and monitoring. It was initially developed by Intel, Microsoft and Toshiba in 1996 and revised regularly since then. In early 2013, stewardship of the specification was transferred to the Unified Extensible Firmware Interface Forum (UEFI). The latest version of the specification is 5.1 which was released in July 2014.
The functional areas of the ACPI specification include:
- System power management
- Device power management
- Processor power management
- Configuration / Plug and Play
- System Events
- Battery management
- Thermal management
- Embedded controllers
- SMBus controller
ACPI mainly consists of ACPI tables. The tables define sets of TLV structures (Tag Length Value). The firmware passes these tables to the kernel as a pointer to a root table. The kernel is free to uses or ignore these tables. All the tables can be decompiled with open source tools. The Linux kernel has a builtin ACPI interpreter and scripting language.
ACPI tables contain blocks of configuration information or, alternatively, executable code in a compiled bytecode called AML (ACPI Machine Language). The bytecode provided by the firmware is executed in kernel space. AML bytecode can be found in the DSDT and in SSDTs (Secondary System Description Table).
The ACPI tables are accessible on Linux under the /sysfs pseudo-filesystem:
# cd /sys/firmware/acpi # ls -al total 0 drwxr-xr-x. 5 root root 0 Dec 27 08:32 . drwxr-xr-x. 6 root root 0 Dec 27 11:03 .. drwxr-xr-x. 5 root root 0 Dec 27 11:14 hotplug drwxr-xr-x. 2 root root 0 Dec 27 11:14 interrupts -r--r--r--. 1 root root 4096 Dec 27 11:14 pm_profile drwxr-xr-x. 3 root root 0 Dec 27 08:32 tables # cd tables # ls -al total 0 drwxr-xr-x. 3 root root 0 Dec 27 13:53 . drwxr-xr-x. 5 root root 0 Dec 27 13:53 .. -r--------. 1 root root 114 Dec 27 11:14 APIC -r--------. 1 root root 56 Dec 27 11:14 BGRT -r--------. 1 root root 38840 Dec 27 11:14 DSDT drwxr-xr-x. 2 root root 0 Dec 27 11:14 dynamic -r--------. 1 root root 244 Dec 27 11:14 FACP -r--------. 1 root root 64 Dec 27 11:14 FACS -r--------. 1 root root 56 Dec 27 11:14 HPET -r--------. 1 root root 60 Dec 27 11:14 MCFG -r--------. 1 root root 877 Dec 27 11:14 SSDT1 -r--------. 1 root root 2474 Dec 27 11:14 SSDT2 -r--------. 1 root root 2706 Dec 27 11:14 SSDT3 # cd dynamic # ls -al total 0 drwxr-xr-x. 2 root root 0 Dec 27 11:14 . drwxr-xr-x. 3 root root 0 Dec 27 13:53 .. -r--------. 1 root root 2107 Dec 27 11:19 SSDT4 -r--------. 1 root root 771 Dec 27 11:19 SSDT5 -r--------. 1 root root 281 Dec 27 11:19 SSDT6
Let us examine one of the more interesting tables, i.e. Differentiated System Description Table (DSDT) which supplies information about supported power events in a given system. This table contains the Differentiated Definition Block which supplies the information and configuration information about the base system.
First of all, you need to figure out which ASL (ACPI Source Language) compiler was used was used to build the table.
# dmesg | grep DSDT [ 0.000000] ACPI: DSDT 0x00000000DA7B1170 0097B8 (v02 ALASKA A M I 00000015 INTL 20051117) #
There are two popular ASL compilers – Intel (INTL) and Microsoft (MSFT). From the above output, we can see the table was compiled using the Intel ASL compiler.
To decompile the DSDT table you need to have an Intel ASL decompiler installed. On Fedora 21 X64 for example, this means you to need to install the acpica-tools-20140828-1.fc21.x86_64 package. Alternatively you can download a compiler/decompiler from the ACPICA (ACPI Component Architecture) project which provides an OS-independent reference implementation of the ACPI Specification.
To decompile and view the DTDT source:
# cat /sys/firmware/acpi/tables/DSDT > /var/tmp/dsdt.dat # iasl -d /var/tmp/dsdt.dat # less dsdt.dsl
/* * Intel ACPI Component Architecture * AML/ASL+ Disassembler version 20141107-64 [Dec 2 2014] * Copyright (c) 2000 - 2014 Intel Corporation * * Disassembling to symbolic ASL+ operators * * Disassembly of /tmp/dsdt.dat, Sat Dec 27 13:23:33 2014 * * Original Table Header: * Signature "DSDT" * Length 0x000097B8 (38840) * Revision 0x02 * Checksum 0x59 * OEM ID "ALASKA" * OEM Table ID "A M I" * OEM Revision 0x00000015 (21) * Compiler ID "INTL" * Compiler Version 0x20051117 (537202967) */ DefinitionBlock ("/tmp/dsdt.aml", "DSDT", 2, "ALASKA", "A M I", 0x00000015)
Here is the section of DSDT which deals with a standard keyboard:
Device (PS2K) { Name (_HID, EisaId ("PNP0303") /* IBM Enhanced Keyboard (101/102-key, PS/2 Mouse) */) // _HID: Hardware ID Name (_CID, EisaId ("PNP030B")) // _CID: Compatible ID Method (_STA, 0, NotSerialized) // _STA: Status { If ((IOST & 0x0400)) { Return (0x0F) } Else { Return (Zero) } } Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { IO (Decode16, 0x0060, // Range Minimum 0x0060, // Range Maximum 0x00, // Alignment 0x01, // Length ) IO (Decode16, 0x0064, // Range Minimum 0x0064, // Range Maximum 0x00, // Alignment 0x01, // Length ) IRQNoFlags () {1} }) Name (_PRS, ResourceTemplate () // _PRS: Possible Resource Settings { StartDependentFn (0x00, 0x00) { FixedIO ( 0x0060, // Address 0x01, // Length ) FixedIO ( 0x0064, // Address 0x01, // Length ) IRQNoFlags () {1} } EndDependentFn () }) Method (_PSW, 1, NotSerialized) // _PSW: Power State Wake { KBFG = Arg0 } }
And here is section dealing with the HPET:
Device (HPET) { Name (_HID, EisaId ("PNP0103") /* HPET System Timer */) // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID Name (BUF0, ResourceTemplate () { Memory32Fixed (ReadWrite, 0xFED00000, // Address Base 0x00000400, // Address Length _Y10) }) Method (_STA, 0, NotSerialized) // _STA: Status { If ((OSYS >= 0x07D1)) { If (HPAE) { Return (0x0F) } } Else { If (HPAE) { Return (0x0B) } } Return (Zero) } Method (_CRS, 0, Serialized) // _CRS: Current Resource Settings { If (HPAE) { CreateDWordField (BUF0, _SB.PCI0.LPCB.HPET._Y10._BAS, HPT0) // _BAS: Base Address If ((HPAS == One)) { HPT0 = 0xFED01000 } If ((HPAS == 0x02)) { HPT0 = 0xFED02000 } If ((HPAS == 0x03)) { HPT0 = 0xFED03000 } } Return (BUF0) /* _SB_.PCI0.LPCB.HPET.BUF0 */ } }
If you examine the above “code”, you will see that decompiling ACPI tables can reveal lots of interesting information about your hardware and firmware. In fact, there is a active community of ACPI hackers which patch ACPI tables to improve the functionality of laptops and gaming systems.
If you are interesting in learning more about ACPI support in Linux, a good paper in read is ACPI in Linux, Architecture, Advances, and Challenges by Brown et al.