微碼
處理器製造商會發佈對處理器微碼的穩定性和安全性更新。這些更新提供了對系統穩定性至關重要的錯誤修復。如果沒有這些更新,則可能會遇到不明原因的崩潰或難以跟蹤的意外停機。
使用 AMD 或 Intel CPU 的用户都應該安裝微碼更新以確保系統穩定性。在虛擬機或容器中時,微碼更新應在主機上實施,而不是客户機.
加載微碼[編輯 | 編輯原始碼]
微碼更新通常隨主板固件一起提供,並在固件初始化時被應用。但是 OEM 可能不會及時發佈固件更新,並且舊系統根本不會獲得新的固件更新,所以 Linux 內核提供了啟動時應用微碼更新的功能。Linux 微碼加載器支持三種加載方式:
- 內置微碼可以編譯到內核中,然後由早期加載程序應用。
- 早期加載在啟動過程中很早就更新微碼(比 initramfs 階段還早),所以是推薦的方式。對於具有嚴重硬件錯誤的 CPU,例如 Intel Haswell 和 Broadwell 處理器系列,必須選擇這種方式。
- 後期加載(危險!)在啟動後更新微碼,這可能太晚了,因為 CPU 可能已經使用了有問題的指令集。即使已經使用了早期加載,後期加載依然有價值,可以在系統不重啟的情況下應用較新的微碼更新。
根據不同的處理器,安裝以下軟件包之一以獲取微碼:
- 對於 AMD 處理器 : amd-ucode包
- 對於 Intel 處理器 : intel-ucode包
initramfs中內建微碼[編輯 | 編輯原始碼]
可以將微碼構入 initramfs. 一些 initramfs 生成器, 比如 dracut (見 dracut.conf(5) § DESCRIPTION), 默認如此. 這使得 #Early loading 和 #Late loading 不再必要. 然而,Arch Linux 默認使用 mkinitcpio 來生成初始化 ramdisk (initramfs), 並不支持這個.但他支持通過 UEFI stub 加載微碼: 見 #Unified kernel images.
早期加載[編輯 | 編輯原始碼]
如果沒有編譯到內核中,微碼必須早期加載. 他可以作為unified kernel image的一部分,或作為一個initrd image 傳遞給你的 boot loader 並被其加載.
請注意,由於用户的早期啟動配置存在很大差異,Arch 的默認配置可能不會自動觸發微代碼更新。
Unified kernel images[編輯 | 編輯原始碼]
參見統一內核鏡像以獲取將微碼包含在單一的 image 中的指導。
Initrd images[編輯 | 編輯原始碼]
必須通過把 /boot/amd-ucode.img
或 /boot/intel-ucode.img
添加為引導加載程序配置文件中的第一個 initrd 啟用這些更新。即在正常的 initrd 文件之前。下文包含常見引導加載程序的説明。
在下面的部分中,把 cpu_manufacturer
換成你的 CPU 的製造商,即 amd
或 intel
。
在自定義內核中啟用早期微碼加載[編輯 | 編輯原始碼]
為了在自定義內核中進行早期加載,需要將 "CPU microcode loading support" 編譯到內核中,而不是編譯為模塊。這將啟用 "Early load microcode" 提示,將其設置為 Y
。
CONFIG_BLK_DEV_INITRD=Y CONFIG_MICROCODE=y CONFIG_MICROCODE_INTEL=Y CONFIG_MICROCODE_AMD=y
GRUB[編輯 | 編輯原始碼]
grub-mkconfig 會自動檢測微碼更新並正確配置 GRUB。安裝微碼軟件包後,重新生成 GRUB 配置以激活加載微碼更新:
# grub-mkconfig -o /boot/grub/grub.cfg
或者,如果手動管理 GRUB 配置文件,可以添加 /boot/cpu_manufacturer-ucode.img
(如果 /boot
是一個單獨的分區,則是 /cpu_manufacturer-ucode.img
):
/boot/grub/grub.cfg
... echo 'Loading initial ramdisk' initrd /boot/cpu_manufacturer-ucode.img /boot/initramfs-linux.img ...
對每個菜單項重複此操作。
systemd-boot[編輯 | 編輯原始碼]
在初始 ramdisk 之前使用 initrd
選項加載微碼,如下所示:
/boot/loader/entries/entry.conf
title Arch Linux linux /vmlinuz-linux initrd /cpu_manufacturer-ucode.img initrd /initramfs-linux.img ...
最新的 cpu_manufacturer-ucode.img
在啟動時必須存在於 EFI 系統分區(ESP)中。ESP 必須掛載到 /boot
才能讓微碼隨 amd-ucode包 和 intel-ucode包 更新。否則需要在每次微碼包更新時手動將 /boot/cpu_manufacturer-ucode.img
複製到 ESP。
EFISTUB[編輯 | 編輯原始碼]
追加兩個 initrd=
選項:
initrd=\cpu_manufacturer-ucode.img initrd=\initramfs-linux.img
rEFInd[編輯 | 編輯原始碼]
編輯 /boot/refind_linux.conf
,將微碼添加第一個initrd=
選項,比如 initrd=boot\cpu_manufacturer-ucode.img
(如果 /boot
是一個單獨的分區,則是 initrd=cpu_manufacturer-ucode.img
)
例如:
"Boot using default options" "root=PARTUUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rw add_efi_memmap initrd=boot\cpu_manufacturer-ucode.img initrd=boot\initramfs-%v.img"
Manual boot stanzas[編輯 | 編輯原始碼]
Users employing manual stanzas in esp/EFI/refind/refind.conf
to define kernels should add the initrd=
parameter with the proper path within the boot partition. This parameter is required as part of the options line, and not in the main part of the stanza. E.g.:
options "root=PARTUUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rw add_efi_memmap initrd=boot\cpu_manufacturer-ucode.img"
Syslinux[編輯 | 編輯原始碼]
cpu_manufacturer-ucode.img
和 initramfs-linux.img
initrd 文件間不要用空格。INITRD
一行必須和下面的示例完全一樣。在 /boot/syslinux/syslinux.cfg
中,可以用逗號分隔多個 initrd:
LABEL arch MENU LABEL Arch Linux LINUX ../vmlinuz-linux INITRD ../cpu_manufacturer-ucode.img,../initramfs-linux.img ...
LILO[編輯 | 編輯原始碼]
LILO(可能還有其他舊的引導加載程序)不支持多個 initrd 鏡像。這時,必須將 cpu_manufacturer-ucode.img
和 initramfs-linux.img
合併成一個鏡像。
initramfs-linux.img
鏡像必須在 cpu_manufacturer-ucode.img
之後。可使用以下命令合併將兩個鏡像合併為 initramfs-merged.img
:
# cat /boot/cpu_manufacturer-ucode.img /boot/initramfs-linux.img > /boot/initramfs-merged.img
現在編輯 /etc/lilo.conf
以加載新鏡像。
... initrd=/boot/initramfs-merged.img ...
然後以 root 身份運行 lilo
:
# lilo
Limine[編輯 | 編輯原始碼]
For Limine you will just need to add the path to the microcode through the MODULE_PATH
option in your limine.cfg file. Here is an example:
limine.cfg
DEFAULT_ENTRY=1 TIMEOUT=3 :Arch COMMENT=Arch Linux PROTOCOL=linux KERNEL_PATH=boot:///vmlinuz-linux CMDLINE=root=UUID=c0748521-eca9-4f38-989c-43811b6e39a1 rw loglevel=3 MODULE_PATH=boot:///cpu_manufacturer-ucode.img MODULE_PATH=boot:///initramfs-linux.img
後期加載[編輯 | 編輯原始碼]
微碼更新的後期加載發生在系統啟動之後。它使用 /usr/lib/firmware/amd-ucode/
和 /usr/lib/firmware/intel-ucode/
中的文件。在 Linux 5.19+ 上,後期加載需要使用 CONFIG_MICROCODE_LATE_LOADING=y
構建內核。
對於 AMD 處理器來説,微碼更新文件由 linux-firmware包 提供。
對於 Intel 處理器來説,沒有軟件包提供微碼更新文件(FS#59841)。要使用後期加載,你需要從Intel 提供的壓縮包裡手動解壓出 intel-ucode/
。
啟用微碼更新的後期加載[編輯 | 編輯原始碼]
如果要手動重新加載微碼,例如在更新 /usr/lib/firmware/amd-ucode/
或 /usr/lib/firmware/intel-ucode/
中的微碼文件後,請運行:
# echo 1 > /sys/devices/system/cpu/microcode/reload
這允許在不重新啟動系統的情況下應用較新的微碼更新。
驗證微碼已在啟動時更新[編輯 | 編輯原始碼]
使用 journalctl 檢查內核消息,以查看微碼是否已更新:
# journalctl -k --grep=microcode
在 Intel 系統上,每次啟動時都應該看到類似於以下的內容,表明微碼很早就更新了:
microcode: microcode updated early to revision 0xde, date = 2020-05-18 microcode: sig=0x806ec, pf=0x80, revision=0xde microcode: Microcode Update Driver: v2.2.
完全有可能,特別是對於較新的硬件,CPU 沒有微碼更新。在這種情況下,輸出可能如下所示:
microcode: sig=0x806ec, pf=0x80, revision=0xde microcode: Microcode Update Driver: v2.2.
在使用早期加載的 AMD 系統上,輸出將類似於以下內容:
microcode: microcode updated early to new patch_level=0x0700010f microcode: CPU0: patch_level=0x0700010f microcode: CPU1: patch_level=0x0700010f microcode: CPU2: patch_level=0x0700010f microcode: CPU3: patch_level=0x0700010f microcode: Microcode Update Driver: v2.2.
在使用後期加載的 AMD 系統上,輸出將在重新加載微碼之前顯示舊微碼的版本,並在重新加載微碼後顯示新微碼的版本。它看起來像這樣:
microcode: CPU0: patch_level=0x0700010b microcode: CPU1: patch_level=0x0700010b microcode: CPU2: patch_level=0x0700010b microcode: CPU3: patch_level=0x0700010b microcode: Microcode Update Driver: v2.2. microcode: CPU2: new patch_level=0x0700010f microcode: CPU0: new patch_level=0x0700010f microcode: CPU1: new patch_level=0x0700010f microcode: CPU3: new patch_level=0x0700010f x86/CPU: CPU features have changed after loading microcode, but might not take effect.
哪些 CPU 可以接受微碼更新[編輯 | 編輯原始碼]
可以從 Intel 自己的網站或 Gentoo wiki 上 AMD 的頁面查看是否支持特定型號:
檢查可用的微碼更新[編輯 | 編輯原始碼]
可以用 iucode-tool包 來檢查 intel-ucode.img
是否包含適用於當前運行的 CPU 的微碼鏡像。
- 安裝 intel-ucode包(檢測並不需要修改 initrd)
- 安裝 iucode-tool包
- 加載
cpuid
內核模塊:# modprobe cpuid
- 解包微指令映像,並搜索你的 cpuid:
# bsdtar -Oxf /boot/intel-ucode.img | iucode_tool -tb -lS -
- 如果有更新可用,它應該會在 selected microcodes 下顯示
- 微碼可能已經在你的 BIOS 裡,所以不會在 dmesg 裡出現。和正在運行的微碼對比:
grep microcode /proc/cpuinfo