ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

M4 Mac mini 想跑 Linux,为什么卡在一条「让 CPU 睡觉」的指令上?

M4 Mac mini 想跑 Linux,为什么卡在一条「让 CPU 睡觉」的指令上? M4 Mac mini 想跑 Linux为什么卡在一条「让 CPU 睡觉」的指令上2024 年 11 月Yureka Lilian 买了一台 M4 Mac mini。理由很直接她赌这台机器和之前的 M1 到 M3 差不多能很快被 Asahi Linux 支持。结果这一赌赌出了近两年。前几天她把这趟折腾写成长文发在博客上原文Hacker News 讨论帖。看完你会发现最后真正卡住所有人的不是驱动、不是 GPU而是一条四字母的指令WFI。先搞明白为什么 M4 特别难过去 Asahi Linux 能一路推进靠的是一套取巧的办法用一个叫 m1n1 的 hypervisor 把 macOS「套」起来跑记录 macOS 驱动和硬件之间的每一次对话——也就是 MMIO 读写轨迹再逆推出硬件该怎么用Asahi Linux / m1n1 项目。M4 是 Apple Silicon 里第一代强制启用 SPTMSecure Page Table Monitor的芯片。这东西是苹果给 macOS 内核加防护用的副作用很直接macOS 没法再被 hypervisor 套着跑。那条最有用的信息通道当场断掉。一关一关地拆第一关是锁死的寄存器。m1n1 一开始只能在 BRINGUP 模式启动一初始化 GXFGuarded Exception Levels就崩。查下来GXF 在 M4 及之后 SoC 的裸启动模式下是被禁掉或锁住的——那就把它变成「能跳就跳」。第二关更有意思内核明明在跑串口却一个字都不吐。她只能退回最原始的手段——在内核极其靠前的位置插入一段汇编版debug_putc只打印一个字母a然后二分定位。a出来了说明代码真的在执行。一路二分到 MMU 初始化那段还在arch/arm64/kernel/head.S的汇编里。原因其实很朴素UART 是内存映射 I/O。MMU 一开所有访存都走虚拟地址而 m1n1 会为 MMIO 建 1:1 映射Linux 不会。于是 MMU 一开写串口就变成写一片没映射的地址日志自然全丢。补上这段 1:1 映射日志立刻回来了。再往后又撞在中断控制器初始化上一条对SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2的写入直接触发崩溃。这是和虚拟化相关的寄存器把它注释掉内核一口气启动到了 shell。真正的主角一颗会「忘事」的 CPU次核启动之后又是新的崩溃而这次的根子在硅本身。ARM 里有一条 WFIWait For Interrupt指令字面意思就是「让这个核睡一会儿等中断叫醒」。问题在于Apple Silicon 从 M1 起就有一个「鸡位」chicken bit——ARM64_REG_CYC_OVRD_ok2pwrdn_force_mask。这个位开着时WFI 会把 x0 到 x31 全部寄存器清零。macOS 内核对应付这招的方式是执行 WFI 前先把寄存器存进栈醒来再恢复。m1n1 在 M1-M3 上会把这个行为关掉让 CPU 像正常 arm64 处理器一样工作。到了 M4这个鸡位被锁死或者干脆被移除了。默认行为变成什么直接违反 ARM64 架构规范的原话「如果系统配置为 WFI 指令可以正常完成那 WFI 就不得造成架构状态的丢失。」2026 年 4 月她的解法非常「暴力」把内核里所有的 WFI 和 WFIT 指令全部替换成 NOP空操作。四个核心全部起来了。为什么这件事值得关注真正的难点不在绕过而在怎么体面地绕过。按理说这种硅的毛病该走内核的 errata 框架让内核在启动早期自己给自己打内存补丁。但这条路被否决了理由很硬核没法准确判断该不该 NOP 掉 WFI。因为虚拟机里的 WFI 是被 macOS hypervisor 截获、用来高效调度不同 guest 的——要是在这种环境下也去 NOP反而把调度玩坏。而检测「我现在是不是在虚拟机里」尤其嵌套虚拟化本身就很麻烦。最后是内核维护者 Will Deacon 给了另一条路由内核新增一个 bootarg允许在需要时关掉 WFI 空闲m1n1 则在裸机上检测到有问题的芯片时条件性地把这个参数加到启动参数里。好消息是这套机制已经合入 mainline Linux 和 m1n1相关 PR现在用最新版本就能让 M4 Mac 原生启动、多核可用——而且同样的 WFI workaround 在 M4 Pro、M4 Max 甚至 M5 上都被验证有效。值得琢磨的是两种修 bug 的姿势硬件厂商的 errata 往往能被内核自动识别、自动打补丁用户无感而这一次因为「无法可靠判断运行环境」只能退成一个人工控制的开关。同一个 bug落在不同的硅上修复的优雅程度完全不同。如果你是那台 M4 Mac mini 的主人想在本地同时跑 macOS 和几个 Linux 环境做验证这套上游方案现在终于能用了。顺带说一句如果测试时需要频繁在多个模型或 API 之间切换做对比像 likeai520.cc 这类中转服务可以省掉一部分逐家接入和验证的琐事把精力留给真正难啃的那部分。小结一台 M4 Mac mini从「赌它能被支持」到「全核原生启动」中间隔着 SPTM 的封锁、一条没映射的串口、一个锁死的寄存器位和一条只有四个字母的指令。开源社区最后给出的答案不是「等苹果开恩」而是把 workaround 做进上游让所有 M4 及之后的机器一起受益。参考来源The forgetful CPU (Linux on M4) — Yureka LilianHacker News 讨论Asahi Linux 项目主页m1n1: disable wfi/wfit if wfi loses state (PR #672)
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进