本文属于《 TinyEMU模拟器基础系列教程》之一,欢迎查看其它文章。
1 busybox简介
BusyBox作为一个集成了众多常用命令和工具的软件,用户可以直接通过命令行调用这些工具,无需单独安装每个工具。这使得BusyBox在嵌入式系统、小型Linux系统或资源受限的环境中特别有用,因为它可以显著减少系统所需的存储空间,同时提供基本的命令行操作和管理能力。
此外,BusyBox的集成性也提高了系统的可维护性和易用性。由于BusyBox包含了大量的常用命令,用户无需担心系统中缺少某些必要的工具,可以更加方便地进行系统配置、文件操作、网络管理等任务。
因此,编译好的BusyBox可执行程序,通常会被放到文件系统的/bin
目录,可以使得这些命令和工具在系统启动时就被加载并可用,方便用户进行系统操作和管理。
2 编译busybox
busybox 官网:https://busybox.net/
可以通过 buildroot 或 busybox 来生成;busybox 代码量比较小,比较简单,生成的 rootfs 也比较小,因此采用busybox这种方式。
2.1 下载busybox源码
git clone https://gitee.com/mirrors/busyboxsource.git
此仓库是为了提升国内下载速度的镜像仓库,每日同步一次。 原始仓库: https://github.com/mirror/busybox
2.2 进入源码目录
cd busyboxsource
2.3 配置busybox
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- defconfig
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- menuconfig
这里RISC-V交叉编译器安装,参考《TinyEMU之Linux Kernel编译》。
2.4 选择使用静态编译
勾选Setting->---Buildroot Options->Build static binary
2.5 执行编译
make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j128
源码目录下,生成了二进制文件: busybox。
可以通过file busybox
命令来查看编译成的busybox 是哪个平台的。
busybox中,包含了大量linux命令工具,当系统启动后,就可以很方便的使用这些命令;所以,我们后续,需要将busybox放入文件系统中。
3 创建文件系统目录结构
3.1 创建工作路径
cd ..
mkdir initramfs
cd initramfs/
sudo su # 切换到 root 账户
3.2 创建文件系统主要目录
mkdir -p {bin,sbin,dev,etc,home,mnt,proc,sys,usr,tmp}
mkdir -p usr/{bin,sbin}
mkdir -p proc/sys/kernel
3.3 创建必要设备节点
cd dev/
sudo mknod sda b 8 0
sudo mknod console c 5 1
cd ..
在dev目录下,创建一个名为sda的块设备文件节点,执行该命令后,dev/sda文件就被创建成功。
- ”b”表示设备类型为块设备
- 8表示主设备号
- 0表示次设备号
在dev目录下,创建一个名为console的字符设备文件节点,执行该命令后,dev/console文件就被创建成功。
- ”c”表示设备类型为字符设备
- 5表示主设备号
- 1表示次设备号
3.4 拷贝编译好的 busybox
cp ../busyboxsource/busybox ./bin/
3.5 创建 init 文件
我们在initramfs目录下,创建init文件。
这个init文件,就是init进程,它是内核启动的第一个用户级进程。
我们把内核启动后,需要做的一些事情,写入init文件中,当内核启动后,就会自动执行它。
vim init
输入以下内容:
#!/bin/busybox sh# Make symlinks
/bin/busybox --install -s# Mount system
mount -t proc proc /proc
mount -t sysfs sysfs /sys
mount -t tmpfs tmpfs /tmp# Busybox TTY fix
setsid cttyhack sh# https://git.busybox.net/busybox/tree/docs/mdev.txt?h=1_32_stable
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -ssh
接下来,解释这些命令。
/bin/busybox --install -s
:将 BusyBox 中的多个命令链接到系统的/bin
目录中,作为单独的命令来使用。mount -t proc proc /proc
:把proc这个虚拟文件系统挂载到/proc目录,proc文件系统由内核提供。mount -t sysfs sysfs /sys
:把sysfs这个虚拟文件系统挂载到/sys目录,sysfs文件系统由内核提供。mount -t tmpfs tmpfs /tmp
:把tmpfs这个虚拟文件系统挂载到/tmp目录,tmpfs文件系统由内核提供。setsid cttyhack sh
:在后台启动一个新的终端shell会话进程,并将其与当前会话分离。echo /sbin/mdev > /proc/sys/kernel/hotplug
:设置Linux内核的热插拔处理脚本为/sbin/mdev,当系统中有设备被热插拔(例如,USB设备被插入或拔出)时,应该调用 /sbin/mdev 这个脚本来处理这些事件。mdev -s
:在系统启动或动态加载驱动程序时,扫描/sys/class和/sys/block目录,查找并读取dev属性文件,获取设备编号,然后根据这些信息在/dev目录下自动创建设备节点文件。
3.6 赋予 init文件 可执行权限
chmod +x init
到这里,initramfs目录下,已经具备了一个linux文件系统的基本目录了。
4 制作文件系统镜像
这一节,就是把上述目录结构,打包成ext2镜像文件。
4.1 创建 ext2 文件
生成4M大小的,空白镜像文件initramfs.ext2
dd if=/dev/zero of=initramfs.ext2 bs=1M count=4
将镜像文件initramfs.ext2,格式化为ext2文件系统
mkfs.ext2 initramfs.ext2
4.2 将目录结构拷贝进 ext2 文件
创建目录
/mnt/ext2/
将initramfs.ext2,挂载到/mnt/ext2/目录
mount -t ext2 initramfs.ext2 /mnt/ext2/
挂载到/mnt/ext2/目录后,当你在 /mnt/ext2/ 下写入文件或修改文件时,这些更改会反映到 initramfs.ext2 文件中。
拷贝initramfs目录内容,至/mnt/ext2/
cp -pr initramfs/* /mnt/ext2/
4.3 创建 init 链接
进入目录
cd /mnt/ext2/sbin/
在/mnt/ext2/sbin/目录下,创建init文件的软链接
ln -s ../init .
ln -s ../init .
命令:在当前目录下创建一个名为init的符号链接,这个链接指向上一级目录中的init文件或目录。
相当于,linux可以从/和/sbin/目录下,执行init脚本。
4.4 取消挂载
cd -
umount /mnt/ext2/
sync # 强制内容立刻写入文件
到这里,我们已经对initramfs.ext2文件写入完毕,写入的内容,主要包括busybox、目录结构、init文件以及软链接等。