基于 Busybox 和 QEMU,我们可以搭建一个非常小的玩具 Linux 系统,可以借此来体验开发编译 Linux 内核的乐趣。
准备工作
由于最近对 Incus System Container 很感兴趣,于是就使用 Incus 创建一个 Debian 12 的容器来进行本次体验。
incus launch mirrors:debian/12 debian12
incus exec debian12 -- bash
进入容器后,安装一些在编译过程中会用的的工具与库。
apt install wget gcc gdb bzip2 bc xz-utils flex bison
apt install libncurses-dev libssl-dev libelf-dev
apt install cpio qemu-system-x86
接着,创建工作目录 kernel-dev
并下载 Kernel 和 Busybox 的源码:
mkdir kernel-dev
cd kernel-dev
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.7.3.tar.xz
wget https://www.busybox.net/downloads/busybox-1.36.1.tar.bz2
tar xf linux-6.7.3.tar.xz
tar xf busybox-1.36.1.tar.bz2
编译 Kernel
在 Kernel 源码目录下,直接 make defconfig
生成默认配置文件 .config
,编辑其内容,修改 CONFIG_LOCALVERSION
来自定义内核版本标识。最后,make -j $(nproc)
使用所有 CPU 核心来编译内核镜像。
cd linux-6.7.3
make defconfig
# Edit .config, eg: CONFIG_LOCALVERSION="-Silver"
make -j $(nproc)
编译 Busybox
在 Busybox 源码目录下,通过 make menuconfig
将 Settings -> Build static binary (no shared libs)
选项启用,然后 make -j $(nproc)
编译。
cd busybox-1.36.1
make menuconfig
make -j $(nproc)
构建 Initramfs
创建 run
目录来作为我们测试 kernel 的工作目录,在该目录下,继续创建 initramfs
目录,并将编译好的 Kernel 和 Busybox 复制进来,创建 init
脚本作为系统的母进程(PID 为 1)。
mkdir -p run/initramfs/bin
cp linux-6.7.3/arch/x86_64/boot/bzImage run/
cp busybox-1.36.1/busybox run/initramfs/bin
init
脚本内容如下,主要负责在内核加载完成后,挂载 /proc
目录,打印一行 “Hello World”,然后返回一个 shell 提供交互。
#!/bin/busybox sh
/bin/busybox mkdir -p /proc && /bin/busybox mount -t proc none /proc
/bin/busybox echo -e "\nHello World!\n"
/bin/busybox sh
另外,需要 chmod +x ./init
使 init
脚本具有可执行权限。
接下来,创建一个 Makefile
脚本,来生成 initramfs 镜像和后续启动 QEMU 虚拟机。
.PHONY: initramfs
initramfs:
cd ./initramfs && find . -print0 | cpio -ov --null --format=newc | gzip -9 > ../initramfs.img
run:
qemu-system-x86_64 \
-kernel bzImage \
-initrd initramfs.img \
-m 1G \
-nographic \
-append "earlyprintk=serial,ttyS0 console=ttyS0"
然后 make initramfs
来构建 initramfs.img
磁盘镜像。
此时,run
目录的文件结构如下:
📂run
├──📃Makefile
├──📃bzImage
├──📂initramfs
│ ├──📂bin
│ │ └── 📃busybox
│ └──📃init
└──📃initramfs.img
运行系统
终于!此时,只需 make run
就可启动 QEMU 虚拟机,屏幕上会滚动显示一些内核输出,并输出 “Hello World”,然后弹出 shell 等待输入。
可以执行下面的命令,来查看我们之前在 .config
中配置的自定义内核版本标识。
busybox uname -r
最后,通过下面的命令来关闭系统,退出虚拟机。
busybox poweroff -f
结束!