微码 - Arch Linux 中文维基

跳转到内容

# 微码

来自 Arch Linux 中文维基
翻译状态：

- 本文（或部分内容）译自 Microcode，最近一次同步于 2025-04-09，若英文版本有所更改，则您可以帮助同步与翻译更改的内容。
- 您可以在 ArchWiki 的对应页面找到本文翻译的原始修订历史。
- 本文可能与英文原文存在出入。

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

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

## 安装

要获取更新的微码，根据处理器类型，安装以下其中一个软件包：

- amd-ucode包 用于 AMD 处理器，
- intel-ucode包 用于 Intel 处理器。

mkinitcpio 和 dracut 默认会生成组合的 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文件。此方法优于#Microcode in a separate initramfs file，因为不需要额外的引导参数配置。

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

##### mkinitcpio

为了使mkinitcpio生成包含微码的initramfs文件，请确保`microcode`在`/etc/mkinitcpio.conf`中的`HOOKS`数组中。

如果`autodetect`钩子位于`microcode`之前，则仅包含当前CPU的微码。要包含系统上可以找到的所有CPU微码文件，请将`microcode`钩子移动到`autodetect`之前或完全删除`autodetect`钩子。

生成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制造商，即`amd`或`intel`。

##### GRUB

grub-mkconfig将自动检测微码更新并适当配置GRUB。安装微码包后，通过运行以下命令重新生成GRUB配置以激活加载微码更新：

    # grub-mkconfig -o /boot/grub/grub.cfg

或者，手动管理GRUB配置文件的用户可以添加`/boot/cpu_manufacturer-ucode.img`（或`/cpu_manufacturer-ucode.img`如果`/boot`是单独的分区）如下：

    /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-ucode包或intel-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.img`或`initrd=cpu_manufacturer-ucode.img`，具体取决于`/boot`中的文件是否在单独分区的根目录中。

微码需要是引导选项列表中声明的第一个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.img`和`initramfs-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镜像。请改用#Microcode initramfs packed together with the main initramfs in one file方法。

##### Limine

对于Limine，您只需通过`MODULE_PATH`选项在您的limine.conf文件中添加微码的路径。以下是一个示例：

    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-ucode包和intel-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 系统上使用延迟加载时，输出将显示重新加载微码前的旧微码版本以及重新加载后的新版本。

## 参见

- 更新微码 – 社区经验
- 关于 Intel 微码更新的笔记 – Ben Hawkes
- 内核微码加载器 – 内核文档
- Haswell/Broadwell 中的勘误 – AnandTech
- iucode-tool GitLab 项目

## 哪些 CPU 接受微码更新

用户可以查阅 Intel 的仓库或 Gentoo 的 AMD 维基，以查看特定型号是否受支持：

- Gentoo:AMD microcode#Microcode firmware files。
- Intel 的 Github 仓库。

### 检测可用的微码更新

对于 Intel，可以使用 iucode_tool(8) 来检查 `/usr/lib/firmware/intel-ucode/` 是否包含运行中 CPU 的微码。

1. 安装 intel-ucode包 和 iucode-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` 输出来获取系列、型号和步进。但您需要将值转换为十六进制。

## 参见

- 更新微码 – 社区经验
- 关于 Intel 微码更新的笔记 – Ben Hawkes
- 内核微码加载器 – 内核文档
- Haswell/Broadwell 中的勘误 – AnandTech
- iucode-tool GitLab 项目

## 禁用微码加载器

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

## 参见

- Updating microcodes – Experiences in the community
- Notes on Intel Microcode updates – Ben Hawkes
- Kernel microcode loader – kernel documentation
- Erratum found in Haswell/Broadwell – AnandTech
- iucode-tool GitLab project
- Intel, AMD, VIA & Freescale CPU Microcode Repositories
- CPUID dumps

分类：​

- CPU
- 安全

微码
添加话题