An operating system discovers most of a computer's built-in hardware by reading a description that firmware hands it at boot, because memory mapped controllers, interrupt lines, clocks and power rails cannot be found by probing. There are two main formats. Devicetree is a static data structure used on many Arm, RISC-V, PowerPC and embedded boards. ACPI is a set of firmware tables plus executable bytecode (AML) used on PCs, x86 servers and Arm servers.
This guide goes one level deeper than our posts on how the motherboard evolved from BIOS to UEFI, TPM and the BMC and on coreboot and open source firmware. We worked from the Devicetree Specification releases, the Linux kernel documentation (docs.kernel.org, version 7.3.0), U-Boot, EBBR and Arm SystemReady documents, ACPICA's release notes and Microsoft's WPBT paper. The UEFI Forum's ACPI pages refused scripted requests, so ACPI section numbers below are the ones the kernel documentation cites from ACPI 6.5.
Key takeaways
- PCI Express and USB devices announce themselves. Controllers wired directly to a system on chip (UARTs, I2C buses, GPIO blocks, timers, interrupt controllers) do not, so firmware has to describe them.
- A devicetree is pure data: a tree of named nodes and properties, written as
.dtssource, compiled bydtcinto a.dtbblob, and passed by the bootloader. On arm64 Linux the bootloader puts the blob's physical address in register x0. - The Devicetree Specification is maintained at devicetree.org. The current release is v0.4, published on 28 June 2023.
- ACPI is data plus code. Static tables such as the RSDP, XSDT, FADT and MADT describe fixed facts, while the DSDT and SSDTs carry AML bytecode that the kernel's ACPI interpreter executes to build a namespace and run control methods for power, configuration and events.
- ACPI is developed under the UEFI Forum. ACPICA's December 2025 release updated its table support to follow the ACPI 6.6 specification; the kernel's arm64 guidance still cites ACPI 6.5 section numbers.
- On Arm servers, ACPI is only supported when booting through UEFI, and Arm's SystemReady program splits compliance into an ACPI band for generic distributions and a Devicetree band for embedded systems.
- Hardware descriptions are an attack surface. AML runs inside the kernel's interpreter, ACPI tables can carry executables for the OS to run (the Windows Platform Binary Table is the documented example), and overlays or SSDTs loaded from writable storage change what the kernel believes about hardware. Linux lockdown blocks ACPI table overrides and custom methods for that reason.
Why can an operating system not simply probe all the hardware?
Some buses were designed for discovery. A PCI or PCI Express device has a configuration space with vendor and device IDs that the OS can read at a known location, and USB devices return descriptors when the host asks. If everything worked this way, firmware would not need to describe anything beyond where the root buses live.
Most of a computer is not built like that. A system on chip places dozens of controllers at fixed physical addresses with no standard way to ask "what lives at this address?" The Linux kernel documentation calls these platform devices: "memory or I/O mapped devices which cannot be detected by hardware." Reading an address where nothing is mapped can fault or stall the bus, and writing to the wrong register can switch off a voltage regulator. Interrupt wiring is invisible from software. An accelerometer on an I2C bus does not broadcast its presence, and the GPIO pin that signals it has new data is a board design decision, not a property of the chip.
Before hardware descriptions became standard, Linux handled this with board files: C source in the kernel tree that hard coded every device for every board. The devicetree usage model document describes that era plainly. Embedded platforms defined static clock structures, platform devices and other data in a board support C file and registered them all at boot. Every new board meant new kernel code, and one kernel image could not run on two boards with different wiring.
The fix was to move the description out of the kernel and into data supplied by firmware or the bootloader. Two answers won.
- Devicetree. A hardware description that is pure data. The kernel matches nodes to drivers by
compatiblestrings and reads addresses, interrupts and clocks from properties. It dominates on Arm boards, embedded Linux, many RISC-V boards and PowerPC. - ACPI. The Advanced Configuration and Power Interface, a set of tables and bytecode published by firmware. It dominates on x86 PCs and servers, and it is the standard for Arm servers that aim to run unmodified enterprise distributions.
Both solve the same problem: tell a generic kernel what is on this specific machine so that the same kernel image can boot on many machines. They make very different choices about who controls behaviour, which matters for compatibility and for security.
What is a devicetree?
The kernel documentation describes the Devicetree (DT) as a data structure and a language for describing hardware, readable by an operating system so that the OS does not have to hard code the details of each machine. Structurally it is a tree of named nodes, each with any number of named properties, plus a way to link one node to another outside the tree structure (a phandle).
Where it came from
The devicetree started as part of Open Firmware, the boot firmware long used on PowerPC and SPARC machines, where firmware passed the tree to the operating system as part of its client interface. According to the kernel's history section, in 2005 PowerPC Linux decided to require devicetree support on all PowerPC platforms, whether or not they used Open Firmware. To make that possible, developers created the Flattened Device Tree (FDT): a binary representation that could be handed to the kernel as a blob without a real Open Firmware implementation. U-Boot, kexec and other bootloaders learned to pass a Device Tree Binary (dtb) and to modify it at boot time. The FDT infrastructure was later generalized for all architectures, and Arm adopted it as the way out of board files.
Source, blob and bindings
Three pieces make up a working devicetree.
| Piece | File | What it is |
|---|---|---|
| Source | .dts and included .dtsi | Human readable text describing nodes and properties. SoC vendors usually ship a .dtsi for the chip and each board includes it and adds its own wiring. |
| Blob | .dtb | The flattened binary form that bootloaders load and the kernel parses. Built by the devicetree compiler, dtc. |
| Overlay | .dtso source, .dtbo blob | A fragment that adds or changes nodes in a base tree, used for add-on boards and optional hardware. |
| Bindings | YAML schemas in the kernel tree | The conventions for what properties a given kind of device must have. The kernel validates .dts files against them. |
A minimal fragment looks like this, adapted from the NVIDIA Tegra example in the kernel's usage model document:
/ {
compatible = "nvidia,harmony", "nvidia,tegra20";
#address-cells = <1>;
#size-cells = <1>;
interrupt-parent = <&intc>;
chosen { };
memory {
device_type = "memory";
reg = <0x00000000 0x40000000>;
};
};
The reg property says where memory starts and how big it is, using the cell sizes declared by #address-cells and #size-cells. Device nodes below the root carry their own reg ranges, interrupts, clocks and so on.
Compatible strings are how drivers find hardware
The compatible property is the heart of the model. It holds a list of strings ordered from most specific to least specific. The kernel's own example for the BeagleBoard xM is:
compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";
That says: this is exactly a BeagleBoard xM, it is compatible with the OMAP 3450 SoC, and with the OMAP3 family in general. The kernel first uses the root node's compatible to identify the machine, then matches every device node against driver tables. A driver that claims "ti,omap3" will bind to any board in the family unless a more specific match exists. The kernel documentation insists that every compatible string be documented in the bindings, and it warns against claiming that one board is compatible with another, because boards in the same product line often differ more than their names suggest.
The usage model document lists three jobs the kernel does with devicetree data: platform identification, runtime configuration and device population. Runtime configuration lives mostly in the /chosen node, which carries the kernel command line (bootargs) and the location of the initrd. Device population happens when the kernel unflattens the blob into an in-memory tree and creates platform devices for nodes at the root and under simple memory mapped buses.
Overlays
A base devicetree describes a fixed board. Add-on hardware such as a sensor cape, a display or a field programmable gate array bitstream changes the hardware, so devicetree grew overlays. The kernel's overlay notes describe an overlay's purpose as modifying "the kernel's live tree" so that new device nodes create devices and removed or disabled nodes deregister them.
An overlay source file starts with /plugin/; and targets a node in the base tree, either by label (&ocp) or by explicit path (&{/ocp}). Targeting by label only works if the base tree was compiled with dtc -@, which keeps a symbol table in the blob. Overlays are usually applied by the bootloader before the kernel starts. The kernel also has an in-kernel API, of_overlay_fdt_apply(), for applying them at runtime, and the overlay notes spend several paragraphs warning that code holding pointers into an overlay after it is removed is a use after free bug. Where you do not need runtime overlays, leave the interfaces that apply them disabled.
Who maintains the specification?
The Devicetree Specification lives at devicetree.org, with its source on GitHub and a mailing list for discussion. The specifications page lists v0.4 as the current release, published on Wednesday 28 June 2023. The GitHub release history shows the earlier milestones.
| Release | Date (GitHub release) |
|---|---|
| v0.1 | 18 December 2017 (first release of the spec document) |
| v0.2 | 20 December 2017 |
| v0.3 | 13 February 2020 |
| v0.4 rc1 | 30 November 2021 |
| v0.4 | 28 June 2023 |
The site's copyright line names Linaro Limited, and the page says the next major release will be scheduled once agreed by the project's technical steering committee. In practice, the device bindings that matter day to day are the YAML schemas in the Linux kernel tree, which the kernel documentation describes in its guide to writing devicetree schemas. The specification defines the format and core conventions. The kernel tree defines most of the per device bindings.
How the bootloader hands it to the kernel
On arm64 the handoff is precise. The kernel's arm64 boot protocol document makes setting up the device tree a mandatory step and requires the blob to sit on an 8 byte boundary and to be no larger than 2 megabytes. At kernel entry, register x0 holds the physical address of the dtb in system RAM, and x1 to x3 must be zero. The bootloader is also expected to add properties the kernel needs, such as an enable-method for each CPU node so secondary cores can be started.
U-Boot, the most common embedded bootloader, has several ways to obtain the tree it uses for its own drivers and passes on. Its devicetree control documentation describes Kconfig options for embedding the blob in the U-Boot image (OF_EMBED, which it says is "suitable for debugging and development only"), keeping it as a separate u-boot.dtb appended to the image (OF_SEPARATE), having a board routine provide it at runtime (OF_BOARD), or taking it from a bloblist passed by an earlier boot stage. U-Boot then loads the OS devicetree, applies any overlays the boot script asks for, fixes up properties such as memory size and the command line, and passes it to the kernel.
When U-Boot boots an OS through its UEFI implementation, it publishes the devicetree as a UEFI configuration table instead of passing a register. That is the route the Arm EBBR specification standardizes, covered below.
What is ACPI?
ACPI is a firmware interface for hardware discovery, configuration and power management. Unlike devicetree, it carries behaviour as well as description. The kernel's arm64 ACPI document puts the difference simply: AML bytecode "allows the platform to encode hardware behavior," and devicetree deliberately does not.
The table hierarchy
ACPI firmware publishes a chain of tables in memory. The kernel's ACPI namespace document and the arm64 guide describe how the OS walks it.
- RSDP (Root System Description Pointer). The starting point. On UEFI systems the firmware publishes its address in the UEFI configuration table under the ACPI 2.0 table GUID. On arm64 the kernel documentation says this is the only defined way to pass ACPI tables to the kernel. On legacy BIOS PCs the ACPI specification instead defines a search of fixed low memory areas for the RSDP signature,
"RSD PTR ". - XSDT (Extended System Description Table). Holds 64 bit pointers to every other table. Its 32 bit predecessor, the RSDT, still exists on many PCs, but the arm64 guide says the kernel ignores it there because it only allows 32 bit addresses.
- FADT (Fixed ACPI Description Table, signature
FACP). Fixed hardware details such as power management register blocks and boot flags, plus the pointer to the DSDT. - DSDT (Differentiated System Description Table). The main block of AML that defines devices, their resources and their control methods.
- SSDTs (Secondary System Description Tables). Additional AML blocks that extend the namespace. Firmware often splits CPU power states, graphics or add-on features into SSDTs.
- MADT (Multiple APIC Description Table, signature
APIC). Lists processors and interrupt controllers. On x86 that means local APICs and I/O APICs; on Arm it describes the Generic Interrupt Controller.
Many more tables cover specific features. The kernel's arm64 list, which cites ACPI 6.5 section numbers, includes the GTDT for generic timers, the PPTT for processor topology, the MCFG for PCI Express configuration space, the SPCR for the serial console, the IORT for I/O remapping, the SRAT and SLIT for NUMA, the HMAT for heterogeneous memory, the BERT, EINJ, ERST and HEST error tables, and the PCCT for platform communication channels. Section references in that guide: RSDP 5.2.5, XSDT 5.2.8, FADT 5.2.9, DSDT 5.2.11.1 and MADT 5.2.12.
AML, ASL and the namespace
The DSDT and SSDTs contain definition blocks encoded in AML, the ACPI Machine Language. Humans write ASL, the ACPI Source Language, which the arm64 guide points to in section 19 of the specification, and a compiler turns it into AML. The kernel's namespace document explains that the DSDT data block together with the SSDTs forms "a hierarchical data structure called the ACPI namespace," shaped like the hardware platform underneath it.
The namespace holds named objects. Device objects represent hardware. Name objects hold data such as _HID (a hardware ID that drivers match on, the ACPI equivalent of a compatible string) and _CRS (current resource settings: memory ranges, interrupts, I2C or GPIO connections). Method objects hold code. Standard method names start with an underscore: _STA reports whether a device is present and enabled, _PS0 and _PS3 move a device between full power and off, _PRT describes PCI interrupt routing, _DSD returns device properties, and _DSM is a catch all device specific method.
The kernel's SSDT overlay document shows a complete small device description: an accelerometer with _HID set to "BMA222E", attached to an I2C controller at bus address 0x18 with a GPIO interrupt, all expressed inside a _CRS method. It is a good example of how much a few dozen lines of ASL say about wiring that no probe could discover.
How the kernel interprets it
Linux does not parse AML itself in ad hoc code. It uses ACPICA, the ACPI Component Architecture, an OS independent reference implementation of the ACPI interpreter and table manager that the kernel imports. ACPICA also ships the user space tools used later in this guide: acpidump, acpixtract and the iasl compiler and disassembler. ACPICA's September 2026 release notes record a licence change to BSD-3-Clause or GPL-2.0-only and say the EFI build of acpidump now builds for RISCV64. The December 2025 release notes say many existing tables were updated "to follow the ACPI 6.6 Specification changes" and newly approved changes from the ACPI Specification Working Group.
At boot the kernel maps the tables, loads the DSDT and SSDTs into the interpreter, and builds the namespace. The kernel's enumeration document then describes how it creates devices: ACPI device objects become struct acpi_device entries, and drivers bind to them by _HID or _CID. For devices behind I2C, SPI or GPIO controllers, the kernel reads _CRS resources to set up the connection. When it needs to change a device's power state or ask whether hardware is present, it evaluates the relevant method, and the interpreter runs the firmware's AML.
This is the key design choice. With devicetree, the kernel contains all the logic and firmware supplies only facts. With ACPI, firmware supplies logic too, and the kernel executes it. The arm64 guide gives the clock example: in devicetree, clocks are described and drivers manage them; in ACPI, the assumption is that firmware leaves the device in a reasonable default state, and if a driver needs to change a clock it calls an ACPI method without needing to know what that method does.
Device properties: _DSD and _DSM
ACPI names are limited to four characters and have no shared registry for ad hoc data, which made it hard to describe the many small properties embedded devices need. The _DSD (Device Specific Data) object addresses this by returning key and value pairs under a UUID. The kernel says drivers should use only the device properties UUID daffd814-6eba-4d8c-8a91-bc9bbf4aa301 and that common properties should be registered with the UEFI Forum. It is blunt about _DSM: the document calls it the cause of many firmware problems and recommends against relying on it.
Who publishes ACPI?
ACPI grew up on PCs, and governance of the specification has since moved into the UEFI Forum, where its ACPI Specification Working Group (ASWG, the group ACPICA's release notes credit for approved change requests) develops it. The kernel's arm64 guide credits that move with opening the process up, says a large share of current ACPI changes are driven by Linux, and argues that ACPI no longer belongs only to Windows. The specification is published on uefi.org. We could not fetch the uefi.org specification pages with a scripted client, so we confirm the current version through ACPICA, whose December 2025 release targets ACPI 6.6, and note that the kernel's arm64 document still cites section numbers from ACPI 6.5.
Devicetree and ACPI compared
| Devicetree | ACPI | |
|---|---|---|
| Format | Flattened binary tree (.dtb) compiled from .dts text | Binary tables with standard headers; DSDT and SSDTs hold AML bytecode compiled from ASL |
| Code or data | Data only | Data plus executable control methods |
| Who writes it | SoC vendor and board maker, often upstreamed into the Linux kernel tree; bootloader fixes up at boot | Platform firmware vendor and OEM, inside the UEFI or BIOS image |
| Who maintains the standard | devicetree.org (spec v0.4, June 2023); per device bindings in the kernel tree | UEFI Forum ACPI Specification Working Group (ACPI 6.6 per ACPICA's December 2025 release) |
| How it reaches the kernel | Register (x0 on arm64), bootloader handoff, or UEFI configuration table | UEFI configuration table pointing at the RSDP; legacy BIOS memory search on old PCs |
| Runtime behaviour | Static after boot except for overlays; the kernel drives all hardware logic | AML methods run in the kernel's interpreter for power, hotplug, thermal and events |
| Power management | Described through bindings; drivers and kernel frameworks implement policy | ACPI's OSPM model with sleep states, device power states and firmware methods |
| Driver matching | compatible strings | _HID and _CID IDs, plus _DSD properties |
| Typical platforms | Arm boards, embedded Linux, many RISC-V boards, PowerPC | x86 PCs and servers, Arm servers, some Arm laptops |
| Update path | Ships with the kernel or bootloader; easy to rebuild and replace | Ships inside firmware; vendor firmware update, or Linux table upgrade through initrd for testing |
| Main security concern | Writable overlays and blobs that are not verified; wrong descriptions | Firmware code executing in kernel context; tables that inject binaries; table overrides |
Neither is better in general. Devicetree suits vertically integrated products where the same team ships firmware, bootloader and kernel. ACPI suits general purpose machines where an OS released years earlier must boot on hardware released years later.
How do Arm servers use ACPI, and why does SystemReady matter?
For years, each Arm board needed its own kernel tree or at least its own devicetree, which made it hard for enterprise distributions to support Arm servers the way they support x86. The kernel's arm64 ACPI document lays out why Arm servers chose ACPI anyway. AML lets vendors encode behaviour so new hardware works with existing OS releases. ACPI's power management model constrains what a platform may do. Server features such as RAS (reliability, availability and serviceability) error reporting already had ACPI bindings in production. And hardware vendors did not want to maintain two separate firmware interfaces, one for Linux and one for Windows.
The same document sets the rules for how Linux on arm64 handles the two schemes.
- ACPI is only supported on platforms that boot via UEFI. The UEFI implementation must point the ACPI 2.0 table GUID at the RSDP.
- The kernel uses one description method per boot. Without command line parameters it tries devicetree first and falls back to ACPI tables if no devicetree is present. With
acpi=forceit tries ACPI first and falls back to devicetree. - The ACPI core ignores the RSDT and uses only 64 bit addresses from the FADT.
- Hardware reduced mode, in which legacy fixed hardware is absent, is enforced on arm64.
- Driver support for ACPI and devicetree should never be mutually exclusive at compile time.
It also sets a compatibility promise that matters for long lived servers: ACPI firmware must keep working with the earliest kernel that supports its baseline ACPI version and with the most recent kernel.
SystemReady bands
Arm SystemReady is Arm's compliance program for this goal. Arm's program page describes it as helping "ensure the interoperability of an operating system on Arm-based hardware" so that developers can build software once and deploy it on any compliant chip. The program is split into bands aligned with the two description methods.
| Band | Description method | Aim, per Arm's program page |
|---|---|---|
| SystemReady band | ACPI | Generic operating systems install on new or old hardware without modification |
| SystemReady Devicetree band | Devicetree | Install and boot for embedded systems where devicetree is preferred, with a focus on forward compatibility, for Linux distributions and BSD |
The detailed requirements are in the Arm SystemReady Requirements Specification (SRS), and the hardware side is defined by the Base System Architecture (BSA), with a pre silicon program that lets chip vendors check BSA compliance before tape out. Arm's developer documentation site refused scripted requests for the base boot requirements documents, so we describe them only as the program page does.
EBBR: one description at a time
The Embedded Base Boot Requirements (EBBR) specification, published openly on GitHub Pages, defines a UEFI subset for embedded Arm and RISC-V devices. It requires the firmware to provide either an ACPI table or a devicetree system description, and states that "EBBR systems must not provide both ACPI and Devicetree tables at the same time." Systems that support both must offer a configuration switch and pass only the selected one to the OS loader. This is the rule that lets a distribution's generic installer boot on an EBBR board using the devicetree in firmware, the same way it boots a server using ACPI.
Why it matters for distribution support
If firmware provides a standard description through UEFI, a distribution can ship one arm64 installer image. If the description lives only in a vendor kernel tree, users are stuck on that vendor's kernel and its patch schedule. That is a supply chain point as much as a convenience: a board that can boot an upstream distribution kernel gets that distribution's security updates, and one that needs a vendor fork gets whatever the vendor backports.
Where do security issues come from?
A hardware description tells the kernel what memory it may touch, which interrupts belong to which driver, and how to power devices on and off. Whoever controls it has a strong say over the kernel. The issues fall into four groups. We describe mechanisms and defences, not attack steps.
1. AML executing in the kernel's interpreter
ACPI control methods are code written by the firmware vendor and run by the kernel's interpreter with kernel privileges. AML can read and write system memory, I/O ports and PCI configuration space through operation regions. That is necessary for it to do its job, and it means a bug or a hostile change in AML runs with the same reach as kernel code.
The kernel has mitigations. AML is bytecode, so it acts only through the operations the interpreter implements, not as native machine code. Linux also has facilities that change what firmware code runs, and the kernel lockdown manual page lists the ACPI ones it disables once lockdown is active: overriding ACPI tables, ACPI error injection, specifying the RSDP address and ACPI custom methods. Distributions that enable lockdown under Secure Boot close those paths for root users who would otherwise be able to change firmware behaviour from user space.
2. Firmware tables that hand the OS a program to run
The clearest documented example is the Windows Platform Binary Table (WPBT). Microsoft's paper, first published on 29 November 2011 and revised on 8 July 2015 to add security guidance, describes it as a fixed ACPI table through which boot firmware gives Windows a platform binary to execute. The table contains the physical address of a Portable Executable image in memory. During initialization Windows writes that image to disk and the Session Manager launches it as a native user mode process.
The paper is explicit about why it exists: to let critical software "persist even when the operating system has changed or been reinstalled," with anti theft software as the main use case. It also warns that because the feature gives persistent execution in the context of Windows, WPBT solutions must be as secure as possible and must not include malware, and it recommends using it only where persistence is a core requirement.
The lesson for defenders is conceptual and general. An ACPI table is not only a description; on some operating systems a table can be a delivery mechanism. A clean OS reinstall does not reset what the firmware publishes. If you rebuild machines as part of incident response, firmware level persistence is outside what a disk wipe removes, and you need to check what tables the firmware publishes and whether your OS honours them. Linux does not run WPBT payloads, but the same principle applies to any table the kernel trusts.
3. Overlays and SSDTs loaded from writable storage
Both ecosystems let you add descriptions after firmware is built, which is a useful feature with a clear risk.
- Devicetree overlays are often stored as
.dtbofiles on a boot partition and applied by the bootloader according to a configuration file or boot script. If that partition is writable by an attacker and the bootloader does not verify the overlay, the attacker can describe a device that does not exist, remap a device's registers, change reserved memory or alter the/chosencommand line. - Linux ACPI table upgrades let you place tables in a
kernel/firmware/acpidirectory inside the first, uncompressed cpio archive of the initrd. The kernel documentation says a table with a matching signature, OEM ID and OEM table ID and a higher OEM revision replaces the firmware's table, and a non matching one is appended, up to 64 tables. Every table thatiaslknows can be overridden except the RSDP and FACS. The feature is meant for working around firmware bugs and testing, and the documentation suggests it is safe to enable because nothing changes without an instrumented initrd. - SSDT overlays can also come from an EFI variable named on the kernel command line with
efivar_ssdt=, whenCONFIG_EFI_CUSTOM_SSDT_OVERLAYSis enabled.
The defences follow from the mechanism. Sign and verify the initrd and the overlays, or build them into a signed image. Keep the boot partition read only in production. Enable lockdown, which disables the table override path. Treat the kernel command line as security relevant input, since it can name an EFI variable to load AML from.
4. Mismatched or wrong tables
Not every problem is malicious. Firmware that describes the wrong interrupt, the wrong memory range or a buggy _DSM can cause drivers to misbehave, and the kernel's arm64 guide names _DSM as a frequent source of firmware problems. A devicetree built for one board revision and loaded on another can claim memory or devices that are not there. When descriptions are wrong, the safe outcome is a device that does not work; the unsafe outcome is a driver given access to memory it should not own. Kernel code that consumes description data needs the same input validation as any other parser.
How do Devicetree and ACPI relate to UEFI, Secure Boot and measured boot?
UEFI is the transport for both on modern systems. ACPI tables reach the OS through the UEFI configuration table on UEFI machines, and the arm64 kernel requires that route. Devicetree can also travel as a UEFI configuration table, which is how U-Boot's UEFI implementation and EBBR firmware hand it to a generic OS loader. See our post on the difference between Secure Boot, trusted boot and measured boot for the general model.
Secure Boot does not sign tables
UEFI Secure Boot verifies signatures on executables: the bootloader, the kernel, drivers and option ROMs (see our post on PCI option ROMs and Secure Boot). ACPI tables are produced by the firmware itself, so their integrity depends on the firmware image being authentic and protected, not on a separate table signature. A devicetree passed by a bootloader is likewise only as trustworthy as the bootloader and the storage it came from. Verified boot schemes can cover it. U-Boot's FIT signature documentation explains that plain FIT hashes catch corruption but not substitution, while signing the hashes lets U-Boot verify images, including a devicetree packaged in the same FIT, against a public key held in non volatile storage.
Measured boot can record descriptions
Measured boot hashes boot components into TPM platform configuration registers (PCRs) and keeps an event log. U-Boot's measured boot documentation is specific about devicetrees. Through its UEFI subsystem, which implements the TCG PC Client Platform Firmware Profile, the optional CONFIG_EFI_TCG2_PROTOCOL_MEASURE_DTB setting "will measure the loaded DTB in PCR 1." For the legacy booti, bootm and bootz paths, U-Boot measures the kernel image, initrd and bootargs by default, and CONFIG_MEASURE_DEVICETREE adds the devicetree in PCR 1.
Whether a given PC firmware measures its ACPI tables, and into which PCR, depends on the firmware implementation and the TCG profile it follows. The TCG specification page returned rate limiting errors to our requests, so we do not state a rule here. The practical answer is to look: read the TPM event log on your own machine and see which events appear (commands below). If your attestation policy depends on hardware description integrity, confirm that the description is actually in the log.
Lockdown ties it together on Linux
On distributions that turn on kernel lockdown when Secure Boot is active, the kernel refuses table overrides, custom ACPI methods, ACPI error injection and a user supplied RSDP address. That keeps the chain intact: Secure Boot verifies the kernel, and lockdown stops root from replacing the firmware's description after the fact.
Step by step: inspect ACPI tables and a devicetree on Linux
These commands only read data. None of them changes firmware. You need root for the ACPI dump and for reading the TPM event log.
Part 1: dump and decompile ACPI tables
Step 1. Install the ACPICA tools. On Debian and Ubuntu the package is acpica-tools; on Fedora it has the same name.
sudo apt install acpica-tools # Debian, Ubuntu
sudo dnf install acpica-tools # Fedora, RHEL family
iasl -v # print the compiler version
Step 2. See which tables the firmware published. The kernel exposes each one as a file.
ls /sys/firmware/acpi/tables/
You should see names such as APIC, DSDT, FACP, MCFG and a series of SSDT1, SSDT2 and so on.
Step 3. Dump all tables into one file and split them, the method shown in the kernel's table upgrade documentation.
mkdir -p ~/acpi && cd ~/acpi
sudo acpidump > acpidump.out
acpixtract -a acpidump.out
ls *.dat
acpixtract -a writes one .dat file per table, for example dsdt.dat, facp.dat and ssdt1.dat.
Step 4. Disassemble to ASL.
iasl -d *.dat
ls *.dsl
Static tables such as the MADT and FADT disassemble into annotated field listings. The DSDT and SSDTs disassemble into ASL with Device, Name and Method blocks. If the DSDT refers to objects defined in SSDTs, the disassembler resolves them better when you give it the other tables as externals:
iasl -e ssdt*.dat -d dsdt.dat
Step 5. Read what matters.
grep -n "Signature\|Oem ID\|Oem Table ID\|Oem Revision" facp.dsl
grep -n "_HID" dsdt.dsl | head -40
grep -n "Method (_DSM" dsdt.dsl ssdt*.dsl | wc -l
The header fields tell you which vendor and firmware revision built each table. _HID lines list the device IDs drivers will match. A count of _DSM methods is a rough sense of how much device specific behaviour the firmware encodes.
Step 6. Check the kernel's view of ACPI at boot.
sudo dmesg | grep -i "ACPI:" | head -40
Look for lines naming each table, the OEM IDs and any ACPI Error or ACPI BIOS Error messages, which usually point to firmware bugs in AML.
Step 7. Check for a WPBT table. On Linux it does nothing, but its presence tells you the firmware is configured to hand a binary to Windows.
ls /sys/firmware/acpi/tables/ | grep -i wpbt || echo "no WPBT table"
Part 2: decompile a devicetree
Step 1. Install the devicetree compiler.
sudo apt install device-tree-compiler # Debian, Ubuntu
sudo dnf install dtc # Fedora
dtc -v
Step 2. On a devicetree system (most Arm single board computers), read the identity of the board the kernel booted with.
tr '\0' '\n' < /proc/device-tree/compatible
tr '\0' '\n' < /proc/device-tree/model; echo
The first command prints the root compatible list, most specific first.
Step 3. Decompile the live tree the kernel is using, straight from the file system view. The kernel's ABI documentation says user space should go through the /proc/device-tree symlink rather than the /sys/firmware/devicetree/base path it points to, because the symlink is the stable interface.
dtc -I fs -O dts -o live.dts /proc/device-tree/ 2>dtc-warnings.txt
less live.dts
This is the tree after the bootloader's fixups and any overlays, which is often different from the .dtb file on disk.
Step 4. Decompile a blob from the boot partition. Paths vary by distribution and board.
ls /boot/dtbs/ /boot/firmware/ 2>/dev/null
dtc -I dtb -O dts -o board.dts /boot/dtbs/$(uname -r)/vendor/board.dtb
Step 5. Compare the shipped blob with the live tree to see what the bootloader changed.
dtc -I dtb -O dts -s -o shipped.dts /boot/dtbs/$(uname -r)/vendor/board.dtb
dtc -I fs -O dts -s -o running.dts /proc/device-tree/
diff -u shipped.dts running.dts | less
The -s option (long form sort in the dtc source) sorts nodes and properties so the diff is readable. Expect differences in /chosen (command line, initrd addresses), memory size and any overlays applied at boot. Anything else is worth understanding.
Step 6. Build an overlay without applying it, to see the format. The base tree must have been built with -@ for label targets to resolve.
cat > sensor.dtso <<'EOF'
/dts-v1/;
/plugin/;
&i2c1 {
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
sensor@18 {
compatible = "vendor,example-sensor";
reg = <0x18>;
};
};
EOF
dtc -@ -I dts -O dtb -o sensor.dtbo sensor.dtso
fdtdump sensor.dtbo | head -40
Do not copy a test overlay into your board's overlay directory on a production device. Applying the wrong overlay can disable storage or console devices and leave the board unbootable until you edit the boot partition from another machine.
Part 3: see whether your boot measured the description
If the machine has a TPM and the tpm2-tools package, read the event log the firmware passed to the kernel. The kernel's TPM driver exposes it in securityfs as binary_bios_measurements, and the tpm2_eventlog manual says the tool takes the path to a binary event log as its argument, in the format defined by the TCG PC Client Platform Firmware Profile.
sudo tpm2_eventlog /sys/kernel/security/tpm0/binary_bios_measurements > eventlog.yaml
grep -n "PCRIndex: 1" -A6 eventlog.yaml | head -60
grep -n -i "acpi\|dtb\|devicetree" eventlog.yaml | head
On U-Boot systems with DTB measurement enabled, you will find the devicetree measured into PCR 1. On PC firmware, look for events that mention ACPI or platform configuration. If nothing names your hardware description, your attestation does not cover it.
A worked example: following one device from description to driver
To make this concrete, follow one I2C sensor through both systems.
In a devicetree, the sensor is a child node of its I2C controller. The node's reg is the bus address, its compatible names the part, and an interrupts or interrupts-extended property points through a phandle to a GPIO controller and pin. When the kernel populates the I2C controller, the I2C core walks child nodes and creates a client device for each. The driver whose match table contains the compatible string probes, reads the interrupt from the node, and requests it.
In ACPI, the same sensor is a Device object in the DSDT or an SSDT, scoped under the I2C controller's object. Its _HID names the part. Its _CRS returns an I2cSerialBus resource with the bus address and controller path, and a GpioInt resource for the interrupt, exactly as in the kernel's BMA222E SSDT example. When the kernel enumerates the namespace, the I2C core finds the I2cSerialBus resource and creates a client device. A driver matching the _HID, or matching through the PRP0001 route that lets ACPI reuse devicetree compatible strings via _DSD, then probes. If the device needs powering on, the kernel may evaluate _PS0, running firmware AML.
The outcome is the same driver binding. The difference is who owns the logic along the way, and where you would have to change things to fix a bug: a devicetree source file you can rebuild, or a firmware image you usually cannot.
Common mistakes
- Assuming hardware is probed. Engineers new to embedded Linux expect a missing sensor to "show up" once the driver is loaded. Without a devicetree node or ACPI device describing it, the kernel has nothing to bind to.
- Editing the shipped
.dtband forgetting the bootloader. The tree the kernel uses is often the bootloader's modified copy, or a different file than you think. Compare/proc/device-treewith the file on disk before debugging. - Building overlays without
-@on the base tree. Label targets then fail to resolve. Either rebuild the base tree with symbols or target by explicit path. - Copying compatible strings between boards. The kernel documentation warns that boards in the same family often differ. Claiming compatibility with a board you are not can bind the wrong board fixups.
- Relying on
_DSMfor new device properties. The kernel asks drivers to use_DSDwith the registered device properties UUID and treats_DSMas a source of firmware problems. - Leaving ACPI table upgrade paths open in production. Initrd table upgrades and EFI variable SSDTs are debugging and bring up tools. Without signed initrds and lockdown, they let anyone who can write the boot partition or EFI variables change the kernel's view of hardware.
- Treating an OS reinstall as a firmware reset. Tables such as WPBT exist precisely so software survives a reinstall. Check what firmware publishes after a rebuild.
- Assuming measured boot covers the description. Some boot paths measure the devicetree and some firmware may not measure ACPI tables. Read the event log rather than assuming.
- Shipping both ACPI and devicetree to the OS. EBBR forbids it, and the arm64 kernel picks one by its own rules, which may not be the one you tested.
- Ignoring
ACPI BIOS Errormessages. They often point to AML bugs that cause suspend, thermal or power failures, and they are worth reporting to the firmware vendor with the decompiled table and kernel version.
FAQ
Does Windows use Devicetree?
Windows on PCs and Arm laptops uses ACPI. The Linux kernel's arm64 ACPI document notes that Microsoft would not collaborate on devicetree, which is one reason Arm servers and Windows on Arm devices use ACPI. Linux supports both.
What is the difference between a DTS, DTSI, DTB and DTBO file?
A .dts is devicetree source for a board, a .dtsi is an include file (usually for a SoC or shared module), a .dtb is the compiled binary blob the kernel reads, and a .dtbo is a compiled overlay that modifies a base tree.
What is the current Devicetree Specification version?
The devicetree.org specifications page lists v0.4, released on 28 June 2023, as the current release.
What is the current ACPI specification version?
ACPI is published by the UEFI Forum. ACPICA's December 2025 release updated its tables to follow ACPI 6.6, and the Linux arm64 documentation still references ACPI 6.5 section numbers. Check uefi.org for the latest published revision.
What is the DSDT in ACPI?
The Differentiated System Description Table is the main table of AML bytecode. It defines the platform's devices, their resources and the control methods the OS calls to configure and power them. SSDTs add more AML on top of it.
Can I fix a buggy ACPI table without a BIOS update?
On Linux, for testing, yes. The kernel can upgrade tables from the initrd when built with ACPI_TABLE_UPGRADE, replacing a table that has a higher OEM revision. It is disabled under kernel lockdown, and the right long term fix is a firmware update from the vendor.
Is AML dangerous?
AML is firmware code run by the kernel's interpreter with access to memory, I/O and configuration space. It is no more dangerous than the rest of the firmware you already trust, but it means firmware bugs and firmware tampering affect the running OS, not just boot.
What does Arm SystemReady certify?
Arm's program checks that hardware and firmware follow its standards so a generic OS can install and boot. The SystemReady band covers ACPI based systems that run unmodified generic operating systems, and the SystemReady Devicetree band covers embedded systems that use devicetree with Linux distributions and BSD.
How do I see which hardware description my Linux system used?
If /sys/firmware/acpi/tables exists and is populated, the kernel found ACPI tables. If /proc/device-tree exists with a meaningful compatible property, the kernel booted with a devicetree. On arm64 the kernel uses only one of them for device enumeration per boot.
Where Safeguard fits
Safeguard does not read, scan or validate ACPI tables, devicetree blobs or firmware images, and it does not do firmware analysis or device management. Its fit here is indirect. The software around hardware descriptions is ordinary open source: the devicetree compiler and libfdt, ACPICA and its tools, U-Boot, the board support repositories that hold .dts sources and overlay build scripts, and the container images used to build bootloaders and kernels. Those repositories and images have dependencies with known vulnerabilities like any other code, and Safeguard can scan them with safeguard scan --dir ., --image for a container image, or --sbom for an SBOM you already have, writing results as JSON under ./output.
Fix it without waiting for upstream
A rebuilt board or reinstalled server pulls its bootloader, kernel build tools and user space dependencies again, and the toolchains that compile devicetrees and ACPI tables ship open source components with their own advisories. The section below applies to that software, not to the firmware tables themselves.
Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.
1. Autonomous remediation: pull requests, not tickets
When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.
2. Gold Open Source: the safe version in seconds, free
gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.
3. Gold Registry: start from components that are already fixed
registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.
When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.
| Your situation | What to use |
|---|---|
| A fixed version exists | Autonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version |
| You need to know today whether you are affected | Gold Open Source lookup and "Am I affected?" checker, free and without login |
| You want vulnerable versions to stop shipping | The Gold scan GitHub Action in CI, plus Safeguard policies and gates |
| Upstream has no fix yet, or will not ship one | A custom Gold request; fork and patch (early access) |
| You want to start clean on new projects | Pull hardened components and images from Gold Registry |
One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.
See how Safeguard would help
The demos below show Safeguard on ordinary software projects, not on firmware or hardware descriptions. They apply to the repositories around a board or server platform: the board support package, the bootloader build container and the scripts that build and sign images.
The first demo is a real Safeguard CLI session. After install, safeguard opens the interactive terminal, you ask it to fix the lodash CVE in a repository, and it reads the finding and advisory, asks before each command, edits package.json to lodash 4.17.21, runs npm install and npm test with your approval, prints a summary and pushes nothing. It ends with /permissions, /model and /scan. The same ask, approve and test loop suits a board support repository where every change to the build should be reviewed before it runs.
Click through it at your own pace, or open it full screen.
Firmware and image build hosts are often kept off the general network. The local runner demo shows how to set up the runner on your own machine, approve it with its device code, and then scan from the terminal. A runner on a build host can scan the source trees and containers stored there.
Click through it at your own pace, or open it full screen.
If your team uses Claude, the third demo shows how to connect Claude to the Safeguard MCP server with OAuth and choose which tools Claude can use. An engineer can then ask about known vulnerabilities in the projects that hold your bootloader and image build tooling, using only the tools you allowed.
Click through it at your own pace, or open it full screen.
To try it on your own repositories, download Safeguard and follow the CLI documentation.
Quick check
An arm64 server boots with both a devicetree and ACPI tables and no special command line. Which does Linux use?
According to the kernel's arm64 ACPI documentation, with no parameters the kernel tries devicetree first and uses ACPI only if no devicetree is present. With acpi=force it tries ACPI first. EBBR firmware avoids the question by never providing both at once.
Why does a Linux system with kernel lockdown refuse an ACPI table override from the initrd?
Lockdown exists to stop even root from changing the running kernel's behaviour. The kernel lockdown manual page lists overriding ACPI tables, ACPI custom methods, ACPI error injection and specifying the RSDP address among the facilities it disables, because each would let user controlled data change what firmware tells the kernel.
Sources
- Devicetree Specification releases, devicetree.org
- Devicetree Specification release history, GitHub
- Linux and the Devicetree (usage model), Linux kernel documentation
- Devicetree Overlay Notes, Linux kernel documentation
- Writing Devicetree Bindings in json-schema, Linux kernel documentation
- Booting AArch64 Linux, Linux kernel documentation
- ACPI on Arm systems, Linux kernel documentation
- ACPI Tables usage on arm64, Linux kernel documentation
- ACPI Support (firmware guide index), Linux kernel documentation
- ACPI Device Tree: Representation of ACPI Namespace, Linux kernel documentation
- ACPI Based Device Enumeration, Linux kernel documentation
- _DSD Device Properties Usage Rules, Linux kernel documentation
- Upgrading ACPI tables via initrd, Linux kernel documentation
- SSDT Overlays, Linux kernel documentation
- kernel_lockdown(7), Linux manual page
- U-Boot devicetree control, U-Boot documentation
- U-Boot devicetree documentation index
- U-Boot Measured Boot, U-Boot documentation
- Embedded Base Boot Requirements (EBBR) specification
- Arm SystemReady certification program, Arm
- ACPICA project repository
- ACPICA releases and release notes
- Device Tree Compiler manual, dtc project
- sysfs-firmware-ofw ABI description, Linux kernel tree
- TPM Event Log, Linux kernel documentation
- tpm2_eventlog manual, tpm2-tools
- U-Boot FIT Signature Verification, U-Boot documentation
- acpica-tools package, Debian
- device-tree-compiler package, Debian
- Windows Platform Binary Table (WPBT) paper, Microsoft
Last reviewed: 24 October 2026. Specification versions, kernel behaviour and firmware support change between releases; check the linked documentation for the versions you run.