2. 嵌入式Linux启动流程
嵌入式 Linux 的启动并不是“上电即进入系统”,而是一条严格分阶段的接力链:Bootloader 先把最基础的硬件唤醒并搬运内核,内核完成子系统初始化后再去寻找并挂载根文件系统,最后由 Rootfs 中的 init 进程把用户空间拉起来。理解这条链路,尤其是 Rootfs 的挂载时机,是后续自己构建根文件系统时判断“为什么卡住”“为什么进不了 shell”的关键。
一、核心原理:三段式接力与 Rootfs 的角色
从职责上看,启动过程可以抽象为三个角色:
- Bootloader(如 U-Boot):负责上电后的最小初始化(时钟、DDR、串口),从 Flash/eMMC/SD/TFTP 读取内核镜像与设备树,设置
bootargs,跳转到内核入口。 - Kernel:解压自身、初始化内存管理、调度、驱动模型,挂载根文件系统,并执行其中的
/sbin/init(或init=指定的程序)。 - Rootfs:提供用户空间所需的目录结构、动态库、init 程序、配置与服务脚本。没有可挂载的 Rootfs,内核在
VFS: Cannot open root device处就会 panic。
因此 Rootfs 在启动中的角色可以概括为:内核与用户空间之间的“交接平台”。内核只负责把 Rootfs 挂到 /,真正让系统“活起来”的是 Rootfs 里的 init 及其启动脚本。
二、方法流程:从复位向量到用户空间
以常见的 ARM + U-Boot + Linux 为例,启动顺序可细化为:
- 上电复位,CPU 从 BootROM 执行,加载 SPL/MLO 到片内 SRAM。
- SPL 初始化 DDR,加载完整 U-Boot 到内存并跳转。
- U-Boot 执行
bootcmd,加载zImage/Image与.dtb,传递bootargs。 - 内核解压、初始化,解析设备树,注册平台设备与驱动。
- 内核根据
root=与rootfstype=挂载根文件系统。 - 执行
/sbin/init,进入用户空间,启动服务与登录界面。
其中第 5 步就是 Rootfs 的挂载时机。它发生在内核驱动初始化基本完成之后、init 启动之前。挂载方式常见有三类:
| 方式 | 典型 bootargs | 适用场景 |
|---|---|---|
| 块设备根文件系统 | root=/dev/mmcblk0p2 rootfstype=ext4 rw | eMMC/SD 卡上的 ext4/UBIFS |
| Initramfs/Initrd | root=/dev/ram0 rdinit=/init | 先挂临时根,再切换真实根 |
| NFS 网络根 | root=/dev/nfs nfsroot=192.168.1.10:/nfsroot ip=dhcp | 开发调试阶段 |
一个典型的 U-Boot 环境变量与内核日志片段如下:
setenv bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rw rootwait'
setenv bootcmd 'mmc dev 0; fatload mmc 0:1 0x80008000 zImage; fatload mmc 0:1 0x83000000 sun8i.dtb; bootz 0x80008000 - 0x83000000'
saveenv
# 内核启动日志
[ 0.000000] Kernel command line: console=ttyS0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rw rootwait
[ 1.234567] mmc0: new high speed SDHC card
[ 1.456789] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode
[ 1.460000] VFS: Mounted root (ext4 filesystem) on device 179:2.
[ 1.470000] Run /sbin/init as init process
三、案例/场景:Rootfs 挂载失败的典型排查
假设板子上电后串口停在如下位置:
[ 1.460000] VFS: Cannot open root device "mmcblk0p2" or unknown-block(179,2)
[ 1.460000] Please append a correct "root=" boot option
[ 1.460000] Kernel panic - not syncing: VFS: Unable to mount root fs
这说明内核已经跑起来了,但找不到 Rootfs。排查顺序建议如下:
- 确认分区是否存在:
mmcblk0p2是否被识别,分区表是否正确。 - 确认文件系统类型:
rootfstype=ext4是否与实际格式一致。 - 确认驱动是否编入内核:MMC 控制器驱动、EXT4 驱动是否已编译进内核而非模块。
- 确认
rootwait:对于 SD/eMMC,建议加上rootwait,等待设备就绪。
bootargs 并 boot,可以快速验证不同 root 参数,而不必重新烧写整个系统。
四、误区与复盘:Rootfs 不是“最后才考虑”的部分
很多初学者把 Rootfs 当成“系统跑起来之后再放进去的东西”,这是最大的误区。实际上,内核在启动后期会主动寻找 Rootfs,如果找不到就直接 panic。因此 Rootfs 的存在性、格式、驱动支持必须在设计启动方案时就确定。
另一个常见误区是混淆 initramfs 与真实根文件系统。initramfs 是内核内置的临时根,用于加载必要驱动后再切换根;而真实 Rootfs 才是最终用户空间。两者挂载时机不同,职责也不同。
复盘时可以记住这条主线:Bootloader 搬内核 → 内核挂 Rootfs → Rootfs 启 init。任何一环断裂,系统都无法进入用户空间。下一节我们将从目录结构开始,真正动手规划一个可启动的 Rootfs。