Repository navigation
meridian: brightness and battery, found by reading the firmware - #2
Merged
Merged
Conversation
Two hardware features that had never worked, plus the tooling that
finally made them findable on a machine with no serial console.
BRIGHTNESS — the PWM registers were being read with the wrong layout.
backlight.rs modelled 0xC8254 the pre-Gen9 way (period in bits 31:16,
duty in 15:0). SKL/KBL use three separate 32-bit registers: CTL 0xC8250,
FREQ 0xC8254, DUTY 0xC8258. Fedora on this laptop reports
max_brightness=120000, which does not fit in 16 bits — so `max` read as
1 and every set wrote the duty into the frequency register. That single
wrong constant is why PWM looked dead, which is what sent this project
through the SMI mailbox and ACPI _BCM. Priority inverted: PWM first,
ACPI as fallback.
BATTERY — raw EC reads, bypassing ACPI entirely. _BIF/_BST need an
EmbeddedControl handler, and installing one walks the namespace, which
#GPs this kernel. The EC ports are reachable, so we read the same
registers the firmware's own AML reads. Ports 0x930/0x934 from the
evaluated _CRS; register map decoded from ECG6/ECG9 in the DSDT,
including the mandatory bank select at 0x03 without which the whole
window reads zeros. Verified against Fedora: last-full 2131 mAh, design
4474 mAh, 11400 mV, 47% health — exact matches. Live in the Entity's
Power row, refreshed by the thermal governor.
ACPI SAFETY — AML is never evaluated from a syscall now. SYSCALL runs at
IF=0 and AcpiEvaluateObject can block; doing it there wedged core 0 and
took scheduling down with it. Evaluation moved to the thermal governor
(IF=1); syscalls are pure cache reads; brightness writes are queued.
FIXES IN c_stubs.rs, all silent and all long-standing:
- ctype tables were all zeros, so isdigit/toupper were always wrong.
That broke vsnprintf's vararg handling AND every by-name namespace
lookup (AcpiNsInternalizeName uses toupper).
- AcpiOsPrintf/AcpiOsVprintf were empty stubs — every ACPICA
diagnostic ever produced was discarded.
- AcpiOsFree was a no-op; ACPICA leaked every allocation. Fixing it
naively exposed the global heap's O(n) free list and hung boot, so
ACPICA now has its own O(1) size-class pool.
- The OS layer (semaphores, locks, thread ids) was entirely no-ops.
DIAGNOSTICS, because the screen is the only channel:
- ACPICA's log is connected; `acpi log` shows the real table load.
- `acpi ls` walks the namespace one node per syscall — AcpiWalkNamespace
#GPs this kernel, and stepping is what localised that.
- WHY_KERNEL_GPF records the faulting IP in CMOS.
- Panic screen reads PLANE_CTL tiling and swizzles CPU writes; the
fault page was painting in stripes because the plane is tiled and the
desktop reaches it via the GPU BLT.
TERMINAL — scrollback (PageUp/Down, Home/End, scrollbar) and the
Meridian interior: JetBrains Mono 13px, the design's .term palette.
Step 11 of the build order.
Also: OSD text was being appended to an already-flushed label batch, so
the popup showed a moving bar with no words. Full ACPI dump (19 SSDTs)
added under nyx-recv/ssdt.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W8QnRasHQfWg2KrnSxigtX
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two hardware features that had never worked, plus the tooling that finally made them findable on a machine with no serial console.
BRIGHTNESS — the PWM registers were being read with the wrong layout. backlight.rs modelled 0xC8254 the pre-Gen9 way (period in bits 31:16, duty in 15:0). SKL/KBL use three separate 32-bit registers: CTL 0xC8250, FREQ 0xC8254, DUTY 0xC8258. Fedora on this laptop reports max_brightness=120000, which does not fit in 16 bits — so
maxread as 1 and every set wrote the duty into the frequency register. That single wrong constant is why PWM looked dead, which is what sent this project through the SMI mailbox and ACPI _BCM. Priority inverted: PWM first, ACPI as fallback.BATTERY — raw EC reads, bypassing ACPI entirely. _BIF/_BST need an EmbeddedControl handler, and installing one walks the namespace, which #GPs this kernel. The EC ports are reachable, so we read the same registers the firmware's own AML reads. Ports 0x930/0x934 from the evaluated _CRS; register map decoded from ECG6/ECG9 in the DSDT, including the mandatory bank select at 0x03 without which the whole window reads zeros. Verified against Fedora: last-full 2131 mAh, design 4474 mAh, 11400 mV, 47% health — exact matches. Live in the Entity's Power row, refreshed by the thermal governor.
ACPI SAFETY — AML is never evaluated from a syscall now. SYSCALL runs at IF=0 and AcpiEvaluateObject can block; doing it there wedged core 0 and took scheduling down with it. Evaluation moved to the thermal governor (IF=1); syscalls are pure cache reads; brightness writes are queued.
FIXES IN c_stubs.rs, all silent and all long-standing:
DIAGNOSTICS, because the screen is the only channel:
acpi logshows the real table load.acpi lswalks the namespace one node per syscall — AcpiWalkNamespace #GPs this kernel, and stepping is what localised that.TERMINAL — scrollback (PageUp/Down, Home/End, scrollbar) and the Meridian interior: JetBrains Mono 13px, the design's .term palette. Step 11 of the build order.
Also: OSD text was being appended to an already-flushed label batch, so the popup showed a moving bar with no words. Full ACPI dump (19 SSDTs) added under nyx-recv/ssdt.
Claude-Session: https://claude.ai/code/session_01W8QnRasHQfWg2KrnSxigtX