微码

来自 ArchWiki


处理器制造商发布处理器 微码 的稳定性和安全性更新。这些更新提供了错误修复,这对系统的稳定性至关重要。没有它们,您可能会遇到难以追踪的虚假崩溃或意外的系统停止。

所有使用 AMD 或 Intel CPU 的用户都应该安装微码更新以确保系统稳定性。在虚拟机和容器中,微码更新应安装在宿主机上,而不是在客户机系统中。

安装

要获取更新的微码,根据处理器类型,安装 以下软件包之一

mkinitcpiodracut 默认生成组合的 initramfs 文件。微码将在启动时自动加载。Booster 不支持生成组合的 initramfs,请参阅 #微码位于单独的 initramfs 文件中 中所需的引导加载程序配置。

加载微码

微码更新通常与主板的固件一起发布,并在固件初始化期间应用。由于 OEM 可能不会及时发布固件更新,并且旧系统根本不会获得新的固件更新,因此 Linux 内核添加了在启动期间应用 CPU 微码更新的功能。Linux 微码加载器 支持三种加载方法

  1. 内置微码 可以编译到内核中,然后由早期加载器应用。
  2. 早期加载 在启动的非常早期更新微码,在 initramfs 阶段之前,并且优于后期加载。对于具有严重硬件错误的 CPU(如 Intel Haswell 和 Broadwell 处理器系列)来说,这是强制性的。
  3. 后期加载 (可能 可能危险的) 在启动后更新微码,这可能为时已晚,因为 CPU 可能已经尝试使用有缺陷的指令。即使已经使用早期加载,后期加载仍然可以用于应用更新的微码更新,而无需重新启动。

早期加载

内核的早期加载器期望在未压缩的 CPIO 归档文件(initramfs 镜像)内的 /kernel/x86/microcode/GenuineIntel.bin/kernel/x86/microcode/AuthenticAMD.bin 中找到微码更新文件。

早期的 initramfs 镜像可以与主 initramfs 镜像组合成一个文件,并作为单个 initramfs 传递给内核(通过引导加载程序的 initrd= 内核命令行选项,或者当打包在统一内核镜像中时),或者它可以作为单独的文件存在,在这种情况下,需要使用多个 initrd= 内核命令行选项。在这两种情况下,包含微码的未压缩 CPIO 归档文件必须放在主 initramfs 之前。

请注意,由于用户早期启动配置的广泛差异,Arch 的默认配置可能不会自动触发微码更新。

自定义构建内核

为了使早期加载在自定义内核中工作,“CPU 微码加载支持”需要编译到内核中,而不是作为模块编译。这将启用“Early load microcode”提示,应将其设置为 Y

CONFIG_BLK_DEV_INITRD=Y
CONFIG_MICROCODE=y
CONFIG_MICROCODE_INTEL=Y
CONFIG_MICROCODE_AMD=y

微码 initramfs 与主 initramfs 打包在一个文件中

未压缩的微码 CPIO 可以预先添加到 initramfs 中,并用作单个 initramfs 文件。此方法优于#微码位于单独的 initramfs 文件中,因为不需要额外的引导参数配置。

提示: 您可以选择将 boot/*-ucode.img 添加到 /etc/pacman.conf 中的 NoExtract,因为微码文件将直接从 /usr/lib/firmware/*-ucode/ 中获取。
mkinitcpio

对于 mkinitcpio 生成包含微码的 initramfs 文件,请确保 microcode/etc/mkinitcpio.conf 中的 HOOKS 数组中。

如果 autodetect hook 在 microcode 之前,则只会包含当前 CPU 的微码。要包含系统上可以找到的所有 CPU 微码文件,请将 microcode hook 移动到 autodetect 之前,或者完全删除 autodetect hook。

生成 initramfs 时,mkinitcpio 将显示

-> Early uncompressed CPIO image generation successful

您可以使用 lsinitcpio(1) 验证 initramfs 是否包含微码更新文件。例如:

# lsinitcpio --early /boot/initramfs-linux.img | grep microcode 
kernel/x86/microcode/
kernel/x86/microcode/AuthenticAMD.bin
dracut

对于 dracut,请参阅 dracut.conf(5) § DESCRIPTION

微码位于单独的 initramfs 文件中

否则,必须通过将 /boot/amd-ucode.img/boot/intel-ucode.img 添加为引导加载程序配置文件中的第一个 initrd 来启用早期微码更新。这在正常的 initrd 文件之前。有关常见引导加载程序的说明,请参见下文。

在以下部分中,将 cpu_manufacturer 替换为您的 CPU 制造商,即 amdintel

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-ucodeintel-ucode 更新时更新微码。否则,在每次更新微码软件包时,将 /boot/cpu_manufacturer-ucode.img 复制到您的 ESP。

EFISTUB

附加两个 initrd= 选项

initrd=\cpu_manufacturer-ucode.img initrd=\initramfs-linux.img
rEFInd
提示: 以前未指定 initrd 内核参数的用户需要按照 rEFInd#配置 中描述的步骤启用传递多个 initrd 参数。

编辑 /boot/refind_linux.conf 中的引导选项,并为微码镜像添加 initrd= 选项作为传递的第一个 initrd 参数。根据 /boot 中的文件是否位于单独分区的根目录,使用 initrd=boot\cpu_manufacturer-ucode.imginitrd=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= 参数,其中包含引导分区中的正确路径。此参数是 options 行的一部分,而不是条目的主要部分。例如:

options  "root=PARTUUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rw add_efi_memmap initrd=boot\cpu_manufacturer-ucode.img"
Syslinux
注意: cpu_manufacturer-ucode.imginitramfs-linux.img initrd 文件之间不能有空格。INITRD 行必须与下面所示的完全一致。

多个 initrd 可以用逗号在 /boot/syslinux/syslinux.cfg 中分隔

LABEL arch
    MENU LABEL Arch Linux
    LINUX ../vmlinuz-linux
    INITRD ../cpu_manufacturer-ucode.img,../initramfs-linux.img
...
LILO

LILO 以及可能其他旧的引导加载程序不支持多个 initrd 镜像。请遵循 #微码 initramfs 与主 initramfs 打包在一个文件中 方法。

Limine

对于 Limine,您只需要通过 limine.conf 文件中的 MODULE_PATH 选项添加微码的路径。这是一个例子

limine.conf
default_entry: 1
timeout: 3

/Arch
    comment: Arch Linux

    protocol: linux
    kernel_path: boot():/vmlinuz-linux
    kernel_cmdline: root=UUID=c0748521-eca9-4f38-989c-43811b6e39a1 rw loglevel=3
    module_path: boot():/cpu_manufacturer-ucode.img
    module_path: boot():/initramfs-linux.img

后期加载

警告: 后期微码加载被认为是危险的,在 Linux 5.19 及更高版本上使用它会污染内核。[1]

微码更新的后期加载发生在系统启动后。它使用 /usr/lib/firmware/amd-ucode//usr/lib/firmware/intel-ucode/ 中的文件。微码更新文件分别由 amd-ucodeintel-ucode 提供。

后期加载需要内核构建时启用 CONFIG_MICROCODE_LATE_LOADING=y,但 Arch 官方支持的内核 目前并非如此。[2]

后期加载微码更新

要手动重新加载微码,例如在更新 /usr/lib/firmware/amd-ucode//usr/lib/firmware/intel-ucode/ 中的微码文件后,运行

# echo 1 > /sys/devices/system/cpu/microcode/reload

这允许在无需重启系统的情况下应用更新的微码更新。

验证微码是否在启动时更新

使用 journalctl 检查内核消息,以查看微码是否已更新

# journalctl -k --grep='microcode:'

每次启动时,应该能看到类似下面的信息,表明微码已在启动早期更新

kernel: microcode: Current revision: 0x00000012
kernel: microcode: Updated early from: 0x0000000e

尤其是在较新的硬件上,CPU 有可能没有微码更新。

在使用延迟加载的 AMD 系统上,输出将显示旧微码的版本,然后在重新加载微码后显示新微码的版本。

哪些 CPU 接受微码更新

用户可以查阅英特尔的仓库或 Gentoo 的 AMD Wiki,通过以下链接查看特定型号是否受支持

检测可用的微码更新

对于英特尔,可以检查 /usr/lib/firmware/intel-ucode/ 是否包含正在运行的 CPU 的微码,使用 iucode_tool(8)

  1. 安装 intel-ucodeiucode-tool
  2. 加载 cpuid 内核模块
    # modprobe cpuid
  3. 搜索您的 cpuid
    $ iucode_tool -lS /usr/lib/firmware/intel-ucode/
  4. 如果有可用的更新,它应该在selected microcodes(已选择的微码)下方显示
  5. 微码可能已存在于您的供应商 BIOS 中,并且不会在 dmesg 中显示加载。与当前运行的微码进行比较,运行 grep microcode /proc/cpuinfo

对于 AMD,可以手动完成。

  1. 找出 CPU 的 family(系列)、model(型号)和 stepping(步进)。例如,通过运行以下命令
    # journalctl -k --grep='CPU0:'
    查看类似 (family: 0x15, model: 0x10, stepping: 0x1) 的输出部分。
  2. 将这些值与 amd-ucode README 中的列表进行匹配。
  3. 如果匹配,将运行中微码的当前修订版与列出的 Patch 值进行比较。
注意: 您也可以使用 lscpu(1)/proc/cpuinfo 输出获取 family(系列)、model(型号)和 stepping(步进)。但您需要将这些值转换为十六进制。

禁用微码加载器

如果更新的 CPU 微码导致问题,您可能需要暂时禁用微码加载器,以便成功启动并降级软件包。要禁用内核的微码加载器,请指定 dis_ucode_ldr 内核参数

另请参阅