24. Linux 微碼載入器¶
- 作者:
Fenghua Yu <fenghua.yu@intel.com>
Borislav Petkov <bp@suse.de>
Ashok Raj <ashok.raj@intel.com>
核心具有 x86 微碼載入工具,旨在提供作業系統中的微碼載入方法。潛在的用例包括在 OEM 生命週期支援之外的平臺上更新微碼,以及在無需重啟的情況下更新長時間執行的系統上的微碼。
載入器支援三種載入方法
24.1. 早期載入微碼¶
核心可以在啟動過程中很早的時候更新微碼。 早期載入微碼可以修復 CPU 問題,避免在核心啟動時出現問題。
微碼儲存在 initrd 檔案中。 在啟動期間,從 initrd 檔案讀取微碼並將其載入到 CPU 核心中。
組合 initrd 映象的格式是(未壓縮)cpio 格式的微碼,後跟(可能已壓縮)的 initrd 映象。 載入器在啟動期間解析組合的 initrd 映象。
cpio 名稱空間中的微碼檔案為
- 在 Intel 上
kernel/x86/microcode/GenuineIntel.bin
- 在 AMD 上
kernel/x86/microcode/AuthenticAMD.bin
在 BSP (引導處理器) 啟動期間(pre-SMP),核心會掃描 initrd 中的微碼檔案。 如果找到與 CPU 匹配的微碼,它將應用於 BSP,然後應用於所有 AP (應用程式處理器)。
載入器還會將與 CPU 匹配的微碼儲存在記憶體中。 因此,當 CPU 從睡眠狀態恢復時,會應用快取的微碼補丁。
這是一個粗略的示例,說明如何準備帶有微碼的 initrd(通常由發行版自動完成,在重新建立 initrd 時,因此您實際上不必自己完成。 此處僅供將來參考記錄)。
#!/bin/bash
if [ -z "$1" ]; then
echo "You need to supply an initrd file"
exit 1
fi
INITRD="$1"
DSTDIR=kernel/x86/microcode
TMPDIR=/tmp/initrd
rm -rf $TMPDIR
mkdir $TMPDIR
cd $TMPDIR
mkdir -p $DSTDIR
if [ -d /lib/firmware/amd-ucode ]; then
cat /lib/firmware/amd-ucode/microcode_amd*.bin > $DSTDIR/AuthenticAMD.bin
fi
if [ -d /lib/firmware/intel-ucode ]; then
cat /lib/firmware/intel-ucode/* > $DSTDIR/GenuineIntel.bin
fi
find . | cpio -o -H newc >../ucode.cpio
cd ..
mv $INITRD $INITRD.orig
cat ucode.cpio $INITRD.orig > $INITRD
rm -rf $TMPDIR
系統需要在 /lib/firmware 中安裝了微碼包,否則您需要修復上面的路徑,如果您的微碼包位於其他位置,或者您直接從處理器供應商的站點下載了它們。
24.2. 延遲載入¶
只需安裝你的發行版提供的微碼包並執行
# echo 1 > /sys/devices/system/cpu/microcode/reload
作為 root 使用者。
載入機制在 /lib/firmware/{intel-ucode,amd-ucode} 中查詢微碼 blob。 預設的發行版安裝包已將其放置在那裡。
自核心 5.19 以來,預設情況下不啟用延遲載入。
/dev/cpu/microcode 方法已在 5.19 中刪除。
24.3. 為什麼延遲載入很危險?¶
24.3.1. 同步所有 CPU¶
接收微碼更新的微碼引擎在 SMT 系統中的兩個邏輯執行緒之間共享。 因此,當在核心的一個 SMT 執行緒上執行更新時,兄弟執行緒會“自動”獲得更新。
由於微碼也可以“模擬” MSR,因此在微碼更新過程中,這些模擬的 MSR 會暫時停止存在。 如果 SMT 兄弟執行緒恰好正在訪問此類 MSR,則可能導致不可預測的結果。 通常的觀察是,此類 MSR 訪問會導致 #GP 異常,以表明前者不存在。
消失的 MSR 只是一個常見的被觀察到的問題。 任何其他正在被修補並由其他 SMT 兄弟執行緒併發執行的指令也可能導致類似、不可預測的行為。
為了消除這種情況,引入了一種基於 stop_machine() 的 CPU 同步,作為保證所有邏輯 CPU 都不會執行任何程式碼,而只是在自旋迴圈中等待,輪詢原子變數的方法。
雖然這解決了裝置或外部中斷、包括 LVT 中斷(例如 CMCI 等)的 IPI,但它無法解決其他無法關閉的特殊中斷。 這些是機器檢查 (#MC)、系統管理 (#SMI) 和非遮蔽中斷 (#NMI)。
24.3.2. 機器檢查¶
機器檢查 (#MC) 是不可遮蔽的。 有兩種型別的 MCE。 致命的不可恢復的 MCE 和可恢復的 MCE。 雖然不可恢復的錯誤是致命的,但在核心上下文中發生的可恢復錯誤也被核心視為致命錯誤。
在某些 Intel 機器上,MCE 也會廣播到系統中的所有執行緒。 如果一個執行緒正在執行 WRMSR,則將在流程結束時獲取一個 MCE。 無論哪種方式,如果系統中的任何執行緒未能簽入 MCE 交匯點,它們將等待執行 wrmsr(0x79) 的執行緒在 MCE 處理程式中會合並最終關閉。
為了偏執並獲得可預測的行為,作業系統可以選擇設定 MCG_STATUS.MCIP。 由於一個系統中最多隻能有一個 MCE,因此如果發出了 MCE 訊號,則上述條件將自動升級為系統重置。 作業系統可以在該核心更新結束時關閉 MCIP。
24.3.3. 系統管理中斷¶
SMI 也廣播到平臺中的所有 CPU。 微碼更新請求在寫入 MSR 0x79 之前對核心的獨佔訪問。 因此,如果一個執行緒正在 WRMSR 流程中,而第二個執行緒收到了一個 SMI,則該執行緒將在 SMI 處理程式中的第一條指令中停止。
由於輔助執行緒在 SMI 中的第一條指令中停止,因此它幾乎不可能正在執行一條正在被修補的指令。 此外,作業系統無法阻止 SMI 發生。
24.3.4. 非遮蔽中斷¶
當核心的 thread0 正在進行微碼更新時,如果 thread1 被拉入 NMI,則由於上述原因,可能會導致不可預測的行為。
作業系統可以選擇多種方法來避免遇到這種情況。
24.3.5. 微碼適合延遲載入嗎?¶
當系統完全執行並執行實際工作負載時,會進行延遲載入。 延遲載入行為取決於在升級到新補丁之前 CPU 上的基本補丁是什麼。
對於 Intel CPU 來說,這是真的。
例如,假設一個 CPU 具有補丁級別 1,並且更新為補丁級別 3。
在 patch1 和 patch3 之間,patch2 可能已棄用軟體可見的功能。
如果軟體甚至可能正在使用該功能,這是不可接受的。 例如,假設 MSR_X 在更新後不再可用,訪問該 MSR 將導致 #GP 錯誤。
基本上,沒有辦法宣告新的微碼更新適合延遲載入。 這是導致預設情況下不啟用延遲載入的另一個問題。
24.4. 內建微碼¶
載入器還支援載入透過常規內建韌體方法 CONFIG_EXTRA_FIRMWARE 提供的內建微碼。 目前僅支援 64 位。
這是一個例子
CONFIG_EXTRA_FIRMWARE="intel-ucode/06-3a-09 amd-ucode/microcode_amd_fam15h.bin"
CONFIG_EXTRA_FIRMWARE_DIR="/lib/firmware"
這基本上意味著,您在本地具有以下樹結構
/lib/firmware/
|-- amd-ucode
...
| |-- microcode_amd_fam15h.bin
...
|-- intel-ucode
...
| |-- 06-3a-09
...
以便構建系統可以找到這些檔案並將它們整合到最終核心映像中。 早期載入器找到它們並應用它們。
不用說,這種方法並不是最靈活的一種,因為它需要每次從 CPU 供應商獲得更新的微碼時都重新構建核心。