Reverse Engineering and Fixing a Lenovo ThinkPad Firmware Bug
How I reverse engineered and fixed a Lenovo ThinkPad firmware bug caused by a missing ACPI method using a custom SSDT loaded from the initrd.
- Linux
- Firmware
Sometimes the best bugs are the ones that shouldn’t exist.
After installing NixOS on my Lenovo ThinkPad T14 Gen 2 Intel, I noticed the kernel printed the same ACPI errors on every boot:
ACPI BIOS Error (bug): Could not resolve symbol [_SB.PC00.RP09.PEGP.DDNT], AE_NOT_FOUNDACPI Error: Aborting method _SB.PC00.LPCB.EC.SEN4._TMPLinux continued to work, but one thermal zone (SEN4) was disabled because its _TMP method aborted during execution.
This investigation was performed on a Lenovo ThinkPad T14 Gen 2 Intel running NixOS, with BIOS version N34ET71W (1.71).
Like many Linux users, my first assumption was simple:
“It’s probably just another harmless BIOS bug.”
It wasn’t.
The Investigation
Instead of ignoring the message, I wanted to understand why it happened.
The first step was dumping every ACPI table exposed by the firmware:
acpidump > acpidumpacpixtract -a acpidumpiasl -d *.datAfter disassembling every table into ASL, I searched through each generated DSDT and SSDT looking for the missing method.
Eventually I found the culprit.
Inside one of Lenovo’s DPTF SSDTs, the SEN4 thermal sensor implemented its _TMP method like this:
Method (_TMP){ ... _SB.PC00.RP09.PEGP.DDNT(Local0) ...}The problem was immediately obvious.
The firmware expected a method named DDNT, but it didn’t actually exist.
Searching every extracted ACPI table for DDNT returned only a single declaration:
External (_SB.PC00.RP09.PEGP.DDNT, MethodObj)There was no implementation anywhere.
The firmware referenced a method that Lenovo never shipped.
Understanding the Bug
At this point it became clear that Linux wasn’t doing anything wrong.
ACPICA was simply executing the AML exactly as the firmware instructed it to.
When _TMP attempted to execute DDNT, ACPICA couldn’t resolve the symbol and aborted the method with AE_NOT_FOUND.
As a consequence:
thermal_zone6(SEN4) was disabled.- No temperature could be read from that thermal zone.
- Every boot generated the same firmware errors.
This wasn’t a Linux bug.
It was a firmware bug.
The Fix
Fortunately, Linux provides an official mechanism for extending ACPI tables during early boot.
Additional SSDTs can be loaded directly from the initrd before ACPI initialization begins, allowing firmware defects to be corrected without modifying either the BIOS or the kernel.
Rather than modifying Lenovo’s original SSDT, I chose to create a supplemental SSDT that only implements the missing method.
DefinitionBlock ("", "SSDT", 2, "RXTS", "DDNTFIX", 0x00000001){ External (_SB.PC00.RP09.PEGP, DeviceObj)
Scope (_SB.PC00.RP09.PEGP) { Method (DDNT, 1, NotSerialized) { Return (Zero) } }}The goal wasn’t to reverse engineer Lenovo’s intended implementation.
The only objective was to provide the missing method so ACPICA could successfully evaluate _TMP without throwing AE_NOT_FOUND.
In this case, a minimal stub implementation was enough.
If Lenovo ever fixes the firmware in a future BIOS release, removing the override is all that’s required.
Packaging the SSDT
The SSDT was compiled using Intel’s ACPICA compiler:
iasl SSDT-DDNT.dslIt was then packaged into an uncompressed initrd archive:
kernel/└── firmware/ └── acpi/ └── SSDT-DDNT.amlFinally, I packaged everything as a reusable Nix package and integrated it into my NixOS configuration through boot.initrd.prepend.
The entire solution is declarative, reproducible, and survives system rebuilds just like the rest of my configuration.
Validation
After rebooting, the kernel reported:
ACPI: SSDT ACPI table found in initrdACPI: Table Upgrade: install [SSDT- RXTS DDNTFIX]The custom SSDT had been loaded successfully during early boot.
More importantly:
- The
AE_NOT_FOUNDerrors disappeared completely. SEN4was no longer disabled.thermal_zone6became available again.- The firmware bug no longer interrupted ACPI evaluation.
Evidence
After applying the SSDT override, the kernel log showed:
ACPI: SSDT ACPI table found in initrdACPI: Table Upgrade: install [SSDT- RXTS DDNTFIX]Before the override, every boot produced firmware errors and disabled the SEN4 thermal zone.
After the override:
- No
AE_NOT_FOUNDerrors were reported. thermal_zone6changed fromdisabledtoenabled.- The thermal zone successfully exposed a temperature through sysfs.
The solution worked exactly as intended.
Lessons Learned
The interesting part of this investigation wasn’t writing ten lines of ASL.
It was discovering that the firmware referenced a method that never existed.
Linux behaved exactly as specified.
ACPICA behaved exactly as specified.
The firmware was wrong.
This also reminded me that the Linux kernel already provides a supported mechanism for working around firmware defects. Most users never need it, but when you do, it’s an incredibly powerful feature.
Final Thoughts
This wasn’t about fixing Linux.
It was about understanding the firmware well enough to prove where the bug actually lived.
Reverse engineering the ACPI tables transformed what initially looked like an annoying boot warning into a reproducible firmware defect with a clean, declarative workaround.
If you encounter an ACPI error, don’t immediately assume Linux is at fault.
Sometimes the kernel logs are telling the truth.
You just have to follow them.