================================================================================
ACPI - ADVANCED CONFIGURATION AND POWER INTERFACE
================================================================================
Author : Tushar Sonawane
Date : 09 September 2026
================================================================================
As an example for this, we are using virutalbox as a demonstration environment.
System Info
---------------------------------
Kernel : 6.6.18
Hostname : Nakshatra
ACPI Firmware : VBOX (VirtualBox built-in ACPI)
ACPI Version : XSDT v01 (ACPI 2.0+)
DSDT Compiler : INTL 20230628 (Intel AML compiler, June 2023)
================================================================================
TABLE OF CONTENTS
================================================================================
PART 1 - WHAT IS ACPI? (Sections 1-3) Understanding basics
PART 2 - ACPI TABLES (Sections 4-6) What each table does
PART 3 - POWER STATES (Section 7) Sleep, idle, performance
PART 4 - ACPI EVENTS (Section 8) How hardware talks to OS
PART 5 - LINUX INTERNALS (Section 9) How Linux uses ACPI
PART 6 - SETUP ON NAKSHATRA (Sections 10-13) Step-by-step install
PART 7 - TOOLS & COMMANDS (Section 14) Tools you will use daily
PART 8 - TROUBLESHOOTING (Sections 15-18) Fixing problems
PART 9 - ADVANCED & SECURITY (Sections 19-20) Expert topics
================================================================================
PART 1 - WHAT IS ACPI?
================================================================================
SECTION 1: UNDERSTANDING ACPI.
===============================================
1.1 Simple Explanation
-----------------------
ACPI stands for "Advanced Configuration and Power Interface."
Think of your computer as a building:
HARDWARE = The physical rooms and equipment inside
BIOS/UEFI = The building's blueprint and wiring diagram
ACPI TABLES = The instruction manual: "Here is what equipment exists
and here is how to turn each thing on or off"
LINUX KERNEL = The building manager who reads the manual and runs things
AML CODE = The actual step-by-step procedures written in the manual
acpid DAEMON = The receptionist who listens for requests (button presses)
When you click "ACPI Shutdown" in VirtualBox:
Step 1: VirtualBox sends a virtual power button press
Step 2: Linux ACPI driver receives the signal
Step 3: acpid daemon catches the event
Step 4: acpid runs your shutdown script
Step 5: System shuts down cleanly
Without ACPI configured in your VM:
- Clicking the VirtualBox close button = FORCED KILL (data loss risk)
- No graceful shutdown possible from the host
- No CPU frequency scaling
- Temperature sensors unavailable
1.2 What ACPI Controls
-----------------------
POWER MANAGEMENT - Sleep, hibernate, shutdown, CPU frequency
HARDWARE DISCOVERY- Tells Linux what devices exist and their addresses
THERMAL CONTROL - Reads temperatures, controls fans, prevents overheating
EVENT HANDLING - Power button, lid open/close, battery plugged in/out
1.3 ACPI in VirtualBox VM
--------------------------------
dmesg output shows VirtualBox provides these ACPI tables:
[0.003925] ACPI: RSDP 0x000E0000 <- "Here are the tables" pointer
[0.003935] ACPI: XSDT <- Master index of all tables
[0.003945] ACPI: FACP <- Fixed hardware features
[0.003954] ACPI: DSDT <- Main device descriptions + AML code
[0.003960] ACPI: FACS <- Sleep/wake support
[0.003969] ACPI: APIC <- Interrupt controller info
[0.003974] ACPI: SSDT <- CPU performance states
All from OEM "VBOX" = VirtualBox is generating these tables for you.
================================================================================
SECTION 2: HOW ACPI WORKS - THE FLOW
======================================
2.1 The Three Layers
---------------------
LAYER 1 - HARDWARE (Physical or Virtual)
What it is: The actual CPU, RAM, storage, virtual NIC, etc.
In VirtualBox: All virtualized by the hypervisor
LAYER 2 - FIRMWARE (BIOS/UEFI / VirtualBox ACPI)
What it is: Runs before Linux boots. Creates ACPI tables in RAM.
In VirtualBox: VirtualBox itself generates the ACPI tables.
These tables say: "Here is what hardware exists and how to use it"
LAYER 3 - OPERATING SYSTEM
What it is: Linux reads those tables, interprets AML code, controls hardware.
Result: Linux knows about all virtual devices and can manage power.
2.2 Full Communication Flow (With Real Example)
-------------------------------------------------
You press power button in VirtualBox (Machine > ACPI Shutdown)
|
v
VirtualBox generates a virtual power button press event
|
v
Linux ACPI driver receives SCI interrupt (IRQ 9 - the ACPI interrupt)
|
v
ACPI driver reads the PM1 event register - sees "power button pressed"
|
v
Linux sends event to userspace via netlink socket
|
v
acpid daemon receives: "button/power PBTN 00000080"
|
v
acpid matches event against /etc/acpi/events/powerbtn rule
|
v
acpid runs: /etc/acpi/actions/powerbtn.sh
|
v
Script runs: /sbin/shutdown -h now
|
v
System shuts down gracefully. No data loss.
================================================================================
SECTION 3: ACPI HISTORY & VERSIONS
=====================================
3.1 Why ACPI Was Created
--------------------------
Before ACPI (before 1997), power management was done by APM (Advanced Power
Management). The problem: the BIOS controlled everything, and Linux had
almost no say. Different BIOS vendors did things differently.
ACPI fixed this by:
- Making the OS (Linux) the one in control of power management
- Having the BIOS just describe the hardware (not control it)
- Creating a standard language (AML) that any OS can interpret
Created in 1996 by: Intel + Microsoft + Toshiba
First released: 1997
3.2 Version History (What Matters to You)
-------------------------------------------
Version | Year | Why It Matters
--------|------|----------------------------------------------------------
1.0 | 1997 | Basic sleep states, C-states, batteries
2.0 | 2000 | 64-bit support - THIS is what VirtualBox uses (XSDT v01)
3.0 | 2004 | Multi-core CPU support (multiple vCPUs in VMs)
4.0 | 2009 | USB 3.0 power management
5.0 | 2011 | ARM processor support (phones, Raspberry Pi, etc.)
6.0+ | 2015+| NVMe storage, CXL memory, server features
6.5 | 2022 | Current latest version
VM: VirtualBox uses ACPI 2.0+ (XSDT = eXtended = 64-bit)
Your kernel 6.6.18 supports all versions up to 6.5.
================================================================================
PART 2 - ACPI TABLES (What Each Table Does)
================================================================================
SECTION 4: UNDERSTANDING ACPI TABLES
======================================
4.1 What Are ACPI Tables?
--------------------------
ACPI tables are binary data blobs (chunks of bytes) placed in RAM by the
firmware before Linux boots. Think of them as a detailed instruction manual
for the hardware.
Simple analogy:
Tables = A recipe book placed in the kitchen before the chef arrives
Linux (the chef) reads the recipes to know how to operate the kitchen
Your VM has these tables (from ls /sys/firmware/acpi/tables/):
APIC, DSDT, FACP, FACS, SSDT + data/ and dynamic/ directories
4.2 How Linux Finds the Tables
--------------------------------
At boot, Linux does this automatically:
Step 1: Searches memory address range 0xE0000 to 0xFFFFF for "RSD PTR "
Your system: Found at 0x000E0000 (matches your dmesg!)
[0.003925] ACPI: RSDP 0x00000000000E0000
Step 2: RSDP points to XSDT at 0xDFFF0030
[0.003935] ACPI: XSDT 0x00000000DFFF0030
XSDT = the master index containing addresses of all other tables
Step 3: Linux reads each table address from XSDT, parses all tables
Step 4: Builds the ACPI namespace (device tree) and starts drivers
4.3 YOUR Tables Explained (From dmesg output)
---------------------------------------------
Table | Address | Size | What It Does
------|-------------|--------|------------------------------------------
RSDP | 0x000E0000 | 36 B | "Tables start here" pointer
XSDT | 0xDFFF0030 | 60 B | Index of all tables (64-bit)
FACP | 0xDFFF00F0 | 244 B | Fixed hardware: sleep ports, IRQ 9, etc.
DSDT | 0xDFFF0620 | 9043 B | Main: all devices, AML code, methods
FACS | 0xDFFF0200 | 64 B | Sleep/wake waking vector
APIC | 0xDFFF0240 | 108 B | vCPU and interrupt controller info
SSDT | 0xDFFF02B0 | 876 B | CPU performance states (P-states)
NOTE: Your DSDT is 9043 bytes (about 9 KB) - that is the entire
hardware description for your VirtualBox VM written in AML bytecode.
4.4 Detailed Table Descriptions
---------------------------------
+------------------------------------------------------------------+
| RSDP - Root System Description Pointer |
| Signature: "RSD PTR " (8 characters with trailing space) |
| Your system: at memory address 0x000E0000, size 36 bytes |
+------------------------------------------------------------------+
| This is the very first thing Linux finds. It is tiny - just a |
| pointer that says "The real ACPI tables are over there." |
| |
| Key fields: |
| Signature = "RSD PTR " -- proves this is ACPI |
| OEM ID = "VBOX " -- VirtualBox made this |
| Revision = 2 -- means ACPI 2.0+ (64-bit) |
| XsdtAddress = 0xDFFF0030 -- where XSDT table lives |
| |
| See it: dmesg | grep RSDP |
+------------------------------------------------------------------+
+------------------------------------------------------------------+
| XSDT - eXtended System Description Table |
| Signature: "XSDT" |
| Your system: at 0xDFFF0030, size 60 bytes, version v01 |
+------------------------------------------------------------------+
| The master index. Contains an array of memory addresses, |
| each pointing to one ACPI table (FACP, DSDT, APIC, SSDT). |
| Linux reads this list to know where all other tables are. |
| |
| XSDT uses 64-bit pointers (RSDT uses 32-bit - older systems). |
| Since your system has XSDT, you are using ACPI 2.0+. |
| |
| See it: ls -la /sys/firmware/acpi/tables/ |
+------------------------------------------------------------------+
+------------------------------------------------------------------+
| FACP (FADT) - Fixed ACPI Description Table |
| Signature: "FACP" (NOT "FADT" - common confusion!) |
| Your system: at 0xDFFF00F0, size 244 bytes, version v04 |
+------------------------------------------------------------------+
| Describes "fixed" hardware - things always in the same place. |
| Contains memory-mapped I/O port addresses for ACPI control. |
| |
| Key information inside FACP: |
| SCI_INT = IRQ number for ACPI events (usually IRQ 9) |
| DSDT_ADDRESS= Where to find the DSDT table |
| FACS_ADDRESS= Where to find the FACS table |
| PM1a_EVT_BLK= I/O port: read to see if power button pressed |
| PM1a_CNT_BLK= I/O port: write here to initiate sleep |
| GPE0_BLK = I/O port: General Purpose Events register block |
| PM_PROFILE = 1 = Desktop computer profile |
| |
| See it: xxd /sys/firmware/acpi/tables/FACP | head -20 |
| First 4 bytes = "FACP" in hex: 46 41 43 50 |
+------------------------------------------------------------------+
+------------------------------------------------------------------+
| DSDT - Differentiated System Description Table |
| Signature: "DSDT" |
| Your system: at 0xDFFF0620, size 9043 bytes |
| Compiled: INTL 20230628 (Intel compiler, June 28 2023) |
+------------------------------------------------------------------+
| THE MOST IMPORTANT TABLE. This is the complete hardware |
| description for your VirtualBox VM. It contains AML bytecode |
| (machine language) that Linux executes to control hardware. |
| |
| What is inside your 9043-byte DSDT: |
| - PCI bus definition (PCI0 - the virtual PCI bus) |
| - Virtual devices (storage, network, display) |
| - Power management methods (_PS0, _PS3 = turn on/off) |
| - Thermal zone (even in VM, VirtualBox defines one) |
| - Battery object (if VirtualBox battery emulation enabled) |
| - GPE (event) handlers for power button and other events |
| |
| Extract and read your actual DSDT: |
| # cat /sys/firmware/acpi/tables/DSDT > /tmp/dsdt.bin |
| # iasl -d /tmp/dsdt.bin (needs iasl tool) |
| # less /tmp/dsdt.dsl (read the source code) |
+------------------------------------------------------------------+
+------------------------------------------------------------------+
| FACS - Firmware ACPI Control Structure |
| Your system: at 0xDFFF0200, size 64 bytes |
| NOTE: Appears TWICE in your dmesg - this is normal in VirtualBox |
+------------------------------------------------------------------+
| Used for suspend/resume (S3 sleep and S4 hibernate). |
| When Linux suspends to RAM (S3): |
| 1. Linux writes the "waking vector" address here |
| (the memory address where CPU should resume execution) |
| 2. Hardware powers off everything except RAM |
| 3. When you wake the VM, CPU jumps to the waking vector |
| 4. Linux resumes exactly where it left off |
| |
| Also contains the "Global Lock" - a hardware mutex that |
| prevents the OS and firmware from accessing hardware at once. |
+------------------------------------------------------------------+
+------------------------------------------------------------------+
| APIC (MADT) - Multiple APIC Description Table |
| Signature: "APIC" (full name is MADT - confusing naming!) |
| Your system: at 0xDFFF0240, size 108 bytes, version v02 |
+------------------------------------------------------------------+
| Describes interrupt controllers. Linux needs this to know: |
| - How many vCPUs your VM has (one Local APIC entry per vCPU) |
| - How interrupt signals are routed to the CPU |
| - Which IRQ numbers map to which hardware |
| |
| If your VM has 2 vCPUs configured, APIC table has 2 LAPIC |
| entries. Linux reads this to set up multi-CPU support. |
| |
| See it: dmesg | grep APIC |
+------------------------------------------------------------------+
+------------------------------------------------------------------+
| SSDT - Secondary System Description Table |
| Signature: "SSDT" |
| Your system: at 0xDFFF02B0, size 876 bytes |
| Name: "VBOXCPUT" -- CPU Table from VirtualBox |
+------------------------------------------------------------------+
| Supplements the DSDT. Your VirtualBox SSDT is named "VBOXCPUT" |
| which means it contains CPU-related definitions. |
| Typically used for: |
| - CPU P-states (_PSS objects: frequency/voltage pairs) |
| - CPU C-states (_CST objects: idle state definitions) |
| - Additional device definitions that didn't fit in DSDT |
| |
| Multiple SSDTs can exist. You can also hot-load custom SSDTs. |
| |
| See it: cat /sys/firmware/acpi/tables/SSDT > /tmp/ssdt.bin |
| iasl -d /tmp/ssdt.bin |
+------------------------------------------------------------------+
4.5 Tables NOT Present in Your VM (And Why)
---------------------------------------------
These tables exist on real hardware but not in your VirtualBox VM:
HPET - High Precision Timer - VirtualBox uses different timing
MCFG - PCIe config space - VirtualBox uses legacy PCI config
SRAT - NUMA topology - Single-node VM, not needed
BERT - Boot error records - No hardware errors to report
HEST - Hardware error sources - No hardware error sources in VM
This is normal. A minimal VM only needs what it uses.
4.6 The data/ and dynamic/ Directories
-----------------------------------------
/sys/firmware/acpi/tables/data/
Binary data associated with certain tables.
/sys/firmware/acpi/tables/dynamic/
Tables loaded at runtime (e.g., custom SSDTs you load).
Empty by default. Used when you do DSDT/SSDT patching.
================================================================================
SECTION 5: ACPI NAMESPACE (The Device Tree)
=============================================
5.1 What Is the ACPI Namespace?
---------------------------------
When Linux reads DSDT + SSDT, it builds an internal tree structure called
the "ACPI Namespace." Think of it like a filesystem - hierarchical paths
to every device.
Every object has a unique path, like: \_SB.PCI0.USB0 or \_TZ.TZ00
5.2 The Namespace Tree Structure
----------------------------------
\ (root, like "/" in Linux)
|
+--_PR (PRocessor objects - your virtual CPUs)
| +-- CPU0 (first vCPU)
| | +-- _CST (C-states this CPU can enter)
| | +-- _PSS (P-states: frequency/voltage list)
| | +-- _PPC (highest usable P-state)
| |
| +-- CPU1 (second vCPU, if you have multiple vCPUs)
|
+--_SB (System Bus - where most devices live)
| |
| +-- PCI0 (the virtual PCI root bridge)
| | +-- Each virtual PCI device (NIC, storage, display)
| |
| +-- AC0 (AC power adapter object)
| | +-- _HID = "ACPI0003" (standard AC adapter ID)
| | +-- _PSR = power source (1=plugged in, 0=battery)
| |
| +-- BAT0 (Battery - only if VirtualBox battery enabled)
| +-- _HID = "PNP0C0A"
| +-- _BIF = battery info (capacity, voltage, etc.)
| +-- _BST = battery status (%, charging/discharging)
|
+--_TZ (Thermal Zones)
| +-- TZ00 (temperature zone 0)
| +-- _TMP = read current temperature
| +-- _CRT = critical temp (emergency shutdown point)
| +-- _PSV = passive temp (start throttling)
| +-- _AC0 = active temp (turn on fan)
|
+--_GPE (General Purpose Events - hardware interrupt handlers)
+-- _Lxx or _Exx methods (handle specific hardware events)
5.3 Common Object Names and Their Meaning
------------------------------------------
Every ACPI name is exactly 4 characters. Here are the important ones:
Name | What it means | Example
------|---------------------------|----------------------------------
_HID | Hardware ID (device type) | "PNP0C0A" = battery
_UID | Unique ID (tells devices | 0 = first battery
| apart if same type) |
_ADR | Address (PCI slot number) | 0x00050000 = slot 5, func 0
_STA | Status: is device working?| 0x0F = present+enabled+working
_CRS | Current resource settings | I/O ports, IRQs this device uses
_INI | Initialization method | Run this when device starts
_PS0 | Power State 0 method | Turn device fully ON
_PS3 | Power State 3 method | Turn device fully OFF
_PSC | Power State Current | What state is device in now?
_PRW | Power Resources for Wake | What can wake the system?
_TMP | Temperature | Read sensor temperature
_CRT | Critical temperature | Emergency shutdown at this temp
_PSS | P-state list | Available CPU frequencies
_CST | C-state list | Available CPU idle states
5.4 Understanding _STA (Device Status Code)
---------------------------------------------
_STA returns a number. Each bit means something:
Bit 0 (value 1) : Device is physically present
Bit 1 (value 2) : Device is enabled (has resources assigned)
Bit 2 (value 4) : Device shows in UI / OS device list
Bit 3 (value 8) : Device is functioning correctly
Bit 4 (value 16) : Battery is present (battery devices only)
0x0F = bits 0+1+2+3 = Present + Enabled + Visible + Functioning = GOOD
0x00 = nothing set = device not present at all
================================================================================
SECTION 6: AML - THE ACPI BYTECODE LANGUAGE
=============================================
6.1 What Is AML?
-----------------
AML (ACPI Machine Language) is stored inside DSDT and SSDT as binary code.
The human-readable version is ASL (ACPI Source Language), which looks
like a mix of C and Pascal.
When Linux boots:
1. ACPICA library (built into Linux kernel) reads the AML bytecode
2. Interprets and executes AML methods when needed
3. AML runs with full kernel privileges
6.2 Example: What VirtualBox DSDT Might Look Like (Simplified ASL)
---------------------------------------------------------------------
// This is what the power button handler might look like in ASL:
Device (PWRB) {
Name (_HID, EisaId ("PNP0C0C")) // Hardware ID: Power Button
Name (_UID, 0) // First power button
Method (_STA, 0, NotSerialized) {
Return (0x0F) // Present+Enabled+Visible+Working
}
}
// AC adapter object:
Device (AC0) {
Name (_HID, "ACPI0003") // Standard AC adapter ID
Name (_PCL, Package() { \_SB }) // Power Consumer List
Method (_PSR, 0) { // Power Source method
Return (ACUR) // Read from hardware register
}
}
// Thermal zone:
ThermalZone (TZ00) {
Method (_TMP, 0) { // Temperature reading method
Return (Add(2732, Multiply(CTMP, 10))) // Convert to tenths of Kelvin
// Formula: (Celsius + 273.15) * 10
// 25°C = (25 + 273) * 10 = 2980
}
Name (_CRT, 3630) // Critical: 90°C = (90+273)*10
Name (_PSV, 3530) // Passive: 80°C = throttle CPU
}
6.3 How to Read Your Actual DSDT
----------------------------------
Step 1: Extract the binary DSDT from your running system:
# cat /sys/firmware/acpi/tables/DSDT > /tmp/dsdt.bin
# ls -la /tmp/dsdt.bin
# Your DSDT is 9043 bytes (from your dmesg: "002353" hex = 9043 decimal)
Step 2: Install the iasl tool (ASL compiler/decompiler):
- Build from source:
# wget https://github.com/acpica/acpica/archive/refs/heads/master.tar.gz
# tar -xzf master.tar.gz
# cd acpica-master && make && make install
Step 3: Decompile binary to readable source:
# cd /tmp
# iasl -d dsdt.bin (creates dsdt.dsl)
# wc -l dsdt.dsl (count lines of source)
# grep "Device" dsdt.dsl (see all device definitions)
# grep "ThermalZone" dsdt.dsl (find thermal zones)
# grep "_PSS" dsdt.dsl (find CPU performance states)
6.4 AML Interpreter in Linux (ACPICA)
---------------------------------------
Linux kernel includes the ACPICA library at:
/usr/src/linux/drivers/acpi/acpica
Key files in ACPICA:
| Prefix | Subsystem | Purpose |
| ------ | ---------- | ------------------------------ |
| ex* | Executor | Executes AML opcodes |
| ps* | Parser | Parses AML bytecode |
| ns* | Namespace | ACPI object tree |
| ev* | Events | ACPI interrupts/GPE |
| tb* | Tables | ACPI table handling |
| ds* | Dispatcher | AML execution state |
| hw* | Hardware | Low-level ACPI hardware access |
| ut* | Utilities | Helper functions |
| rs* | Resources | IRQ/IO/DMA descriptors |
| db* | Debugger | AML debugger |
| os* | OS layer | OS abstraction |
================================================================================
PART 3 - POWER STATES
================================================================================
SECTION 7: ALL POWER STATES EXPLAINED
=======================================
7.1 Overview: Why So Many "States"?
-------------------------------------
ACPI manages power at different levels simultaneously:
G-States = The whole system (is the computer on, sleeping, or off?)
S-States = Depth of sleep (how deeply is the system sleeping?)
C-States = CPU idle (how deeply is the CPU idling between tasks?)
P-States = CPU performance (how fast is the CPU running?)
D-States = Individual device power (is this NIC on or off?)
Analogy - Think of an office building:
G-state = Is the building open, after-hours, or closed for renovation?
S-state = Are the lights off with security mode, or completely locked?
C-state = Is an office occupied, empty-with-AC-off, or sealed shut?
P-state = How brightly are the lights in each office?
D-state = Is each individual appliance on, standby, or unplugged?
7.2 G-States (Global System Power States)
-------------------------------------------
G0 - WORKING
System is running normally. You are in G0 right now.
All components powered. OS in full control.
Power use: 100% (full load)
G1 - SLEEPING
System appears off but can wake up.
This umbrella contains S1, S2, S3, and S4 states.
Power use: Varies by S-state.
G2 - SOFT OFF
OS has shut down cleanly. Very little power drawn.
Like G3 but the power supply still provides 5V standby.
Pressing power button returns to G0 (requires full boot).
Result of: shutdown -h now command
G3 - MECHANICAL OFF
Power cable unplugged. Zero power consumption.
All memory and state completely lost.
7.3 S-States (Sleep States - Inside G1)
-----------------------------------------
These are what you interact with most directly.
S0 - Normal Operation (same as G0)
Everything running. Normal operation.
S1 - CPU Stop Grant (Rarely Used)
CPU stops executing but keeps its cache contents.
Everything else stays powered.
Wake time: Near-instant
Power saving: About 15-20% compared to S0
S3 - Suspend to RAM *** MOST COMMON SLEEP STATE ***
This is what people call "Sleep" or "Suspend."
What happens when you do: echo mem > /sys/power/state
1. Linux saves all CPU register states to RAM
2. Linux writes the "waking vector" address to the FACS table
(Your FACS is at 0xDFFF0200 in your VM)
3. All devices are powered down
4. Only RAM stays powered (needs a small trickle of power)
5. System appears completely off
What happens when you wake the VM:
1. Power restored to CPU
2. CPU jumps to the waking vector address in FACS
3. Linux resumes execution exactly where it stopped
4. All your programs are still open and working
Wake time: 1-3 seconds
Power use: About 1-5W (just RAM + wake circuits)
Risk: If power fails while sleeping, data may be lost
Command: echo mem > /sys/power/state
S4 - Suspend to Disk (Hibernate)
Saves everything to disk, then powers completely off.
What happens:
1. Linux writes entire RAM contents to swap partition/file
2. System powers completely off (like G2)
3. Zero power consumption while hibernated
What happens when you power on:
1. System boots (briefly)
2. Linux reads RAM image from disk
3. Restores exactly your previous state
4. Continues where you left off (slower than S3 wake)
Wake time: 20-60 seconds
Power use: Zero (completely off)
Risk: None - everything safely saved to disk
Requirement: Swap space must be >= total RAM size
Command: echo disk > /sys/power/state
S5 - Soft Off (Normal Shutdown)
OS has shut down. System needs full reboot to return.
NOT a sleep state - requires full boot.
Result of: shutdown -h now or poweroff
Check which sleep states your VM supports:
# cat /sys/power/state
Typical output: freeze standby mem disk
7.4 CPU C-States (Idle States)
--------------------------------
When the CPU has nothing to do, it can enter progressively deeper
idle states to save power. The deeper the state, the more power saved,
but the longer it takes to wake up and respond.
C0 - Active (CPU is executing your code)
Full power, full speed. Happens when programs are running.
C1 - Halt (CPU executes HLT instruction and waits)
CPU stops, but stays ready to respond instantly.
Wake time: 1 microsecond (effectively instant)
Power saving: ~15-20%
How it works: The HLT assembly instruction tells CPU to pause.
C1E - Enhanced Halt (Intel-specific upgrade to C1)
Same as C1 but also reduces CPU voltage slightly.
Power saving: ~25-30%
C2 - Stop Clock
CPU clock completely stopped. CPU cannot be interrupted directly.
Wake time: ~1-10 microseconds
Power saving: ~40-50%
C3 - Sleep
CPU cache contents flushed to RAM. CPU voltage may reduce.
Wake time: ~50-100 microseconds
Power saving: ~60-70%
Downside: Must reload caches when waking (brief slowness)
C6 - Deep Power Down (Intel Nehalem and newer)
CPU core voltage drops to near zero.
CPU state saved to on-die hardware storage.
Wake time: ~100-200 microseconds
Power saving: ~80-90%
C7, C8, C9, C10 - Platform-Level States (Modern Intel)
Entire system components powered down. Multi-core package states.
Power saving: up to 95% of idle power
Wake time: up to 1000 microseconds
View C-states available in your VM:
# ls /sys/devices/system/cpu/cpu0/cpuidle/
# cat /sys/devices/system/cpu/cpu0/cpuidle/state0/name
# cat /sys/devices/system/cpu/cpu0/cpuidle/state0/latency (wake time in us)
# cat /sys/devices/system/cpu/cpu0/cpuidle/state0/usage (times entered)
7.5 CPU P-States (Performance States / DVFS)
----------------------------------------------
P-states control the CPU's clock frequency and voltage.
The CPU can run slower (and use less power) when not needed.
This is called DVFS: Dynamic Voltage and Frequency Scaling.
P0 = Maximum performance (highest GHz, highest voltage)
Use when: running heavy workloads, compiling, video encoding
Power: Maximum
P1, P2, P3... = Intermediate states (lower GHz, lower voltage)
Use when: moderate workloads
Pn = Lowest performance state (minimum GHz, minimum voltage)
Use when: nearly idle, just browsing or editing text
Power: Minimum
CPU Frequency Governors control P-state selection:
Governor | Behavior
--------------|-----------------------------------------------------
performance | Always use P0 (max speed). No scaling.
powersave | Always use Pn (min speed). No scaling.
ondemand | Jump between P0 and Pn based on current load.
conservative | Gradually step up/down. Smoother than ondemand.
schedutil | Uses Linux scheduler data. BEST CHOICE for most users.
Check and change governor:
# cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq (current KHz)
# cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq (max KHz)
Change all CPUs at once:
# for g in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
echo schedutil > "$g"
done
7.6 Device D-States (Per-Device Power)
----------------------------------------
Every PCI device can individually enter power states:
D0 - Fully On : Device operating normally. Responds to requests.
D1 - Partial On : Device-specific reduced power. Limited function.
D2 - More Reduced : Even less power. Fewer functions available.
D3hot - Logic Off : Device appears off but power still connected.
Can be woken by software without reinit.
D3cold - Power Off : Power physically removed. Must fully reinitialize.
Check device power states:
# for d in /sys/bus/pci/devices/*/; do
echo "$(basename $d): $(cat $d/power_state 2>/dev/null)"
done
================================================================================
PART 4 - ACPI EVENTS
================================================================================
SECTION 8: HOW HARDWARE TALKS TO LINUX VIA ACPI
=================================================
8.1 What Are ACPI Events?
--------------------------
Events are signals that tell Linux something changed in hardware:
- Power button was pressed
- Lid was closed (laptops)
- Battery is getting low
- AC adapter plugged or unplugged
- Temperature crossed a threshold
- USB device plugged in (hotplug)
In VirtualBox, these are emulated:
- VirtualBox sends power button event when you click ACPI Shutdown
- VirtualBox can emulate battery change events
- Temperature events are minimal in a VM
8.2 The ACPI Interrupt (SCI - System Control Interrupt)
---------------------------------------------------------
ACPI uses ONE shared interrupt for ALL events. This is IRQ 9 by default.
How it works:
1. Hardware (or VirtualBox) sets a bit in a hardware register
2. SCI interrupt fires on IRQ 9
3. Linux ACPI driver's interrupt handler runs
4. Handler reads event registers to find out WHAT happened
5. Dispatches to the appropriate driver or userspace
Check your SCI interrupt:
# grep "9:" /proc/interrupts
# dmesg | grep -i "SCI"
8.3 GPE - General Purpose Events
----------------------------------
Most ACPI events use GPE (General Purpose Event) registers.
There are two banks: GPE0 and GPE1, with up to 255 event bits total.
Each GPE bit has:
Status register bit = "Did this event happen?" (hardware sets it)
Enable register bit = "Should this trigger an interrupt?" (OS sets it)
When a GPE fires:
1. Hardware sets the GPE status bit
2. SCI interrupt fires
3. Linux reads GPE status, finds which bit is set
4. Clears the status bit (acknowledges the event)
5. Runs the matching AML handler:
_L0A = Level-triggered handler for GPE bit 10 (0xA)
_E0B = Edge-triggered handler for GPE bit 11 (0xB)
View GPE activity on your system:
# ls /sys/firmware/acpi/interrupts/
# cat /sys/firmware/acpi/interrupts/sci (total SCI count)
# watch -n1 cat /sys/firmware/acpi/interrupts/sci
8.4 ACPI Notifications (Internal Signaling)
---------------------------------------------
AML code can send notifications to device objects using Notify():
Notify(\_SB.BAT0, 0x80) = "Something changed about battery BAT0"
Common notification codes:
0x00 = Bus Check : Re-enumerate this bus
0x01 = Device Check : Check if device is still present
0x02 = Device Wake : This device woke the system from sleep
0x03 = Eject Request : User wants to hotplug/remove this
0x80 = Status Change : Battery %, AC status, temperature changed
8.5 Real Event Flow Example: AC Adapter Unplugged
--------------------------------------------------
1. VirtualBox emulates AC adapter disconnect
2. ACPI GPE fires (battery/AC event bit set in GPE register)
3. Linux kernel ACPI handler runs, executes AML GPE handler method
4. AML method calls: Notify(\_SB.AC0, 0x80)
(Tells Linux: "AC adapter status changed")
5. Linux AC adapter driver (ac.c) re-reads AC status from hardware
Updates: /sys/class/power_supply/AC/online (changes from 1 to 0)
6. Linux sends event to userspace via netlink socket:
Message: "ac_adapter ACPI0003:00 00000000"
7. acpid receives this event string
8. acpid matches it against /etc/acpi/events/ac-adapter rule:
event=ac_adapter
9. acpid runs: /etc/acpi/actions/ac-adapter.sh
10. Your script reads /sys/class/power_supply/AC/online = 0
Changes CPU governor to powersave
Logs: "ACPI: AC adapter unplugged - switching to battery mode"
8.6 Monitor Events in Real Time
---------------------------------
# acpi_listen
(Press power button in VirtualBox: Machine > ACPI Shutdown)
Output: button/power PBTN 00000080 00000000
# watch -n1 cat /sys/firmware/acpi/interrupts/sci
(Counter increments every time any ACPI event fires)
================================================================================
PART 5 - LINUX ACPI INTERNALS
================================================================================
SECTION 9: HOW LINUX HANDLES ACPI
====================================
9.1 Boot Sequence: What Happens Step by Step
---------------------------------------------
Step 1: LILO/GRUB loads vmlinuz into RAM
The kernel image is loaded. Execution begins.
Step 2: Early kernel finds ACPI tables
Searches memory 0xE0000-0xFFFFF for "RSD PTR " signature
Your system: Found at 0x000E0000 (confirmed by your dmesg!)
Reads XSDT at 0xDFFF0030. Gets list of all table addresses.
Step 3: Kernel validates all tables
Checks checksums of each table. If checksum fails, table rejected.
[0.003919] "Early table checksum verification disabled" -- VirtualBox
disables early checksum (slightly risky but OK for VM).
Step 4: ACPICA initializes and parses DSDT + SSDT
Builds the ACPI namespace tree in kernel memory.
Runs _INI methods for all devices.
Sets up GPE handlers for all event bits.
Step 5: Interrupt routing set up
APIC table read. IRQ routing configured.
SCI interrupt (IRQ 9) registered.
Step 6: ACPI drivers attach to devices
For each ACPI namespace device, kernel finds matching driver:
_HID "PNP0C0A" -> battery driver (battery.c)
_HID "ACPI0003"-> AC adapter driver (ac.c)
_HID "PNP0C0C" -> power button driver (button.c)
ThermalZone -> thermal driver (thermal.c)
Step 7: CPU frequency and idle set up
SSDT "VBOXCPUT" read for CPU P-states
cpufreq driver (acpi-cpufreq or intel_pstate) initialized
cpuidle driver reads C-states
Step 8: acpid starts (userspace, after kernel boot)
/etc/rc.d/rc.acpid start is called
acpid opens netlink socket to receive events from kernel
Reads all files in /etc/acpi/events/
Begins waiting for events
9.2 Key Kernel Source Files
-----------------------------
For those who want to explore the Linux ACPI code:
drivers/acpi/acpica/ ACPICA AML interpreter (~50,000 lines from Intel)
amlexec.c Runs individual AML opcodes
amlparse.c Parses binary AML bytecode
tbfind.c Locates and validates ACPI tables
drivers/acpi/
ac.c AC power adapter driver
battery.c Battery driver
button.c Power button, sleep button, lid switch
fan.c Fan driver
thermal.c Thermal zone driver (reads temp, controls fan)
processor_idle.c CPU C-state (idle) management
processor_freq.c CPU P-state (frequency) management
ec.c Embedded Controller (important for laptops)
9.3 The Sysfs Interface (Modern Way to Read ACPI Data)
-------------------------------------------------------
Sysfs (/sys/) is the modern interface. Use this, not /proc/acpi/.
ACPI Tables (Raw):
/sys/firmware/acpi/tables/DSDT Your 9043-byte DSDT binary
/sys/firmware/acpi/tables/FACP FADT binary
/sys/firmware/acpi/tables/APIC MADT binary
/sys/firmware/acpi/tables/SSDT SSDT binary
Events/Interrupts:
/sys/firmware/acpi/interrupts/sci Total SCI interrupt count
/sys/firmware/acpi/interrupts/gpe00 GPE bit 0 event count
(increments each time an ACPI event fires)
Battery and AC:
/sys/class/power_supply/AC/online 1=plugged in, 0=battery
/sys/class/power_supply/BAT0/capacity Battery % (0-100)
/sys/class/power_supply/BAT0/status "Charging", "Discharging", "Full"
/sys/class/power_supply/BAT0/energy_now Current energy in microwatt-hours
Temperature:
/sys/class/thermal/thermal_zone0/temp Temperature in millidegrees C
45000 = 45.0 degrees C
CPU Frequency:
/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq Current freq KHz
/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor Active governor
/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq Max allowed freq
CPU Idle:
/sys/devices/system/cpu/cpu0/cpuidle/state0/name C-state name
/sys/devices/system/cpu/cpu0/cpuidle/state0/latency Wake time (us)
/sys/devices/system/cpu/cpu0/cpuidle/state0/usage Times entered
Sleep Control:
/sys/power/state Write: mem, disk, freeze
/sys/power/pm_trace Write 1 to enable debug trace
Wakeup Control:
/proc/acpi/wakeup Enable/disable wakeup sources
================================================================================
PART 6 - SETUP (STEP BY STEP)
================================================================================
SECTION 10: VERIFYING ACPI IS WORKING IN YOUR VM
==================================================
10.1 Quick System Check
------------------------
Run these commands right now to see ACPI status:
# Check kernel version and ACPI boot messages:
$ uname -r
6.6.18
$ dmesg | grep -i acpi | head -20
(You already know this works - your dmesg shows VirtualBox ACPI loaded)
# Check what tables are available:
$ ls /sys/firmware/acpi/tables/
APIC DSDT FACP FACS SSDT data/ dynamic/
# Check ACPI firmware version (from DSDT header):
$ dmesg | grep DSDT
[0.003954] ACPI: DSDT 0x00000000DFFF0620 002353 (v02 VBOX VBOXBIOS 00000002 INTL 20230628)
# This tells you: VBOX made it, INTL (Intel) compiled it, June 2023
# Check if acpi command is installed:
$ which acpi
$ acpi --version
# Check if acpid is installed:
$ which acpid
$ acpid --version
# Check available sleep states:
$ cat /sys/power/state
# Check CPU frequency info:
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
10.2 VirtualBox Specific: Verify ACPI Is Enabled
--------------------------------------------------
In VirtualBox with your VM POWERED OFF:
1. Open VirtualBox Manager
2. Select your VM
3. Click Settings -> System -> Motherboard tab
4. Confirm: "Enable ACPI" checkbox is CHECKED
5. Confirm: "Enable I/O APIC" is CHECKED
ACPI cannot be disabled in VirtualBox GUI (it is always on)
but these settings affect what features are available.
To test ACPI shutdown from VirtualBox (after setup is complete):
Machine menu -> ACPI Shutdown
OR press: Ctrl+H (host key + H)
Guest should receive a power button event and shut down cleanly.
================================================================================
SECTION 11: INSTALLING ACPI PACKAGES.
===================================================
11.1 What Packages You Need
-----------------------------
Package | Purpose | Required?
----------|----------------------------------------|-----------
acpid | ACPI event daemon (listens + responds) | YES
acpi | CLI tool to read battery/temp/AC info | YES
pm-utils | pm-suspend, pm-hibernate commands | RECOMMENDED
cpupower | CPU frequency management tool | RECOMMENDED
11.2 Install Package verification.
--------------------------------------------------
Verify installation
$ which acpid
/usr/sbin/acpid
$ which acpi
/usr/bin/acpi
$ ls /etc/rc.d/rc.acpid (init script should be present)
11.3 Install Using installpkg (If You Have the Packages)
----------------------------------------------------------
$ installpkg /path/to/acpid-2.0.34-x86_64-1.txz
$ installpkg /path/to/acpi-1.7-x86_64-2.txz
11.4 Verify Installation Worked
---------------------------------
$ ls -la /usr/sbin/acpid (acpid binary exists)
$ ls -la /usr/bin/acpi (acpi binary exists)
$ ls /etc/acpi/events/ (event config directory)
$ ls /etc/acpi/actions/ (action scripts directory - may be empty)
$ ls -la /etc/rc.d/rc.acpid (init script)
================================================================================
SECTION 12: STARTING AND ENABLING acpid
=========================================
12.1 Start acpid Right Now
----------------------------
$ /etc/rc.d/rc.acpid start
Verify it is running:
$ pgrep acpid
1234 (shows PID if running)
$ ps aux | grep acpid
Check it is listening for events:
$ ls /run/acpid.socket (UNIX socket should exist)
12.2 Make acpid Start Automatically at Every Boot
--------------------------------------------------
OS uses rc.d scripts. A script runs at boot if it is executable.
$ chmod +x /etc/rc.d/rc.acpid
$ ls -la /etc/rc.d/rc.acpid
-rwxr-xr-x 1 root root ... /etc/rc.d/rc.acpid
12.3 Stop / Restart acpid
---------------------------
$ /etc/rc.d/rc.acpid stop
$ /etc/rc.d/rc.acpid restart (use after changing config files)
12.4 Debug Mode (See Events in Real Time)
------------------------------------------
$ acpid -d -f
(Runs in foreground, prints every event to terminal)
Now click Machine > ACPI Shutdown in VirtualBox - you will see the event.
Press Ctrl+C to stop debug mode.
================================================================================
SECTION 13: CONFIGURING acpid EVENT HANDLERS
==============================================
13.1 How acpid Works
---------------------
acpid reads configuration files from /etc/acpi/events/.
Each file defines: what event to watch for, and what script to run.
Event arrives from kernel
|
v
acpid reads /etc/acpi/events/*
|
v
Matches event string using regex in "event=" field
|
v
Runs the command in "action=" field
13.2 Event File Format
-----------------------
File location: /etc/acpi/events/anything-you-want
Format:
event=<regex pattern matching the event string>
action=<script or command to run>
Event string format from kernel: "bus/device TYPE VALUE"
Examples:
button/power PBTN 00000080 <- Power button pressed
button/sleep SBTN 00000080 <- Sleep button pressed
button/lid LID 00000080 <- Lid state changed
ac_adapter ACPI0003 00000000 <- AC unplugged
ac_adapter ACPI0003 00000001 <- AC plugged in
battery BAT0 00000080 <- Battery status changed
13.3 Complete Working Configuration for Your VirtualBox VM
===========================================================
Create these files exactly as shown. Run the chmod commands after each.
--- POWER BUTTON HANDLER ---
File: /etc/acpi/events/powerbtn
Contents:
# Triggered when VirtualBox sends ACPI Shutdown signal
event=button/power
action=/etc/acpi/actions/powerbtn.sh
File: /etc/acpi/actions/powerbtn.sh
Contents:
#!/bin/sh
logger -t acpid "Power button pressed - shutting down"
/sbin/shutdown -h now "ACPI power button"
$ chmod +x /etc/acpi/actions/powerbtn.sh
--- SLEEP BUTTON HANDLER ---
File: /etc/acpi/events/sleepbtn
Contents:
event=button/sleep
action=/etc/acpi/actions/sleepbtn.sh
File: /etc/acpi/actions/sleepbtn.sh
Contents:
#!/bin/sh
logger -t acpid "Sleep button pressed - suspending to RAM"
echo mem > /sys/power/state
$ chmod +x /etc/acpi/actions/sleepbtn.sh
--- LID SWITCH HANDLER ---
File: /etc/acpi/events/lid
Contents:
event=button/lid
action=/etc/acpi/actions/lid.sh
File: /etc/acpi/actions/lid.sh
Contents:
#!/bin/sh
# Check actual lid state from sysfs
LID=$(cat /proc/acpi/button/lid/LID/state 2>/dev/null | awk '{print $2}')
if [ "$LID" = "closed" ]; then
logger -t acpid "Lid closed - suspending"
echo mem > /sys/power/state
else
logger -t acpid "Lid opened"
fi
$ chmod +x /etc/acpi/actions/lid.sh
--- AC ADAPTER HANDLER ---
File: /etc/acpi/events/ac-adapter
Contents:
event=ac_adapter
action=/etc/acpi/actions/ac-adapter.sh
File: /etc/acpi/actions/ac-adapter.sh
Contents:
#!/bin/sh
sleep 1 # Wait for sysfs to update
AC=$(cat /sys/class/power_supply/AC/online 2>/dev/null)
if [ "$AC" = "1" ]; then
logger -t acpid "AC plugged in - switching to performance"
for g in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
[ -f "$g" ] && echo performance > "$g"
done
else
logger -t acpid "AC unplugged - switching to powersave"
for g in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
[ -f "$g" ] && echo powersave > "$g"
done
fi
$ chmod +x /etc/acpi/actions/ac-adapter.sh
--- BATTERY LOW HANDLER ---
File: /etc/acpi/events/battery
Contents:
event=battery
action=/etc/acpi/actions/battery.sh
File: /etc/acpi/actions/battery.sh
Contents:
#!/bin/sh
sleep 1
CAP=$(cat /sys/class/power_supply/BAT0/capacity 2>/dev/null)
[ -z "$CAP" ] && exit 0
logger -t acpid "Battery level: ${CAP}%"
if [ "$CAP" -le 5 ]; then
logger -t acpid "Battery CRITICAL (${CAP}%) - hibernating now!"
echo disk > /sys/power/state
elif [ "$CAP" -le 15 ]; then
logger -t acpid "Battery LOW (${CAP}%) - please plug in power"
fi
$ chmod +x /etc/acpi/actions/battery.sh
--- RESTART acpid AFTER CREATING FILES ---
$ /etc/rc.d/rc.acpid restart
--- TEST YOUR CONFIGURATION ---
In VirtualBox: Machine > ACPI Shutdown
Your VM should begin shutting down cleanly.
Check log: tail -10 /var/log/syslog
================================================================================
SECTION 13b: LOADING ACPI KERNEL MODULES
==========================================
13b.1 Do You Need to Load Modules?
------------------------------------
There are two kernel variants:
kernel-huge : Most drivers built INTO the kernel. Modules less needed.
kernel-generic : Most drivers as separate modules. Must load them.
Check which you have:
$ uname -r
(If it says "-generic", you need to load modules)
13b.2 Load ACPI Modules Now
-----------------------------
$ modprobe ac (AC adapter driver)
$ modprobe battery (Battery driver)
$ modprobe button (Power/sleep/lid buttons)
$ modprobe fan (Fan driver)
$ modprobe thermal (Thermal zone driver)
$ modprobe processor (CPU power management)
$ modprobe acpi-cpufreq (CPU frequency scaling via ACPI)
Verify they loaded:
$ lsmod | grep acpi
$ lsmod | grep battery
$ lsmod | grep thermal
13b.3 Make Module Loading Permanent
-------------------------------------
Add to /etc/rc.d/rc.modules.local (create if missing):
$ cat > /etc/rc.d/rc.modules.local << 'MODEOF'
#!/bin/sh
# Load ACPI modules at boot
/sbin/modprobe ac 2>/dev/null
/sbin/modprobe battery 2>/dev/null
/sbin/modprobe button 2>/dev/null
/sbin/modprobe fan 2>/dev/null
/sbin/modprobe thermal 2>/dev/null
/sbin/modprobe processor 2>/dev/null
/sbin/modprobe acpi-cpufreq 2>/dev/null
MODEOF
$ chmod +x /etc/rc.d/rc.modules.local
================================================================================
PART 7 - TOOLS AND COMMANDS
================================================================================
SECTION 14: ACPI TOOLS - HOW TO USE EACH ONE
==============================================
14.1 acpi - Quick Status Tool
-------------------------------
Show all ACPI info:
$ acpi -V
Battery only:
$ acpi -b
Battery 0: Discharging, 78%, 02:34:12 remaining
AC adapter:
$ acpi -a
Adapter 0: on-line
Temperature:
$ acpi -t
Thermal 0: ok, 45.0 degrees C
Fan:
$ acpi -f
Watch battery continuously:
$ watch -n5 acpi -b
14.2 acpi_listen - Event Monitor
----------------------------------
Watch all ACPI events in real time:
$ acpi_listen
Now trigger events:
- VirtualBox: Machine > ACPI Shutdown -> you see: button/power PBTN 00000080
- Plug/unplug charger -> you see: ac_adapter ACPI0003:00 00000000
14.3 Reading ACPI Tables Directly
-----------------------------------
See all tables available:
$ ls -lh /sys/firmware/acpi/tables/
Extract DSDT (your VM's hardware description):
$ cat /sys/firmware/acpi/tables/DSDT > /tmp/dsdt.bin
$ ls -la /tmp/dsdt.bin
(Should be 9043 bytes - matches 0x002353 hex from your dmesg)
Peek at table header:
$ xxd /sys/firmware/acpi/tables/DSDT | head -5
First 4 bytes: 44 53 44 54 = "DSDT"
Bytes 4-7: length of table
Decompile DSDT to readable source (needs iasl):
$ iasl -d /tmp/dsdt.bin
$ wc -l /tmp/dsdt.dsl (count lines of source code)
$ grep -i "thermal" /tmp/dsdt.dsl
$ grep "_PSS" /tmp/dsdt.dsl (CPU performance states)
$ grep "Device" /tmp/dsdt.dsl (all device definitions)
14.4 cpupower - CPU Frequency Management
------------------------------------------
Show full CPU frequency info:
$ cpupower frequency-info
Show for all CPUs:
$ cpupower -c all frequency-info
Set governor:
$ cpupower frequency-set -g schedutil
$ cpupower frequency-set -g performance
$ cpupower frequency-set -g powersave
Set specific frequency:
$ cpupower frequency-set -f 2GHz
Show C-state info:
$ cpupower idle-info
Monitor stats:
$ cpupower monitor -i 1 (update every 1 second)
14.5 powertop - Power Analysis
--------------------------------
Run interactive mode:
$ powertop
Tab = switch between tabs
Tabs: Overview, Idle stats, Frequency, Device stats, Tunables, Wakeup
The "Tunables" tab shows power optimizations:
"Bad" = not optimized for power saving
Press Enter on any "Bad" item to fix it
Auto-apply all optimizations:
$ powertop --auto-tune
Generate HTML report:
$ powertop --html=/tmp/report.html --time=30
$ firefox /tmp/report.html
14.6 Reading Key sysfs Values
-------------------------------
Battery percentage:
$ cat /sys/class/power_supply/BAT0/capacity
AC adapter status:
$ cat /sys/class/power_supply/AC/online
1 = plugged in, 0 = on battery
Temperature (convert: divide by 1000 for degrees C):
$ cat /sys/class/thermal/thermal_zone0/temp
$ echo "$(cat /sys/class/thermal/thermal_zone0/temp) / 1000" | bc
Current CPU frequency:
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
(value in KHz, divide by 1000 for MHz, divide by 1000000 for GHz)
Available sleep states:
$ cat /sys/power/state
ACPI event interrupt count:
$ cat /sys/firmware/acpi/interrupts/sci
================================================================================
PART 8 - TROUBLESHOOTING
================================================================================
SECTION 15: DEBUGGING ACPI PROBLEMS
======================================
15.1 First Steps for Any ACPI Problem
---------------------------------------
Step 1: Check dmesg for ACPI errors:
$ dmesg | grep -i "ACPI Error"
$ dmesg | grep -i "ACPI Warning"
$ dmesg | grep -i "ACPI" | grep -i "fail"
Step 2: Check if acpid is running:
$ pgrep acpid
Step 3: Check what ACPI sees:
$ acpi -V
Step 4: Check sysfs:
$ ls /sys/class/power_supply/
$ ls /sys/class/thermal/
$ cat /sys/power/state
15.2 Enable Detailed ACPI Debug Output
----------------------------------------
At runtime (immediately, no reboot needed):
$ echo 0xFFFFFFFF > /sys/module/acpi/parameters/debug_layer
$ echo 0xFFFFFFFF > /sys/module/acpi/parameters/debug_level
$ dmesg | grep -i acpi | tail -30
(Turn off debug: echo 0 > /sys/module/acpi/parameters/debug_layer)
At boot (persistent, add to lilo.conf append line):
acpi.debug_layer=0xFFFFFFFF acpi.debug_level=0xFFFFFFFF
(Then run: lilo -v)
15.3 Debug Suspend/Resume Problems
------------------------------------
Enable PM trace (finds which device caused crash):
$ echo 1 > /sys/power/pm_trace
$ echo mem > /sys/power/state
(After reboot following crash):
$ dmesg | grep "hash matches"
Check which devices can trigger wakeup:
$ cat /proc/acpi/wakeup
================================================================================
SECTION 16: ACPI IN VIRTUALBOX - SPECIFIC NOTES
=================================================
16.1 How VirtualBox Provides ACPI
-----------------------------------
Your dmesg already confirmed VirtualBox is providing these ACPI tables:
OEM ID: "VBOX " (VirtualBox)
DSDT Creator: "INTL 20230628" (Intel ASL compiler, June 2023)
SSDT Name: "VBOXCPUT" (VirtualBox CPU table)
VirtualBox generates all ACPI tables itself (no real BIOS involved).
This is why the tables are clean and have few bugs.
16.2 VirtualBox-Specific Features
------------------------------------
ACPI Shutdown from host:
Machine > ACPI Shutdown sends a power button event to the guest.
The guest MUST have acpid running to handle this gracefully.
Fake Battery (for testing battery-related scripts):
From HOST terminal (not inside the VM):
$ VBoxManage setextradata "YourVMName" \
"VBoxInternal/Devices/acpi/0/Config/BatteryLevel" 80
This makes a virtual battery at 80% appear inside the guest.
VirtualBox must be restarted for the change to take effect.
Check VM ACPI settings without GUI:
$ VBoxManage showvminfo "YourVMName" | grep -i acpi
16.3 VirtualBox Kernel Parameters
------------------------------------
Add to /etc/lilo.conf append line for VirtualBox guests:
append = "acpi=on quiet"
If you have clock/timing issues in VirtualBox:
append = "acpi=on clocksource=acpi_pm quiet"
If ACPI causes boot hangs (troubleshoot only):
append = "acpi=noirq quiet"
16.4 Testing ACPI Works End-to-End
-------------------------------------
Test 1: acpid receives power button event
$ acpi_listen & (start in background)
In VirtualBox: Machine > ACPI Shutdown (then click Cancel immediately)
Expected: "button/power PBTN 00000080 00000000" appears in terminal
Test 2: Graceful shutdown
Make sure /etc/acpi/events/powerbtn and powerbtn.sh exist and are correct
In VirtualBox: Machine > ACPI Shutdown
Expected: vm begins clean shutdown process
Test 3: Check acpid log
$ tail -20 /var/log/syslog | grep acpid
================================================================================
SECTION 17: BUILDING A CUSTOM KERNEL WITH ACPI SUPPORT
========================================================
(Only needed if default kernel lacks something you need)
17.1 Get Kernel Source
------------------------
Download newer kernel (your current is 6.6.18):
$ wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.6.18.tar.xz
$ tar -xf linux-6.6.18.tar.xz
$ cd linux-6.6.18
17.2 Start with Your Working Config
--------------------------------------
$ cp /proc/config.gz /tmp/
$ zcat /tmp/config.gz > .config
(This copies your current working kernel config as starting point)
17.3 Navigate ACPI Options in menuconfig
-----------------------------------------
$ make menuconfig
Go to: Power management and ACPI options --->
ACPI (Advanced Configuration and Power Interface) Support [*]
ACPI EC (Embedded Controller) [*]
ACPI Button [*]
ACPI Fan [*]
ACPI Processor [*]
ACPI Thermal Zone [*]
ACPI Battery [M] (module)
ACPI AC Adapter [M] (module)
ACPI Debug Statement Support [*]
Go to: CPU Frequency scaling --->
CPU Frequency scaling [*]
Default governor: schedutil
ACPI Processor P-States driver [M]
Intel P state control [M] (Intel CPUs)
Go to: CPU Idle --->
CPU idle PM support [*]
Menu governor [*]
17.4 Build and Install
------------------------
$ make -j$(nproc) (compile using all CPU cores)
$ make modules_install (install modules to /lib/modules/)
$ cp arch/x86/boot/bzImage /boot/vmlinuz-6.6.18-acpi
$ cp System.map /boot/System.map-6.6.18-acpi
Update LILO:
$ nano /etc/lilo.conf
Add:
image = /boot/vmlinuz-6.6.18-acpi
root = /dev/sda1
label = AcpiKernel
read-only
append = "acpi=on quiet"
$ lilo -v
$ reboot
17.5 Important Kernel Config Symbols
--------------------------------------
Symbol | What It Does
----------------------------|----------------------------------------
CONFIG_ACPI=y | Enable ACPI (required)
CONFIG_ACPI_SLEEP=y | S3/S4 sleep support
CONFIG_ACPI_EC=y | Embedded controller (laptops)
CONFIG_ACPI_AC=m | AC adapter module
CONFIG_ACPI_BATTERY=m | Battery module
CONFIG_ACPI_BUTTON=y | Power/sleep/lid buttons
CONFIG_ACPI_FAN=y | Fan control
CONFIG_ACPI_THERMAL=y | Thermal management
CONFIG_ACPI_PROCESSOR=y | CPU power management
CONFIG_ACPI_DEBUG=y | Debug output (disable in production)
CONFIG_CPU_FREQ=y | Frequency scaling framework
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y | Recommended governor
CONFIG_X86_ACPI_CPUFREQ=m | ACPI CPU freq driver (most x86 CPUs)
CONFIG_X86_INTEL_PSTATE=y | Intel P-state driver (Intel CPUs)
CONFIG_CPU_IDLE=y | CPU idle framework
CONFIG_INTEL_IDLE=y | Intel native idle driver
CONFIG_THERMAL=y | Thermal framework
================================================================================
SECTION 18: COMMON ERRORS AND FIXES
=====================================
18.1 VM Does Not Shut Down Gracefully From VirtualBox
------------------------------------------------------
Symptom: Clicking "ACPI Shutdown" in VirtualBox window does nothing.
VM shows a force-quit dialog instead.
Diagnosis:
$ pgrep acpid
(No output = acpid is not running)
Fix:
$ /etc/rc.d/rc.acpid start
$ pgrep acpid (should show a PID now)
$ ls /etc/acpi/events/powerbtn (event file must exist)
$ ls -la /etc/acpi/actions/powerbtn.sh (must be executable -rwxr-xr-x)
Recreate event file if missing:
$ echo 'event=button/power' > /etc/acpi/events/powerbtn
$ echo 'action=/etc/acpi/actions/powerbtn.sh' >> /etc/acpi/events/powerbtn
Recreate action script if missing:
$ cat > /etc/acpi/actions/powerbtn.sh << 'EOF'
#!/bin/sh
logger -t acpid "Power button pressed"
/sbin/shutdown -h now "ACPI power button"
EOF
$ chmod +x /etc/acpi/actions/powerbtn.sh
$ /etc/rc.d/rc.acpid restart
18.2 "acpi: No battery found" or No Battery Output
----------------------------------------------------
Symptom: acpi -b shows nothing or error.
Fix Step 1: Load the module
$ modprobe battery
$ ls /sys/class/power_supply/
Fix Step 2: If still nothing, VirtualBox battery emulation may be off.
From HOST machine:
$ VBoxManage setextradata "YourVMName" \
"VBoxInternal/Devices/acpi/0/Config/BatteryLevel" 75
Restart VirtualBox VM. Now battery should appear.
18.3 Temperature Shows 0 or Nothing
-------------------------------------
Symptom: acpi -t shows 0°C or no output.
cat /sys/class/thermal/thermal_zone0/temp shows 0.
Fix:
$ modprobe thermal
$ ls /sys/class/thermal/
Note: In a VM, temperature sensors may not be realistic.
VirtualBox often reports 0 or a fake temperature. This is NORMAL for VMs.
For real hardware temperature on Intel CPUs:
$ modprobe coretemp
$ ls /sys/class/hwmon/
For AMD CPUs:
$ modprobe k10temp
18.4 CPU Frequency Not Changing
---------------------------------
Symptom: CPU always at same speed regardless of load.
No /sys/devices/system/cpu/cpu0/cpufreq/ directory.
Fix:
$ modprobe acpi-cpufreq
$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver
(Should show "acpi-cpufreq" or "intel_pstate")
Note: In a VirtualBox VM, the host's actual CPU frequency scaling
may affect what P-states are exposed to the guest.
18.5 Boot Hangs at ACPI Stage
--------------------------------
Symptom: Boot freezes after ACPI messages. Cursor stops.
Fix - at LILO prompt, type additional boot parameters:
linux acpi=noirq (disable ACPI IRQ routing - try first)
linux pci=noacpi (disable ACPI for PCI only)
linux acpi=off (disable ACPI entirely - last resort)
If "acpi=noirq" works, add it permanently to lilo.conf:
$ nano /etc/lilo.conf
append = "acpi=noirq quiet"
$ lilo -v
18.6 S3 Suspend Fails or System Won't Wake
-------------------------------------------
Symptom: echo mem > /sys/power/state fails or system won't wake.
Fix:
$ cat /sys/power/state (check if "mem" is listed)
If "mem" is missing: S3 not supported by this VM config.
For VirtualBox: Add to lilo.conf append:
acpi_sleep=s3_bios
Enable trace to debug:
$ echo 1 > /sys/power/pm_trace
$ echo mem > /sys/power/state
After crash/reboot:
$ dmesg | grep "hash matches"
18.7 ACPI Errors in dmesg (System Still Works Fine)
----------------------------------------------------
Symptom: dmesg shows lines like:
"ACPI Error: Could not resolve symbol [\_SB.PCI0.XHC]"
Explanation: Many ACPI errors in dmesg are harmless.
They often mean the VirtualBox DSDT references something that doesn't
exist in this particular VM configuration.
IF your system works correctly, you can ignore these.
================================================================================
PART 9 - ADVANCED TOPICS
================================================================================
SECTION 19: DSDT PATCHING - FIXING BROKEN FIRMWARE
====================================================
19.1 When Is DSDT Patching Needed?
------------------------------------
DSDT patching is rarely needed for VirtualBox VMs.
It is more common on real laptops with buggy BIOS.
Use it when: dmesg shows ACPI errors causing real problems.
19.2 The Complete DSDT Patching Process
-----------------------------------------
Step 1: Extract your current DSDT
$ cat /sys/firmware/acpi/tables/DSDT > /tmp/dsdt.bin
$ ls -la /tmp/dsdt.bin
(Your DSDT is 9043 bytes)
Step 2: Decompile to ASL source
$ cd /tmp
$ iasl -d dsdt.bin
(Creates dsdt.dsl - the human-readable source)
$ wc -l dsdt.dsl
Step 3: Find and fix the problem in the .dsl file
$ nano /tmp/dsdt.dsl
(Search for the method or device causing issues)
Make your changes. Save the file.
Step 4: Recompile back to binary
$ iasl -tc /tmp/dsdt.dsl
(Creates dsdt.aml if no errors)
(Fix any compile errors shown, then retry)
Step 5: Create initrd override
$ mkdir -p /tmp/acpi_patch/kernel/firmware/acpi
$ cp /tmp/dsdt.aml /tmp/acpi_patch/kernel/firmware/acpi/
$ cd /tmp/acpi_patch
$ find . | cpio -H newc --create > /tmp/acpi_override.cpio
Step 6: Combine with existing initrd
$ cat /tmp/acpi_override.cpio /boot/initrd.gz > /boot/initrd-patched.gz
Step 7: Update LILO to use patched initrd
$ nano /etc/lilo.conf
Add: initrd = /boot/initrd-patched.gz
$ lilo -v
$ reboot
Step 8: Verify patch loaded
$ dmesg | grep "ACPI: Override"
(Should show: "ACPI: Table Upgrade: override [DSDT]")
================================================================================
SECTION 20: ACPI SECURITY
===========================
20.1 Why ACPI Is a Security Risk
----------------------------------
AML code in your DSDT runs with full kernel privileges.
A malicious DSDT could do anything the kernel can do.
In a VM: VirtualBox generates your DSDT, so you trust it as much as
you trust VirtualBox itself. Risk is low.
On real hardware: A physically compromised BIOS could inject
malicious DSDT code. This is why BIOS updates matter.
20.2 Key Security Points
--------------------------
CONFIG_ACPI_CUSTOM_METHOD:
If enabled, allows writing AML code from userspace via
/proc/acpi/custom_method. DISABLE in production kernels.
Check: ls /proc/acpi/custom_method (should not exist)
Kernel Lockdown Mode:
Prevents loading custom DSDT/SSDT, restricts ACPI writes.
$ cat /sys/kernel/security/lockdown
Values: "none", "integrity", "confidentiality"
Secure Boot:
Validates firmware but NOT ACPI tables by default.
Still worth enabling as it protects the bootloader.
20.3 acpid Script Security
----------------------------
All files in /etc/acpi/actions/ run as ROOT.
Always check ownership and permissions:
$ ls -la /etc/acpi/actions/
(All scripts should be: -rwxr-xr-x root root)
Always use absolute paths in scripts:
BAD: shutdown -h now
GOOD: /sbin/shutdown -h now
================================================================================
PART 10 - QUICK REFERENCE
================================================================================
SECTION 21: quick reference guide
==================================
SERVICE MANAGEMENT
Start acpid : /etc/rc.d/rc.acpid start
Stop acpid : /etc/rc.d/rc.acpid stop
Restart acpid : /etc/rc.d/rc.acpid restart
Auto-start on boot : chmod +x /etc/rc.d/rc.acpid
Check if running : pgrep acpid
Debug mode (foreground) : acpid -d -f
STATUS CHECKING
All ACPI info : acpi -V
Battery status : acpi -b
AC adapter : acpi -a
Temperature : acpi -t
Fan : acpi -f
Monitor events : acpi_listen
ACPI kernel messages : dmesg | grep -i acpi
ACPI errors only : dmesg | grep -i "ACPI Error"
READING SYSFS DIRECTLY
Sleep states available : cat /sys/power/state
Battery percentage : cat /sys/class/power_supply/BAT0/capacity
AC plugged in? : cat /sys/class/power_supply/AC/online
Temperature (millideg C) : cat /sys/class/thermal/thermal_zone0/temp
CPU current frequency : cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
CPU governor : cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
ACPI interrupt count : cat /sys/firmware/acpi/interrupts/sci
POWER CONTROL
Suspend to RAM (S3) : echo mem > /sys/power/state
Hibernate (S4) : echo disk > /sys/power/state
Freeze only : echo freeze > /sys/power/state
CPU FREQUENCY
Set governor all CPUs:
for g in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do
echo schedutil > "$g"
done
Using cpupower : cpupower frequency-set -g schedutil
Show info : cpupower frequency-info
MODULE MANAGEMENT
Load all ACPI modules : modprobe ac battery button fan thermal processor acpi-cpufreq
Check loaded modules : lsmod | grep -E "acpi|battery|thermal"
ACPI TABLES
List tables : ls /sys/firmware/acpi/tables/
Extract DSDT : cat /sys/firmware/acpi/tables/DSDT > dsdt.bin
Decompile DSDT : iasl -d dsdt.bin (creates dsdt.dsl)
Dump all tables : acpidump > all_tables.dat
WAKEUP DEVICES
Show wakeup sources : cat /proc/acpi/wakeup
Toggle USB wakeup : echo XHC > /proc/acpi/wakeup
BOOTLOADER (after every change to /etc/lilo.conf)
Apply LILO config : lilo -v
VIRTUALBOX SPECIFIC
Fake battery in VM : VBoxManage setextradata "VMName"
"VBoxInternal/Devices/acpi/0/Config/BatteryLevel" 80
ACPI Shutdown from host : Machine > ACPI Shutdown (or Ctrl+H)
DEBUGGING
Enable full ACPI debug : echo 0xFFFFFFFF > /sys/module/acpi/parameters/debug_layer
echo 0xFFFFFFFF > /sys/module/acpi/parameters/debug_level
Disable ACPI debug : echo 0 > /sys/module/acpi/parameters/debug_layer
Suspend debug trace : echo 1 > /sys/power/pm_trace
POWER STATE REFERENCE TABLE
G0 = System on | S0 = Running
G1 = System sleeping | S3 = Suspend to RAM (S3)
G2 = Soft off | S4 = Hibernate (S4)
G3 = Power unplugged | S5 = Shutdown
C0 = CPU active | P0 = Max frequency
C1 = CPU halt | Pn = Min frequency
C3 = CPU sleep | D0 = Device fully on
C6 = CPU deep sleep | D3 = Device fully off
KEY CONFIG FILES
/etc/acpi/events/ Event rules (one file per event type)
/etc/acpi/actions/ Action scripts (what to do for each event)
/etc/lilo.conf Bootloader config (kernel boot parameters)
/etc/rc.d/rc.acpid startup script for acpid
/etc/rc.d/rc.modules.local Add modprobe commands here
/var/log/syslog Check here for acpid log messages
================================================================================