非對稱 32 位 SoC¶
作者:Will Deacon <will@kernel.org>
本文件描述了非對稱 32 位 SoC 對執行 32 位 (AArch32) 應用程式的影響。
日期:2021-05-17
簡介¶
一些 Armv9 SoC 存在一個 big.LITTLE 的缺陷,即只有一部分 CPU 能夠執行 32 位使用者應用程式。 在這樣的系統上,Linux 預設將這種不對稱視為“不匹配”,並停用對 PER_LINUX32 personality 和 32 位 ELF 二進位制檔案的 execve(2) 的支援,後者返回 -ENOEXEC。 如果在 64 位專用 CPU 的後期聯機期間檢測到不匹配,則聯機操作將失敗,並且新的 CPU 將無法用於排程。
令人驚訝的是,生產這些 SoC 的目的是為了執行舊的 32 位二進位制檔案。 毫不奇怪,這與 Linux 的預設行為並不太相容。
未來的 SoC 似乎不可避免地會放棄 32 位支援,因此,如果您不幸需要在此類過渡平臺上執行 32 位程式碼,那麼明智的做法是考慮重新編譯、模擬或淘汰等替代方案。 如果這些選項都不實用,請繼續閱讀。
啟用核心支援¶
由於核心支援對使用者空間來說並非完全透明,因此,允許 32 位任務在非對稱 32 位系統上執行需要顯式的“選擇加入”,並且可以透過在核心命令列上傳遞 allow_mismatched_32bit_el0 引數來啟用。
在本文件的其餘部分,我們將使用非對稱系統來表示執行 Linux 且啟用了此核心命令列選項的非對稱 32 位 SoC。
使用者空間影響¶
在非對稱系統上執行的 32 位任務的行為與在同構系統上的行為基本相同,只有少數與 CPU 親和性相關的關鍵差異。
sysfs¶
能夠在 /sys/devices/system/cpu/aarch32_el0 中描述執行 32 位任務的 CPU 子集,並在 ABI 檔案測試/sysfs-devices-system-cpu 中進一步記錄。
注意: CPU 由此檔案進行通告,因為它們被檢測到,因此稍後聯機支援 32 位的 CPU 可能導致核心在執行時修改檔案內容。 一旦通告,CPU 將永遠不會從此檔案中刪除。
execve(2)¶
在同構系統上,任務的 CPU 親和性會在 execve(2) 過程中保留。 這在非對稱系統上並非總是可能的,尤其是在要執行的新程式是 32 位,但親和性掩碼包含僅限 64 位的 CPU 時。 在這種情況下,核心將按如下方式確定新的親和性掩碼
如果親和性掩碼中支援 32 位的子集不為空,則親和性將限制為該子集,並儲存舊的親和性掩碼。 此儲存的掩碼會在
fork(2)中繼承,並在 32 位程式的execve(2)中保留。注意: 此步驟不適用於
SCHED_DEADLINE任務。 請參見 SCHED_DEADLINE。否則,將遍歷任務的 cpuset 層級結構,直到找到包含至少一個支援 32 位的 CPU 的祖先。 然後,任務的親和性將更改為與遍歷確定的 cpuset 中支援 32 位的子集匹配。
如果失敗(即記憶體不足),則親和性將更改為核心知道的所有支援 32 位的 CPU 的集合。
32 位任務隨後對 64 位程式執行的 execve(2) 將使在 (1) 中儲存的親和性掩碼無效,並嘗試使用儲存的掩碼恢復任務的 CPU 親和性(如果先前有效)。 由於截止時間策略或 cpuset 層級結構的中間更改,此恢復可能會失敗,在這種情況下,execve(2) 將繼續執行,且親和性不變。
對 32 位任務呼叫 sched_setaffinity(2) 將僅考慮請求的親和性掩碼中支援 32 位的 CPU。 成功後,將更新任務的親和性,並且先前 execve(2) 中儲存的任何掩碼都將無效。
SCHED_DEADLINE¶
在非對稱 32 位系統上,拒絕顯式允許 32 位截止時間任務進入預設根域(例如,透過呼叫 sched_setattr(2)),除非透過將 -1 寫入 /proc/sys/kernel/sched_rt_runtime_us 來停用准入控制。
如果任務的根域包含任何僅限 64 位的 CPU 且啟用了准入控制,則從 64 位截止時間任務執行 execve(2) 的 32 位程式將返回 -ENOEXEC。 併發離線支援 32 位的 CPU 仍然可能需要 execve(2) 中描述的過程,在這種情況下,將跳過步驟 (1),並在控制檯上發出警告。
注意: 如果要在非對稱系統上將 SCHED_DEADLINE 與 32 位任務一起使用,建議將一組支援 32 位的 CPU 放入單獨的根域中。 否則,很可能會錯過截止時間。
Cpusets¶
非對稱系統上 32 位任務的親和性可能包括 cpuset 未明確允許的 CPU。
連線到僅允許 64 位 CPU 的 cpuset 的 64 位任務執行 32 位程式。
cpuset 允許的所有支援 32 位的 CPU(包含 32 位任務)均已離線。
在這兩種情況下,都會根據 execve(2) 中描述的過程的步驟 (2) 來計算新的親和性,並且無論 cgroup 版本如何,cpuset 層級結構都不會更改。
CPU 熱插拔¶
在非對稱系統上,阻止使用者空間離線檢測到的第一個支援 32 位的 CPU,並且任何此類嘗試都將返回 -EPERM。 請注意,即使主 CPU(即 CPU 0)是僅限 64 位的 CPU,也仍然允許掛起。
KVM¶
雖然 KVM 不會在非對稱系統上向任何 vCPU 通告 32 位 EL0 支援,但 EL1 上已損壞的客戶機仍可能嘗試在 EL0 上執行 32 位程式碼。 在這種情況下,從 32 位模式的 vCPU 執行緒退出將返回到主使用者空間,exit_reason 為 KVM_EXIT_FAIL_ENTRY,並且在後續 KVM_ARM_VCPU_INIT 操作成功重新初始化之前,將保持不可執行狀態。
NOHZ FULL¶
為了避免在強制遷移 32 位任務時擾亂自適應滴答 CPU(使用 nohz_full= 指定),當啟用對非對稱 32 位系統的支援時,會將這些 CPU 視為僅限 64 位的 CPU。