Asahi Linux 7.2 进度报告技术解读:M3 收官、M4 复活与 PSCI 新通道

Asahi Linux Progress Report: Linux 7.2 技术解读

Linux 7.2 发布当天,Asahi Linux 项目照例发出了新的进度报告。这份报告里最实质的三件事:M3 系列 bring-up 接近完工,官方明确「almost ready to cut an official release」;M4 与早期 M5 完成初步点亮,NVMe 和 PCIe 已经工作;视频管线上,硬件解码进入桌面集成阶段,AGX 渲染帧向显示控制器 DCP 的直接扫描输出(direct scanout)已经打通开发版链路,等待 Kwin 放行。本文基于官方报告原文,逐项拆解这些变化背后的技术机制。

Asahi Linux 对各代 Apple Silicon 芯片的支持状态

为什么值得读

Asahi Linux 的目标是在 Apple Silicon Mac 上本地运行标准 Linux。这件事的特殊性在于:Apple 不公开芯片文档,项目组只能靠逆向工程弄清每个硬件块的行为,再把结论以补丁形式贡献回上游内核。每份进度报告因此有两个身份,既是移植工作的进展表,也是对 Apple 平台安全架构和功耗设计的逆向解剖。对做嵌入式、系统级开发的人而言,这是少数能持续读到现代 SoC 安全机制一手分析的公开材料。

不要 Thinking Different:cpuidle 与 PSCI 难题

Apple Silicon 的电源管理职责分散在多个硬件块之间:SMC 负责系统管理,PMGR 管电源门控,PMP 也参与其中。其中最影响续航的部分是应用核心自身的休眠方式。

ARM 核心最基本的休眠手段是执行 WFI(Wait For Interrupt)指令:核心停止执行代码,保留全部状态,等待中断唤醒,因此适合在运行中的系统里临时停放某个核。Apple 核心另外提供一个深度 WFI 模式,关掉更多供电单元,代价是丢失核心状态。Asahi 目前的下游 cpuidle 驱动的做法是:先把核心状态保存下来,再让核心进入这种深度 WFI 循环。

问题出在上游化。为了避免每个厂商往内核里塞私有电源管理代码,arm64 维护者规定上游硬件必须使用 PSCI(Power State Coordination Interface),由固件提供一套标准的 CPU 电源管理调用接口。PSCI 调用通过 SMC 或 HVC 指令发起,把执行流交给更高异常级别的固件;内核预期自己跑在 EL2,调用后应由 EL3 的固件接手。而 Apple 的核心根本不实现 EL3,m1n1 引导器加载内核时它已经在 EL2 上运行,没有人可以接电话。电池寿命至关重要,现状又不可能长期维持。一个快速的解法是让 m1n1 把内核加载到 EL1,自己在 EL2 里扮演 PSCI 固件,但这会破坏虚拟化等架构特性。

报告给出的思路是把规格书读得宽一点。PSCI 标准本身只定义 API,并未绑定具体传递通道,SMC 和 HVC 只是示例;而 m1n1 在生产系统的启动链中位于 mBoot 之后,它加载 U-Boot 以提供 UEFI 环境,UEFI 有一套类似早年 BIOS 中断的 Runtime Services 机制,允许操作系统调用来自固件的代码。Sven 据此实现了基于 UEFI Runtime Services 的 PSCI conduit:让 m1n1 保留自己的内存区域(此前它的内存可以被载荷直接回收覆写)、在其中留下一份 PSCI 实现,内核即使与固件处在同一异常级别,也能经由这条通道完成电源管理调用。m1n1 侧改造已经完成,内核侧补丁已发到邮件列表(RFC 状态)。

M4 的 WFI 崩溃与被锁死的 chicken bits

ARM 规范要求处于 WFI 的核心必须保留全部状态,这不是 Apple Silicon 的默认行为。从 M1 到 M3,每颗核心的状态保持可以用一组 chicken bits(工程师行话,指用来开关某个行为的杂项寄存器位)逐核配置。Apple 近年开始把这些位的设置挪进 mBoot,并在 M4 及之后的芯片上锁定相关寄存器。这对 m1n1 是减负,对调优则是收权,尤其麻烦的是:在 M4 上直接执行 WFI 会导致核心丢失状态、当场崩溃。

Yureka 在做 M4 bring-up 时发现了这个问题,并加入了一个内核命令行参数,让 idle loop 的停放行为可配置,包括退化为普通空转循环。这保证 M4 机器在 cpuidle 驱动加载之前的早期内核初始化阶段不会崩溃;驱动接管后,再走保存状态加深度 WFI 的老路。相关补丁已进入 linux-next。

请来 SPTM:hypervisor 在 M4 复活

报告中最能当作安全架构教材的一节。传统上由内核直接负责页表管理,这类代码一旦出现漏洞,攻击者就拿到整个地址空间。Apple 多年前为 XNU 内核引入 Page Protection Layer(PPL),用硬件特性把页表管理与内核其他部分隔离;后来攻击者仍找到了攻入 PPL 的办法。借鉴 IOMFB(显示驱动)被塞进 DCP 协处理器固件并用 IOMMU 隔离的经验,PPL 最终演化成 SPTM(Secure Page Table Monitor):一个独立 Mach-O 二进制,启动时由 iBoot/mBoot 加载进 GXF(Guarded Execution Framework)的 GL2 特权级,配合自定义页表权限体系 SPRR,锁死内存管理控制权;XNU 通过 IPC 与之协作,连不上就在初始化极早期 panic 停机。

这套设计对逆向工程是硬墙:M4 及以上机型上 XNU 强制依赖 SPTM,m1n1 hypervisor 曾因此在 M4 上完全失效——在 hypervisor 下跑 XNU 会因为没有 SPTM 而崩溃,让 mBoot 把 m1n1 当作 XNU 启动则会让 m1n1 自己因拿不到内存管理权而崩溃。

突破口依然是多年前打下的:Sven 早前完成了 SPRR 和 GXF 的逆向(文档公开在项目文档站)。现在 m1n1 hypervisor 学会了模拟这两套机制,可以把 Apple 的 SPTM 二进制按 XNU 预期的方式加载、对 XNU 镜像做一些修改后载入,然后像 M1 到 M3 时代一样监视两者的 MMIO 访问。代价是追踪速度变慢,但没有到不可用的程度。macOS 内部机制的模拟器跑在开源 hypervisor 里,这也是观察 M4 之后平台安全设计最直接的窗口。

M3 系列:bring-up 收官清单

M3 机型的兼容性拼图在本周期基本补完:

  • 摄像头:M3 Max 的图像信号处理器相比其他机型少了一条初始化消息,chaos_princess 为 Linux 驱动补上这个分支之后,所有带内置摄像头的 M3 设备都有了完整支持。
  • 麦克风:M3 新增高频 decimator,需要新的系数集合和一条大得多的初始化消息,同样已解决。
  • USB/雷雳:Type-C 口负责协商 USB3、DisplayPort 和雷雳连接的物理层模块叫 ATCPHY,因制程转向台积电 N3 需要新的初始化参数序列。更大的变化是 USB 端口控制器换代:M1 到入门款 M3 用的是挂在 I2C 总线上的 TI 方案 CD3217(即 ACE2),M3 Pro/Max 起换成 ACE3 并改挂 SPMI 总线。mildsunrise 与 chaos_princess 逆向后发现 ACE3 寄存器集与 CD3217 基本相同,只是外面裹了一层 SPMI 接口。SPMI 与 ACE3 现都在 Asahi Linux 上工作,全部 M3 机型具备 USB 3.0 与雷雳能力。
  • GPU 与显示:AGX 与 DCP 的固件 ABI 与特定 macOS 版本绑定,Apple 不保证跨版本稳定,因此每个硬件世代锚定一个 macOS 版本。M3 系列锚定 macOS 14.8.3 的 ABI,DCP 支持已接近 M1/M2 所用 macOS 13.5 ABI 的功能对等。

综合以上,官方宣布距离正式版发布已经很近,「coming weeks」内有后续消息。

M4 与早期 M5:初步点亮

除了上文 M4 的 WFI 问题,Yureka 与 Sven 还一起查明 macOS 15.x 固件包里 NVMe 控制器固件的破坏性变更,并在 m1n1 和 Linux 两端同时实现适配,M4 与 M5 的 NVMe 已经工作。Yureka 另外让 PCIe 达到了总线设备可枚举的状态,并修复了一个启用多个 CPU 核心后不久导致系统崩溃的问题。功能清单还很短,离进入 Asahi Installer 有距离,但两个最新世代都已有可见进展。

视频解码成熟与桌面集成的难题

上次报告宣布的 Apple Video Decoder(AVD)本周期继续打磨:sofus 的工作让 H.264、H.265、VP9 解码在所有 Asahi 支持的机型上基本可靠,M3 及以上再加 AV1。

真正的难点在集成方式。AVD 是彻底的无状态解码器:输入一个编码帧,输出一块视频缓冲,不做码流解析、不做会话管理。这与内核里的 V4L2 Stateless API 设计完全对口,但该 API 上游存在十余年,桌面软件生态始终没有跟进:GStreamer 只有基础支持,FFmpeg 不打补丁就不支持,浏览器长期押注 VA-API/NVDEC/VDPAU,新方向又是 Vulkan Video,V4L2 Stateless 处于尴尬位置。

Bootlin 曾写过一层 VA-API 到 V4L2 Stateless 的翻译层,让通用桌面软件能用上无状态硬件,可惜早已无人维护、不打补丁编译不过。sofus fork 了它并为 AVD 调通:装上翻译层、给登录会话设一个环境变量,任何实现 VA-API 的软件都能借助 AVD 硬解视频。目前它还没有随 Fedora Asahi Remix 默认安装,也不兼容 Firefox 的视频解码沙箱,可用的发行版本仍在路上。

直通扫描:省电的最后一段拷贝

传统上硬件解码的意义是降低 CPU 占用,但播放视频时的浪费不止于此:CPU 要把解码后的帧搬进 GPU 显存,GPU 合成画面后再复制一份给显示控制器内存,再让控制器扫描输出,全程按视频帧率反复进行。理想情况是一条零拷贝链路:如果解码器、合成器和显示控制器共享同一块帧缓冲,画面不动时 GPU 可以整个关掉,合成器只需要让显示控制器按解码器的产出刷新屏幕,全屏应用时合成器甚至可以直接把应用自己的帧缓冲地址递给显示控制器,自己的渲染活动全部停掉。macOS 的 Quartz 就是这样工作的。

实现前提是链路上所有硬件块使用同一种帧缓冲格式(像素排布、寻址、压缩三者都要一致)。报告算过账:一张 1920x1080 的原始 8 位 ARGB 帧缓冲超过 66 MiB,4K 下接近 214 MiB,不加压缩地在 60 甚至 240fps 下反复读写,内存总线的带宽与功耗都不可承受。视频数据惯例上半平面 Y'CbCr 存储,图形硬件普遍用瓦片化寻址,各家厂商的显示家族内部正是靠统一寻址与压缩格式才得以互相直通。Apple 的答案是两套格式:AGX 格式仅在 GPU 内部使用,Interchange 格式则被 GPU、DCP 显示控制器和 AVD 解码器共同支持。

Asahi 侧的现状:AGX 驱动早有 Interchange 的基础支持,只是没有接线。Oliver Bestmann 与报告作者把它接进了 DCP 内核驱动以及 Asahi、Honeykrisp 两个 Mesa 驱动,叠加此前的 Y'CbCr 与 overlay plane 支持,AGX 渲染帧向 DCP 的直通扫描输出已经打通;AVD 输出 Interchange 缓冲的支持在跟进中。软件侧还差最后一环:Kwin(KDE Plasma 的合成器)把 AGX 和 DCP 当作两块独立 GPU(multi-GPU),经由 DMA-BUF 的直通扫描因此被整体禁用;Kwin 开发者正在改进,Plasma 6.8 有望放开。

上游化的长尾

常规上游工作没有停:让扬声器保护组件 speakersafetyd 得以运转的若干 I2S 外设改动、启用 SMC 硬件监控驱动的 Devicetree 补丁,以及 macOS 27 带来的 SMC 固件接口变更的全部修复,均已合入上游。报告中引用的多数速度数字未变的直观印象,作者的解释是大部分东西早已上游完毕,剩下的要么是无法上游的庞大工程(GPU、DCP),要么正因为清完了历史欠账才有余力开工的新特性。

结语

从 M1 到 M5,五代的 bring-up 同时在线,M3 即将收获第一个官方安装镜像世代的收尾,M4 的核心障碍 SPTM 已经绕开。对所有关心「一台消费级设备如何被逐个硬件块地逆向」的人来说,这份项目记录的下一次更新值得排在日历上。

来源: