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程序,是内核进入用户空间的“落脚点”。
核心结论:Bootloader负责“把内核搬进内存”,内核负责“把Rootfs挂起来”,Rootfs负责“把用户程序跑起来”。Rootfs位于启动链路的末端,但它是系统真正可用的标志。

二、Rootfs在启动链路中的位置

内核启动的最后阶段会执行prepare_namespace(),根据bootargs中的root=参数去挂载根文件系统。挂载成功后,内核会尝试执行/sbin/init(或/init、/linuxrc),此时控制权才从内核态转移到用户态。

因此,Rootfs的位置非常明确:它位于内核初始化之后、用户空间启动之前。没有Rootfs,内核即使全部初始化成功,也只能打印Kernel panic - not syncing: No init found,无法进入Shell。

嵌入式Linux启动链路与Rootfs位置 ① Bootloader U-Boot / Barebox 初始化DDR/时钟/串口 加载 zImage + .dtb 跳转内核入口 跳转 ② Linux内核 vmlinuz / Image 内存/中断/驱动初始化 解析 bootargs 挂载根文件系统 挂载 ③ 根文件系统 Rootfs /bin /etc /lib /dev 执行 /sbin/init 进入用户态Shell 内核与Rootfs的“交接参数”:bootargs root=/dev/mmcblk0p2 rootfstype=ext4 rw console=ttyS0,115200 init=/sbin/init 失败点1 内核未加载成功 失败点2 VFS无法挂载rootfs 失败点3 No init found

三、关键参数与交接机制

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启动为例,完整链路如下:

  1. 上电后ROM Code从eMMC的boot分区加载U-Boot SPL到内部SRAM运行。
  2. SPL初始化DDR,再把完整的U-Boot加载到DDR并跳转。
  3. U-Boot从eMMC的kernel分区读取zImage和imx6ull-14x14-evk.dtb到DDR。
  4. U-Boot把bootargs写入内核启动参数区,执行bootz跳转内核。
  5. 内核初始化完成后,根据root=/dev/mmcblk0p2挂载eMMC第二个分区为根文件系统。
  6. 内核执行/sbin/init,BusyBox init读取/etc/inittab,启动Shell和应用程序。
调试技巧:如果串口只打印到“Uncompressing Linux... done, booting the kernel”就停住,通常是内核镜像或设备树加载地址错误;如果打印到“VFS: Cannot open root device”则重点检查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启动流程中不可替代的一环。