光之远征团跨服战

记一次如何手动编译一个linux内核

记一次记一次如何手动编译一个linux内核并从 QEMU 测试到替换宿主内核#### 特别声明与警告⚠️ 警告:本文涉及修改和替换系统的核心组件(内核)。此操作具有一定风险,可能导致系统无法启动。

实验环境: 整个过程必须在虚拟机(如 VMware Workstation 或 VirtualBox)中进行。虚拟机提供的“沙盒”环境,可以大胆尝试而无需担心损坏物理主机系统。本文所有操作均在 VMware Workstation 17 Pro 中完成。

备份: 在进行替换内核操作前,务必为你的虚拟机创建一个快照。如果操作失误,你可以快速回滚到之前的状态。

适用范围: 本文旨在用于学习和测试目的。请不要在生产环境或你无法承担风险的机器上直接操作。

使用以下命令查询当前系统内核版本:

1uname -r

实验目标

在 Ubuntu 24.04 中从国内镜像站下载并编译 Linux 内核源码(版本 6.16.7)。

使用 QEMU 模拟器测试新编译的内核和初始内存磁盘(initramfs),确保其能正常启动。

将经过测试的内核安装到宿主 Ubuntu 系统中,并使其成为默认启动选项。

第一步:安装必要的编译工具和依赖库打开终端 (Ctrl+Alt+T),执行以下命令来安装所有必要的工具:

1234567sudo apt update && sudo apt upgrade -y# 编译内核和模块所需的工具sudo apt install -y build-essential libncurses-dev libssl-dev libelf-dev bison flex dwarves zstd debhelper-compat dh-exec build-essential devscripts# QEMU 模拟器和其它工具sudo apt install -y qemu-system-x86 git wget cpio# 制作安装包所需的工具sudo apt install -y dpkg-dev

第二步:从清华大学镜像站下载 Linux 内核源码为了避免网络问题,我们使用 wget 从国内镜像站下载压缩包。本文使用清华大学镜像源。

12345678# 先回到当前用户的目录cd ~# 使用清华大学 tuna 镜像源下载 Linux 6.16.7 源码包 (.tar.gz)wget https://mirrors.tuna.tsinghua.edu.cn/kernel/v6.x/linux-6.16.7.tar.gz# 解压 .gz 格式的源码包tar -xzvf linux-6.16.7.tar.gz

第三步:配置内核 - 关键步骤:确保驱动支持这是最关键的一步,这一步我们不仅要生成默认配置,还要确保内核支持从 initramfs 启动,这是现代 Linux 系统启动的标配

生成默认配置:

12345# 首先进入源码目录 (注意目录名已变为 linux-6.16.7)cd linux-6.16.7# 随后生成默认配置make defconfig

深入配置以启用必需驱动:运行 make menuconfig 进行更详细的检查。我们需要确保以下选项被启用:

1make menuconfig

在打开的界面中,逐项检查并确认以下选项:

General setup —>

[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support **【这是非常关键的一项,必须为 】*

Device Drivers —>

Block devices —>

<*> RAM block device support 【确保编译进内核,而不是 M】

(65536) Default RAM disk size (kbytes) 【保持默认或调整,64MB 通常足够】

[*] The Extended 4 (ext4) filesystem 【与宿主系统保持一致,通常是 ext4,如果是Btrfs或者其他的请自行更改】

[*] Second extended fs support 【保留 ext2/ext3 支持,这里注意,第一次切换是[M]而不是[*]】

SCSI device support —>

<*> SCSI disk support 【QEMU 的虚拟硬盘通常是 SCSI 或 VirtIO】

Miscellaneous filesystems —>

[*] SquashFS 4.0 - Squashed file system support 【initramfs 中可能用到】

使用空格键切换选择状态:* 是编译进内核,M 是编译为模块。对于启动最核心的驱动(如 RAM disk, ext4),建议直接编译进内核(*),以避免模块加载问题。

配置完成后,保存并退出。

第四步:开始编译内核使用多线程编译以节省时间。这里的 $(nproc) 会自动获取你 CPU 的核心数。

1make -j$(nproc)

这个过程的长短取决于你的CPU性能,如果你给虚拟机分配的核心数比较少可能会导致虚拟机卡顿,但是完成后应该就好了,中途如果有warning可以忽略,如果出现error请自行回头检查是否遗漏或者多选了哪些选项导致,如果完全安装本教程来的我也不知道怎么办了,反正人和代码有一个能跑就行,完成后核心产物是 arch/x86/boot/bzImage

第五步:使用 BusyBox 制作简易根文件系统 (initramfs)我们需要一个最小的根文件系统来在 QEMU 中测试内核。

下载并编译 BusyBox:

123456cd ~# 下载 BusyBox (可能需要魔法,没有魔法的话也可以寻找国内镜像源或者试多几次)wget https://busybox.net/downloads/busybox-1.37.0.tar.bz2tar -xvf busybox-1.37.0.tar.bz2cd busybox-1.37.0make menuconfig

进入 Settings —>,选中 [*] Build static binary (no shared libs),然后退出并保存

这里有一个坑,因为 BusyBox 1.37.0 版本与当前系统的内核头文件不兼容,特别是网络工具 tc (Traffic Control) 相关的代码,这个会导致编译时报错,解决方法是禁用tc,这是最快最简单的解决方案,因为我们只是用 BusyBox 制作一个简单的 initramfs,并不需要 TC 功能

Networking Utilities —> [ ] tc

然后又开始漫长的编译环节

1make -j$(nproc) && make install

设置初始化脚本和打包:

1cd _install

进入该目录后输入ls命令你应该能看到这几个文件:

bin linuxrc sbin usr

1mkdir -p proc sys dev etc

创建并编辑初始化脚本 init,内容可以自行更改,但是尽量不要出现中文:

1234567891011121314151617181920cat > init << EOF#!/bin/shecho "This is the Linux kernel compiled by feng."echo "Mounting proc, sys, dev..."mount -t proc none /procmount -t sysfs none /sysmount -t devtmpfs none /dev# 创建控制台设备并设置权限mknod -m 660 /dev/console c 5 1mknod -m 660 /dev/tty0 c 4 0mknod -m 660 /dev/ttyS0 c 4 64echo "Booting completed successfully."# 使用 setsid 启动 shell 以确保它有控制终端exec setsid /bin/sh -c 'exec /bin/sh /dev/ttyS0 2>&1'EOF

赋予执行权限并打包:

123chmod +x initfind . -print0 | cpio --null -ov --format=newc | gzip -9 > ../initramfs.cpio.gzcd ~

第六步:在 QEMU 中测试内核这是验证我们编译的内核是否成功的重要一步。如果 QEMU 都无法启动,绝不能安装到宿主机。

123456qemu-system-x86_64 \ -kernel ~/linux-6.16.7/arch/x86/boot/bzImage \ -initrd ~/busybox-1.37.0/initramfs.cpio.gz \ -append "console=ttyS0 rdinit=/init quiet" \ -nographic \ -m 2G

注意 -append 参数使用了 rdinit=/init,这是专门指定 initramfs 中的初始化脚本。路径已更新为 linux-6.16.7。

如果成功看到 shell 提示符 / #,说明内核编译和 initramfs 制作成功,输入uname -r可以看到linux内核的版本,右边是ubuntu的内核版本:

可以看到前三行是自定义的init脚本的输出内容,表明内核成功启动并挂载了必要的文件系统。

最后一行 /bin/sh: can't access tty; job control turned off 是正常的,特别是在这种简单的 initramfs 环境中

输入 poweroff 或按 Ctrl+A 然后 X 退出 QEMU。

这里多嘴提一句,在make menuconfig时我们是可以自定义可以通过内核配置界面设置本地版本:

运行 make menuconfig

导航到:

12General setup ---> () Local version - append to kernel release

在其中输入你的自定义后缀,比如我这里:-feng-compiled

保存配置并重新编译内核即可

注意事项

修改 EXTRAVERSION 会影响内核模块的命名,所有内核模块也会带有这个后缀。

如果你已经安装了之前编译的内核到宿主机,你需要重新安装新编译的内核包。

确保你的自定义后缀不包含空格或特殊字符,最好只使用字母、数字和连字符。

完成这些步骤后,你的自定义内核就会显示你想要的版本名称了

第七步:编译并安装内核到宿主机系统大家可以尝试使用QEMU进行冒烟测试,这样就可以放心地将内核安装到宿主机了,真机也可以,这里时间问题就不进行测试了,我们直接安装到宿主机中

编译内核并生成 Debian 安装包:回到内核源码目录,使用以下命令来生成便于安装和管理的 .deb 包。

12345cd ~/linux-6.16.7# 清理之前的编译结果(可选)make clean# 重新编译并打包make -j$(nproc) bindeb-pkg

这一步可能会报错提示缺少默默依赖包,解决方法是他说缺哪个我们就去安装哪个,直到可以编译为止:

这个过程结束后,会在内核源码目录的上一级目录(即 ~/)生成几个 .deb 文件,例如 linux-image-6.16.7_6.16.7-1_amd64.deb。

安装编译好的内核包:使用 dpkg 命令安装生成的包,我们需要安装以下两个核心包(版本号会根据你的实际编译结果变化):

12cd ~sudo dpkg -i linux-image-6.16.7-feng-compiled_6.16.7-5_amd64.deb linux-headers-6.16.7-feng-compiled_6.16.7-5_amd64.deb`linux-image-*`: 包含内核本体和 initramfs 镜像。

linux-headers-*: 包含内核头文件,用于编译外部内核模块(如 NVIDIA 驱动)

安装程序 dpkg 会自动调用 update-grub,将新内核添加到 GRUB 启动菜单中

不出意外的话应该会如图所示:

第八步:重启并进入新内核

重启系统:

1sudo systemctl reboot

选择新内核启动:在 GRUB 启动菜单出现时,迅速按下 Shift 键(对于 BIOS 启动)或 Esc 键(对于 UEFI 启动)以显示菜单选项。选择 “Advanced options for Ubuntu”,然后选择你刚编译的 “Ubuntu, with Linux 6.16.7” 启动项。

验证:系统启动后,打开终端,输入:

1uname -r

如果输出显示 6.16.7,那么恭喜你!你已经成功使用自己手动编译的 Linux 内核了!

故障排除与回滚

如果新内核无法启动: 别担心,这正是我们做快照的原因。

重启虚拟机,在 GRUB 菜单中选择之前默认的旧内核启动(例如 6.14.0-xx-generic)。

启动成功后,你可以卸载有问题的自定义内核:

123# 请使用实际安装的包名,可以通过 dpkg -l | grep linux-image 查看sudo apt remove linux-image-6.16.7 linux-headers-6.16.7sudo update-grub

或者,最推荐的方式:直接使用 VMware 的快照功能回滚到安装前的状态,这是最干净、最安全的方式。

总结本次实验我们成功完成了既定目标:

安全环境:在 VMware 虚拟机中操作,风险可控

获取与配置:下载源码,并重点配置了 RAM disk 和 initramfs 等关键驱动

初步验证:使用 QEMU 模拟器进行“冒烟测试”,确保内核基本功能正常

生产安装:通过生成 .deb 包的方式,将测试通过的内核成功地安装到宿主机 Ubuntu 系统中

篝火营地官网 - 篝火营地拥有来自全球知名游戏媒体如Fami通、Polygon等的独家授权内容,为玩家提供最新的游戏评测、访谈、新闻资讯等
《神偷奶爸3》测评


最新发表

友情链接