2. 嵌入式Linux启动流程
嵌入式Linux设备从上电到出现可交互的Shell,并不是“一步到位”的过程,而是由Bootloader、Linux内核、根文件系统(Rootfs)三个核心角色依次接力完成的。理解它们之间的依赖关系,以及Rootfs在启动链路中的位置,是排查“内核起来了但进不了系统”“卡在VFS: Unable to mount root fs”这类问题的关键。
一、启动链路的三级接力
可以把整个启动过程理解为一场三级接力赛:第一棒是Bootloader,第二棒是内核,第三棒是根文件系统。每一棒都必须把“交接棒”准确交给下一棒,任何一棒掉链子,系统都无法进入用户态。
- Bootloader(如U-Boot):上电后最先运行,负责初始化DDR、时钟、串口等最基础的硬件,然后把内核镜像(zImage/Image)和设备树(.dtb)从Flash、eMMC、SD卡或网络加载到内存,最后跳转到内核入口。
- Linux内核:接管CPU后完成内存管理、中断、驱动等初始化,挂载根文件系统,并启动第一个用户态进程(init)。
- 根文件系统(Rootfs):提供
/bin、/etc、/lib、/dev等目录和init程序,是内核进入用户空间的“落脚点”。
二、Rootfs在启动链路中的位置
内核启动的最后阶段会执行prepare_namespace(),根据bootargs中的root=参数去挂载根文件系统。挂载成功后,内核会尝试执行/sbin/init(或/init、/linuxrc),此时控制权才从内核态转移到用户态。
因此,Rootfs的位置非常明确:它位于内核初始化之后、用户空间启动之前。没有Rootfs,内核即使全部初始化成功,也只能打印Kernel panic - not syncing: No init found,无法进入Shell。
三、关键参数与交接机制
Bootloader与内核之间通过启动参数(bootargs)传递信息,其中与Rootfs最相关的是root=、rootfstype=、rootwait和init=。这些参数决定了内核去哪里找根文件系统、用什么文件系统类型解析、是否等待设备就绪,以及启动哪个init程序。
# U-Boot中设置bootargs的典型示例
setenv bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rw rootwait init=/sbin/init'
setenv bootcmd 'mmc read 0x80000000 0x1000 0x2000; bootm 0x80000000'
saveenv
boot
如果root=指向的分区不存在,或者文件系统类型不匹配,内核会报错并进入panic。如果init=指定的程序不存在,内核会依次尝试/sbin/init、/etc/init、/bin/init、/bin/sh,全部失败后同样panic。
四、典型场景:从eMMC启动的完整链路
以一块i.MX6ULL开发板从eMMC启动为例,完整链路如下:
- 上电后ROM Code从eMMC的boot分区加载U-Boot SPL到内部SRAM运行。
- SPL初始化DDR,再把完整的U-Boot加载到DDR并跳转。
- U-Boot从eMMC的kernel分区读取
zImage和imx6ull-14x14-evk.dtb到DDR。 - U-Boot把
bootargs写入内核启动参数区,执行bootz跳转内核。 - 内核初始化完成后,根据
root=/dev/mmcblk0p2挂载eMMC第二个分区为根文件系统。 - 内核执行
/sbin/init,BusyBox init读取/etc/inittab,启动Shell和应用程序。
root=参数和分区表。
五、常见误区与复盘
| 误区 | 现象 | 正确理解 |
|---|---|---|
| 认为内核自带根文件系统 | 烧录内核后无法进入Shell | 内核只负责挂载,Rootfs必须单独提供(initramfs或独立分区) |
| 忽略bootargs中的root= | VFS报错,找不到根设备 | root=必须与分区设备节点一致,如/dev/mmcblk0p2 |
| Rootfs中缺少init | Kernel panic: No init found | Rootfs必须包含可执行的init或通过init=指定 |
| 文件系统类型不匹配 | 挂载失败,提示unknown filesystem | rootfstype需与分区实际格式一致(ext4/ubifs/squashfs) |
复盘时建议按“Bootloader→内核→Rootfs”的顺序逐级确认:先看串口是否有U-Boot打印,再看内核是否解压并启动,最后看VFS挂载和init执行。每一级的日志都是定位问题的关键线索。Rootfs虽然位于链路末端,但它决定了系统能否真正“活”起来,是嵌入式Linux启动流程中不可替代的一环。