当前位置:首页>Linux>嵌入式Linux多阶段接力的启动链?

嵌入式Linux多阶段接力的启动链?

  • 2026-10-11 06:45:40
嵌入式Linux多阶段接力的启动链?

1. 几道题

先看几道题,自测看看是否需要阅读本篇文章。

Q1. 上电后 DRAM 尚未初始化时,通常由谁运行?

A. 完整 U-Boot(在 DDR 中)

B. BootROM / SPL(片内 SRAM 路径)

C. Linux 内核早期解压代码

D. systemd 的 generator

答案:B。早期只能在 SRAM/ROM 路径,SPL 负责把 DDR 拉起来再加载 U-Boot proper。

Q2. U-Boot 与 Linux 内核之间,最核心的「硬件描述」契约是?

A. /etc/fstab

B. systemd target

C. Device Tree Blob (DTB) + bootargs

D. glibc ABI

答案:C。DTB 描述板级硬件,bootargs 传递 root/console 等运行参数。

Q3. 「业务上电后要延迟 5 秒再连云」这类策略,优先放在哪一层?

A. 用户态服务 / 应用(如 systemd timer 或业务逻辑)

B. 内核调度器源码

C. BootROM

D. 设备树 clock 节点

答案:A。产品策略应留在用户态,便于迭代且不影响内核稳定性。

Q4. 串口停在 “Starting kernel …” 之后没有继续,优先怀疑?

A. systemd 某个 unit 挂了

B. 应用层 segfault

C. D-Bus 未启动

D. 内核早期启动 / 控制台 / DTB 或解压跳转问题

答案:D。此时 PID 1 尚未运行,应查内核早期与 U-Boot 交接(地址、DTB、console)。

2. 软件是怎么“叠”在硬件上的

嵌入式Linux从来不是“一个大程序”,而是一条多阶段接力的启动链,加上运行期稳定存在的内核空间 + 用户空间。

这张图有两个时间维度,千万不要混为一谈:

  • 启动期(一次性):BootROM → SPL → U-Boot → Kernel → 挂载rootfs → 启动init
  • 运行期(长期):内核 + rootfs上的进程树;应用通过系统调用与驱动交互

3. 五层职责

3.1 BootROM —— 我们改不了的那一层

BootROM固化在i.MX6ULL硅片里,出厂即定。它根据启动引脚/熔丝选择启动介质(SD、eMMC、NAND、USB下载等),把第一级可执行镜像载入片内SRAM。

我们不需要动它,但必须知道它的存在。

3.2 SPL + U-Boot —— 把DDR“扶起来”的接力手

为什么要分SPL和完整U-Boot?因为上电瞬间DRAM还不可用,完整U-Boot放不进片内SRAM。

  • SPL:U-Boot的精简第一级,运行于片内SRAM,负责把DDR调起来
  • U-Boot:完整bootloader,提供命令行、环境变量、从存储/网络加载内核镜像与DTB

这一层的核心职责是准备“可启动的内存布局”:

  • 内核、DTB、可选initramfs的加载地址
  • 组装bootargs(内核命令行)
  • 把控制权干净地交给内核——之后通常不再回来

bootargs是U-Boot传给Linux的命令行字符串,典型内容如console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait。它是启动层与内核层之间的重要契约。

3.3 Linux内核 —— 资源管理者与硬件抽象中枢

内核我们先记住四大块就够用了:

Linux 内核四大块

内核不该塞业务策略(比如“三次重试后弹窗提示用户”)。那是用户态的事。内核只做三件事:接口稳定、资源安全、策略可配置。

3.4 根文件系统 —— 内核启动后的“世界”

根文件系统是内核mount成功后的完整世界:动态库、配置、/dev、/etc、服务单元、应用二进制。

没有可用的rootfs,内核会直接panic——经典报错:

VFS: Unable to mount root fs on unknown-block(0,0)

Rootfs可由eMMC/SD分区、NFS、initramfs等承载。Buildroot/Yocto的核心产物之一就是它。

3.5 用户态与PID 1 —— 产品的“灵魂”

内核启动的第一个用户进程是PID 1,也就是init。

我们接触的systemd就是init的一种实现:它负责服务依赖图、日志、目标运行态。在它之上,才是我们的采集、UI、云连接、OTA等业务进程。

PID 1如果退出,内核通常会panic或触发重启策略。它比普通进程“高贵”得多。

4. 层与层之间的“契约接口”

架构清晰,往往因为接口比实现更稳定。记住四条跨层契约:

四条跨层契约接口

工作落地一句话:改需求时先问“我改的是哪条契约的哪一侧?”

改契约本身(比如换root设备命名、改DTB兼容字符串)比改内部实现更危险,必须回归启动与量产流程。

5. i.MX6ULL上实操

U-Boot层

  • 打断启动,执行printenv,找bootargs、bootcmd、fdt_file/fdtfile、loadaddr
  • 典型加载地址(NXP 6UL/6ULL常见):kernel ≈ 0x80800000,DTB ≈ 0x83000000
  • 跳转命令常见:bootz ${loadaddr} - ${fdt_addr}(中间的-表示无initramfs)

Linux内核层

  • cat /proc/cmdline —— 看到U-Boot传入的bootargs
  • ls /sys/firmware/devicetree/base —— 查看运行中的设备树

用户态层

  • ps -p 1 -o comm= —— 确认PID 1是systemd还是其他
  • systemctl status —— 看服务依赖图

最新文章

随机文章