Skip to content

Add LpcThinkpadEC: ThinkPad 0x1600 EC window - #105

Open
mews-se wants to merge 2 commits into
namazso:mainfrom
mews-se:lpc-thinkpad-ec
Open

Add LpcThinkpadEC: ThinkPad 0x1600 EC window#105
mews-se wants to merge 2 commits into
namazso:mainfrom
mews-se:lpc-thinkpad-ec

Conversation

@mews-se

@mews-se mews-se commented Aug 26, 2026

Copy link
Copy Markdown

Adds the module #61 asks for: same shape as LpcACPIEC, but for the second EC interface ThinkPads decode at 0x1600 — the ACPI EC command set on 0x1600/0x1604 plus the row transfer region at 0x1610..0x161F, the window tp_smapi's thinkpad_ec.c drives on Linux. Newer ThinkPads want this interface rather than 0x62/0x66.

#61 stalled on the hardware gate, since Pawn has no DMI access. This takes the DellSMM route instead and probes the hardware at load: an unimplemented LPC port reads 0xFF, and 0xFF is never a valid EC status (every bit set, including both reserved ones), so main() refuses to load unless 0x1604 answers with a live status byte.

Reference points: TPFanCtrl2's portio.cpp and tp_smapi's thinkpad_ec.c. Verified on a ThinkPad X13 Gen 3, where this window and protocol drive the fan today and the status port reads 0x00/0x20/0x50 at 0x1604, never 0xFF. The signed-module requirement means the blob from this branch has not itself been loaded on hardware.

@namazso namazso left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do have DMI checks now, please see ValveLeds.p

@namazso
namazso marked this pull request as draft August 30, 2026 00:32
@namazso

namazso commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Also, I changed this to draft, please test it on the unrestricted driver (you'll have to use 2.1.0 or your own builds because 2.2.0 accidentally shipped with signature verification enabled on the unrestricted driver as well) before marking it as ready.

ThinkPads decode a second interface to the embedded controller as a 32
byte window at 0x1600: the ACPI EC command set on 0x1600/0x1604 and the
row transfer region at 0x1610..0x161F. Newer models want this interface
rather than 0x62/0x66. Same shape as LpcACPIEC, with a load time gate
that refuses machines where the window reads as a floating bus.

Closes namazso#61
@mews-se

mews-se commented Aug 30, 2026

Copy link
Copy Markdown
Author

Reworked the DMI gate to match LedsValve.p — reg_query_sz against \Registry\Machine\HARDWARE\DESCRIPTION\System\BIOS, requiring SystemManufacturer == LENOVO and SystemFamily or SystemVersion starting with "ThinkPad", with the 0xFF probe on 0x1604 kept as a sanity check after the gate. Verified the values against the real registry on the X13 (LENOVO / "ThinkPad X13 Gen 3") and it compiles clean with the CI pawncc (4.1.7152, same flags as ci.yml).

I couldn't finish the unrestricted-driver test on my machine though. The 2.1.0 unrestricted driver won't load here — sc start returns ERROR_DRIVER_BLOCKED (1275), and that persists with the vulnerable-driver blocklist disabled, testsigning on and Memory Integrity off. Looks like a VBS code-integrity policy is still active and rejects it because it's signed with your own cert rather than an MS-cross-signed one, and I'd rather not disable VBS on my daily machine to get around it. On the restricted driver the module is rejected as unsigned, as expected. Could you verify the load on your end, or is the DMI rework enough to take it from there?

@namazso

namazso commented Aug 30, 2026

Copy link
Copy Markdown
Owner

VBS shouldn't interfere, test signing means that things just need to be signed, but it doesn't care by whom. You could try using the old 2.0.1 version instead... I plan to try fixing this in 2.3.0, but it's a bit more complicated with DriverStore's involvement since all versions since 2.1.0 live side-by-side and are chosen by Windows.

@mews-se

mews-se commented Aug 30, 2026

Copy link
Copy Markdown
Author

Tried 2.0.1 as you suggested, on a clean Windows 11 24H2 VM (QEMU) so I could keep it off my daily machine — same result, ERROR_DRIVER_BLOCKED (1275).

I loaded the driver directly with sc create pointing at the raw .sys, which bypasses DriverStore entirely, so the side-by-side situation isn't in play here. Environment was testsigning on, Secure Boot off, HVCI off, and VulnerableDriverBlocklistEnable=0. Both the 2.1.0 unrestricted (your cert) and the 2.0.1 unrestricted (WDKTestCert) get 1275, while the normal WHQL-signed driver loads fine.

The VM has 8 active CI policies out of the box (CodeIntegrityPolicyEnforcementStatus=1), so it looks like 24H2 ships the driver blocklist as an always-on WDAC policy that the registry toggle doesn't turn off, and it catches the unrestricted build by hash regardless of testsigning — i.e. it may be more than the DriverStore side-by-side issue on 24H2. No CI operational event is logged for the block, just the 1275 from sc start.

I can test a specific build or config on that VM if it helps the 2.3.0 work.

@namazso

namazso commented Aug 30, 2026

Copy link
Copy Markdown
Owner

I'm not sure what you're doing wrong, here's it all working on 24H2. Fully updated, defender enabled:

vmconnect_LqYB29Not7.mp4

Are you sure you have "Test Mode" correctly displayed in the bottom right of your desktop?

@mews-se

mews-se commented Aug 30, 2026

Copy link
Copy Markdown
Author

Following your video it just worked — Test Mode was up, so that wasn't it; the earlier failures were on my end. Installed the unrestricted 2.0.1 through the installer ("Install unrestricted edition (FOR DEVELOPERS)") and the module loads and runs.

Verified on the X13 (23H2), unsigned module built from this branch:

  • loads on the unrestricted driver, main()STATUS_SUCCESS (DMI gate passes: LENOVO / ThinkPad X13 Gen 3)
  • live EC reads — 0x16040x00, 0x16000x05
  • a read outside the allowlist (0x0062) → STATUS_ACCESS_DENIED

DMI gate is the LedsValve-style reg_query_sz rework, now hardware-verified. Marking it ready.

@mews-se
mews-se marked this pull request as ready for review August 30, 2026 17:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants