4. rootfs基础概念

在嵌入式 Linux 系统中,rootfs(根文件系统)是内核启动后挂载的第一个文件系统,也是用户空间所有进程、配置、库和设备的“落脚点”。对于 RK3568 这类 ARM64 平台,rootfs 不仅决定系统能否正常启动,还直接影响后续应用部署、调试和维护的便利性。理解 rootfs 的层次标准、目录结构、BusyBox 的角色、init 进程的职责以及系统库与运行时依赖,是构建可启动、可维护系统的前提。

一、核心原理:FHS 与根目录结构

Linux 根文件系统遵循 FHS(Filesystem Hierarchy Standard,文件系统层次标准)。FHS 规定了各目录的用途,使不同发行版和嵌入式系统之间保持一致性。RK3568 的 rootfs 通常包含以下关键目录:

目录用途典型内容
/bin基础用户命令ls、cp、sh、mount
/sbin系统管理命令init、ifconfig、reboot
/etc系统配置inittab、fstab、passwd
/lib共享库与内核模块libc.so、ld-linux、modules
/dev设备节点console、ttyS0、mmcblk
/proc内核与进程信息虚拟文件系统,运行时生成
/sys设备与驱动模型虚拟文件系统,运行时生成
/usr用户程序与资源bin、lib、share
/var可变数据log、run、tmp
/rootroot 用户主目录启动脚本、调试文件

在嵌入式场景中,/proc 和 /sys 通常由内核在启动时挂载,/dev 可由 devtmpfs 或 mdev 动态管理。因此,制作 rootfs 时不必手动填充这些目录,但必须在启动脚本中正确挂载它们。

二、BusyBox:嵌入式 rootfs 的“瑞士军刀”

BusyBox 将大量常用 Unix 命令集成到一个可执行文件中,通过符号链接或硬链接提供不同命令入口。它体积小、依赖少,非常适合 RK3568 这类资源受限的嵌入式设备。典型 rootfs 中,/bin 和 /sbin 下的命令大多指向 /bin/busybox。

# 查看 busybox 支持的命令
./busybox --list

# 创建符号链接示例
ln -s /bin/busybox /bin/ls
ln -s /bin/busybox /bin/mount
ln -s /bin/busybox /sbin/init

BusyBox 的 init 程序是嵌入式系统最常用的 init 实现。它读取 /etc/inittab,按配置执行系统初始化、启动 shell 或应用程序。相比 systemd,BusyBox init 更轻量,启动流程更直观,适合快速构建和调试。

BusyBox 的配置通过 menuconfig 完成,可裁剪不需要的命令以进一步减小体积。RK3568 的 SDK 通常已提供默认配置,但建议根据实际需求关闭未使用的功能。

三、init 进程:用户空间的第一个进程

内核启动完成后,会尝试执行 /sbin/init、/etc/init 或 /bin/init。init 进程 PID 为 1,负责挂载文件系统、启动服务、管理运行级别和回收孤儿进程。在 BusyBox init 中,/etc/inittab 是核心配置文件:

# /etc/inittab 示例
::sysinit:/etc/init.d/rcS
::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r

其中,sysinit 指定系统初始化脚本,askfirst 在控制台启动一个 shell,ctrlaltdel 定义组合键行为,shutdown 在系统关闭时执行清理。对于 RK3568 产品化系统,通常会将 askfirst 替换为直接启动应用程序,或通过脚本判断启动模式。

init 进程的启动顺序非常关键:先挂载 /proc、/sys、/dev,再加载内核模块,然后配置网络、启动服务,最后进入应用。任何一步失败都可能导致系统无法进入用户空间。

四、系统库与运行时依赖

RK3568 是 ARM64 架构,rootfs 中的可执行文件必须与目标架构匹配。系统库主要包括:

  • C 库:glibc 或 musl。glibc 功能完整但体积较大,musl 更轻量,适合嵌入式。
  • 动态链接器:如 /lib/ld-linux-aarch64.so.1,负责加载共享库。
  • 基础库:libm、libpthread、libdl 等,通常随 C 库提供。
  • 应用依赖库:如 libssl、libcurl、Qt 库等,需根据应用需求部署。

检查运行时依赖可使用 readelf 或 ldd:

# 查看可执行文件依赖
readelf -d /bin/busybox | grep NEEDED

# 在目标板上检查动态库
ldd /usr/bin/myapp

如果缺少某个共享库,程序会报 “error while loading shared libraries”。此时需要将对应库文件复制到 /lib 或 /usr/lib,并确保动态链接器路径正确。对于交叉编译环境,还要注意库的版本和 ABI 兼容性。

不要直接将主机 x86_64 的库复制到 RK3568 rootfs。必须使用交叉编译工具链生成的 ARM64 库,否则会出现 “Exec format error” 或无法加载。

五、案例与复盘:一个最小可启动 rootfs

假设我们要为 RK3568 构建一个最小 rootfs,步骤如下:

  1. 创建目录骨架:bin、sbin、etc、lib、dev、proc、sys、usr、var、root。
  2. 交叉编译 BusyBox,安装到 rootfs。
  3. 创建 /etc/inittab 和 /etc/init.d/rcS。
  4. 复制交叉工具链中的 libc 和动态链接器到 /lib。
  5. 制作镜像并烧录,观察串口启动日志。

常见误区包括:忘记挂载 /proc 导致 ps 命令失败;inittab 路径错误导致 init 无法启动;库文件权限不足导致动态链接失败;/dev/console 不存在导致没有串口输出。复盘时应优先检查内核命令行中的 root= 参数、init 路径和库依赖。

RK3568 rootfs 结构与启动关系 内核 → init → BusyBox 命令 → 系统库 → 应用 Linux Kernel 挂载 rootfs rootfs(根文件系统) /bin /sbin 命令入口 /etc inittab / rcS /lib libc / ld-linux /dev console / ttyS0 /proc /sys 运行时挂载 /usr /var 应用与数据 BusyBox ls / mount / sh / init init (PID 1) 读取 /etc/inittab 系统库与运行时 glibc / musl / libssl 用户应用 依赖库正确加载 关键检查点:root= 参数、init 路径、/proc 挂载、动态链接器、库 ABI 匹配

总结来看,rootfs 是 RK3568 系统启动链条中承上启下的关键环节。FHS 提供目录规范,BusyBox 提供轻量命令集,init 负责启动流程,系统库保证程序运行。只有这四者协同正确,系统才能从内核顺利过渡到用户空间,并为后续应用部署打下稳定基础。