跳转至内容

微代码 (Microcode)

来自 ArchWiki


处理器制造商会发布针对处理器 微代码 (microcode) 的稳定性与安全更新。这些更新提供的 Bug 修复对于系统的稳定性至关重要。如果没有这些更新,你可能会遇到难以追踪的随机崩溃或意外的系统停机。

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

安装

为了获取更新的微代码,根据处理器的不同,请 安装 以下软件包之一:

mkinitcpiodracut 默认生成 组合的 initramfs 文件。微代码将在启动时自动加载。

注意 Booster 不支持生成组合的 initramfs,请参阅 #微代码位于独立的 initramfs 文件中 中所需的 引导加载程序 配置。

加载微代码

微代码更新通常随主板固件一起提供,并在固件初始化期间应用。由于 OEM 厂商可能无法及时发布固件更新,且旧系统可能根本无法获得新固件更新,因此 Linux 内核增加了在启动期间应用 CPU 微代码更新的能力。Linux 微代码加载器支持三种加载方法:

  1. 内置微代码 (Built-in microcode) 可以编译进内核,然后由早期加载器应用。
  2. 早期加载 (Early loading) 在启动非常早期的阶段(在 initramfs 阶段之前)更新微代码,比后期加载更受推荐。对于存在严重硬件 Bug 的 CPU(如 Intel Haswell 和 Broadwell 处理器系列),这是强制要求的。
  3. 后期加载 (Late loading)(这 可能危险的)在启动后更新微代码,这可能太晚了,因为 CPU 可能已经尝试执行了有缺陷的指令。即使已经使用了早期加载,后期加载仍可用于在无需重启的情况下应用更新的微代码。

早期加载

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

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

请注意,由于用户的早期启动配置差异很大,Arch 的默认配置可能无法自动触发微代码更新。

自定义构建的内核

为了使 自定义内核 的早期加载能够工作,需要将 “CPU microcode loading support” 编译进内核,而不能编译为模块。这将启用 “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.confNoExtract 中,因为微代码文件将直接从 /usr/lib/firmware/*-ucode/ 中获取。
mkinitcpio

为了让 mkinitcpio 生成包含微代码的 initramfs 文件,请确保 /etc/mkinitcpio.confHOOKS 数组中包含 microcode

如果 autodetect 钩子在 microcode 之前,则仅包含当前 CPU 的微代码。要包含系统中能找到的所有 CPU 微代码文件,请将 microcode 钩子移至 autodetect 之前,或者完全移除 autodetect 钩子。

在生成 initramfs 时,mkinitcpio 将显示

-> Early uncompressed CPIO image generation successful

你可以使用 lsinitcpio(1) 来验证 initramfs 是否包含微代码更新文件。例如,针对 linux

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

对于 统一内核镜像 (UKI),你可以使用

# lsinitcpio --early /esp/EFI/linux/arch-linux.efi | 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 作为第一个 initramfs(在普通 initramfs 文件之前)来启用早期微代码更新。常见引导加载程序的说明如下。

在以下章节中,请将 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

使用 initrd 选项在初始 ramdisk 之前加载微代码,如下所示:

/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#Configuration 中描述的步骤启用传递多个 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"
手动引导段 (Manual boot stanzas)

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 两个 initramfs 文件之间不得有空格。INITRD 行必须完全如下面所示。

/boot/syslinux/syslinux.cfg 中,多个 initramfs 文件可以用逗号分隔。

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

LILO 以及其他潜在的旧版引导加载程序不支持多个 initramfs 镜像。请改用 #微代码 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

后期加载

警告 后期加载微代码被认为是危险的,使用它会使内核被污染 (taint)

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

后期加载要求内核在构建时设置 CONFIG_MICROCODE_LATE_LOADING=y,但目前 Arch 官方支持的内核 并非如此。[1]

后期加载微代码更新

要手动重新加载微代码(例如在更新了 /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 接受微代码更新

用户可以通过以下链接参考 Intel 的仓库或 Gentoo 关于 AMD 的 Wiki,以查看特定型号是否受支持:

检测可用的微代码更新

对于 Intel,可以使用 iucode_tool(8) 查明 /usr/lib/firmware/intel-ucode/ 中是否包含当前运行 CPU 的微代码。

  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. 如果匹配,将运行中微代码的当前版本 (revision) 与列出的 Patch 值进行比较。
注意 你也可以使用 lscpu(1)/proc/cpuinfo 的输出获取 family、model 和 stepping。但你需要将这些值转换为十六进制。

禁用微代码加载器

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

参见

© . This site is unofficial and not affiliated with Arch Linux.

Content is available under GNU Free Documentation License 1.3 or later unless otherwise noted.