当前位置:首页>Linux>嵌入式Linux启动流程与关键机制解析

嵌入式Linux启动流程与关键机制解析

  • 2026-10-11 07:47:45
嵌入式Linux启动流程与关键机制解析

一、启动全流程:分层接力

嵌入式 Linux 启动是一条从硬件到用户空间的逐级接力链,可概括为6个阶段:
上电→ BootROM → 第一阶段引导(SPL/ATF)→ U-Boot → Kernel → rootfs → init → 用户空间。
  • BootROM:芯片固化代码,判断启动介质,加载 SPL。
  • SPL:初始化 DDR、基础时钟,加载完整 U-Boot 到内存。
  • U-Boot:全面初始化外设,加载内核与设备树,传递参数,最后跳转入内核。
  • Kernel:解压、初始化内存/中断/调度等核心子系统,解析设备树驱动,挂载 rootfs。
  • init:启动第一个用户进程,拉起服务与应用程序,系统进入可用状态。
总结为如下表所示:

阶段

主体

核心任务

常见异常现象

上电

SoC BootROM

判断启动介质、加载 SPL 到 SRAM

无任何输出、串口无字符

SPL / TF-A

一级引导

DDR、时钟、电源初始化

卡在 SPL、反复重启

U-Boot

二级引导

加载 kernel + dtb、设置 bootargs、跳转内核

U-Boot 正常,不进内核

Kernel

Linux 内核

解压、子系统初始化、驱动探测

内核打印中途死机

rootfs

根文件系统

挂载根分区、准备用户空间

Kernel panic: VFS

init

用户空间

systemd / init 启动服务与应用

卡在 init、无法登录

二、UBoot 的工作机制

UBoot 的两个核心职责不是“启动 Linux”,而是:
  1. 准备好运行环境:DDR、时钟、串口、存储设备;
  2. 把控制权交给内核:加载 Image / zImage、加载 .dtb、构造启动参数、跳转执行。

三、两个关键 U-Boot 变量:bootcmd 与 bootargs

二者功能层级完全不同(“bootcmd 管进不进,bootargs 管能不能活。”),排障时需先分清“死在进内核前”还是“进内核后”:
bootcmd(启动动作链):决定 U-Boot 怎么把内核拉起来。包含从存储读取镜像/dtb、设置地址、执行 bootm/booti/bootz等命令。若配置错误,通常连内核都进不去(无 early boot log、直接回 U-Boot 命令行)。
典型形式:
bootcmd=mmc dev 0; \
load mmc 0:1 ${kernel_addr_r} Image; \
load mmc 0:1 ${fdt_addr_r} board.dtb; \
booti ${kernel_addr_r} - ${fdt_addr_r}
bootargs(内核启动参数):决定内核接手后按什么配置继续初始化。常见含 console=、 root=、 rootwait、 init=等。若配置错误,内核往往能启动一段,但会死在控制台、挂载根文件系统或 init 环节。
典型示例:
bootargs=console=ttyFIQ0,1500000 \
root=/dev/mmcblk0p2 \
rootfstype=ext4 \
rootwait \
init=/sbin/init

对比项

bootcmd

bootargs

作用阶段

U-Boot 执行阶段

内核启动阶段

本质

命令脚本

字符串参数

决定内容

从哪里、用什么方式启动内核

内核起来后如何运行

典型示例

load mmc 0:1 ...; booti ...

console=ttyFIQ0 root=/dev/mmcblk0p2

出错表现

不进内核、停在 U-Boot

内核启动失败、rootfs 挂载失败

调试重点

镜像地址、dtb 地址、启动命令

console、root、init、mem

四、设备树(DTB)与启动参数的真实传递路径

❌ 常见误解 :“内核直接用 UBoot 的 bootargs 环境变量。”
✅ 真实机制(非常关键),实际流程如下:
U-Boot
├─ 读取 bootargs 环境变量
├─ 加载 DTB 到内存
├─ 修改 DTB 中的 /chosen/bootargs
│     ↓
└─ bootm / booti / bootz
↓
内核
↓
解析 /chosen/bootargs
↓
真实查看:/proc/cmdline

四、常见启动故障速查表(工程实战)

现象

优先排查点

串口完全无输出

电源、晶振、BootROM、启动拨码

卡在 SPL

DDR 初始化、供电、时钟

U-Boot 正常,不进内核

bootcmd、镜像地址、dtb 地址

内核启动中途卡死

内核配置、驱动、设备树

提示 VFS: Unable to mount root fs

root=、rootfs、存储驱动

无 console 输出

console=、stdout-path

init 启动失败

init=、rootfs 完整性、systemd

五、核心认知总结(可直接用于文档)

启动是接力赛:BootROM → SPL → U-Boot → Kernel → rootfs → init
bootcmd ≠ bootargs:前者是“怎么做”,后者是“做什么”
dtb 是交付物,不是静态文件:U-Boot 可动态修改
所有启动问题都可按阶段二分定位
真实参数永远以 /proc/cmdline为准
======================================
嵌入式 Linux 启动流程图
======================================
[1] 芯片上电
↓
[2] BootROM 运行
├── 判断启动介质(SD/eMMC/NAND/SPI Flash)
└── 加载 SPL 到 SRAM 并执行
↓
[3] SPL(Secondary Program Loader)
├── 初始化 DDR 内存
├── 配置时钟与电源
└── 加载 U-Boot 到 DDR 并跳转
↓
[4] U-Boot 启动阶段
├── 环境变量初始化(bootcmd, bootargs)
├── 加载 Kernel 镜像(zImage/uImage)到内存
├── 加载 Device Tree Blob(dtb)到内存
├── 设置启动参数(可动态修改 /chosen/bootargs)
└── 执行 bootm/booti/bootz 跳转至内核
↓
[5] Linux Kernel 接管
├── 自解压与初始化内存管理、调度器等子系统
├── 解析设备树(dtb)并初始化硬件驱动
└── 挂载 rootfs(依据 bootargs 中的 root= 参数)
↓
[6] 用户空间初始化
├── 启动 init 进程(PID=1)
├── systemd / busybox init 启动服务
└── 系统进入可用状态

最新文章

随机文章