工程趣聞 2026 年 10 月 3 日

2026-10-03 — arm64 新增 idle=nop,處理 M4 上 WFI 遺失暫存器

primary=https://yuka.dev/blog-2026-10-02-linux-m4.html primary=https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d97afae6f16a4f8ac7d50af0070816270b5380c1 primary=https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=baaa9b126b875b40ffd9356da52c7c871917e5bb primary=https://github.com/AsahiLinux/m1n1/pull/672

arm64 新增 idle=nop,處理 M4 上 WFI 遺失暫存器

Yureka Lilian 個人部落格 · 2026-10-02

Linux arm64 現在可以用開機參數 idle=nop 把 idle loop 裡的 WFI 整個拿掉,取代過去「沒有補丁就只能在 M4 上單核開機」的狀況。這組補丁由 Yureka Lilian 提交,Will Deacon 擔任 committer,目的是讓 Apple M4 Mac mini 能帶著所有核心開到 shell。

原本的問題

Apple 自家 CPU 對 WFI(Wait For Interrupt)有已知怪癖:依 XNU 原始碼中 ARM64_REG_CYC_OVRD_ok2pwrdn_force_mask 這個 chicken bit 的狀態,執行 WFI 會把暫存器 x0-x31 清成零。XNU 的做法是進 WFI 前把暫存器存到 stack,醒來再還原。

M1 到 M3 上,m1n1 會先關掉這個行為,Asahi 核心之後才為了更深的睡眠狀態重新打開。作者的觀察是,M4 上這個 chicken bit 不是被鎖住就是被移除,預設行為違反 Arm 規格:「WFI 若能完成,就不得造成架構狀態遺失」。

結果是 Linux 一進 idle 就崩潰。作者在 2026 年 4 月的繞法,是把核心裡所有 WFI 與 WFIT(帶 timeout 的版本)換成 NOP,才讓全部核心起來。

為什麼不走 errata 框架

正常情況下,指令行為異常會當成 erratum,用 alternatives 框架在開機時 patch。但 Apple 的情形無法可靠判斷該不該 patch:macOS 之下跑的 Linux VM 與實機有相同的 MIDR,開啟巢狀虛擬化時甚至看起來像跑在 EL2,但 VM 內的 WFI 會被 hypervisor 攔截並正確處理,應該繼續使用。

因此 Will Deacon 建議改成:核心提供參數,由 m1n1 在確認是實機且 WFI 會丟狀態時,才加上開機參數。

核心改動

項目內容
d97afae6f16a新增 idle=<wfi|yield|nop>,commit 時間 2026-08-06
baaa9b126b87新增 arm64.nowfxt,把 ID_AA64ISAR2_EL1 的 WFxT 欄位清零,commit 時間 2026-09-18
m1n1 PR #672偵測到 WFI/WFIT 會丟狀態時,由 kboot 加上對應開機參數

第一個補丁的 idle= 三個值各有分工:wfi 是預設,yield 改用 YIELD 提示指令,nop 則在 idle loop 完全不執行任何 idle 指令。文件說明 nop 適合 WFI 行為異常的平台,代價是 CPU 不會進低功耗狀態,耗電較高。

idle=nop            # 不執行 WFI,繞過狀態遺失
arm64.nowfxt        # 停用 WFxT(含 WFIT)

影響範圍

直接受益的是想在 M4 系列實機上跑 mainline Linux 的人。作者表示同樣的 WFI 繞法在 M4 Pro、M4 Max 與 M5 上也有效。要用到修正,需要同時有包含上述兩個 commit 的核心,以及合入 PR #672 的 m1n1。

對一般 arm64 使用者,這兩個參數也可以拿來除錯:idle= 的說明提到可用於覆寫 idle 機制做除錯與效能測試,arm64.nowfxt 的 commit message 則說明它有助於排查其他行為古怪的 WFxT 實作。

目前的代價要看清楚:idle=nop 讓核心無法進入睡眠狀態。作者說之後會另外加機制讓 Linux 讓核心睡眠,短期可用下游的 cpuidle-apple 驅動,長期期待 Sven 的 PSCI EFI conduit 工作;這部分上游尚未完成。

其餘開機障礙

文章還記錄了幾個較小的障礙:M4 上 GXF 在 raw boot mode 被鎖,m1n1 要略過初始化;RVBAR 已含正確值,寫入反而崩潰;缺少 smp_start_offset 時 m1n1 不會啟動 secondary cores。此外 SYS_IMP_APL_VM_TMR_FIQ_ENA_EL2 的寫入曾造成崩潰,作者表示新版 iBoot 已解鎖,不再需要註解掉。

找到 WFI 之前,作者先用最原始的方式除錯:把 m1n1 的 debug_putc 組語放進核心極早期的開機碼,印出單一字元來二分搜尋崩潰位置。第一個卡點是 MMU 啟用後,UART 的 MMIO 位址沒有 1:1 對應,補上對應後才印得更遠;之後定位到中斷控制器初始化,再往後才輪到 secondary cores 與 WFI。這段過程也解釋了為何 stdout-path = "serial0" 缺失時,earlycon 完全沒有輸出。

原始來源:部落格原文、idle= commit、nowfxt commit、m1n1 PR #672


End of article
0
Would love your thoughts, please comment.x
()
x