关于固件

在某些较新的 PC 上,可能需要或希望加载固件以使其发挥最佳性能。内核或内核驱动程序在 /lib/firmware 中查找固件映像。但在 LFS 中,/lib 是指向 usr/lib 的符号链接,因此实际包含固件文件的目录是 /usr/lib/firmware

目前,大多数固件可以在 git 仓库中找到,可通过 URL https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/plain 在浏览器中查看。为了方便,LFS 项目创建了一个每日更新的镜像,这些固件文件可以通过 wget 或 Web 浏览器在 https://anduin.linuxfromscratch.org/BLFS/linux-firmware/ 访问。

要获取固件,请将浏览器指向上述仓库之一,然后下载您需要的项目。如果您想要所有这些固件文件(例如,您要将系统分发到多个硬件系统上),可以安装 git-2.55.0 并克隆 https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git,或者在浏览器中打开此 URL,并下载 Tag 表中列出的最新快照。

[重要]

重要

请注意,某些所需的固件文件(和目录)实际上是指向其他文件(或目录)的符号链接。这些符号链接并不存储在 Git 仓库中,而是在 WHENCE 文件中予以说明。每行以 Link: 开头的行描述一个符号链接。如果您正在下载所需项目,且它是一个这样的符号链接(或位于这样的符号链接目录中),您需要手动创建符号链接并下载目标。另一方面,如果您想要所有固件文件,请使用 ./copy-firmware.sh /usr/lib/firmware 命令,该命令将复制固件文件并创建 WHENCE 文件中的所有符号链接,而不是使用像 cp -r * /usr/lib/firmware/ 这样的普通复制命令。

对于某些其他固件,特别是 Intel 微码和某些 Wi-Fi 设备,所需的固件不在上述仓库中。下面将讨论其中一些,但有时需要在互联网上搜索所需固件。

固件文件通常被称为 blob,因为您无法确定它们会做什么。请注意,固件是在各种不同许可证下分发的,这些许可证不允许反编译或逆向工程。

PC 的固件分为四类:

[注意]

注意

虽然加载固件 blob 本身不需要,但以下工具可能有助于确定、获取或准备所需固件,以便将其加载到系统中: cpio-2.15(或 libarchive-3.8.8)、 git-2.55.0pciutils-3.15.0Wget-1.25.0

CPU 的微码更新

通常,微码可以由 BIOS 或 UEFI 加载,并且可以通过升级到这些的新版本进行更新。在 Linux 上,如果您使用的是 AMD 10h 或更高版本的处理器(于 2007 年末首次推出),或者使用的是 1998 年及以后的 Intel 处理器(Pentium4、Core 等),并且已发布更新的微码,则您也可以从内核加载微码。这些更新仅在机器断电前有效,因此需要在每次启动时应用。

[注意]

注意

在极少数情况下,来自内核的微码更新可能无效。例如,尽管 intel-microcode-20241029 包含旨在修复臭名昭著的过度电压问题的 Raptor Lake 微码修订版 0x12b(该问题会导致稳定性问题甚至永久性 CPU 损坏),但当内核启动时,微码已经 为时已晚,无法修复该问题。解决此问题的唯一方法是更新 BIOS。

随着新漏洞的出现,Intel 为其 Skylake 及更新处理器提供微码更新,并且过去也为 SandyBridge 及更新处理器提供更新,尽管这些处理器不再支持新的修复。新版本的 AMD 固件很少见,通常仅适用于少数型号,尽管主板制造商会获得 AGESA(AMD 通用封装软件架构)更新以更改 BIOS 值,例如支持更多内存变体、新的漏洞修复或更新的 CPU。

加载微码有两种方式,称为“早期”和“晚期”。早期加载在用户空间启动之前进行,晚期加载在用户空间启动之后进行。然而,晚期加载已知存在问题且不再受支持(参见内核提交 x86/microcode: Taint and warn on late loading)。事实上,早期加载是为了解决早期 Intel Haswell 处理器中一个特定的勘误表(该处理器启用了 TSX)所必需的(参见 Intel Disables TSX Instructions: Erratum Found in Haswell, Haswell-E/EP, Broadwell-Y)。如果没有此更新,glibc 在异常情况下可能会执行错误操作。

在本书的先前版本中,建议晚期加载微码以查看其是否被应用,然后使用 initrd 强制早期加载。但现在 Intel 微码压缩包的内容已有文档记录,并且 AMD 微码可以通过 Python 脚本读取以确定其适用的机器,因此没有真正的理由使用晚期加载。

仍有可能手动强制晚期加载微码。但这可能导致内核故障,您应自行承担风险。您需要重新配置内核以支持晚期加载,但早期加载始终受 x86(无论 32 位还是 64 位)系统上的 Linux 内核 6.6 或更高版本支持。此处的说明将向您展示如何为早期加载创建 initrd。也可以将相同的微码 bin 文件构建到内核中,这允许早期加载,但需要重新编译内核才能更新微码。

要确认您拥有的处理器(如果不止一个,它们将相同),请查看 /proc/cpuinfo。通过运行以下命令确定 cpu family、model 和 stepping 的十进制值(它还将报告当前的微码版本):

head -n7 /proc/cpuinfo

将 cpu family、model 和 stepping 转换为十六进制数字对,并记住 microcode 字段的值。现在您可以检查是否有任何可用的微码。

如果您正在为不同机器创建 initrd 以更新固件(如发行版所做的那样),请转到“微码的早期加载”并将所有 Intel blob 连接到 GenuineIntel.bin,或将所有 AMD blob 连接到 AuthenticAMD.bin。这会创建更大的 initrd——对于 20200609 更新中的所有 Intel 机器,大小为 3.0 MB,而单台机器通常为 24 KB。

Intel 的 CPU 微码

第一步是获取最新版本的 Intel 微码。这必须通过导航到 https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files/releases/ 并下载其中的最新文件来完成。在撰写本文时,最安全的微码版本是 microcode-20260227。以正常方式解压此文件,微码位于 intel-ucode 目录中,包含各种形式为 XX-YY-ZZ 的 blob。还有其他各种文件和一个发行说明。

过去,Intel 没有提供哪些 blob 更改了版本的详细信息,但现在发行说明详细说明了这一点。您可以将 /proc/cpuinfo 中的微码版本与发行说明中您的 CPU 型号的版本进行比较,以了解是否有更新。

为较旧处理器提供的最新固件用于处理现已公开的漏洞,对于其中一些漏洞,例如微架构数据采样(MDS),您可能希望通过禁用超线程来增强保护,或者由于其对编译时间的影响而禁用内核的默认缓解措施。请阅读 https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/index.html 上的在线文档。

对于 Meteor Lake 移动版(描述为 Intel(R) Core(TM) Ultra 5 125H CPU),相关值为 cpu family 6、model 140、stepping 4,因此在这种情况下所需的标识为 06-aa-04。发行说明称其最新微码版本为 0x25。如果 /proc/cpuinfomicrocode 字段的值为 0x25 或更大,则表示 BIOS 已应用微码更新。否则,请继续执行 “微码的早期加载”一节

AMD 的 CPU 微码

首先从 https://anduin.linuxfromscratch.org/BLFS/linux-firmware/amd-ucode/ 下载适用于您 CPU 系列的固件容器。系列始终以十六进制指定。10h 至 14h(16 至 20)系列位于 microcode_amd.bin 中。15h、16h、17h(Zen、Zen+、Zen2)和 19h(Zen3)系列有自己的容器,但很少有机器能获得更新的微码。相反,AMD 向主板制造商提供更新的 AGESA,制造商可能会据此提供更新的 BIOS。在 https://github.com/AMDESE/amd_ucode_info/blob/master/amd_ucode_info.py 有一个 Python3 脚本。下载该脚本并针对 bin 文件运行,以检查哪些处理器有更新。

对于这些示例中非常老的 Athlon(tm) II X2,其值为 cpu family 16、model 5、stepping 3,标识为 Family=0x10 Model=0x05 Stepping=0x03。amd_ucode_info.py 脚本输出的一行描述了其微码版本:

Family=0x10 Model=0x05 Stepping=0x03: Patch=0x010000c8 Length=960 bytes

如果 /proc/cpuinfomicrocode 字段的值为 0x10000c8 或更大,则表示 BIOS 已应用微码更新。否则,请继续执行 “微码的早期加载”一节

微码的早期加载

如果您已确定您的系统有可用的更新微码,那么是时候准备进行早期加载了。这需要额外的包 cpio-2.15(或 libarchive-3.8.8)并创建 initrd,然后需要将其添加到 grub.cfg 中。

在何处准备 initrd 无关紧要,一旦它正常工作,您可以将相同的 initrd 应用于此机器上的后续 LFS 系统或更新内核,至少在发布任何更新的微码之前。使用以下命令:

mkdir -p initrd/kernel/x86/microcode
cd initrd

对于 AMD 机器,使用以下命令(将 <MYCONTAINER> 替换为您的 CPU 系列容器的名称):

cp -v ../<MYCONTAINER> kernel/x86/microcode/AuthenticAMD.bin

或者对于 Intel 机器,使用以下命令复制适当的 blob:

cp -v ../intel-ucode/<XX-YY-ZZ> kernel/x86/microcode/GenuineIntel.bin

现在准备 initrd(您也可以使用 libarchive-3.8.8 中的 bsdcpio 代替 cpio):

find * | cpio -o -H newc > /boot/microcode.img

现在您需要在 /boot/grub/grub.cfg 中添加一个新条目,并且应该在节内的 linux 行之后添加一行新行。如果 /boot 是一个单独挂载点:

initrd /microcode.img

如果不是,则:

initrd /boot/microcode.img

如果您已经使用 initrd 启动(参见 “关于 initramfs”一节),则应将适当的 blob 或容器放入 /usr/lib/firmware 后,再次运行 mkinitramfs。更准确地说,在运行 mkinitramfs 之前,将 Intel blob 放入 /usr/lib/firmware/intel-ucode 目录,或将 AMD 容器放入 /usr/lib/firmware/amd-ucode 目录。或者,您可以将两个 initrd 放在同一行,如 initrd /microcode.img /other-initrd.img(如果 /boot 不是单独挂载点,请按上述方式调整)。

现在您可以使用添加的 initrd 重新启动,然后使用以下命令检查早期加载是否成功:

dmesg | grep -e 'microcode' -e 'Linux version' -e 'Command line'

如果您更新以解决漏洞,可以查看 lscpu 命令的输出,以了解现在报告的内容。

在 AMD 和 Intel 机器上,早期加载发生的位置和时间有很大不同。首先,一个 Intel(Meteor Lake 移动版)早期加载的示例:

[    0.000000] Linux version 6.17.6 (xry111@stargazer) (gcc (GCC) 15.2.0, GNU ld (GNU Binutils) 2.45) #1 SMP PREEMPT_DYNAMIC Sun Nov  9 21:03:48 CST 2025
[    0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-6.17.6 root=/dev/nvme0n1p6 ro
[    1.459687] microcode: Current revision: 0x00000025
[    1.459699] microcode: Updated early from: 0x00000024

一个历史悠久的 AMD 示例:

[    0.000000] Linux version 4.15.3 (ken@testserver) (gcc version 7.3.0 (GCC))
               #2 SMP Sun Feb 18 02:32:03 GMT 2018
[    0.000000] Command line: BOOT_IMAGE=/vmlinuz-4.15.3-sda5 root=/dev/sda5 ro
[    0.307619] microcode: microcode updated early to new patch_level=0x010000c8
[    0.307678] microcode: CPU0: patch_level=0x010000c8
[    0.307723] microcode: CPU1: patch_level=0x010000c8
[    0.307795] microcode: Microcode Update Driver: v2.2.

显卡的固件

ATI Radeon 视频芯片的固件

早期的 radeon 设备仅需要一个 2 KB 的固件 blob。较新的设备需要几个不同的 blob,其中一些更大。radeon 固件目录的总大小超过 500 KB——在大型现代系统上,您可能可以腾出空间,但每次构建系统时安装所有未使用的文件仍然是一种冗余。

更好的方法是安装 pciutils-3.15.0,然后使用 lspci 识别安装的 VGA 控制器。

有了这些信息,请查看 Xorg 维基的 RadeonFeature 页面,了解 Decoder ring for engineering vs marketing names 以识别系列(您可能需要了解此信息以用于 BLFS 中的 Xorg 驱动程序——Southern Islands 和 Sea Islands 使用 radeonsi 驱动程序)和具体型号。

既然您知道使用的控制器,请查阅 Gentoo 维基的 Radeon 页面,其中有一个表格列出了各种芯片组所需的固件 blob。请注意,Southern Islands 和 Sea Islands 芯片在 3.17 及更新内核上使用的固件与旧内核不同。识别并下载所需的 blob,然后安装它们:

mkdir -pv /usr/lib/firmware/radeon
cp -v <YOUR_BLOBS> /usr/lib/firmware/radeon

建议将内核 amdgpu 驱动程序构建为模块,因为固件文件在加载时需要可访问。如果出于任何原因将其构建为内核映像的一部分,您需要将固件文件包含在 initramfs 中(详细信息请阅读 “关于 initramfs”一节),或将它们包含在内核映像本身中(详细信息请阅读 “在内核映像中包含固件 Blob”一节)。

AMD/ATI amdgpu 视频芯片的固件

所有使用 amdgpu 内核驱动程序的视频控制器都需要固件,无论您将使用 xorg amdgpu 驱动程序、xserver 的 modesetting 驱动程序,还是仅使用内核模式设置来获得大于 80x25 的控制台帧缓冲。

安装 pciutils-3.15.0 并使用它检查型号名称(查找“VGA compatible controller:”)。如果您有 APU(加速处理单元,即 CPU 和视频在同一芯片上),那可能会告诉您名称。如果您有单独的 amdgpu 视频卡,则需要搜索以确定它使用的名称(例如,描述为 Advanced Micro Devices, Inc. [AMD/ATI] Baffin [Radeon RX 550 640SP / RX 560/560X] 的卡需要 Polaris11 固件)。在 Gentoo 维基的 AMDGPU 页面末尾的内核部分有一个“Family, Chipset name, Product name and Firmware”表。

一旦确定了固件名称,请安装其所有相关文件。例如,上面提到的 Baffin 卡有 21 个不同的 polaris11* 文件,诸如 renoir 和 picasso 之类的 APU 至少有 12 个文件,并且在未来的更新中可能会增加更多(例如,raven APU 现在有第 13 个文件 raven_ta.bin)。

mkdir -pv /usr/lib/firmware/amdgpu
cp -v <YOUR_BLOBS> /usr/lib/firmware/amdgpu

如果磁盘空间不是问题,您可以安装所有当前的 amdgpu 固件文件,而不必担心具体安装的是哪个芯片组。

建议将内核 amdgpu 驱动程序构建为模块,因为固件文件在加载时需要可访问。如果出于任何原因将其构建为内核映像的一部分,您需要将固件文件包含在 initramfs 中(详细信息请阅读 “关于 initramfs”一节),或将它们包含在内核映像本身中(详细信息请阅读 “在内核映像中包含固件 Blob”一节)。

NVIDIA 视频芯片的固件

从 Kepler 开始的一些 NVIDIA GPU(包括所有 NVIDIA GeForce RTX GPU 和 GTX 9xx 系列及更新)需要 NVIDIA 签名的固件才能工作。对于 Nouveau 驱动程序,NVIDIA 已在 linux-firmware 的 nvidia/ 目录中发布了签名的固件文件。阅读 Nouveau 维基的 CodeNames 页面 以找出您的 NVIDIA GPU 的代号(例如,GeForce RTX 5080 的代号为 GB203)。您需要的固件文件目录名称是将代号转换为小写的结果(例如 gb203)。该目录(或其某些内容)可能实际上是指向另一个目录(或另一个目录中的某些文件)的符号链接,然后您需要自己 创建符号链接并下载其目标(例如,gb207 是指向 gb202 的符号链接)。

如果您在 linux-firmware 树或 WHENCE 文件(作为符号链接)中都找不到 GPU 的目录,则意味着您的 GPU 不需要任何固件,或者它比 Blackwell(RTX 50xx 系列)更新,并且其固件尚未发布(截至 2025 年中)。

对于从 Tesla 到 Kepler 的 NVIDIA GPU,Nouveau 驱动程序需要一些额外的固件来支持视频解码加速。这些固件文件未由 NVIDIA 发布,但可以从 NVIDIA 二进制驱动程序中提取。关于哪些芯片需要提取的固件,更准确的信息请参见 Nouveau 维基的 VideoAcceleration。要提取并安装这些固件文件,请执行:

wget https://anduin.linuxfromscratch.org/BLFS/nvidia-firmware/extract_firmware.py
wget https://us.download.nvidia.com/XFree86/Linux-x86/340.32/NVIDIA-Linux-x86-340.32.run
sh NVIDIA-Linux-x86-340.32.run --extract-only
python3 extract_firmware.py
mkdir -p /usr/lib/firmware/nouveau
cp -d nv* vuc-* /usr/lib/firmware/nouveau/

网络接口的固件

内核喜欢为某些网络驱动程序加载固件,尤其是 Realtek 的驱动程序(/usr/lib/linux-firmware/rtl_nic/ 目录),但它们通常在没有固件的情况下也能工作。因此,您可以启动内核,检查 dmesg 中有关此缺失固件的消息,如有必要,下载固件并将其放在 /usr/lib/firmware 中的指定目录中,以便在后续启动时找到它。请注意,对于当前内核,无论驱动程序是编译进内核还是构建为模块,这都有效,无需将此固件构建到内核中。以下是一个示例,其中 R8169 驱动程序已编译进内核,但固件未提供。一旦提供了固件,后续启动中就不会再提到它。

dmesg | grep firmware | grep r8169
[    7.018028] r8169 0000:01:00.0: Direct firmware load for rtl_nic/rtl8168g-2.fw failed with error -2
[    7.018036] r8169 0000:01:00.0 eth0: unable to load firmware patch rtl_nic/rtl8168g-2.fw (-2)

无线设备监管数据库的固件

不同国家对无线设备的无线电频谱使用有不同的规定。您可以安装固件,使无线设备遵守当地的频谱法规,这样您就不会被当地机构询问,也不会发现您的无线网卡干扰其他设备(例如遥控器)的频率。监管数据库固件可以从 https://kernel.org/pub/software/network/wireless-regdb/ 下载。要安装它,只需从压缩包中提取 regulatory.dbregulatory.db.p7s/usr/lib/firmware。请注意,cfg80211 驱动程序需要被选为模块,才能加载 regulatory.* 文件,或者这些文件需要作为固件包含在内核中,如上文 “显卡的固件”一节 所述。

接入点(AP)会向您的无线网卡发送国家代码,wpa_supplicant-2.11 会告诉内核从 regulatory.db 加载该国家的法规并强制执行。请注意,有些 AP 不发送此国家代码,因此您可能被限制在相当受限的使用范围内(特别是如果您想将接口用作 AP)。

音频开放固件(Sound Open Firmware)

某些系统(尤其是配备最新 Intel CPU 的笔记本电脑)利用 CPU 附带的 DSP 与音频编解码器连接。必须将 Sound Open Firmware 加载到 DSP 上才能使其正常工作。这些固件文件可以从 https://github.com/thesofproject/sof-bin/releases 下载。解压压缩包并进入解压后的目录,然后以 root 用户身份安装固件:

install -vdm755 /usr/lib/firmware/intel &&
cp -rv sof* /usr/lib/firmware/intel/

alsa-lib-1.2.16.1 还需要使用 Sound Open Firmware 的系统的 Use Case Manager 配置文件。请阅读 alsa-lib-1.2.16.1 页面以获取安装说明。一旦固件被加载(您可能需要重新启动以便内核加载它们)并且 UCM 配置文件安装完毕,按照 “Configuring ALSA Utilities”一节 为 ALSA 正确设置您的声卡。

其他设备的固件

识别正确的固件通常需要您安装 pciutils-3.15.0,然后使用 lspci 识别设备。然后您应该在线搜索以检查它使用哪个模块、哪个固件以及从哪里获取固件——并非所有固件都在 linux-firmware 中。

如果可能,您应该在首次启动 LFS 系统时使用有线连接。要使用无线连接,您需要使用网络工具,例如 iw-6.17Wireless Tools-29wpa_supplicant-2.11

其他设备(例如某些 SCSI 控制器、蓝牙适配器或电视录像机)也可能需要固件。同样的原则适用。

在内核映像中包含固件 Blob

某些驱动程序,尤其是 ATI 或 AMD GPU 的驱动程序,要求固件文件在加载时可访问。处理这些驱动程序的最简单方法是将其构建为内核模块。另一种方法是创建包含固件文件的 initramfs(详细信息请阅读 “关于 initramfs”一节)。如果您不想使用这两种方法,可以将固件文件包含在内核映像本身中。首先将所需的固件文件安装到 /usr/lib/firmware 中,然后设置以下内核配置并重新构建内核:

Device Drivers --->
  Generic Driver Options --->
    Firmware loader --->
      (xx/aa.bin xx/bb.bin) Build named firmware blobs into the kernel binary
                                                           ...  [EXTRA_FIRMWARE]
      # This is the default, you can change it to "/usr/lib/firmware"
      # if you want:
      (/lib/firmware)         Firmware blobs root directory [EXTRA_FIRMWARE_DIR]

xx/aa.bin xx/bb.bin 替换为所需固件文件相对于 /usr/lib/firmware 的路径列表,以空格分隔。一种比手动输入列表(可能很长)更容易的方法是运行以下命令:

echo CONFIG_EXTRA_FIRMWARE='"'$({ cd /usr/lib/firmware; echo amdgpu/* })'"' >> .config
make oldconfig

amdgpu/* 替换为匹配所需固件文件的 shell 模式。

[警告]

警告

请勿将包含固件的内核映像分发给他⼈,否则可能违反 GPL。