4. Jetson系统启动流程与BSP定制
Jetson 的启动不是“上电即进 Linux”这么简单,而是一条由多级固件逐棒交接的链:BootROM → MB1 → MB2 → UEFI → 内核 → 根文件系统。理解这条链,才能知道 BSP 定制应该改哪一层、启动画面为什么出现在某个时刻、分区表为什么不能随意挪动,以及 OTA 升级究竟在替换什么。
一、五级启动链与各阶段职责
上电后,芯片内部固化的 BootROM 首先运行。它只做最少的事:初始化最基础的时钟与存储接口,按熔丝和 strap 引脚决定的顺序(如 QSPI、SD、USB 恢复模式)寻找 MB1。BootROM 代码不可修改,因此它决定了“设备能从哪些介质启动”这一硬约束。
MB1 运行在 BPMP(Boot and Power Management Processor)上,负责初始化 DRAM、配置电源与时钟、加载并校验后续镜像。MB2 继续完成内存与安全相关初始化,然后跳转到 UEFI(EDK2 固件)。UEFI 阶段承担设备枚举、PCIe/USB/网络初始化、读取 extlinux.conf 或 UEFI 启动项、加载内核 Image、设备树 *.dtb 与 initrd,最后把控制权交给内核。内核挂载根文件系统后启动 init,用户空间才真正跑起来。
二、BSP 定制的四个落点
NVIDIA 提供的 Jetson Linux BSP 包含源码包(sources/)与预编译包(Linux_for_Tegra/)。定制通常落在四处:
- MB1/MB2 配置:通过
p3701.conf之类的板级配置与bpmp相关 DTB 调整内存、启动介质顺序、安全启动开关。这一层改动风险最高,出错往往表现为“上电无任何输出”。 - UEFI 与启动项:修改
Linux_for_Tegra/bootloader/下的 UEFI 镜像或extlinux.conf,控制内核参数、启动超时、默认启动项与启动画面。 - 内核与设备树:在
sources/kernel/kernel-jammy-src中裁剪驱动、修改tegra234-p3701-*.dts中的 pinmux、I2C/SPI 节点、GPIO 定义。 - 根文件系统与分区:通过
flash.xml(或*.xml分区表)定义各分区偏移与大小,决定是否启用 A/B 冗余。
三、定制启动画面
启动画面分两段:UEFI 阶段的 logo 与内核阶段的 bootlogo。UEFI logo 由 Linux_for_Tegra/bootloader/ 中的 bmp.blob 提供,可用 NVIDIA 提供的 build_bmpblob.py 把自定义 BMP 打包替换。内核 logo 则通过内核配置 CONFIG_LOGO 与 logo_linux_clut224.ppm 替换,并在 extlinux.conf 中加 video=tegrafb0:1920x1080 等参数固定分辨率,避免 logo 拉伸。
四、分区布局与 OTA 基础
OTA 的本质是“把新镜像写入非活动槽,再切换启动指针”。因此分区表必须预留 A/B 两套 kernel 与 rootfs。以 32GB eMMC 为例,一种可参考的示例划分如下(数值为示例,实际需按镜像大小调整):
| 分区 | 大小示例 | 作用 |
|---|---|---|
| A_kernel | 64 MB | 槽 A 内核 + dtb |
| A_rootfs | 6 GB | 槽 A 根文件系统 |
| B_kernel | 64 MB | 槽 B 内核 + dtb |
| B_rootfs | 6 GB | 槽 B 根文件系统 |
| recovery | 1 GB | 恢复镜像,用于回滚 |
| APP / UDA | 剩余 | 应用数据与用户数据 |
NVIDIA 提供 nv_update_engine 与 ota_tools 实现 A/B 升级。一次典型 OTA 流程是:设备从服务器下载 ota_payload → 校验签名 → 写入 B 槽 → 设置 bootloader 环境变量指向 B → 重启验证 → 成功后标记 B 为活动槽。若验证失败,recovery 分区可回滚到 A 槽。
# 生成 OTA 包(示例)
sudo ./ota_tools/nv_ota_package.sh \
--board jetson-orin-nano \
--rootfs A \
--output ota_payload.tar.gz
# 设备端应用
sudo nv_update_engine --install ota_payload.tar.gz
sudo reboot
五、实操检查点
定制完成后,建议按以下顺序验证:先用 flash.sh 烧录并观察串口日志,确认 BootROM→MB1→MB2→UEFI 各阶段无报错;再检查 /proc/device-tree 中自定义节点是否生效;最后用 nvbootctrl 查看当前活动槽与槽状态。若串口在 MB1 阶段就停止,优先怀疑内存参数或启动介质配置;若在 UEFI 后停止,则检查 extlinux.conf 路径与内核镜像是否匹配。
掌握这条启动链后,后续的驱动开发、系统裁剪与量产烧录都会变得有据可依:每一层改动都能对应到具体的镜像、配置文件和验证手段,而不是盲目试错。