Over-ride ACPI table(s) such as DSDT at kernel boot
Fixing bugs in ACPI tables by loading a modified DSDT at boot-time. Debian and many other distro kernel configs enable CONFIG_ACPI_TABLE_UPGRADE=y
(see https://www.kernel.org/doc/html/latest/admin-guide/acpi/initrd_table_override.html )
In this example the device is a PC Engines APU2 (AMD GX-421TC SoC) with Coreboot firmware that includes in its ACPI DSDT a definition for the AMD Fusion Controller Hub (FCH) GPIOs and the attached LEDs and buttons where the ACPI GPIO device declares the "AMD0030" name. This causes the kernel pinctrl_amd
driver to claim the device instead of the platform device pcengines_apuv2
and gpio_amd_fch
, resulting in kernel error messages from the latter due to the MMIO resources it tries to reserve already reserved by pinctrl_amd
via ACPI.
The steps here remove the offending Devices from the Coreboot DSDT so pinctrl_amd
does not reserve the resources.
The same steps, with a different edit at line 6, apply generically to any ACPI host.
The generic kernel-documented method of including the modified ACPI table is shown in acpi_dsdt_initrd.sh
below.
NOTE: Debian functionality is currently (2024-10-17) broken and does NOT work as advertised. I've published a merge request to fix it but is unlikely to back-port to stable. My patch branch can be found at https://salsa.debian.org/Iam_Tj/initramfs-tools/-/tree/fix-ACPI-DSDT
Debian integrates adding a DSDT (but no other ACPI tables) into initramfs-tools
so only needs:
sudo cp ./dsdt.modified.aml /etc/initramfs-tools/DSDT.aml
sudo update-initramfs -u -v
Confirmation appears at the end of the verbose (-v
) report:
Adding DSDT /etc/initramfs-tools/DSDT.aml
If all goes well on reboot the kernel should report something similar to:
apu2 kernel: ACPI: Table Upgrade: override [DSDT-COREv4-COREBOOT]
apu2 kernel: ACPI: DSDT 0x00000000CFE9C280 Physical table override, new table: 0x00000000CFE87000
apu2 kernel: ACPI: DSDT 0x00000000CFE87000 00173B (v02 COREv4 COREBOOT 00010002 INTL 20200925)
...
apu2 kernel: ACPI: DSDT ACPI table found in initrd [kernel/firmware/acpi/dsdt.aml][0x173b]
And now the generic naming of the items ("apu" not "apu2") is in use so any scripts that manipulate them will need correcting:
$ ls /sys/class/leds/
apu:green:1 apu:green:2 apu:green:3 ath10k-phy0 mmc0::
# copy the loaded DSDT
sudo cat /sys/firmware/acpi/tables/DSDT | dd of=dsdt.dat
# decompile
iasl -d dsdt.dat
# remove the GPIO, LED, and Button devices (and increment revision)
gawk '/DefinitionBlock/ {revision=strtonum($7) + 1; $7=sprintf( "0x%08x)", revision)} S==1 {brace=gensub(/{/,"}",1); S=2} /Scope \(_SB\.PCI0\)/{S=1} /Scope \(PCI0\)/{S=1} S==0 {print} brace==$0 {S=0}' dsdt.dsl >dsdt.modified.asl
# review the change
diff -u dsdt.dsl dsdt.modified.asl | less
# compile
iasl -sa dsdt.modified.asl
## Only when **NOT** using ***patched*** Debian `initramfs-tools` integrated DSDT load support
# create the required initrd layout
mkdir --parents kernel/firmware/acpi
cp dsdt.modified.aml kernel/firmware/acpi/dsdt.aml
# create the ACPI over-ride initrd
find kernel -type d -o -type f -name '*.aml' | cpio -H newc --create > initrd.acpi.img
# capture name of **EXISTING** initrd.img (naming varies across distros - this is Debian 12 with a symbolic link to the default)
i=$(realpath -e /boot/initrd.img); echo $i
# **move** to a back-up
sudo mv "${i}" "${i}.bak"
# concatenate default onto ACPI over-ride and replace default initrd
sudo cat ./initrd.acpi.img "${i}.bak" | sudo dd of="${i}"