Translate

Archives

Decompiling ACPI Tables

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.

Comments are closed.