Linux 软件包包含 Linux 内核。
构建内核需要三步 —— 配置、编译、安装。阅读内核源代码树中的 README
文件,了解不同于本手册的内核配置方法。
初次构建 Linux 内核是 LFS 构建过程中最具挑战性的环节之一。内核配置依赖于系统硬件和您的个人需求。内核配置包含大约 12,000 个选项,尽管只有约三分之一对于大多数计算机系统是必要的。LFS 编辑建议不熟悉内核编译的用户严格遵循以下步骤。这些步骤的目的是使您能够在第 11.3 节 “重启系统”中重启进入 LFS 系统,并通过命令行登录。这里给出的步骤并不试图优化或定制内核配置。
https://www.linuxfromscratch.org/hints/downloads/files/kernel-configuration.txt 介绍了内核配置的常识。https://anduin.linuxfromscratch.org/LFS/kernel-nutshell/ 提供了更多关于内核配置的信息。这两份文档都有些过时,但仍然较好地概括了配置过程。
如果所有其他尝试都无法解决问题,可以在 lfs-support 邮件列表提问。注意为了防止垃圾邮件,必须先订阅列表才能向列表发送邮件。
运行以下命令,准备编译内核:
make mrproper
该命令确保内核源代码树绝对干净,内核开发组建议在每次编译内核前运行该命令。尽管内核源代码树在解压后应该是干净的,但这并不完全可靠。
有多种配置内核选项的方法。例如,通常我们通过目录驱动的界面完成这一工作:
make menuconfig
以上命令中可选的 make 环境变量及含义:
LANG=<host_LANG_value>
LC_ALL=
它们根据宿主使用的 locale 建立 locale 设定。在 UTF-8 Linux 文本终端下,有时必须这样做才能正确绘制基于 ncurses 的配置菜单接口。
在这种情况下,一定要将 <host_LANG_value>
替换成宿主环境中的 $LANG
变量值。您也可以使用宿主环境中
$LC_ALL
或 $LC_CTYPE
的值代替。
这会启动 ncurses 目录驱动的界面。如果希望了解其他 (图形) 界面,可以输入 make help。
一个较好的初始内核配置可以通过运行 make defconfig 获得。它会考虑您的当前系统体系结构,将基本内核配置设定到较好的状态。
一定要按照以下列表启用/禁用/设定其中列出的内核特性,否则系统可能不能正常工作,甚至根本无法引导:
General setup ---> [ ] Compile the kernel with warnings as errors [WERROR] CPU/Task time and stats accounting ---> [*] Pressure stall information tracking [PSI] [ ] Require boot parameter to enable pressure stall information tracking ... [PSI_DEFAULT_DISABLED] < > Enable kernel headers through /sys/kernel/kheaders.tar.xz [IKHEADERS] [*] Control Group support ---> [CGROUPS] [*] Memory controller [MEMCG] [ ] Configure standard kernel features (expert users) ---> [EXPERT] Processor type and features ---> [*] Build a relocatable kernel [RELOCATABLE] [*] Randomize the address of the kernel image (KASLR) [RANDOMIZE_BASE] General architecture-dependent options ---> [*] Stack Protector buffer overflow detection [STACKPROTECTOR] [*] Strong Stack Protector [STACKPROTECTOR_STRONG] Device Drivers ---> Generic Driver Options ---> [ ] Support for uevent helper [UEVENT_HELPER] [*] Maintain a devtmpfs filesystem to mount at /dev [DEVTMPFS] [*] Automount devtmpfs at /dev, after the kernel mounted the rootfs ... [DEVTMPFS_MOUNT] Firmware Drivers ---> [*] Mark VGA/VBE/EFI FB as generic system framebuffer [SYSFB_SIMPLEFB] Graphics support ---> <*> Direct Rendering Manager (XFree86 4.1.0 and higher DRI support) ---> ... [DRM] [*] Display a user-friendly message when a kernel panic occurs ... [DRM_PANIC] (kmsg) Panic screen formatter [DRM_PANIC_SCREEN] [*] Enable legacy fbdev support for your modesetting driver ... [DRM_FBDEV_EMULATION] <*> Simple framebuffer driver [DRM_SIMPLEDRM] Console display driver support ---> [*] Framebuffer Console support [FRAMEBUFFER_CONSOLE]
如果在构建 64 位系统,还需要启用一些特性。如果使用 menuconfig 进行配置,需要首先启用 CONFIG_PCI_MSI
,然后启用 CONFIG_IRQ_REMAP
,最后启用 CONFIG_X86_X2APIC
,这是因为只有选定了一个选项的所有依赖项后,该选项才会出现。
Processor type and features ---> [*] Support x2apic [X86_X2APIC] Device Drivers ---> [*] PCI support ---> [PCI] [*] Message Signaled Interrupts (MSI and MSI-X) [PCI_MSI] [*] IOMMU Hardware Support ---> [IOMMU_SUPPORT] [*] Support for Interrupt Remapping [IRQ_REMAP]
如果正在构建 32 位系统,且系统运行的硬件有超过 4GB 内存,调整内核配置,使其能够使用多达 64GB 物理内存:
Processor type and features ---> High Memory Support ---> (X) 64GB [HIGHMEM64G]
如果 LFS 系统分区在 NVME SSD 上 (即,分区的设备节点是 /dev/nvme*
,而非 /dev/sd*
),启用 NVME 支持,否则 LFS 系统无法引导:
Device Drivers ---> NVME Support ---> <*> NVM Express block device [BLK_DEV_NVME]
根据系统的需求,可能需要一些其他配置选项。BLFS 软件包需要的内核配置选项列表可以在 BLFS 内核配置索引查阅。
如果您的硬件支持 UEFI,且您希望通过 UEFI 引导 LFS 系统,则您需要按照 BLFS 页面的说明,调整一些内核配置选项,即使您准备使用宿主发行版提供的 UEFI 加载器引导 LFS 系统,也需要进行调整。
上述配置选项的含义:
Randomize the
address of the kernel image (KASLR)
为内核映像启用 ASLR,以预防一些基于内核中关键数据或代码的固定地址的攻击。
Compile the
kernel with warnings as errors
如果使用了和内核开发者不同的编译器和/或配置,启用该选项可能导致构建失败。
Enable kernel
headers through /sys/kernel/kheaders.tar.xz
启用该选项将会导致构建内核需要 cpio。LFS 没有安装 cpio。
Configure
standard kernel features (expert users)
该选项会导致配置界面出现一些新选项,但改变这些选项的设定值可能导致危险后果。不要使用该选项,除非您知道您在做什么。
Strong Stack
Protector
为内核启用 SSP。我们通过在配置 GCC 时使用 --enable-default-ssp
,已经为所有用户态代码启用了它,但是内核并不使用
GCC 默认的 SSP 设定。因此我们在这里显式地启用它。
Support for
uevent helper
如果启用了该选项,它可能干扰 Udev 的设备管理。
Maintain a
devtmpfs
该选项会使内核自动创建设备节点,即使 Udev 没有运行。Udev 之后才在这些设备节点的基础上运行,管理它们的访问权限并为它们建立符号链接。所有 Udev 用户都需要启用该选项。
Automount
devtmpfs at /dev
该选项使得内核在切换到根文件系统之后,执行 init 前,将内核获知的设备信息挂载到 /dev。
Display a
user-friendly message when a kernel panic
occurs
该选项使得内核在内核恐慌时正确显示消息。如果不启用它,诊断内核恐慌原因会更加困难:如果没有运行 DRM
驱动,则我们只能使用 VGA 控制台,而它只能显示 24 行,因此有用的内核消息往往已被刷新到屏幕以外;而如果正在运行
DRM 驱动,在内核恐慌时屏幕显示往往会完全错乱。在 Linux-6.12 中,适用于主流 GPU
型号的驱动程序都无法真正支持该选项提供的功能,但在专用的 GPU 驱动加在之前,VESA (或 EFI)
帧缓冲之上运行的简单帧缓冲驱动 (“Simple framebuffer driver”)
能够支持它。如果将专用的 GPU 驱动构建为内核模块 (而非内核映像的一部分),且没有使用
initramfs,则这一功能在根文件系统成功挂载之前会正常工作,而这足以提供诊断大多数由错误配置 LFS
(例如,第 10.4 节 “使用 GRUB
设定引导过程” 中 root=
的设定值不正确) 导致的内核恐慌。
Panic screen
formatter
将该选项设为 kmsg
,以确保在内核恐慌时显示恐慌前的内核消息。该选项的默认值,user
,会导致内核只显示一条“用户友好”的,对于诊断毫无帮助的消息。还有一个可选的值
qr_code
,会使得内核将恐慌前的消息压缩到一个二维码中,并显示该二维码。和文本输出相比,使用外部设备
(如智能手机) 解码二维码能得到更多行内核消息。但二维码输出功能需要 Rust 编译器才能构建,而 LFS 不提供
Rust 编译器。
Mark VGA/VBE/EFI
FB as generic system framebuffer
和 Simple framebuffer driver
它们允许使用 VESA 帧缓冲 (或者如果使用 UEFI 引导 LFS 系统,则使用 EFI 帧缓冲) 作为 DRM 设备。GRUB 会设置好 VESA 帧缓冲 (在使用 UEFI 时,EFI 固件会设置好 EFI 帧缓冲),这样在 GPU 专用的 DRM 驱动加载前,基于 DRM 的内核恐慌处理程序也能正常工作。
Enable legacy
fbdev support for your modesetting driver
和
Framebuffer Console
support
它们允许使用基于 DRI (Direct Rendering Infrastructure) 的 GPU 驱动显示
Linux 控制台。鉴于已经启用了 CONFIG_DRM
(Direct Rendering Manager),需要同时启用这两项特性,否则一旦 DRI
驱动被加载,就只能看到空白屏幕。
Support
x2apic
支持以 x2APIC 模式运行 64 位 x86 处理器的中断控制器。64 位 x86 系统的固件可能启用了 x2APIC,此时未启用该选项的内核在引导时会发生内核恐慌。该选项在固件禁用 x2APIC 时没有作用,但无害。
某些情况下,make oldconfig
更为合适。阅读 README
文件了解更多信息。
如果希望的话,也可以将宿主系统的内核配置文件 .config
拷贝到解压出的 linux-6.12.5
目录
(前提是可以找到该文件)。然而我们不推荐这样做,一般来说,浏览整个配置目录,并从头创建内核配置是更好的选择。
编译内核映像和模块:
make
如果要使用内核模块,可能需要在 /etc/modprobe.d
中写入模块配置。讨论模块和内核配置的信息位于第 9.3 节 “设备和模块管理概述”和
linux-6.12.5/Documentation
目录下的内核文档中。另外 modprobe.d(5)
也可以作为参考。
如果内核配置使用了模块,安装它们:
make modules_install
在内核编译完成后,需要进行额外步骤完成安装,一些文件需要拷贝到 /boot
目录中。
如果要使用单独的 /boot
分区 (包括和宿主发行版共用一个
/boot
分区的情况),需要将这些文件拷贝到该分区中。最简单的方法是首先在 /etc/fstab
中加入 /boot
分区的条目 (详见前一节),然后在 chroot 环境中以 root
身份执行以下命令:
mount /boot
该命令中省略了指向设备节点的路径,因为 mount 可以从 /etc/fstab
中读取它。
指向内核映像的路径可能随机器平台的不同而变化。下面使用的文件名可以依照您的需要改变,但文件名的开头应该保持为 vmlinuz,以保证和下一节描述的引导过程自动设定相兼容。下面的命令假定机器是 x86 体系结构:
cp -iv arch/x86/boot/bzImage /boot/vmlinuz-6.12.5-lfs-r12.2-54
System.map
是内核符号文件,它将内核 API
的每个函数入口点和运行时数据结构映射到它们的地址。它被用于调查分析内核可能出现的问题。执行以下命令安装该文件:
cp -iv System.map /boot/System.map-6.12.5
内核配置文件 .config
由上述的 make menuconfig
步骤生成,包含编译好的内核的所有配置选项。最好能将它保留下来以供日后参考:
cp -iv .config /boot/config-6.12.5
安装 Linux 内核文档:
cp -r Documentation -T /usr/share/doc/linux-6.12.5
需要注意的是,在内核源代码目录中可能有不属于 root 的文件。在以 root 身份解压源代码包时 (就像我们在 chroot 环境中所做的那样),这些文件会获得它们之前在软件包创建者的计算机上的用户和组 ID。这一般不会造成问题,因为在安装后通常会删除源代码目录树。然而,Linux 源代码目录树一般会被保留较长时间,这样创建者当时使用的用户 ID 就可能被分配给本机的某个用户,导致该用户拥有内核源代码的写权限。
之后在 BLFS 中安装软件包时往往需要修改内核配置。因此,和其他软件包不同,我们在安装好内核后可以不移除源代码树。
如果要保留内核源代码树,对内核源代码目录运行 chown -R
0:0 命令,以保证 linux-6.12.5
目录中所有文件都属于 root。
如果正在使用保留的内核源码树和新的内核配置重新构建内核,则一般不>应该执行 make mrproper 命令。该命令会清理
.config
文件和之前构建的所有 .o
文件。尽管可以从 /boot
中的副本恢复 .config
,清理所有 .o
文件仍然会造成巨大的浪费:对于简单的内核配置变更,通常只需要 (重新) 构建少数几个
.o
文件,在不进行清理时,内核构建系统会正确跳过其他
.o
文件。
然而,如果更新了 GCC,则应该执行 make
clean 命令,以清理之前构建的所有 .o
文件,否则可能导致构建失败。
有的内核文档建议创建符号链接 /usr/src/linux
指向内核源代码目录,这仅仅适用于 2.6 系列之前的内核。在 LFS 系统上绝对不要创建它,因为在构建完基本 LFS
系统后,它可能在您构建其他软件包时引起问题。
多数情况下 Linux 内核模块可以自动加载,但有时需要指定加载顺序。负责加载内核模块的程序 modprobe 和 insmod 从 /etc/modprobe.d
下的配置文件中读取加载顺序,例如,如果 USB 驱动程序
(ehci_hcd、ohci_hcd 和 uhci_hcd) 被构建为模块,则必须按照先加载 echi_hcd,再加载
ohci_hcd 和 uhci_hcd 的正确顺序,才能避免引导时出现警告信息。
为此,执行以下命令创建文件 /etc/modprobe.d/usb.conf
:
install -v -m755 -d /etc/modprobe.d
cat > /etc/modprobe.d/usb.conf << "EOF"
# Begin /etc/modprobe.d/usb.conf
install ohci_hcd /sbin/modprobe ehci_hcd ; /sbin/modprobe -i ohci_hcd ; true
install uhci_hcd /sbin/modprobe ehci_hcd ; /sbin/modprobe -i uhci_hcd ; true
# End /etc/modprobe.d/usb.conf
EOF