================================================================================
        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

================================================================================