你是否想过亲手构建一个最精简的 Linux 内核?这不仅是深入理解操作系统启动流程和内核模块化的绝佳实践,也能为嵌入式开发或系统研究打下坚实基础。本文将以 x86 和 树莓派 3 (64位 ARM) 两个平台为例,手把手带你完成从源码获取、配置、编译到 QEMU 模拟器测试的全过程。
1. 编译 x86 架构最小内核
1.1 内核编译
第一步:获取内核源码
首先,我们需要获取 Linux 内核的源代码。你可以从官方的 Git 仓库克隆最新的稳定版本或开发版本。
git clone https://github.com/torvalds/linux.git
第二步:生成最小配置
进入源码目录后,使用 make tinyconfig 命令生成一个绝对最小化的默认配置。这是我们的起点。
make tinyconfig
第三步:修改内核配置
最小配置过于精简,缺乏运行一个基本系统所需的支持。我们需要通过 menuconfig 界面手动启用一些关键选项。
make menuconfig
你需要导航并确保以下选项被启用(=y):
64-bit Kernel (CONFIG_64BIT=y)
General Setup -> Configure standard kernel features (expert users) -> Enable support for printk (CONFIG_PRINTK=y) (用于内核日志输出)
General Setup -> Initial RAM filesystem and RAM disk (initramfs/initrd) support (CONFIG_BLK_DEV_INITRD=y) (支持初始内存文件系统)
General Setup -> kernel compression mode (Gzip) (CONFIG_RD_GZIP=y) (内核压缩模式)
Executable file formats -> Kernel support for ELF binaries (CONFIG_BINFMT_ELF=y) (支持ELF可执行文件格式)
Executable file formats -> Kernel support for scripts starting with #! (CONFIG_BINFMT_SCRIPT=y) (支持脚本解释器)
File systems -> Pseudo filesystems -> /proc file system support (CONFIG_PROC_FS=y) (支持/proc虚拟文件系统)
Device Driver -> Character devices -> Enable TTY (CONFIG_TTY=y) (启用终端)
Device Driver -> Character devices -> Serial Drivers -> 8250/16550 and compatible serial support (CONFIG_SERIAL_8250=y) (串口驱动)
Device Driver -> Character devices -> Serial Drivers -> Console on 8250/16550 and compatible serial port (CONFIG_SERIAL_8250_CONSOLE=y) (将串口设为控制台)
第四步:开始编译内核
配置完成后,使用 make 命令进行编译。-j4 参数表示使用4个并行任务以加速编译过程,你可以根据你的CPU核心数调整。
make -j4
编译成功后,生成的内核镜像文件位于 arch/x86/boot/bzImage,大小约为800KB。
1.2 制作初始内存文件系统 (initramfs)
仅有内核无法启动,我们还需要一个包含最基本工具(如 sh)的根文件系统。这里使用一个现成的工具脚本来生成。
第一步:获取工具脚本
git clone https://github.com/hacker-jie/kernel-utils.git
第二步:生成 initramfs
进入 kernel-utils 目录,运行脚本:
./kernel-utils/mk-initrd
运行脚本后,它会交互式地询问一些问题,为了生成最小镜像,对所有提问都选择 n (No)。脚本最终会生成 initramfs.cpio.gz 文件,大小约为1.3MB。
1.3 使用 QEMU 进行测试
现在,我们有了内核 (bzImage) 和根文件系统 (initramfs.cpio.gz),可以使用 QEMU 模拟器来启动这个最小系统了。
qemu-system-x86_64 -kernel [PATH_TO_KERNEL]/arch/x86/boot/bzImage -initrd [PATH_TO_ROOTFS]/initramfs.cpio.gz -m 32M -nographic -append “init=/bin/sh console=ttyS0”
-kernel: 指定内核镜像路径。
-initrd: 指定初始内存盘路径。
-m 32M: 为虚拟机分配32MB内存。
-nographic: 不使用图形界面,将控制台重定向到当前终端。
-append: 传递内核启动参数,这里指定初始化程序为 /bin/sh,控制台设备为 ttyS0 (串口)。
如果一切顺利,你将在终端中看到内核启动日志,并最终获得一个 sh 的 shell 提示符。
2. 编译树莓派 3 (64位 ARM) 最小内核
对于嵌入式平台如树莓派,流程类似,但需要针对其特定的架构和硬件进行调整。
2.1 内核编译
第一步:获取树莓派内核源码
树莓派基金会维护了自己的内核分支:
git clone https://github.com/raspberrypi/linux.git
第二步:生成最小配置
make tinyconfig
第三步:修改配置
除了启用与 x86 类似的基础功能外(如 CONFIG_BINFMT_ELF, CONFIG_BLK_DEV_INITRD, CONFIG_PRINTK, CONFIG_TTY, CONFIG_PROC_FS),还必须启用树莓派 3 特定的硬件支持:
CONFIG_ARCH_BCM2835 (BCM2835 SoC 支持)
CONFIG_MAILBOX 和 CONFIG_BCM2835_MBOX (邮箱通信)
CONFIG_RASPBERRYPI_FIRMWARE (树莓派固件接口)
CONFIG_SERIAL_AMBA_PL011 和 CONFIG_SERIAL_AMBA_PL011_CONSOLE (PL011 UART 串口驱动与控制台)
第四步:指定交叉编译器并编译
为 ARM 64 位架构编译需要对应的交叉编译工具链。
make -j4 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
注:确保系统已安装 gcc-aarch64-linux-gnu 包 (sudo apt install -y gcc-aarch64-linux-gnu)。
编译完成后,内核镜像文件为 arch/arm64/boot/Image。
2.2 文件系统
使用与 x86 章节相同的 kernel-utils/mk-initrd 方法生成 initramfs.cpio.gz。
2.3 QEMU 测试
QEMU 命令行需要调整为树莓派 3 的机器模型 (-M raspi3b),并加载对应的设备树文件 (-dtb)。
qemu-system-aarch64 -M raspi3b -kernel [PATH_TO_KERNEL]/arch/arm64/boot/Image -dtb [PATH_TO_DTB]/bcm2710-rpi-3-b.dtb -initrd [PATH_TO_ROOTFS]/initramfs.cpio.gz -m 1024M -nographic -append “init=/bin/sh console=ttyAMA0,115200”
2.4 进阶方案:使用 Buildroot 为树莓派构建一体化镜像
手动配置和组合内核、文件系统略显繁琐。Buildroot 是一个更强大的工具,它可以自动构建一个完整的、可定制的嵌入式 Linux 系统,包括交叉工具链、内核、根文件系统及引导程序。
项目简介
tiny_raspi 项目利用 Buildroot 的 EXTERNAL 机制,为树莓派 3 提供了一个极度精简的配置模板。相比使用 Buildroot 默认 raspberrypi3_64_defconfig 生成的 150MB+ 镜像,它能生成一个仅包含最基本功能的微小内核和根文件系统。
你需要准备三个核心文件来描述这个外部定制:
external.desc
external.mk
Config.in
编译步骤
git clone https://github.com/calinyara/tiny_raspi.git
cd tiny_raspi
git clone git://git.buildroot.net/buildroot
mkdir build
mkdir buildroot_dl
cd build
make BR2_EXTERNAL=../tiny_raspi_buildroot/ O=$PWD -C ../buildroot/ tiny_raspberrypi3_64_defconfig
make -j4
编译完成后,在 build/images/ 目录下会生成三件套:内核 Image、根文件系统 rootfs.cpio.gz 和设备树文件 bcm2710-rpi-3-b.dtb。Buildroot 已为我们自动集成了编译好的根文件系统。
QEMU 运行
使用生成的一体化文件直接启动测试:
qemu-system-aarch64 -M raspi3b -kernel ./images/Image -dtb ./images/bcm2710-rpi-3-b.dtb -initrd ./images/rootfs.cpio.gz -m 1024 -nographic -append “init=/bin/sh console=ttyAMA0,115200”
总结
通过以上步骤,我们完成了从手动配置编译到使用自动化工具构建最小 Linux 系统的全过程。这不仅是一次对内核 编译原理 和构建流程的实操,更是理解现代 操作系统 如何从源码到镜像,再到在模拟或真实硬件上启动的宝贵经历。无论是为了学习、研究还是嵌入式开发,掌握定制化 内核 的能力都至关重要。如果你对系统底层技术有更多兴趣,欢迎在 云栈社区 交流探讨。