跳转至内容

微代码 (Microcode)

来自 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 微码加载支持”编译到内核中,而不是 编译为模块。这将启用“早期加载微码”提示,应将其设置为 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.conf 中的 HOOKS 数组中包含 microcode

如果 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 作为第一个 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 选项在初始内存盘之前加载微码,如下所示:

/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 参数。根据文件是否位于单独分区的根目录下,使用 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  "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 行必须与下图所示完全一致:

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

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

后期加载

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

后期加载微码更新发生在系统启动之后。它使用 /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 的系列、型号和步进。例如,通过运行以下命令:
    # journalctl -k --grep='CPU0:'
    查看输出部分,例如 (family: 0x15, model: 0x10, stepping: 0x1)
  2. 根据 amd-ucode README 中的列表匹配相应的值。
  3. 如果匹配,请将当前运行微码的 当前修订版 与列出的 Patch 值进行比较。
注意 您也可以使用 lscpu(1)/proc/cpuinfo 输出获取系列、型号和步进。但您需要将值转换为十六进制。

禁用微码加载器

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

参见