Linux 最小根文件系统

启动流程

Linux系统启动顺序如下:

graph LR
A[Bootloader] --> |启动|B[Linux内核] -->|识别| C[根文件系统] --> |运行|D[应用]

参考之前的rCore项目,首先会执行由QEMU提供的BootLoader,然后启动rCore,最后再运行操作系统,相当于根文件系统。

Linux 文件系统结构

理论上是这样的

graph TD
    root["/"]
    root --> bin["/bin"]
    root --> sbin["/sbin"]
    root --> dev["/dev"]
    root --> etc["/etc"]
    root --> lib["/lib"]
    root --> home["/home"]
    root --> root_dir["/root"]
    root --> usr["/usr"]
    root --> var["/var"]
    root --> proc["/proc"]
    root --> mnt["/mnt"]
    root --> tmp["/tmp"]

其中:

  1. /bin 存放所有用户可用的、最基本的命令(理论上)
  2. /sbin 存放管理员可用的命令
  3. /dev 存放设备文件,一切外设都可以在Linux中以文件的形式访问,例如 /mnt/nvme0n1p1就代表一个 nvme 固态的分区
  4. /etc 各种配置文件
  5. /lib 放共享库和可加载模块
  6. /home 用户目录,每个普通用户都会在该目录下有个家目录
  7. /root 根用户的家目录
  8. /usr 并不是 user,而是 Unix System Resource。里面有/usr/bin, /usr/sbin, /usr/lib等子文件夹,之所以这么做,是因为在资源受限的设备中,根文件系统与 /usr 分区不在一个物理分区,开机后先挂载根文件系统,再运行 /bin 中的 mount 指令挂载 /usr 分区。 因此 /usr 中的程序和库都是相对上层,非必须的。不过在普通的发行版中,/bin是一个符号链接,指向了/usr/bin,因为在现代硬件上,存储空间已经够大辣。
  9. /var 顾名思义,存放可变数据,例如/var/log存放日志,/var/tmp存放持久临时文件。
  10. /proc 是一个虚拟文件系统,将内核的状态、硬件信息等以文件形式暴露出来。用于用户空间与内核空间交互,主要用于查询和配置系统运行时的状态。
  11. /mnt 临时文件系统挂载点,例如U盘,移动硬盘等,插入后会出现在/dev目录下,然后需要挂载到此处访问。
  12. /tmp 顾名思义,存放临时文件,重启后会被清空。

以Ubuntu24.04为例,实际是这样的:

lrwxrwxrwx   1 root root    7 Apr 22  2024 bin -> usr/bin/
drwxr-xr-x   2 root root 4.0K Feb 26  2024 bin.usr-is-merged/
drwxr-xr-x   2 root root 4.0K Apr 22  2024 boot/
drwxr-xr-x  15 root root 3.8K Jun 20 10:52 dev/
drwxr-xr-x 108 root root 4.0K Jun 20 10:52 etc/
drwxr-xr-x   3 root root 4.0K Jun 19 00:29 home/
-rwxrwxrwx   1 root root 2.6M Apr 24 07:34 init*
lrwxrwxrwx   1 root root    7 Apr 22  2024 lib -> usr/lib/
drwxr-xr-x   2 root root 4.0K Apr  8  2024 lib.usr-is-merged/
lrwxrwxrwx   1 root root    9 Apr 22  2024 lib64 -> usr/lib64/
drwx------   2 root root  16K Jun 19 00:28 lost+found/
drwxr-xr-x   2 root root 4.0K Jan  7 04:13 media/
drwxr-xr-x   6 root root 4.0K Jun 19 00:28 mnt/
drwxr-xr-x   2 root root 4.0K Jan  7 04:13 opt/
dr-xr-xr-x 299 root root    0 Jun 20 10:52 proc/
drwx------   6 root root 4.0K Jun 19 11:25 root/
drwxr-xr-x  21 root root  600 Jun 20 10:52 run/
lrwxrwxrwx   1 root root    8 Apr 22  2024 sbin -> usr/sbin/
drwxr-xr-x   2 root root 4.0K Mar 31  2024 sbin.usr-is-merged/
drwxr-xr-x   2 root root 4.0K Jun 19 00:28 snap/
drwxr-xr-x   2 root root 4.0K Jan  7 04:13 srv/
dr-xr-xr-x  13 root root    0 Jun 20 10:52 sys/
drwxrwxrwt  10 root root 4.0K Jun 20 10:53 tmp/
drwxr-xr-x  12 root root 4.0K Jan  7 04:13 usr/
drwxr-xr-x  13 root root 4.0K Jun 19 00:28 var/

System-V 启动顺序

  1. 加载 /boot/zImage 内核与 .dtb 后缀的设备树

  2. /sbin/init 内核启动它作为第一个进程 作用

    • 读配置文件
    • 根据配置文件启动其他APP

    在基于rCore的系统中,第一个进程是终端,目的也是为了启动其他APP。因此,对于最简系统,后面的步骤可以不需要,到这里就算是启动系统了。

  3. 读配置文件 /etc/inittab

  4. 启动其他APP

    • 启动时需要读取/lib下的动态链接库

制作busybox最小根文件系统

编译

  1. 首先修改Makefile中的CROSS_COMPILE变量指定交叉编译工具链,当然也可以在执行make的时候指定,或者修改环境变量,不过还是直接改Makefile默认值方便: CROSS_COMPILE ?= arm-buildroot-linux-gnuebihf-

  2. 执行make menuconfig进入TUI设置界面,这里默认就行

  3. 执行make -j$(nproc)编译 到这里才发现我没装工具链,参考开发手册下载后, 在~/.config/fish/config.fish中添加

    set -x ARCH arm
    set -x CROSS_COMPILE arm-buildroot-linux-gnueabihf-
    fish_add_path /home/szy/Softwares/100ask_imx6ull-sdk/ToolChain/arm-buildroot-linux-gnueabihf_sdk-buildroot/bin/
    
  4. 在当前目录下安装make CONFIG_PREFIX=tmp install

然后tmp目录结构如下:

.
├── bin
├── linuxrc -> bin/busybox
├── sbin
└── usr

准备内核和DTS

cd tmp
mkdir boot
cp ~