微码
处理器制造商会发布对处理器微码的稳定性和安全性更新。这些更新提供了对系统稳定性至关重要的错误修复。如果没有这些更新,则可能会遇到不明原因的崩溃或难以跟踪的意外停机。
使用 AMD 或 Intel CPU 的用户都应该安装微码更新以确保系统稳定性。
微码更新通常随主板固件一起提供,并在固件初始化时被应用。但是 OEM 可能不会及时发布固件更新,并且旧系统根本不会获得新的固件更新,所以 Linux 内核提供了启动时应用微码更新的功能。Linux 微码加载器支持三种加载方式:
- 早期加载在启动过程中很早就更新微码(比 initramfs 阶段还早),所以是推荐的方式。对于具有严重硬件错误的 CPU,例如 Intel Haswell 和 Broadwell 处理器系列,必须选择这种方式。
- 后期加载(危险)在启动后更新微码,这可能太晚了,因为 CPU 可能已经使用了有问题的指令集。即使已经使用了早期加载,后期加载依然有价值,可以在系统不重启的情况下应用较新的微码更新。
- 内置微码可以编译到内核中,然后由早期加载程序应用。
早期加载[编辑 | 编辑源代码]
安装[编辑 | 编辑源代码]
根据处理器,安装以下软件包:
- AMD 处理器安装 amd-ucode包。
- Intel 处理器安装 intel-ucode包。
微码必须由引导加载程序加载。由于用户的早期启动配置存在很大差异,Arch 的默认配置可能不会自动触发微码更新。许多 AUR 内核在这方面都遵循官方 Arch 内核。
必须通过把 /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。
Unified kernel images[编辑 | 编辑源代码]
参见 Unified kernel image#Manually。
EFISTUB[编辑 | 编辑源代码]
追加两个 initrd=
选项:
initrd=\cpu_manufacturer-ucode.img initrd=\initramfs-linux.img
rEFInd[编辑 | 编辑源代码]
编辑 /boot/refind_linux.conf
中的引导选项并将 initrd=boot\cpu_manufacturer-ucode.img
(如果 /boot
是一个单独的分区,则是 initrd=cpu_manufacturer-ucode.img
)添加为第一个 initramfs。例如:
"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"
如果在 esp/EFI/refind/refind.conf
中通过手动配置定义所要引导的内核,那么只需将 initrd=boot\cpu_manufacturer-ucode.img
(如果 /boot
是一个单独的分区,则是 initrd=cpu_manufacturer-ucode.img
)添加到 options 一行,不要修改配置的主干部分。例如:
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
后期加载[编辑 | 编辑源代码]
微码更新的后期加载发生在系统启动之后。它使用 /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/
。
启用微码更新的后期加载[编辑 | 编辑源代码]
与早期加载不同,Arch Linux 上微码更新的后期加载通过 /usr/lib/tmpfiles.d/linux-firmware.conf
默认启用。启动后,文件由 systemd-tmpfiles-setup.service(8) 解析,并更新 CPU 微码。
如果要手动重新加载微码,例如在更新 /usr/lib/firmware/amd-ucode/
或 /usr/lib/firmware/intel-ucode/
中的微码文件后,请运行:
# echo 1 > /sys/devices/system/cpu/microcode/reload
这允许在不重新启动系统的情况下应用较新的微码更新。
禁用微码更新的后期加载[编辑 | 编辑源代码]
对于 AMD 系统来说,即使不安装 amd-ucode包,CPU 微码仍然会被更新,因为 /usr/lib/firmware/amd-ucode/
中的文件由 linux-firmware包 提供(FS#59840)。和容器(FS#46591)不支持更新 CPU 微码,所以你可能想禁用微码更新。
要禁用危险的晚期微码更新,需要覆盖 linux-firmware包 提供的 /usr/lib/tmpfiles.d/linux-firmware.conf
这个 tmpfile。这可以通过在 /etc/tmpfiles.d/
中创建同名的文件来完成:
# ln -s /dev/null /etc/tmpfiles.d/linux-firmware.conf
内置于 initramfs 中的微码[编辑 | 编辑源代码]
如果您使用的 initramfs 生成器已经将微码 cpio 放在 initramfs 的最前面,则不需要#早期加载和#后期加载。例如,dracut 已经默认这样做;参见 dracut.conf(5) § DESCRIPTION。
验证微码已在启动时更新[编辑 | 编辑源代码]
使用 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