---
# System prepended metadata

title: ACPI
tags: [linux kernel]

---

# ACPI

Advanced Configuration and Power Interface [(ACPI)](https://uefi.org/specs/ACPI/6.6/ ), is an open industry standard that lets the operating system (OS) manage computer hardware for power, configuration, and status monitoring.

ACPI is the key element in implementing OSPM. ACPI-defined interfaces are intended for wide adoption to encourage hardware and software vendors to build ACPI-compatible (and, thus, OSPM-compatible) implementations.

![2025-12-29 18-26-32 的螢幕擷圖](https://hackmd.io/_uploads/HyJwuC1Nbl.png)

## ACPI description 

Like device tree, ACPI uses a hierarchical architecture to describe hardware information. for example
```
Device (FOO) {
  Name (_HID, "BMA222E")
  Name (_CRS, ResourceTemplate () {
    GpioIo (Exclusive, ..., IoRestrictionOutputOnly,
            "\\_SB.GPI0") {15} // red
    GpioIo (Exclusive, ..., IoRestrictionOutputOnly,
            "\\_SB.GPI0") {16} // green
    GpioIo (Exclusive, ..., IoRestrictionOutputOnly,
            "\\_SB.GPI0") {17} // blue
    GpioIo (Exclusive, ..., IoRestrictionOutputOnly,
            "\\_SB.GPI0") {1} // power
  })
  
  Name (_DSD, Package () {
    ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
    Package () {
            Package () {
                    "led-gpios",
                    Package () {
                            ^FOO, 0, 0, 1,
                            ^FOO, 1, 0, 1,
                            ^FOO, 2, 0, 1,
                    }
            },
            Package () {
                    "power-gpios",
                    Package () {^FOO, 3, 0, 0},
            },
    }
  })
}
```
This describes a “device - FOO” and it’s name is “BMA222E” and with 4 gpio resource, it similar with 
```
foo_device {
        compatible = "acme,foo";
        ...
        led-gpios = <&gpio 15 GPIO_ACTIVE_HIGH>, /* red */
                    <&gpio 16 GPIO_ACTIVE_HIGH>, /* green */
                    <&gpio 17 GPIO_ACTIVE_HIGH>; /* blue */

        power-gpios = <&gpio 1 GPIO_ACTIVE_LOW>;
};
```

## ACPI in x86 system:

The ACPI information is under /sys/firmware/acpi/tables/

```
$ ls /sys/firmware/acpi/tables/
 APIC    DBGP      FACS   NHLT     SSDT11   SSDT17   SSDT22   SSDT7   WSMT
'ASF!'   DMAR      FPDT   OEMD     SSDT12   SSDT18   SSDT23   SSDT8
 BGRT    DSDT      HPET   PHAT     SSDT13   SSDT19   SSDT3    SSDT9
 BOOT    DTPR      LPIT   SDEV     SSDT14   SSDT2    SSDT4    TPM2
 data    dynamic   MCFG   SSDT1    SSDT15   SSDT20   SSDT5    UEFI1
 DBG2    FACP      MSDM   SSDT10   SSDT16   SSDT21   SSDT6    UEFI2
```

we can use iasl -d to disassemble the data

e.g:
```
sudo cat /sys/firmware/acpi/tables/DSDT > dsdt.aml
iasl -d dsdt.aml
```

or we also can use acpidump and acpixtract to get all information.
```
acpidump >acpidump
acpixtract -a acpidump
```
We put the dynamic add ACPI under ==/sys/kernel/config/acpi/table/== to support hot-plug, especially for ==“configfs”== loading

Defined devices are under ==/sys/bus/acpi/devices/==
```
$ ls /sys/bus/acpi/devices/
10EC1308:00  ACPI0007:2b  device:24  device:52  device:80    LNXPOWER:07
ABCD0000:00  ACPI0007:2c  device:25  device:53  device:81    LNXPOWER:08
ACPI0003:00  ACPI0007:2d  device:26  device:54  device:82    LNXSYBUS:00
ACPI0007:00  ACPI0007:2e  device:27  device:55  device:83    LNXSYBUS:01
ACPI0007:01  ACPI0007:2f  device:28  device:56 ....

ACPI0007:24  device:1d    device:4b  device:79  LNXPOWER:00  PRP00001:00
ACPI0007:25  device:1e    device:4c  device:7a  LNXPOWER:01  PRP00001:01
....
```

And active devices are under ==/sys/bus/platform/devices/==

## Build ACPI Machine Language (aml) file

Use iasl -ve to build it

## Upgrading ACPI tables 

we have 3 ways to upgrade the ACPI tables

### 1. Loading ACPI SSDTs from initrd

1. Enable ==CONFIG_ACPI_TABLE_UPGRADE==
or use ==CONFIG_ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD== for buildin kernel
2. create a tmp directory, and goto the directory.
3. Copy the aml to ==kernel/firmware/acpi/==
:::info
this path is defined in ==acpi_table_upgrade== function
char cpio_path[32] = "kernel/firmware/acpi/"
:::
4. Use ==find kernel -type f | cpio -o -H newc > /boot/acpi_override.cpio== to create the cpio file under ==/boot/acpi_override.cpio==
7. Merge acpi_override.cpio into initramfs, ==cat /boot/acpi_override.cpio $initramfs_file > $new_initramfs_file==
8. (option) Add debug option into boot cmd, 
    e.g: acpi.debug_level=0x2 acpi.debug_layer=0xFFFFFFFF


### 2. Loading ACPI SSDTs from EFI variables

https://www.kernel.org/doc/html/latest/admin-guide/acpi/ssdt-overlays.html#loading-acpi-ssdts-from-efi-variables  

### 3. configfs

We need to check whether CONFIG_ACPI_CONFIGFS is enabled. This allows the config filesystem to pass ACPI binary data.
```
$ cat /boot/config-6.14.0-37-generic | grep "CONFIG_ACPI_CONFIGFS"
CONFIG_ACPI_CONFIGFS=m
```
Then put the aml data under  ==/sys/kernel/config/acpi/table/==
:::info
The configfs mount point is at ==/sys/kernel/config==, and the ==acpi/table== interface is the key mechanism in the Linux kernel for supporting ACPI table upgrades.
:::
Under this path, creating a directory triggers ACPI to create an ACPI template and wait for the user to provide a binary AML file.
Then, using "file write" to copy the buffer and "file release" to finalize the update causes the new ACPI data to take effect. 

e.g:
```
cd /sys/kernel/config/acpi/table
mkdir my_ssdt
cat ~/ssdt.aml > my_ssdt/aml
```

## ACPI detail
:::spoiler  ACPI table define

| **Table Name**  | **Full Name**                                 | **Purpose / Description**                                                                                                            |
| --------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| **RSDP**        | Root System Description Pointer               | Entry point of ACPI. Provides the physical address of the RSDT or XSDT so the operating system can locate all ACPI tables.           |
| **RSDT**        | Root System Description Table                 | Contains 32-bit pointers to other ACPI tables. Used by legacy systems.                                                               |
| **XSDT**        | Extended System Description Table             | Same as RSDT but uses 64-bit pointers. Preferred by modern operating systems.                                                        |
| **FADT (FACP)** | Fixed ACPI Description Table                  | Describes fixed hardware features such as power management, sleep states, reset mechanism, and contains the pointer to the DSDT.     |
| **DSDT**        | Differentiated System Description Table       | Main ACPI table containing AML code that defines devices, power states, and platform-specific control logic.                         |
| **SSDT**        | Secondary System Description Table            | Supplements or overrides the DSDT. Commonly used for CPU definitions, power management, and dynamically loaded hardware information. |
| **MADT / APIC** | Multiple APIC Description Table               | Describes interrupt controllers and CPU topology, including Local APICs, I/O APICs, and interrupt routing.                           |
| **SRAT**        | System Resource Affinity Table                | Defines NUMA topology by mapping CPUs and memory regions to proximity domains.                                                       |
| **SLIT**        | System Locality Information Table             | Provides relative distance information between NUMA nodes, used for scheduling and memory allocation decisions.                      |
| **HPET**        | High Precision Event Timer                    | Provides a high-resolution hardware timer used by the OS for precise timing and scheduling.                                          |
| **MCFG**        | PCI Express Configuration Space Mapping Table | Describes the memory-mapped configuration space (ECAM) for PCI Express devices.                                                      |
| **BGRT**        | Boot Graphics Resource Table                  | Allows the OS to reuse the UEFI boot logo for a smooth transition from firmware to OS graphics.                                      |
| **NFIT**        | NVDIMM Firmware Interface Table               | Describes non-volatile memory (NVDIMM/PMEM) regions and their access methods.                                                        |
| **FPDT**        | Firmware Performance Data Table               | Provides firmware boot performance metrics such as boot phase timestamps.                                                            |
| **SDEV**        | Secure Devices Table                          | Describes secure hardware devices and their interfaces for trusted execution environments.                                           |
| **IORT**        | I/O Remapping Table                           | Describes IOMMU and interrupt remapping hardware, mainly used on ARM and heterogeneous systems.                                      |
| **PRMT**        | Platform Runtime Mechanism Table              | Defines platform-specific runtime services and low-level firmware interaction mechanisms.                                            |
| **TPM2**        | Trusted Platform Module 2.0 Table             | Describes the TPM 2.0 device, its interface, and event log location for security features like measured boot.                        |

:::

:::spoiler ACPI debug output
[ACPI debug level](https://elixir.bootlin.com/linux/v6.17.9/source/include/acpi/acoutput.h )

| Requirement | Component debug_layer | debug_level Constant |
|------|------------|-------------|
| how AML Debug() messages only| 0x00000080 | 0x00000002 |
| Show all ACPI messages | 0xFFFFFFFF | 0xFFFFFFFF |
| ACPI table–related messages | 0x00000008 | 0x00002000 |
| Event / IRQ–related messages | 0x00000004 | 0x80000000 |


| Component Name | Hex Value | Description |
|----------------|-----------|-------------|
| ACPI_UTILITIES | 0x00000001 | Common utility functions |
| ACPI_HARDWARE | 0x00000002 | Hardware access related (I/O, MMIO, EC, etc.) |
| ACPI_EVENTS | 0x00000004 | ACPI events / GPE / IRQ / interrupts |
| ACPI_TABLES | 0x00000008 | ACPI table reading / loading |
| ACPI_NAMESPACE | 0x00000010 | Namespace evaluation / parsing |
| ACPI_PARSER | 0x00000020 | AML parser (parses AML bytecode) |
| ACPI_DISPATCHER | 0x00000040 | ACPI internal dispatcher (method call state machine) |
| ACPI_EXECUTER | 0x00000080 | AML method execution / Debug opcode execution (Debug()) |
| ACPI_RESOURCES | 0x00000100 | Resource parsing (CRS / ResourceTemplate) |
| ACPI_CA_DEBUGGER | 0x00000200 | ACPICA debugger messages |
| ACPI_OS_SERVICES | 0x00000400 | OS services call messages |
| ACPI_CA_DISASSEMBLER | 0x00000800 | AML disassembler messages |
| ACPI_COMPILER | 0x00001000 | ACPI compiler messages |
| ACPI_TOOLS | 0x00002000 | ACPI tools messages |
| ACPI_ALL_DRIVERS | 0xFFFF0000 | All ACPI driver messages |

| Level Constant | Hex Value | Description |
|----------------|-----------|-------------|
| ACPI_LV_INIT | 0x00000001 | Initialization messages |
| ACPI_LV_DEBUG_OBJECT | 0x00000002 | Output from AML Debug() |
| ACPI_LV_INFO | 0x00000004 | General informational messages |
| ACPI_LV_REPAIR | 0x00000008 | Automatic repair messages |
| ACPI_LV_TRACE_POINT | 0x00000010 | Trace point messages |
| ACPI_LV_INIT_NAMES | 0x00000020 | Name / namespace initialization |
| ACPI_LV_PARSE | 0x00000040 | AML parser messages |
| ACPI_LV_LOAD | 0x00000080 | Table load messages |
| ACPI_LV_DISPATCH | 0x00000100 | Method dispatch messages |
| ACPI_LV_EXEC | 0x00000200 | Method execution messages |
| ACPI_LV_NAMES | 0x00000400 | Name / object messages |
| ACPI_LV_OPREGION | 0x00000800 | OperationRegion messages |
| ACPI_LV_BFIELD | 0x00001000 | BitField messages |
| ACPI_LV_TABLES | 0x00002000 | Table dump / reload messages |
| ACPI_LV_VALUES | 0x00004000 | Value / object content messages |
| ACPI_LV_OBJECTS | 0x00008000 | Object creation / deletion messages |
| ACPI_LV_RESOURCES | 0x00010000 | Resource parsing messages |
| ACPI_LV_USER_REQUESTS | 0x00020000 | User request messages |
| ACPI_LV_PACKAGE | 0x00040000 | Package-related messages |
| ACPI_LV_ALLOCATIONS | 0x00100000 | Memory allocation messages |
| ACPI_LV_FUNCTIONS | 0x00200000 | Function call messages |
| ACPI_LV_OPTIMIZATIONS | 0x00400000 | Optimizer messages |
| ACPI_LV_MUTEX | 0x01000000 | Mutex / lock messages |
| ACPI_LV_THREADS | 0x02000000 | Thread-related messages |
| ACPI_LV_IO | 0x04000000 | I/O messages |
| ACPI_LV_INTERRUPTS | 0x08000000 | Interrupt messages |
| ACPI_LV_AML_DISASSEMBLE | 0x10000000 | AML disassembly messages |
| ACPI_LV_VERBOSE_INFO | 0x20000000 | Verbose information messages |
| ACPI_LV_FULL_TABLES | 0x40000000 | Full table dump messages |
| ACPI_LV_EVENTS | 0x80000000 | Event messages (GPE / interrupts) |

:::

## LEDs GPIO in ACPI 
LED in the GPIO subsystem, the Linux kernel creates a default path at ==/sys/class/leds/==
```
/sys/class/leds/
├── green -> ../../devices/pci0000:00/PRP0001:00/leds/green
└── red -> ../../devices/pci0000:00/PRP0001:00/leds/red
```
We can see that the path directs to the devices directory
```
/sys/devices/pci0000:00/PRP0001:00/leds
├── green
│   ├── brightness
│   ├── device -> ../../../PRP0001:00
│   ├── max_brightness
│   ├── power
│   │   ├── autosuspend_delay_ms
│   │   ├── control
│   │   ├── runtime_active_time
│   │   ├── runtime_status
│   │   └── runtime_suspended_time
│   ├── subsystem -> ../../../../../class/leds
│   ├── trigger
│   └── uevent
└── red
    ├── brightness
    ├── device -> ../../../PRP0001:00
    ├── max_brightness
    ├── power
    │   ├── autosuspend_delay_ms
    │   ├── control
    │   ├── runtime_active_time
    │   ├── runtime_status
    │   └── runtime_suspended_time
    ├── subsystem -> ../../../../../class/leds
    ├── trigger
    └── uevent
```
How could we do ?
1. Check kernel config ==CONFIG_GPIO_LEDS==
2. Use =={ "compatible", "gpio-leds" }== to notify the kernel using leds-gpio driver.
3. Use ==Name (_HID, "PRP0001")== to notify the kernel using common driver.

:::spoiler example
```

DefinitionBlock (
    "leds-acpi.aml",    // Output file name
    "SSDT",             // Table Signature
    3,                  // DSDT Revision (keep same or higher than your system's DSDT)
    "INTEL",            // OEM ID
    "LEDS",             // OEM Table ID (custom name)
    0x00000002)         // OEM Revision
{
    External (\_SB, DeviceObj)
    External (\_SB.PC00, DeviceObj)
    External (\_SB.PC00.GPIO, DeviceObj)  // GPIO controller reference
    Scope (\_SB.PC00)
    {
            Device (LEDS)
            {
                Name (_HID, "PRP0001")
                Name (_DDN, "GPIO LEDs device")

                Name (_CRS, ResourceTemplate () {
                    GpioIo (
                        Exclusive,                  // Not shared
                        PullNone,                   // No need for pulls
                        0,                          // Debounce timeout
                        0,                          // Drive strength
                        IoRestrictionOutputOnly,    // Only used as output
                        "\\_SB.PC00.GPIO",          // GPIO controller (Note: PC00 is not PCI0)
                        0)                          // Must be 0
                    {
                        70,                         // GPIO pin 70 (index 0)
                        80                          // GPIO pin 80 (index 1)
                    }
                })

                Name (_DSD, Package () {
                    ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                    Package () {
                        Package (0x02) { "compatible", "gpio-leds" },
                    },
                    ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
                    Package () {
                        Package (0x02) {"led-0", "LED0"},
                        Package (0x02) {"led-1", "LED1"},
                    }
                })

                /*
                * For more information about these bindings see:
                * Documentation/devicetree/bindings/leds/common.yaml,
                * Documentation/devicetree/bindings/leds/leds-gpio.yaml and
                * Documentation/firmware-guide/acpi/gpio-properties.rst.
                */
                Name (LED0, Package () {
                    ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                    Package () {
                        Package (0x02) {"label", "green"},
                        Package (0x02) {"default-state", "off"},
                        Package (0x02) {"gpios", Package (0x04) {
                            ^LEDS,           // Reference parent device (LEDS)
                            0x00,            // Resource Index (corresponds to GpioIo in _CRS)
                            0x00,            // Pin Index (index 0 in GPIO list in _CRS, i.e., GPIO 70)
                            0x00             // Flags: Active Low
                        }},
                        Package (0x02) {"retain-state-suspended", 1},
                    }
                })
                Name (LED1, Package () {
                    ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
                    Package () {
                        Package (0x02) {"label", "red"},
                        Package (0x02) {"default-state", "off"},
                        Package (0x02) {"gpios", Package (0x04) {
                            ^LEDS,           // Reference parent device (LEDS)
                            0x00,            // Resource Index (corresponds to GpioIo in _CRS)
                            0x01,            // Pin Index (index 1 in GPIO list in _CRS, i.e., GPIO 80)
                            0x00             // Flags: Active Low
                        }},
                        Package (0x02) {"retain-state-suspended", 1},
                    }
                })
            }
    }
}
```
:::




# ACPI in kernel
## ACPI initialization flow
1. Load RSDP Discovery
    #define ACPI_HI_RSDP_WINDOW_BASE        0x000E0000
3. Parsing RSDP table to get RSDT/XSDT
4. Parsing XSDT/RSDT
5. Table Installation
    Install FADT/ DSDT/ SSDT/ MADT/ FACS into global table ist
7. FADT Parsing
    Extract DSDT/ FACS data, hardware feature flags, power management register addresses.
9. Loading to aml namesapce.
    Create namespece for each.
    Process additional SSDT table.
    Initialize the namespace object.
11. Device Enumeration.
    Walk ACPI namesapce tree from root
    Execute STA, Read HID, uuid for mapping device type
    
    | Device | HID |
    | -------- | -------- |
    | System device | LNXSYSTM |
    | Battery | PNP0C0A |
    | AC Adapter | ACPI0003 |
    | Power Button | LNXPWRBN |
    | Sleep Button | LNXSLPBN |
    |  High Precision Event Timer | PNP0103 |
    | Power Button (alternative) | PNP0C0C |
    
13. Binding driver

## Device driver support 
Device drivers support two types of data structures: [struct of_device_id and struct acpi_device_id](https://elixir.bootlin.com/linux/v6.17.8/source/include/linux/device/driver.h#L106)
Here are the define:
```
	const struct of_device_id	*of_match_table;
	const struct acpi_device_id	*acpi_match_table;
```
and the ==struct of_device_id== for support ==dts==
```
struct of_device_id {
	char	name[32];
	char	type[32];
	char	compatible[128];
	const void *data;
};
```
In dts we often see
```
my_device@1000 {
    compatible = "vendor,my-device";
};
```


==struct acpi_device_id== for support ACPI
```
struct acpi_device_id {
	__u8 id[ACPI_ID_LEN];
	kernel_ulong_t driver_data;
	__u32 cls;
	__u32 cls_msk;
};
```
so like driver code in Kernel
```
static const struct acpi_device_id  thermal_device_ids[] = {
	{ACPI_THERMAL_HID, 0},
	{"", 0},
};
```
and ACPI asl code will have 
```
Name (_HID, "ACPI_THERMAL_HID")
```
This will map the ACPI code to linux kernel driver


### How to map LED and reset button to ACPI via device tree?
Use =="PRP0001"== for generic code to define these device.
```
#define ACPI_DT_NAMESPACE_HID	"PRP0001"
...
static const struct acpi_device_id generic_device_ids[] = {
	{ACPI_DT_NAMESPACE_HID, },
	{"", },
};

static struct acpi_scan_handler generic_device_handler = {
	.ids = generic_device_ids,
	.attach = acpi_generic_device_attach,// will call acpi_default_enumeration
};
```
and ACPI define 
```
{ "compatible", "gpio-leds" }
{ "compatible", "gpio-keys-polled" } 
```
so these can map to gpio-leds and gpio-key-polled device tree






## init flow
![ascii-art-image](https://hackmd.io/_uploads/SyTW8KaG-l.png)
[ACPI config base addree](https://elixir.bootlin.com/linux/v6.17.8/source/include/acpi/acconfig.h#L153)
## How ACPI loads at bootup
```
/ arch / x86 / boot / compressed / head_64.S  
| - SYM_CODE_START(startup_64) 
|   | - leaq rva(.Lrelocated)(%rbx), %rax 
| - SYM_FUNC_START_LOCAL_NOALIGN(.Lrelocated)
|       | - call extract_kernel  
|                | - / arch / x86 / boot / compressed / misc.c 
|                    | - asmlinkage __visible void *extract_kernel(void *rmode, unsigned char *output)
|                                                  | - boot_params_ptr->acpi_rsdp_addr = get_rsdp_addr();
|                                                  |                             |- / arch / x86 / boot / compressed / acpi.c 
|                                                  |                                 | - acpi_physical_address get_rsdp_addr(void) 
|                                                  |                                     | - if (!pa) 
|                                                  |                                           pa = efi_get_rsdp_addr(); 
|                                                  |                                         if (!pa) 
|                                                  |                                           pa = bios_get_rsdp_addr();
|                                                  |                                                |- rsdp = scan_mem_for_rsdp((u8 *) ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE);
|                                                  |                                                   #define ACPI_HI_RSDP_WINDOW_BASE        0x000E0000 /* Physical Address */ 
|                                                  |                                                   #define ACPI_HI_RSDP_WINDOW_SIZE        0x00020000 
|                                                  | - entry_offset = decompress_kernel(output, virt_addr, error); 
| - jmp *%rax 
| - SYM_CODE_END(startup_64)       

```
after booting up the start_kernel will load acpi table
```
Kernel/head_64.s 
| - SYM_CODE_START_NOALIGN(startup_64) 
|    | - leaq common_startup_64(%rip), %rdi 
|    | - jmp	*.Lcommon_startup_64(%rip)
|   SYM_CODE_END(startup_64)
| - SYM_DATA_LOCAL(.Lcommon_startup_64, .quad common_startup_64)) 
| - SYM_INNER_LABEL(common_startup_64, SYM_L_LOCAL) 
| - SYM_CODE_START(secondary_startup_64)
|     | - callq *initial_code(%rip) 
|   SYM_CODE_END(secondary_startup_64)
| - SYM_DATA(initial_code, .quad x86_64_start_kernel) 
                                | - asmlinkage __visible void __init __noreturn x86_64_start_kernel(char * real_mode_data) 

x86_64_start_kernel(char * real_mode_data)
| - kasan_early_init(); 
| - x86_64_start_reservations(real_mode_data); 
|   | - start_kernel(); 
        | - setup_arch(&command_line);
        |   |   e820__memory_setup();
        |   |   acpi_table_upgrade();
        |   |       | - char cpio_path[32] = "kernel/firmware/acpi/";
        |   |       |   if (IS_ENABLED(CONFIG_ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD)) 
        |   |       |   file = find_cpio_data(cpio_path, data, size, &offset);
        |   |       |   acpi_initrd_files[table_nr].data = file.data;
        |   |       |   acpi_initrd_files[table_nr].size = file.size;
        |   |   /* Look for ACPI tables and reserve memory occupied by them. */
        |   |   acpi_boot_table_init();
        |   |       | - acpi_locate_initial_tables(void)
        |   |       |   | - acpi_initialize_tables()
        |   |       |   |   | - acpi_tb_parse_root_table() // process RSDT/ XSDT
        |   |       |   |   |   | - acpi_tb_install_standard_table() // read FADT/ DSDT/ SSDT/ APIC...
        |   |       |   |   |   | - acpi_tb_parse_fadt() //  FADT Parsing
```

## Configfs working 
### How does configfs (Configuration filesystem) work?

This is a filesystem. First, we check where the system is mounted?
```
$ mount -l | grep config
configfs on /sys/kernel/config type configfs (rw,nosuid,nodev,noexec,relatime)
```
The mount point is on ==/sys/kernel/config== , the configfs filesystem call is registered in the Linux kernel and accessible via the VFS system.

Start acpi module - call [module_init(acpi_configfs_init)](https://elixir.bootlin.com/linux/v6.17.8/source/drivers/acpi/acpi_configfs.c#L262), This will register ACPI subsystem into configfs ([configfs_register_subsystem](https://elixir.bootlin.com/linux/v6.17.8/source/fs/configfs/dir.c#L1872)) with the name  ==“.ci_namebuf = "acpi"==

Set  ACPI default group - table ( [configfs_register_default_group(root, "table", &acpi_tables_type)](https://elixir.bootlin.com/linux/v6.17.8/source/fs/configfs/dir.c#L1840)) In the acpi_tables_type, this sets [acpi_table_aml_write](https://elixir.bootlin.com/linux/v6.17.8/source/drivers/acpi/acpi_configfs.c#L24), which handles writing binary AML data into acpi configfs.


```
fs/configfs                                          drivers / acpi / acpi_configfs.c
     |                                                               | - module_init(acpi_configfs_init);
     |                                                                   | - configfs_register_subsystem(&acpi_configfs);
     |                                                                   |    /                          | - .ci_namebuf = "acpi",
     | - dir.c -- configfs_register_subsystem  <------------------------------
     |         |                                                         | - configfs_register_default_group(root, "table", &acpi_tables_type);
     |         |                                                             /                                              | - ct_group_ops = &acpi_table_group_ops,
     |         | - configfs_register_default_group  <------------------------                                                                  |- .make_item = acpi_table_make_item
     |         |     (parent_group, name, item_type)                                                                                                /          | - config_item_init_type_name(
     |         |                                                                                                                                   /                      &table->cfg, name, &acpi_table_type);
     |         | - configfs_mkdir <---------------------------------------------------------------------------------------------------------------                                           | - .ct_bin_attrs = acpi_table_bin_attrs,
     |         |   | - item = type->ct_group_ops->make_item                                                                                                                                                      | -  acpi_table_aml_write
     |         |                                                                                                                                                                                                      | - .write = acpi_table_aml_write
     |         | -  configfs_lookup                                                                                                                                                                                        /       | - ret = acpi_load_table(table->header, &table->index);
     |              | -  if (sd->s_type & CONFIGFS_ITEM_BIN_ATTR)  inode->i_fop = &configfs_bin_file_operations;                                                                                                          /
     |              |                                                             |- .write_iter = configfs_bin_write_iter, (write to buffer)                                                                            /
     |              |                                                             |- .release = configfs_release_bin_file, (write to trigger aml write)                                                                 /
     |              |                                                                             | - buffer->bin_attr->write  <----------------------------------------------------------------------------------------
     |              | -  inode->i_fop = &configfs_file_operations;

```

```
static struct configfs_bin_attribute *acpi_table_bin_attrs[] = {
	&acpi_table_attr_aml,
	NULL,
};

acpi_table_attr_aml = CONFIGFS_BIN_ATTR(acpi_table_, aml, NULL, MAX_ACPI_TABLE_SIZE);
{

    #define CONFIGFS_BIN_ATTR(_pfx, _name, _priv, _maxsz)		\
    static struct configfs_bin_attribute _pfx##attr_##_name = {	\
    	.cb_attr = {						\
    		.ca_name	= __stringify(_name),		\
    		.ca_mode	= S_IRUGO | S_IWUSR,		\
    		.ca_owner	= THIS_MODULE,			\
    	},							\
    	.cb_private	= _priv,				\
    	.cb_max_size	= _maxsz,				\
    	.read		= _pfx##_name##_read,			\
    	.write		= _pfx##_name##_write,			\
    }

}
```


# Reference:
[quick to learn ACPI](https://jia.je/hardware/2022/12/10/acpi-notes/#cmosrtc)

https://www.kernel.org/doc/html/latest/admin-guide/acpi/ssdt-overlays.html 

https://www.kernel.org/doc/html/latest/admin-guide/acpi/initrd_table_override.html 

https://www.kernel.org/doc/html/latest/admin-guide/acpi/fan_performance_states.html 

https://uefi.org/specs/ACPI/6.6/ 

[Predefined ACPI Names](https://uefi.org/specs/ACPI/6.6/05_ACPI_Software_Programming_Model.html#predefined-acpi-names)

