qemu+linux kernel+busybox搭建linux内核学习环境
前言:里面的知识很多理解的都不到位,不保证正确性,等后期学习好,再来修改。
前提:架构x86_64
一、准备工作
sudo apt update sudo apt install build-essential qemu-system-x86 gdb git flex bison libncurses5-dev libssl-dev libelf-dev
二、编译 Linux 内核(以最新版本为例):
git clone https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git # 官方链接,国内会很慢 git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux-stable.git # 清华源,速度快(推荐) cd linux # 进入源码目录 make defconfig # 默认配置 make -j$(nproc) # 开始编译
最终会生成启动镜像:arch/x86/boot/bzImage
三、准备根文件系统(rootfs)
内核需要一个“根文件系统”来启动,否则会卡在 init 过程,可以用 BusyBox 来生成一个极简 rootfs。
# 下载 busybox
git clone https://busybox.net/git/busybox.git # 速度也较为慢,但是文件比较小
cd busybox # 进入源码目录
make menuconfig # 菜单配置,要配置成静态编译(重要)
make install # 它会生成 _install 目录
cd _install
mkdir -p proc sys dev # (可选)创建一些必要的文件夹
vi init # (可选)创建一个自定义的init脚本,不创建的话要指定其他地方的文件作为初始化文件,后面会讲到。
find . | cpio -o --format=newc | gzip > ../rootfs.img.gz # 打包制作成一个 ramdisk
相关知识点:
- 一定要静态编译busybox,否则它使用的是本地linux的动态库,但是linux启动的时候并没有这些库,所以找不到将会无法启动rootfs,当时在这里卡了半天,一直以为是打包格式/名字的关系,比如
initramfs.cpio.gz和rootfs.img.gz名字的区别,但是并不是本质影响,最重要的还是静态编译。但是也引出了一个不同文件系统的区别,在2中展开。 - Ramfs、rootfs 和 initramfs区别(自己理解还不到位,仅作临时参考):内核文档这样介绍的Ramfs、rootfs 和 initramfs — Linux 内核文档,通过再询问GPT,他给出的总结:
ramfs:提供了一个完全驻留内存的文件系统机制。
rootfs:内核启动时默认挂载的第一个根文件系统(通常基于 ramfs/tmpfs)。
initramfs:是一个以 cpio 格式打包的文件系统镜像,启动时解压到 rootfs 中作为系统的早期根。
对比表格
对比项 ramfs rootfs initramfs 本质 内存文件系统类型 启动时自动挂载的根文件系统实例 一个 cpio 压缩归档(init 镜像) 所在层 文件系统类型(VFS 实现) 文件系统实例(挂载点 /)文件系统内容来源(打包镜像) 是否在内存中 ✅ 是 ✅ 是 ✅ 解压后在内存中 主要作用 提供纯内存文件系统机制 作为启动时的临时根 提供早期用户空间文件和可执行程序 是否可持久化 ❌ 否 ❌ 否 ❌ 否 与内核关系 文件系统内核模块 内核自动创建 内核自动加载或附带 与用户空间关系 不直接暴露 启动早期可见 含 /init 用户程序
注意:ramfs、rootfs、initramfs 都不是“真正的根文件系统”,只是内存中的临时根环境,因为真正的文件系统特点是:位于磁盘或块设备(例如 /dev/sda1、eMMC、NAND、NVMe、SD 卡等); 使用常见格式(ext4、xfs、btrfs、squashfs 等); 能够持久化数据; 作为系统长期运行时的主存储空间。 - 根文件系统各种初始化的区别(自己理解还不到位,仅作临时参考,感觉不同根文件系统有差别)
linuxrc:早期内核中的启动脚本,现在基本不用了
init:这个是最基本的init,现代linux还在用的。会根据启动选项选择,比如qemu的选项-append "console=ttyS0 root=/dev/ram rdinit=/bin/sh",其中rdinit=/bin/sh就是指定初始化文件(这些命令是传递给linux内核的启动参数,像在u-boot中也会配置这样的启动参数)。如果没有指定,会自动运行根目录/init,但是GPT说:如果/init不存在,尝试/sbin/init→/etc/init→/bin/init→/bin/sh,我自己实验,重命名/init后即使存在/sbin/init以及/bin/sh也会进入不了根文件系统,所以还需要再确定。
/etc/init.d/rcS:系统初始化脚本,在init之后运行,也就是说基本是进入系统后,再对系统进行的一些配置工作。
下图来自:Linux启动流程-CSDN博客
四、启动QEMU
qemu-system-x86_64 \
-kernel linux_src/arch/x86/boot/bzImage \
-initrd busybox_src/rootfs.img.gz \
-append "console=ttyS0 root=/dev/ram rdinit=/bin/sh" \
-nographic

浙公网安备 33010602011771号