This series introduces three ACPI devices that are particularly useful
for laptop/mobile virtualization:
* Battery
* AC adapter
* Laptop lid button
Link to v3: https://lists.nongnu.org/archive/html/qemu-devel/2025-08/msg04138.html
Link to GitHub PR, for ease of review: https://github.com/blochl/qemu/pull/4
Changes in v4:
--------------
* Rebased on latest master
Based on the feedback on v3:
* Documentation patch split: each device is now introduced by a
separate documentation patch followed by the code patch.
* sysfs/procfs host mirroring removed from the C devices: QEMU no
longer reads /sys or /proc directly. The devices are now purely
QMP-controlled. A reference Python script is added in
scripts/laptop-mirror.py that demonstrates how a management layer
can translate host sysfs/procfs state into the QMP commands.
* Battery I/O region cleanup: the battery registers are now native
DWORD-access only, matching the AML AML_DWORD_ACC field layout.
* find_*_device() now reports ambiguity: when more than one matching
device is present, QMP returns "More than one X device present".
* QAPI cleanups:
- Stray blank documentation lines in *-set-state removed.
- All the new types and commands carry "Since: 11.1".
- The C devices no longer #include "qemu/error-report.h" now that
they don't call warn_report().
- battery-set-state now rejects impossible combinations
(charging && discharging, charge/discharge without present,
out-of-range charge-percent and rate).
* I/O port unknown-address handling: the default branches in the
ioport_read paths now g_assert_not_reached() instead of logging and
returning 0.
* Set the devices not hotpluggable.
* ISA vs. PCI base: kept ISA. ACPI defines PNP0C0A (battery),
ACPI0003 (AC adapter) and PNP0C0D (lid) as namespace devices under
\_SB with control methods (_BIF/_BST, _PSR, _LID) - see ACPI 6.5
sections 10.2, 10.3 and 9.4
(https://uefi.org/sites/default/files/resources/ACPI_Spec_6_5_Aug29.pdf).
There is no PCI class code defined for any of these in the first place,
and no actual laptop puts them on PCI - the signals come out of the
embedded controller and surface as fixed-hardware ACPI devices.
Guest power-management code matches the same way: Linux uses
drivers/acpi/{battery,ac,button}, Windows acpi.sys, macOS and the
BSDs follow the same pattern. Making the devices PCI would mean
inventing a device class no guest has a driver for.
Changes in v3:
--------------
* Rebased on latest master
* Addressed the v2 review by Igor Mammedov
Changes in v2:
--------------
Based on the feedback from Philippe Mathieu-Daudé and Michael S. Tsirkin:
* Complete redesign with dual-mode operation:
- QMP control mode (default): Devices are controlled via QMP commands,
providing deterministic behavior essential for migration and CI/testing
- Host mirroring mode (opt-in): Original sysfs/procfs monitoring behavior,
now disabled by default
* Migrated to modern QEMU ACPI architecture:
- Devices now implement ACPI_DEV_AML_IF interface
- AML generation moved from centralized acpi-build.c to device files
* Added a QMP interface:
- battery-set-state/query-battery
- ac-adapter-set-state/query-ac-adapter
- lid-button-set-state/query-lid-button
* Documentation improvements:
- Converted to .rst format
- Added examples for both QMP and "fake" sysfs/procfs testing
The dual-mode design ensures these devices are migration-safe and
deterministic by default, while still allowing host state mirroring
when explicitly requested for desktop use cases.
Use cases:
----------
1. Testing: CI systems can programmatically control power states.
2. Cloud: Expose a virtual battery for usage-based resource limiting.
3. Desktop virtualization: Mirror host laptop state to the guest via
the laptop-mirror.py reference script (or a libvirt equivalent).
4. Development: Test power management without physical hardware.
Example usage:
--------------
# QMP-controlled battery
qemu-system-x86_64 -device battery \
-qmp unix:/tmp/qmp.sock,server=on,wait=off
# Control via QMP
{"execute": "battery-set-state",
"arguments": {"state": {"present": true, "charging": false,
"discharging": true, "charge-percent": 42,
"rate": 500}}}
# Or, to mirror host laptop state through QMP:
$builddir/run scripts/laptop-mirror.py -s /tmp/qmp.sock
The series has been tested with Windows and Linux guests, correctly
showing battery status, AC adapter state, and lid button events in
guest UIs and triggering appropriate power management actions.
Thanks again for the reviews.
Leonid.
Leonid Bloch (8):
hw/acpi: Support extended GPE handling for additional ACPI devices
docs/specs: Introduce the QEMU Battery documentation
hw/acpi: Introduce the QEMU Battery
docs/specs: Introduce the QEMU AC adapter documentation
hw/acpi: Introduce the QEMU AC adapter
docs/specs: Introduce the QEMU lid button documentation
hw/acpi: Introduce the QEMU lid button
scripts: Add laptop-mirror reference script
MAINTAINERS | 27 ++
docs/specs/acad.rst | 126 ++++++++++
docs/specs/battery.rst | 154 ++++++++++++
docs/specs/button.rst | 131 ++++++++++
docs/specs/index.rst | 3 +
docs/tools/index.rst | 1 +
docs/tools/laptop-mirror.rst | 82 ++++++
hw/acpi/Kconfig | 12 +
hw/acpi/acad-stub.c | 20 ++
hw/acpi/acad.c | 251 ++++++++++++++++++
hw/acpi/battery-stub.c | 20 ++
hw/acpi/battery.c | 364 +++++++++++++++++++++++++++
hw/acpi/button-stub.c | 20 ++
hw/acpi/button.c | 227 +++++++++++++++++
hw/acpi/core.c | 17 +-
hw/acpi/meson.build | 6 +
hw/acpi/trace-events | 12 +
hw/i386/Kconfig | 3 +
include/hw/acpi/acad.h | 25 ++
include/hw/acpi/acpi_dev_interface.h | 3 +
include/hw/acpi/battery.h | 32 +++
include/hw/acpi/button.h | 23 ++
qapi/acpi.json | 165 ++++++++++++
scripts/laptop-mirror.py | 219 ++++++++++++++++
24 files changed, 1941 insertions(+), 2 deletions(-)
create mode 100644 docs/specs/acad.rst
create mode 100644 docs/specs/battery.rst
create mode 100644 docs/specs/button.rst
create mode 100644 docs/tools/laptop-mirror.rst
create mode 100644 hw/acpi/acad-stub.c
create mode 100644 hw/acpi/acad.c
create mode 100644 hw/acpi/battery-stub.c
create mode 100644 hw/acpi/battery.c
create mode 100644 hw/acpi/button-stub.c
create mode 100644 hw/acpi/button.c
create mode 100644 include/hw/acpi/acad.h
create mode 100644 include/hw/acpi/battery.h
create mode 100644 include/hw/acpi/button.h
create mode 100755 scripts/laptop-mirror.py
--
2.54.0