微码
处理器制造商会发布对处理器微码的稳定性和安全性更新。这些更新提供了对系统稳定性至关重要的错误修复。如果没有这些更新,则可能会遇到不明原因的崩溃或难以跟踪的意外停机。
使用 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