Jetson AGX Orin 本地 OTA 全流程解析与实战总结(A/B + _alt + UEFI Capsule)


📺 B站博主个人介绍

📘 博主书籍-京东购买链接*:Yocto项目实战教程

📘 加博主微信,进技术交流群jerrydev


Jetson AGX Orin 本地 OTA 全流程解析与实战总结(A/B + _alt + UEFI Capsule)

适用范围:Jetson AGX Orin(T234),L4T/JetPack R36.x 系列 local/offline OTAnv_ota_start.sh + payload 包)。

文档定位:面向工程落地的“过程复盘 + 机制解释 + 排障清单”。全篇采用客观描述,不使用第一人称。


1. 背景与目标

在 Jetson 平台上,本地 OTA 的典型目标是:

  • 在设备本地执行 nv_ota_start.sh <ota_payload_package.tar.gz>
  • 将新版本写入 非当前运行槽位(A/B Rootfs 模型)
  • 使用 UEFI Capsule 触发 bootloader 延迟更新(重启阶段执行)
  • 通过状态变量/链路计数完成切槽与回滚保护

实践中,最常见的困惑集中在两点:

  1. “日志看起来更新了很多分区,是否等于 A/B 两边都被更新?”
  2. “bootloader 为什么显示‘重启后才更新’?脚本跑完是否就代表升级生效?”

本文以真实运行日志为例,拆解 OTA 触发、解包、分区写入、_alt 交换、Capsule 投递与验证步骤,建立清晰的心智模型。


在这里插入图片描述

2. 三套机制必须区分清楚:A/B、_alt、Capsule

2.1 Rootfs A/B(槽位更新模型)

  • A/B 的核心是:同一类关键分区存在 A 槽与 B 槽两套

  • 运行时通常处于 A 或 B 其中之一。

  • 本地 OTA 的常规策略是:

    • 当前运行在 A → 更新 B
    • 当前运行在 B → 更新 A
  • OTA 完成写入后,需要通过 重启与槽位选择机制使系统切到新槽位启动。

2.2 _alt(同名分区的安全交换更新)

  • _alt 机制常用于 recovery / recovery-dtb 等关键但不一定属于 rootfs 槽位的分区。

  • 典型成对存在:XX_alt

  • 更新策略不是“同时更新两边”,而是:

    1. 先把新镜像写到 X_alt
    2. 校验成功后 swap 分区 name/GUID,让 X 指向新内容
    3. 把旧侧擦空,作为下一轮 X_alt

该机制用于提升“断电/中断时的可恢复性”,与 A/B 槽位是两个不同层级的可靠性手段。

2.3 UEFI Capsule(bootloader 的延迟执行更新)

  • Capsule 模式下,Linux 阶段并不逐个分区刷 bootloader。

  • Linux 只做两件事:

    • *.Cap 文件投递到 ESP 的 EFI/UpdateCapsule 目录
    • 写入 UEFI 变量(例如 OsIndications)触发下一次启动执行更新
  • 真正的 bootloader 更新发生在 下一次 reboot 的早期阶段(UEFI 执行)


3. 真实日志复盘:本次 OTA 实际更新了哪些对象

以下结论来自一次 nv_ota_start.sh 的完整输出(日志编号示例:/ota_log/ota_YYYYMMDD-HHMMSS.log)。

3.1 关键判定:当前槽位与目标更新槽位

日志中出现:

  • ROOTFS_AB_ENABLED=1 → rootfs A/B 已启用
  • ROOTFS_CURRENT_SLOT=0 → 当前运行在 A 槽(slot 0)
  • UPDATE_SLOT=B → 本次选择更新 B 槽

结论:rootfs 与 A/B 相关分区将以“更新 B 槽”为主线。

3.2 Rootfs(B) 的实际写入目标

日志中出现:

  • nv_ota_rootfs_updater.sh -p /dev/mmcblk0p2 ... system.img
  • Rootfs on non-current slot(B) is updated

结论:rootfs(B) 被写入到设备节点 /dev/mmcblk0p2

说明:p2 是“本设备当前 GPT 排布的结果”。脚本通常依据分区名/槽位映射解析设备节点,而非硬编码固定 p2

3.3 Kernel / Kernel-DTB(A/B 槽位分区)

日志中出现:

  • Updating B_kernel partition done(写入 boot.img 并回读校验)
  • Updating B_kernel-dtb partition done(写入 DTB 并回读校验)

结论:本次更新了 B 槽对应的 kernel 与 kernel-dtb。

3.4 recovery / recovery_alt(_alt 安全交换更新)

日志中出现:

  • 先对 recovery_alt 写入并校验
  • Start swapping partition name and guid.
  • Set name recovery_alt to ... and recovery to ...
  • Erase recovery_alt ... successfully.

结论:recovery 采用 _alt 机制完成“写入 → swap → 擦空旧侧”的安全更新。

该现象常被误解为“两个分区都被更新”。实际上更新语义是:

  • 新镜像先落在 alt
  • swap 后 recovery 指向新镜像
  • 旧侧被擦空并作为下一次 alt

3.5 recovery-dtb / recovery-dtb_alt(若目标已一致则跳过)

日志中出现:

  • The recovery-dtb is already updated. Skip update process.

结论:recovery-dtb 已经与目标镜像一致,本次跳过写入流程。

3.6 ESP 分区镜像(esp.img 缺失 → 跳过分区级刷新)

日志中出现:

  • .../esp.img ... is not found
  • Skip updating esp partition as no valid image is found

结论:未进行 esp 分区的“镜像级刷新”。

注意:即便 esp.img 缺失,bootloader capsule 仍可能会使用 ESP 挂载点作为投递目录。

3.7 Bootloader(Capsule 投递与触发)

日志中出现:

  • trigger_uefi_capsule_update
  • TEGRA_BL.Cap 复制到 ESP 的 EFI/UpdateCapsule
  • 写入 UEFI 变量
  • Bootloader on non-current slot(B) is to be updated once device is rebooted

结论:bootloader 更新被“触发并排队”,实际刷写发生在重启阶段。


4. 为什么会更新这些分区:从脚本结构解释“谁决定刷哪些”

本地 OTA 的“刷写清单”由两层逻辑共同决定:

  1. update_control 文件决定“是否更新 rootfs / bootloader”
  2. rootfs 分支内的固定流程决定“更新哪些分区集合”(包含 A/B 与部分 misc/_alt 分区)

4.1 update_control:决定更新大类(rootfs / bootloader)

典型代码路径:

  • nv_ota_update_implement.sh 调用 get_update_control $OTA_WORK_DIR UPDATE_BOOTLOADER UPDATE_ROOTFS

  • get_update_control() 读取 OTA_WORK_DIR/update_control 的内容(例如包含 bootloaderrootfs 两行)

  • 读取到关键字后设置变量:

    • UPDATE_BOOTLOADER=1
    • UPDATE_ROOTFS=1

当日志显示:

  • UPDATE_BOOTLOADER=1, UPDATE_ROOTFS=1

意味着两条分支都会执行。

4.2 Rootfs 分支:在 A/B 启用时固定更新非当前槽 + kernel + dtb

当检测到:

  • ROOTFS_AB_ENABLED=1

主流程会进入“rootfs A/B 更新路径”,其典型顺序为:

  1. 选择更新槽位(A → 更新 B,B → 更新 A)
  2. 更新 misc 分区(可能包含 recovery/recovery-dtb/esp 等)
  3. 更新 rootfs(非当前槽)
  4. 更新与槽位绑定的 kernel
  5. 更新与槽位绑定的 kernel-dtb
  6. 清理/复位槽位链路状态变量(例如 rootfs 状态变量)

4.3 Bootloader 分支:Capsule 投递与触发

UPDATE_BOOTLOADER=1,脚本通常不会在 Linux 里直接刷写一长串 bootloader 分区,而是:

  1. 挂载 ESP(脚本常见挂载点:/opt/nvidia/esp 或类似路径)
  2. 复制 TEGRA_BL.CapEFI/UpdateCapsule
  3. 写 UEFI 变量触发下次启动更新

这就是日志出现“once device is rebooted”的原因。


5. OTA_WORK_DIR 与 internal_device:它们与 payload 的关系

5.1 OTA_WORK_DIR(例如 /ota_work):解包后的执行现场

nv_ota_start.sh 的核心动作之一是将 payload 解包到 OTA_WORK_DIR。该目录通常包含:

  • 解包后的 ota_package.tar(及其校验)
  • OTA 运行脚本(nv_ota_*.sh*.func 等)
  • 控制文件(update_control、备份清单等)
  • internal_device/(核心镜像集合)
  • 若干运行时临时文件与备份文件

因此,OTA_WORK_DIR 不仅包含“要刷的镜像”,还包含“决定怎么刷”的策略与脚本。

5.2 internal_device:用于刷写的核心镜像集合

典型结构:

  • internal_device/system.img:rootfs 镜像
  • internal_device/system.img.sha1sum:rootfs 校验
  • internal_device/images-R36-ToT/:分区镜像集合(kernel/dtb/recovery 等)与映射索引信息

可将 internal_device/ 视为“payload 中用于设备刷写的核心组件集合”。


6. 为什么日志里看到具体的 /dev/mmcblk0p9 / p12 / p2?是否写死?

一般情况下并非写死,原因如下:

  • recovery 类分区:脚本按分区 名称/label 查找对应设备节点,设备上具体落到 p9/p12 取决于 GPT 布局
  • rootfs(B):脚本按槽位映射选择 B 对应的 rootfs 分区,设备上具体落到 p2 同样取决于 GPT 布局
  • kernel/dtb:部分实现会根据索引(如 flash.idx 或同类映射文件)以 offset 写入块设备,因此日志可能显示 offset 而非 pN

排障时建议优先关注:

  • 日志中的 分区名(recovery、B_kernel 等)
  • 槽位变量(ROOTFS_CURRENT_SLOTUPDATE_SLOT

而非过度依赖 pN 号在不同设备上的一致性。


7. 3 分钟验证清单:确认“写入完成”与“重启生效”

7.1 OTA 跑完但未重启:确认 B 槽内容已写入

  1. 查看槽位信息:
sudo nvbootctrl dump-slots-info
sudo nvbootctrl get-current-slot
  1. 挂载 B 槽 rootfs 分区检查版本文件(示例以日志中的 /dev/mmcblk0p2 为准):
sudo mkdir -p /mnt/rootfsB
sudo mount /dev/mmcblk0p2 /mnt/rootfsB
cat /mnt/rootfsB/etc/nv_tegra_release 2>/dev/null || true
sudo umount /mnt/rootfsB

含义:即使系统仍在 A 槽运行,也能确认 B 槽 rootfs 真实被更新

7.2 重启后:确认切槽与版本生效

sudo nvbootctrl dump-slots-info
sudo nvbootctrl get-current-slot
cat /etc/nv_tegra_release
uname -a

目标状态通常包括:

  • current slot 指向新槽位(例如 B)
  • 系统版本信息与新包一致
  • 槽位状态正常(slot status/boot success 相关字段合理)

8. _alt 分区 vs 无 _alt 分区:差异总结

8.1 有 _alt:更强的更新可靠性(写 alt → 校验 → swap)

  • 适用:recovery 这类关键分区

  • 优点:

    • 更新中断更容易恢复
    • 可分阶段推进(日志常出现类似 S1/S4 的状态描述)

8.2 无 _alt:直接覆盖写(或按 A/B 槽位写入)

  • 适用:kernel 等与槽位绑定的分区
  • 优点:流程简单
  • 风险:如果该分区本身不具备“同名备用副本”,中断时需依赖其它机制兜底(例如 A/B 槽位回滚、boot chain 校验等)

再次强调:

  • _alt 是同一功能分区的安全更新副本机制
  • A/B 是整套系统运行与更新的双槽机制

两者解决的问题不同。


9. 常见提示与误判点(基于日志场景)

9.1 “脚本跑完了,但系统看起来没升级”

常见原因:

  • bootloader capsule 需要重启后执行
  • 当前仍在旧槽位运行,尚未切换到更新后的槽位

建议按第 7 节完成“未重启写入验证”与“重启后生效验证”。

9.2 “esp.img not found” 是否等于失败?

不必直接判定为失败。该信息仅表示:

  • 本次 OTA 包未提供 esp 分区镜像,因此脚本跳过 esp 的镜像级刷新

如果 capsule 投递正常,ESP 仍可能被用于 capsule 文件存放与触发。

9.3 “entry_table.ota_backup not found” 是否等于失败?

该信息更像是“备份文件缺失”的提示。是否影响升级,需要结合脚本是否在此处 exit 以及后续关键步骤是否继续推进来判断。若流程持续执行且写入校验通过,一般不是主致命点。


10. 本次升级的“分区更新清单(按模块归类)”

以下清单可直接用于项目文档/交付记录。

10.1 Rootfs A/B(目标:B 槽)

  • rootfs(B):/dev/mmcblk0p2(从日志得出)
  • B_kernel:写入 boot.img(回读校验通过)
  • B_kernel-dtb:写入 kernel_tegra...dtb(回读校验通过)

10.2 _alt 安全更新分区

  • recovery / recovery_alt:完成写入、swap 与擦空流程
  • recovery-dtb / recovery-dtb_alt:目标镜像已一致,跳过写入

10.3 ESP / Capsule

  • esp.img:缺失 → 跳过 esp 镜像级更新
  • TEGRA_BL.Cap:已投递到 EFI/UpdateCapsule 并设置触发变量 → 重启后执行

11. 附:如何把 OTA 包进一步“解剖成对照表”

为了形成可审计的“刷写清单”,可将以下信息整理成表格:

  • 分区名(例如 B_kernel、recovery)
  • 镜像文件名(例如 boot.img、recovery.img)
  • 写入方式(分区设备节点 / offset 写入 / _alt 交换 / capsule 投递)
  • 校验方式(sha1、回读比对、UEFI 变量/状态)

所需输入通常包括:

  1. internal_device/images-R36-ToT/ 的文件清单(ls -l
  2. images 目录下用于映射的索引文件(例如 flash.idx 或同类映射文件)
  3. OTA 日志末尾关键段(包含写入与校验结果)

整理后即可得到一张“分区名 → 镜像 → 实际设备/offset → 校验结果”的对照表,用于发布记录或交付文档。


12. 复盘性总结(可作为博文结尾)

Jetson AGX Orin 的本地 OTA 日志需要从三套机制解读:

  • A/B 决定 rootfs 与关键槽位分区只更新 非当前槽
  • _alt 决定 recovery 类分区采用“写 alt → swap → 擦空旧侧”的安全更新
  • Capsule 决定 bootloader 更新属于“Linux 投递触发,重启后 UEFI 执行”的延迟生效模式

当日志显示:

  • UPDATE_SLOT=B
  • Rootfs on non-current slot(B) is updated
  • Updating B_kernel ... done
  • trigger_uefi_capsule_update + once device is rebooted

即可判定:

  • B 槽 rootfs/kernel/dtb 已写入
  • recovery 已按 _alt 完成安全更新
  • bootloader 更新已触发并等待重启执行

验证步骤应分成两阶段:

  1. 重启前验证 B 槽确已写入
  2. 重启后验证切槽与 capsule 执行结果

📺 B站博主个人介绍

📘 博主书籍-京东购买链接*:Yocto项目实战教程

📘 加博主微信,进技术交流群jerrydev


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值