Microcode (简体中文)

From ArchWiki
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
翻译状态:本文是 Microcode翻译。上次翻译日期:2020-05-19。如果英文版本有所更改,则您可以帮助同步翻译。

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

使用 AMD 或 Intel CPU 的用户都应该安装这些微代码更新,以确保系统稳定性。

通常主板的固件会包含微代码更新,并在初始化时使用最新的微代码版本。但是 OEM 可能无法给所有机型提供及时的最新固件,所以 Linux 内核提供了启动时应用最新微代码的功能。Linux microcode 加载器 支持三种加载方式:

  1. 早期加载 在非常早的启动阶段生效,比 initramfs 阶段还早,所以是推荐的方式,如果 CPU 有严重的硬件问题时尤其如此,比如 Intel Haswell 和 Broadwell 处理器。
  1. 后期加载 在启动后生效,有时这个时间太晚了,因为 CPU 可能已经执行了有问题的指令集。即使已经启用了早加载,晚加载依然有价值,可以让系统不重启的时候也应用到最新的微代码更新。
  1. 内置微代码 可以编译到内核中,在启动的早期阶段应用。.

启用早期微码更新

由于用户的早期引导配置具有很大的可变性,因此Arch的默认配置不会自动启用早加载。AUR 里很多内核都遵循这个设定。

要启用早加载,必须通过把 /boot/amd-ucode.img 或者 /boot/intel-ucode.img 作为第一个 initrd 添加到 bootloader 的配置文件里来启用。下面的章节有常见的 bootloader 的配置。

注意:cpu_manufacturer 换成 CPU 的制造商, 即 amd 或者 intel
提示: 对于 安装在可移动设备的 Arch Linux,两个厂商的微码文件都要加到配置文件里,顺序没有关系。

安装

对于 AMD 处理器,安装 amd-ucode

对于 Intel 处理器,安装 intel-ucode

如果你在一个移动介质上安装Arch Linux,需要应该安装以上两个厂商处理器的微码软件包。

在自定义内核中启用微代码加载

启用 “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-mkconfig does not add the microcode images to the fallback initramfs boot entry. See FS#60999.

或者,手动管理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

/boot/loader/entries/entry.conf
 title   Arch Linux
 linux   /vmlinuz-linux
 initrd  /cpu_manufacturer-ucode.img
 initrd  /initramfs-linux.img
 options ...

最新的 cpu_manufacturer-ucode.img 必须在启动时存在于 ESP分区. ESP 必须挂载到 /boot,这样才能在 amd-ucodeintel-ucode 更新时才能更新里面的 img 文件。否则需要在微代码更新时手动将 /boot/cpu_manufacturer-ucode.img 复制到 ESP。

Unified kernel images

For unified kernel images, first generate the initrd to integrate by creating a new one as follows:

$ cat /boot/cpu_manufacturer-ucode.img /boot/initramfs-linux.img > my_new_initrd.img
$ objcopy ... --add-section .initrd=my_new_initrd .img

EFISTUB

Append two initrd= options:

initrd=\cpu_manufacturer-ucode.img initrd=\initramfs-linux.img

rEFInd

Edit boot options in /boot/refind_linux.conf and add initrd=boot\cpu_manufacturer-ucode.img (or initrd=cpu_manufacturer-ucode.img if /boot is a separate partition) as the first initramfs. For example:

"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"
提示: Users who previously did not specify an initrd kernel parameter will need to follow the steps described in rEFInd#Configuration to enable passing of multiple initrd parameters.

如果在 esp/EFI/refind/refind.conf 中使用 手动配置 定义所要引导的内核,那么添加 initrd=/boot/cpu_manufacturer-ucode.img (如果 /boot 独立分区则添加initrd=/cpu_manufacturer-ucode.img) 到选项行。并不需要修改配置的主干部分。

 options  "root=PARTUUID=XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX rw add_efi_memmap initrd=boot\cpu_manufacturer-ucode.img"

Syslinux

注意:cpu_manufacturer-ucode.imginitramfs-linux initrd 文件间不要用空格,下面的点不是省略号,INITRD 行必须和下面示例中一样。

在配置文件/boot/syslinux/syslinux.cfg中,多个 initrd 可以通过逗号来分隔。

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

LILO

LILO和其他的老版本启动引导器可能不支持多个initrd镜像,所以intel-ucodeinitramfs-linux 需要被合并成一个镜像。

警告: 每次更新内核后都要重新合并!
注意: 顺序很重要。原来的 initramfs-linux 必须在 intel-ucode之后

合并两个镜像并生成 initramfs-merged.img

# cat /boot/intel-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/ 文件夹里的文件。

对于 AMD 处理器来说,微码更新的文件由 linux-firmware 软件包提供。

对于 Intel 的处理器,没有任何软件包提供微码更新文件 (FS#59841)。要使用后期加载,你可能需要从英特尔提供的压缩包里手动解压出 intel-ucode/ 文件夹。

启用微码更新后期加载

后期加载是默认启用的,由 /usr/lib/tmpfiles.d/linux-firmware.conf 实现。在启动过程完成之后,微码更新文件由 systemd-tmpfiles-setup.service(8) 解析,实现 CPU 微码更新。

如果要手动触发微码更新:

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

更新了 linux-firmware 之后想不重启就应用微码更新,这个命令比较有用。要自动化这个过程,可以创建一个 pacman hook

/etc/pacman.d/hooks/microcode_reload.hook
[Trigger]
Operation = Upgrade
Type = Path
Target = usr/lib/firmware/amd-ucode/*

[Action]
Description = Applying CPU microcode updates...
When = PostTransaction
Depends = sh
Exec = /bin/sh -c 'echo 1 > /sys/devices/system/cpu/microcode/reload'

禁用微码更新的后期加载

对于 AMD 的处理器来说,即使不安装 amd-ucode,CPU 的微码仍然会被更新,因为所需的文件是由 linux-firmware 提供的(FS#59840)。

虚拟机容器 (FS#46591) 不支持 CPU 微代码更新,所以需要禁用此功能。需要覆盖 /usr/lib/tmpfiles.d/linux-firmware.conf 这个 tmpfile,通过在 /etc/tmpfiles.d/ 创建一个名字也是 linux-firmware.conf 的文件来实现。当然也可以这样来实现覆盖的效果:

# ln -s /dev/null /etc/tmpfiles.d/linux-firmware.conf

验证微指令已在启动时更新

使用 /usr/bin/dmesg 可以查看微代码有没有更新:

# dmesg | grep microcode

在 Intel 系统上,你应当会看到和下面类似的一些东西,表明微指令已在早先更新:

[    0.000000] CPU0 microcode updated early to revision 0x1b, date = 2014-05-29
[    0.221951] CPU1 microcode updated early to revision 0x1b, date = 2014-05-29
[    0.242064] CPU2 microcode updated early to revision 0x1b, date = 2014-05-29
[    0.262349] CPU3 microcode updated early to revision 0x1b, date = 2014-05-29
[    0.507267] microcode: CPU0 sig=0x306a9, pf=0x2, revision=0x1b
[    0.507272] microcode: CPU1 sig=0x306a9, pf=0x2, revision=0x1b
[    0.507276] microcode: CPU2 sig=0x306a9, pf=0x2, revision=0x1b
[    0.507281] microcode: CPU3 sig=0x306a9, pf=0x2, revision=0x1b
[    0.507286] microcode: CPU4 sig=0x306a9, pf=0x2, revision=0x1b
[    0.507292] microcode: CPU5 sig=0x306a9, pf=0x2, revision=0x1b
[    0.507296] microcode: CPU6 sig=0x306a9, pf=0x2, revision=0x1b
[    0.507300] microcode: CPU7 sig=0x306a9, pf=0x2, revision=0x1b
[    0.507335] microcode: Microcode Update Driver: v2.00 <tigran@aivazian.fsnet.co.uk>, Peter Oruba

如果硬件比较新,也可能没有任何微代码更新,结果应该是下面这样:

[    0.292893] microcode: CPU0 sig=0x306c3, pf=0x2, revision=0x1c
[    0.292899] microcode: CPU1 sig=0x306c3, pf=0x2, revision=0x1c
[    0.292906] microcode: CPU2 sig=0x306c3, pf=0x2, revision=0x1c
[    0.292912] microcode: CPU3 sig=0x306c3, pf=0x2, revision=0x1c
[    0.292956] microcode: Microcode Update Driver: v2.00 <tigran@aivazian.fsnet.co.uk>, Peter Oruba

在 AMD 系统上,微指令会在启动的更晚阶段被更新,所以输出会看起来像这样:

[    0.807879] microcode: CPU0: patch_level=0x01000098
[    0.807888] microcode: CPU1: patch_level=0x01000098
[    0.807983] microcode: Microcode Update Driver: v2.00 <tigran@aivazian.fsnet.co.uk>, Peter Oruba
[   16.150642] microcode: CPU0: new patch_level=0x010000c7
[   16.150682] microcode: CPU1: new patch_level=0x010000c7
注意: 微代码的日期和 intel-ucode 软件包版本不一定一样,而是代表英特尔最后一次更新微代码的时间。

哪些 CPU 可以接受微指令更新

可以从 Intel 和 AMD 的网站查看支持的型号:

检查可用微指令更新

可以通过 iucode-tool 来检查 intel-ucode.img 是否包含适用于你 CPU 的微指令映像。

  1. 安装 intel-ucode (检测并不需要修改 initrd)
  2. 从 AUR 安装 iucode-tool
  3. 加载 cpuid 内核模块:
    # modprobe cpuid
  4. 解包微指令映像,并根据你的 cpuid 搜索是否适用:
    # bsdtar -Oxf /boot/intel-ucode.img | iucode_tool -tb -lS - 
  5. 如果有更新可用,它应该会在 selected microcodes 之下显示
  6. 微码可能已经在你的BIOS里,所以不会在dmesg里出现。和正在运行的微码对比:grep microcode /proc/cpuinfo

参阅