2. 嵌入式Linux启动流程
在RK3568这类ARM64 SoC上,上电到进入用户空间并不是“一步到位”,而是由多个引导阶段接力完成。每个阶段运行在不同的存储介质、不同的内存环境、不同的权限级别中,职责边界非常清晰。理解这条链路,是后续排查“卡在串口无输出”“内核起来了但挂载rootfs失败”“U-Boot找不到内核”等问题的前提。
整体顺序可以概括为:BootROM → SPL(TPL/SPL)→ U-Boot(proper)→ Kernel → rootfs → init。前三个阶段属于“引导加载”,后两个阶段属于“操作系统启动”。下面这张图展示了RK3568典型启动链路中各阶段的运行位置、加载对象与交接关系。
各阶段职责与关键动作
BootROM 是芯片出厂固化的只读代码,位于片内 SRAM。它在上电复位后首先运行,根据启动引脚或 eFuse 配置选择启动介质,从固定偏移读取 SPL 镜像,校验头部信息后跳转执行。BootROM 不可修改,但可以通过启动模式引脚决定从 eMMC、SD 卡还是 SPI NOR 启动,这是“变砖”后仍能通过 SD 卡恢复的底层保障。
SPL(Secondary Program Loader) 是 U-Boot 编译产物中的第一阶段。它体量很小,能在 SRAM 中运行,核心任务是初始化 DDR 控制器、时钟和关键引脚,然后把完整的 U-Boot 从存储介质搬运到 DDR 并跳转。RK3568 的 DDR 初始化参数与具体颗粒型号相关,因此 SPL 通常由 Rockchip 提供的 DDR bin 与 U-Boot 打包生成。
U-Boot 是功能完整的引导程序,运行在 DDR 中,提供命令行交互、环境变量、网络、USB、文件系统读写等能力。它的核心职责是加载内核镜像(Image 或 zImage)、设备树(dtb)以及可选的 initramfs,并通过 bootargs 向内核传递根文件系统位置、控制台、内存布局等参数。
Kernel 被跳转后先进行自解压与早期初始化,随后探测并初始化 CPU、中断控制器、时钟、存储、网络等驱动。当内核完成基础初始化后,会根据 bootargs 中的 root= 参数挂载根文件系统,并执行其中的 init 程序。
rootfs 是用户空间的起点。内核挂载 rootfs 后执行 /sbin/init(或 systemd、busybox init),由它拉起服务、登录界面和应用进程,系统才算真正“可用”。
典型启动日志与阶段识别
串口日志是判断启动卡在哪一阶段的最直接依据。下面是一段 RK3568 典型启动日志的关键片段:
BootROM: 1.0
SPL: v2017.09
DDR: 2GB, 1560MHz
U-Boot 2017.09 (rk3568)
Hit any key to stop autoboot: 0
Loading kernel from mmc 0:1 ...
## Booting Android Image at 0x00280000 ...
Kernel: Image
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 5.10.110
[ 2.345678] Run /sbin/init as init process
从日志可以清晰看到:BootROM 打印版本后交给 SPL,SPL 打印 DDR 信息后交给 U-Boot,U-Boot 打印 autoboot 倒计时并加载内核,内核打印版本与 init 进程启动。如果日志停在某一行不再前进,就能快速定位问题阶段。
各阶段职责速查表
| 阶段 | 运行位置 | 核心职责 | 常见故障现象 |
|---|---|---|---|
| BootROM | 片内 SRAM | 选择启动介质,加载并校验 SPL | 串口完全无输出 |
| SPL | 片内 SRAM | 初始化 DDR/时钟,加载 U-Boot | 打印 DDR 后卡死 |
| U-Boot | DDR | 加载 Kernel/dtb,传 bootargs | 找不到内核或 dtb |
| Kernel | DDR | 驱动初始化,挂载 rootfs | Kernel panic,无法挂载根 |
| rootfs | DDR + 存储 | 启动 init,拉起用户空间 | init 不存在或服务失败 |
案例:rootfs 挂载失败如何反推
假设串口日志显示内核已经启动,但最后停在:
[ 3.120000] VFS: Cannot open root device "mmcblk0p5" or unknown-block(0,0)
[ 3.120000] Please append a correct "root=" boot option
[ 3.120000] Kernel panic - not syncing: VFS: Unable to mount root fs
这说明 Kernel 阶段已经运行,问题出在 rootfs 定位。排查顺序应为:先确认 U-Boot 环境变量中 bootargs 的 root= 是否与实际分区一致;再确认该分区是否已烧录 rootfs 镜像;最后检查内核是否使能了对应的 MMC 驱动与文件系统(ext4、squashfs 等)。这类问题不需要重新编译 BootROM 或 SPL,只需修正 bootargs 或重新烧录 rootfs。
printenv bootargs 查看当前内核参数,用 setenv bootargs ... 临时修改后 boot 验证,确认无误再写入环境变量保存。
常见误区与复盘
- 误区一:认为 U-Boot 负责初始化 DDR。实际上 DDR 初始化在 SPL 阶段完成,U-Boot 运行时 DDR 已可用。若 DDR 参数错误,通常卡在 SPL 而非 U-Boot。
- 误区二:把 rootfs 当成“内核的一部分”。rootfs 是独立镜像,内核只负责挂载它。内核与 rootfs 可以分别升级,但需保证驱动与文件系统格式匹配。
- 误区三:忽略 bootargs 的传递。控制台、根分区、内存大小都依赖 bootargs,U-Boot 传错参数会直接导致内核启动异常。
- 误区四:启动失败就重烧全部镜像。应先看串口日志定位阶段,再针对性修复,避免浪费时间。
掌握这条启动链路后,后续构建 rootfs、打包镜像、配置 U-Boot 环境变量时,就能清楚知道每个文件最终会被谁读取、在哪个阶段生效,从而把“系统起不来”拆解成可定位、可验证的具体环节。