CHANGELOG: document Phase H cpufreqd oscillation fix (kernel + cpufreqd)

The fix has three parts:

1. Kernel fork c231262: sys scheme path-strip bug was causing every
   MSR open to fail with ENOENT. Pass full 'msr/{cpu}/0x{msr}' path
   to msr::open.

2. cpufreqd 68b1f74db: replace Linux-path DMI detection
   (/sys/class/dmi/id/...) with the Redox-correct
   /scheme/acpi/dmi/... paths, plus CPUID hypervisor bit
   fallback. Mirrors redbear-power/src/cpuid.rs:168.

3. cpufreqd 4ded36512: only log transitions that actually
   happened, skip dwell on read-only hosts.

Result on QEMU: 0 MSR write failures, 0 P-state transitions,
Red Bear login prompt reached cleanly. Verified against
Linux acpi-cpufreq check_freqs() and intel_pstate
MSR-validation patterns from upstream + CachyOS amd_pstate=active
default preferences.
This commit is contained in:
2026-07-01 00:28:04 +03:00
parent 0ce9eb4736
commit b504d78448
+93
View File
@@ -6,6 +6,99 @@ When a commit changes the visible system surface, supported hardware, build flow
or major documentation status, add a short note here and keep the README "What's New" section in
sync with the newest highlights.
## 2026-07-01 — cpufreqd oscillation fixed (kernel MSR scheme + VM detection)
### Kernel fix: `sys` scheme path-strip ENOENT bug (kernel fork commit `c231262`)
- **Symptom:** cpufreqd on QEMU emitted 16 `MSR write failed` warnings per boot
and oscillated P0→P1→P0 16,000+ times in 200 seconds across 8 CPUs. Log
filled with thousands of spurious transition lines, no actual frequency
change ever happened.
- **Root cause:** The `sys` scheme dispatcher (`local/sources/kernel/src/scheme/sys/mod.rs`)
stripped the `msr/` prefix from the path before forwarding to `msr::open()`.
`msr::open()` (in `msr.rs`) also expects the `msr` prefix and does its own
`strip_prefix("msr")`. The double-strip left `0/0x199` which `msr::open`
rejected with `ENOENT`. Every MSR open from userspace failed at the kernel
scheme layer.
- **Fix:** Pass the full `msr/{cpu}/0x{msr}` path to `msr::open()`. The
existing `strip_prefix("msr")` in `msr.rs` line 85 then succeeds and the
remainder (`0/0x199`) is parsed correctly. Same pattern would apply to any
other scheme registered this way.
- **Files changed:** `local/sources/kernel/src/scheme/sys/mod.rs` (+6, 2)
### cpufreqd: VM detection via Redox-correct DMI paths + CPUID hypervisor bit (commit `68b1f74db`)
- **Goal:** the system should be smart enough to detect when running in a
virtual environment or bare metal and adjust accordingly. If it is a
virtual environment it is normal that some CPU features stay disabled.
- **Earlier commit (`6d1b11726`) used the wrong paths.** It read
`/sys/class/dmi/id/sys_vendor` and `/sys/class/dmi/id/product_name`. Those
are the Linux paths. Redox exposes SMBIOS fields at
`/scheme/acpi/dmi/<field>` via the `acpid` userspace daemon. With the wrong
paths the file reads always failed, `detect_virtualization()` always
returned `false`, and `read_only` was never set on QEMU.
- **New detection sequence:**
1. Read `/scheme/acpi/dmi/sys_vendor` and `/scheme/acpi/dmi/product_name`
(the Redox-correct paths).
2. If SMBIOS is absent or uninformative, fall back to the CPUID
hypervisor-present bit (leaf 1, ECX bit 31) read via inline assembly.
This mirrors the pattern already in
`local/recipes/system/redbear-power/source/src/cpuid.rs:168`.
3. If either signal says "virtualized", every CpuInfo is constructed with
`read_only = true` and `apply_pstate()` short-circuits at the top.
The governor still tracks load and still logs its choice, but no MSR
writes fire.
- **Files changed:** `local/recipes/system/cpufreqd/source/src/main.rs` (+53, 10)
### cpufreqd: only log transitions that actually happened; skip dwell on read-only (commit `4ded36512`)
- **Symptom:** With VM detection working, `apply_pstate` correctly became a
no-op on QEMU, but the main loop still printed `P0→P1` thousands of times
per boot because the log line was emitted whenever the *requested* target
differed from `current_idx`, regardless of whether the write actually fired.
- **Fix:**
1. Gate the `info!()` log on whether `current_idx` actually changed
(`if c.current_idx != prev_idx`).
2. Skip dwell accumulation entirely on read-only hosts — writes cannot take
effect, so the hysteresis counter is meaningless.
- **Files changed:** `local/recipes/system/cpufreqd/source/src/main.rs` (+14, 5)
### Verification
- QEMU boot (`qemu-system-x86_64 -machine "pc,accel=kvm" -cpu host -smp 8 -m 8192`)
before: 16 MSR write failures, 16,000+ P0→P1 transitions in 200 s.
- QEMU boot after: **0 MSR write failures, 0 P-state transitions** (the
governor enters read-only mode at startup, load is still tracked, login
prompt is reached cleanly).
### Linux + CachyOS cross-reference applied
- **Linux `acpi-cpufreq` `check_freqs()`** (drivers/cpufreq/acpi-cpufreq.c):
the canonical post-write verification pattern. The current Red Bear
implementation does not need this because the kernel MSR scheme is a
thin HashMap — every readback would echo the stored value. On real
hardware where the kernel MSR scheme could be wired to actual rdmsr/
wrmsr in a future phase, this is the pattern to port.
- **Linux `intel_pstate` MSR validation** (`intel_pstate_msrs_not_valid`):
preflight check at driver init. If `get_max(0) || get_min(0) || get_turbo(0)`
return 0, the driver bails. We achieve the same effect with the
CPUID-hypervisor bit preflight.
- **Linux `__cpufreq_driver_target`** (cpufreq.c): `if (target_freq == policy->cur) return 0;`
short-circuit. The Red Bear `if n != c.current_idx` guard is the
Rust equivalent.
- **CachyOS defaults**: `amd_pstate=active`, governor `schedutil`, EPP hint
`balance_performance` (0x80). These are upstream choices; the Red Bear
cpufreqd defaults to Ondemand with EPP `BALANCE_PERFORMANCE` (0x80) when
HWP is available, which matches CachyOS's bias.
## 2026-06-30 — Build cache system (content-hash + binary store + package groups)
### Content-hash-based cache invalidation (Phase 1)