真机实测笔记:Mac mini M4(macOS 26.2)

June 5, 2026 · View on GitHub

2026-06-05,M3 里程碑真机验证过程中的发现。这些数据修正/补充了 research-macos-smc-fan.md 的调研结论(其实测仅覆盖 MacBook 形态),属于目前没有公开文献记录的代际组合。

1. 风扇控制路径:直写可行,无 Ftst

实测值
机型Mac mini M4(单风扇,min 1000 / max 4900 RPM)
模式 keyF0Md(大写),ui8,attr 0xd0(读+写)
目标 keyF0Tg,flt,attr 0xd4(读+写)
Ftst不存在(读返回 0x84 SmcNotFound)
FS! (Intel 强制手动)不存在
解锁方式直写 F0Md=1 即可,与 M1/M5 同路径

修正调研结论:「M4 需要 Ftst 解锁」仅适用于 M4 Max MacBook(agoodkind 实测机型)。Ftst 的存在性按机型形态分布,不按芯片代际——桌面 M4 无 thermalmonitord 式锁定,直写即通。运行时探测策略再次被验证为正确设计。

mini 特有的风扇 key(用途未知,待研究):FEna(hex_ 只读)、FOff(ui8,attr 0x81=读+私有写)、FBAD(attr 0xd0 可写)、F0Dc(flt,attr 0x95)、F0CRF0S0-S7F0StF0TEFrqdFpds

2. ⚠️ SMC 写入异步生效(最重要的工程发现)

写入成功后立即回读返回旧值,新值要数百毫秒后才可见:

写 F0Tg=2500 → 立即读 = 1000.0(旧值)→ 1s 后读 = 2500.0
写 F0Md=0   → 立即读 = 01(旧值)  → 1s 后读 = 00

后果:M2 设计的「写后立即回读校验」在这种固件上必然误报失败,且错误报告会掩盖「写实际已生效」的事实(曾导致 F0Md 被置 1 而上层以为失败,留下无主手动态)。

修复SMCWriteRetryPolicy 增加沉降窗口——校验阶段最多重读 6 次、间隔 200ms(共 ~1.2s),仍不匹配才计为一次失败尝试进入重写。回归测试 testVerificationToleratesAsynchronousApply

尚不确定异步生效是 M4 mini 固件特性还是更广泛行为(M2/M3 验证时这台机器没电池,充电 key 写入未实测)。设计上按「所有 SMC 写都可能异步」处理。

3. 多写者冲突:与 Macs Fan Control 实测

  • MFC 运行时持有风扇手动态(mode=1 @ 其设定转速),并持续重断言——我们的恢复 auto 写入被立刻顶回(回读校验如实报告 expected 00, read back 01
  • 启动对账检测到了异界残留并尝试恢复,但被 MFC 顶回(此场景的失败现已记入 error 日志)
  • 结论:外部风扇工具与 smctl 互斥使用;后续可考虑探测已知风扇工具进程并在 CLI 报错里提示。daemon 内部多客户端仲裁(FanArbitrator 思路)不解决跨进程冲突

4. 温度护栏标定(实战触发数据)

  • 编译负载下结温热点传感器(Tp0E/Tp3P 类)常态 95–103℃,M1 里程碑时 Tp3P 曾读到 103.5℃;Apple Silicon 结温规格 ~110℃
  • 初版 ceiling 95℃ + 瞬时触发:fan set 2500 后 368ms 即被打回(temperature 101.67C reached ceiling 95C)——护栏链路完整实战验证 ✅,但标定过严,负载下功能不可用
  • 调整为:默认 100℃(硬上限 105 不变)+ 连续 2 tick 持续超限才触发(去抖尖峰,反应 <2.5s);传感器失明仍立即触发不去抖
  • 锁存(latch)实战验证 ✅:触发后 fan set 被拒绝,错误信息引导等待降温(释放阈值 = ceiling − 5℃)

5. 验证完成清单(M3 真机)

  • 直写解锁(direct 路径)+ 实际转速跟随(2500 RPM 爬升曲线)
  • 恢复 auto + 转速回落
  • 温度护栏实战触发 + 锁存拒绝 + 日志可见
  • 死手钩子(kickstart SIGTERM 时日志确认风扇+充电恢复)
  • 启动对账检测异界残留(MFC 场景)
  • Ftst 回退路径(需 M4 Max/M2-M3 MacBook 实测,本机不适用)
  • 曲线 profile(quiet/custom)长时运行稳定性