为什么有了 Device Tree,Jetson 还需要 BCT?从 `.dts`、`.bct` 到 UEFI 讲清 Jetson 启动配置
📺 B站 嵌入式孙老师:博主个人介绍
📘 博主书籍-京东购买链接*:Yocto项目实战教程
📘 加博主微信,进技术交流群: jerrydev
为什么有了 Device Tree,Jetson 还需要 BCT?从 .dts、.bct 到 UEFI 讲清 Jetson 启动配置
在 Jetson BSP 中,经常能同时看到这些文件:
tegra264-br-bct-common-l4t.dts
tegra264-mb1-bct-pinmux-*.dts
tegra264-mb1-bct-pmic-*.dts
tegra264-p3834-0008-sdram-bct-l4t.dts
br_bct_BR.bct
applet_t264_sigheader.bin.encrypt
kernel-*.dtb
*.dtbo

这里很容易产生三个疑问:
- BCT 为什么也使用
.dts/.dtsi? - 已经有 Device Tree,为什么还需要这么多 BCT?
- 前面用了 BCT,为什么到了 UEFI 又开始使用 Device Tree?
问题的关键在于:
DTS 是配置的源文件语言,BCT 是早期启动固件使用的配置产物,DTB 是 UEFI 或 Linux 使用的设备树产物。
它们并不是同一层面的概念。
一、先看 Jetson 启动配置的完整分层
Jetson 并不是从上电开始就运行 UEFI 和 Linux,而是由多个启动阶段逐步建立运行环境。
上电
│
▼
Boot ROM阶段
│ 读取BR-BCT
│ 定位、认证并加载后续启动组件
▼
MB1
│ 读取Mem-BCT和MB1-BCT
│ 初始化DRAM、Pinmux、电源、UPHY和安全环境
▼
MB2
│ 读取MB2-BCT
│ 完成后续平台初始化
▼
UEFI
│ 使用UEFI阶段的Device Tree配置
│ 选择Kernel、Kernel DTB和启动设备
▼
Linux Kernel
│ 解析Kernel Device Tree
│ 匹配驱动并管理设备
▼
用户空间
在 T264 的官方启动架构中,最早期 ROM 阶段还可进一步划分为 PSCROM、HPSEROM、SBROM 等组件。为了便于理解,本文将这些不能由用户替换、位于启动链最前端的 ROM 组件统称为 Boot ROM 阶段。(NVIDIA Docs)
这条流程说明了一件事:
Jetson 不是在 BCT 和 Device Tree 之间二选一,而是在不同启动阶段使用不同的配置机制。
二、为什么不能从上电开始就使用 Kernel Device Tree?
Linux Device Tree 描述的是:
系统中有哪些设备
设备占用哪些寄存器和中断
依赖哪些Clock、Reset和Regulator
应该匹配哪个Linux驱动
但要加载 Linux 和 Kernel DTB,系统首先必须具备:
可访问的启动存储
可工作的外部DRAM
基本电源和时钟
正确的Pinmux
已建立的内存安全区域
可运行的后续Bootloader
这就产生了一个典型的启动依赖问题:
想加载Kernel DTB
↓
需要先初始化内存和启动存储
↓
初始化内存和启动存储又需要配置数据
如果把所有配置都放在 Kernel DTB 中,就会陷入循环:
硬件没有初始化
↓
无法正常加载和使用Kernel DTB
没有配置数据
↓
又不知道如何初始化硬件
BCT 的作用,就是在 UEFI 和 Linux 尚未运行时,为早期启动组件提供能够直接使用的平台配置。
MB1 会根据 Memory BCT 初始化 SDRAM,并根据 MB1-BCT 完成 Pinmux、GPIO、Pad Voltage、安全配置、内存 carveout 等工作。此时 Linux 尚未启动。(NVIDIA Docs)
可以用一句话概括:
BCT 负责建立 UEFI 和 Linux 能够运行的基础环境;Kernel Device Tree 负责描述 Linux 接管之后的硬件。
三、为什么 Jetson 需要多个 BCT?
因为 Jetson 启动不是一个程序完成的。
不同阶段运行环境不同、权限不同、任务也不同。每一个启动组件只应该读取自己需要的数据。
| 配置类型 | 主要消费者 | 解决的问题 |
|---|---|---|
| BR-BCT | Boot ROM阶段 | 后续组件在哪里、如何加载和验证 |
| Mem-BCT | MB1 | DRAM、MC、EMC如何初始化 |
| MB1-BCT | MB1及相关早期流程 | Pinmux、GPIO、电源、UPHY、安全等如何配置 |
| MB2-BCT | MB2 | MB2阶段的平台与安全配置 |
| UEFI DT | UEFI | UEFI如何认识平台并选择启动资源 |
| Kernel DT | Linux Kernel | Linux如何识别和驱动设备 |
1. BR-BCT:告诉 Boot ROM 从哪里继续启动
BR-BCT 主要保存 Boot ROM 所需的启动信息,例如:
启动介质配置
启动组件的位置
组件大小
加载地址
入口地址
Hash和认证相关信息
启动链相关状态
它解决的是:
芯片刚上电时,如何找到、验证并加载下一级启动程序?
这类数据并不是 Linux 设备拓扑,因此不适合放进 Kernel Device Tree。
2. Mem-BCT:先让 DRAM 工作
MB1 要加载体积更大的固件、UEFI 和 Linux,首先必须初始化外部内存。
Mem-BCT 中主要包含:
SDRAM配置
Memory Controller配置
External Memory Controller配置
内存训练参数
不同RAM Code对应的配置
Warmboot和频率切换相关参数
在实际 T264 BSP 配置目录中,可以看到类似文件:
tegra264-p3834-0008-sdram-bct-l4t.dts
tegra264-p3834-0008-sdram-bct-warmboot-l4t.dts
tegra264-p3834-0008-sdram.dtsi
tegra264-p3834-0008-sdram-dfs.dts
tegra264-p3834-0005-rc00.dtsi
...
tegra264-p3834-0005-rc15.dtsi
这些文件反映了不同模组、内存配置和 RAM Code 对应的参数组合。
3. MB1-BCT:完成早期平台初始化
这是 BSP Bring-up 中最常接触的一类 BCT。
从实际 T264 BSP 文件名可以看出,MB1-BCT 配置被拆分成多个功能模块:
tegra264-mb1-bct-pinmux-*.dts
tegra264-mb1-bct-gpio-*.dts
tegra264-mb1-bct-padvoltage-*.dts
tegra264-mb1-bct-pmic-*.dts
tegra264-mb1-bct-uphy-lanes-*.dts
tegra264-mb1-bct-prod-*.dts
tegra264-mb1-bct-cprod-*.dts
tegra264-mb1-bct-carveout-*.dtsi
tegra264-mb1-bct-ratchet-*.dts
tegra264-mb1-bct-misc-*.dts
对应的功能大致包括:
MB1-BCT
├── Pinmux和GPIO初始状态
├── Pad Voltage
├── PMIC与电源配置
├── UPHY Lane分配
├── Controller Prod参数
├── 启动存储配置
├── 内存Carveout
├── 安全与防回滚配置
└── 其他平台静态参数
它解决的是:
Linux 启动以前,SoC 和板级硬件应该处于什么状态?
NVIDIA 将 BCT 定义为供特定启动组件使用的平台配置数据;MB1 和相关启动阶段通过 MB1-BCT 获取平台静态配置。(NVIDIA Docs)
4. MB2-BCT:服务于后续启动阶段
实际 BSP 中还可以看到:
tegra264-mb2-bct-common.dtsi
tegra264-mb2-bct-misc-*.dts
tegra264-mb2-bct-firewall-*.dts
这些配置主要服务于 MB2 阶段的平台、安全和其他启动参数。
需要注意的是:
不能只凭文件名判断一份配置最终属于哪个 BCT。
正确的判断方法是继续查看:
它被哪个Board Config变量引用
由哪个工具处理
最终生成哪个二进制文件
由哪个启动组件读取
例如,某些文件名中虽然带有 mb1-bct,但最终可能通过特定配置变量进入 MB2 阶段的生成流程。
四、BCT 的 .dts/.dtsi 与 .bct 到底有什么区别?
这是最容易混淆的地方。
.dts/.dtsi 是源文件
例如:
tegra264-br-bct-common-l4t.dts
tegra264-mb1-bct-pinmux-*.dts
tegra264-mb1-bct-pmic-*.dts
它们是便于工程师阅读、组合和维护的文本配置。
其中:
.dts :通常作为一个完整配置的入口
.dtsi :通常作为可复用或可覆盖的配置片段
.bct 是生成后的二进制配置
例如:
br_bct_BR.bct
它是经过 NVIDIA BCT 工具链处理后生成的二进制 Boot Configuration Table,供早期启动组件读取。
完整关系是:
BCT .dts/.dtsi
│
│ include、合并和覆盖
▼
tegrabct_v2 / TegraFlash工具链
│
▼
二进制.bct
│
▼
Boot ROM / MB1 / MB2读取
从 T23x 开始,NVIDIA 将 BCT 的源配置格式改为 DTS。Boot ROM 和 MB1 实际消费的仍是由 tegrabct_v2 生成的二进制 BCT,而不是 Linux 使用的普通 DTB。(NVIDIA Docs)
因此:
.dts/.dtsi = 工程师维护的BCT源码
.bct = 启动固件读取的二进制产物
br_bct_BR.bct 并不是改了后缀的 DTB,也不能使用 Linux Device Tree 的方式理解或直接修改。
五、既然不是 Linux Device Tree,为什么 BCT 也使用 DTS?
因为 DTS 在这里首先是一种结构化配置语言。
它具备几个明显优势:
支持树状组织
支持#include
支持公共配置复用
支持板级差异覆盖
适合不同模组、载板和SKU组合
已有成熟的解析和检查工具
例如,同一份公共配置可以被不同板级入口文件包含:
#include "tegra264-mb1-bct-defaults.dtsi"
#include "tegra264-mb1-bct-pmic-common.dtsi"
#include "tegra264-board-specific.dtsi"
这比大量平铺的:
parameter_a = value_a;
parameter_b = value_b;
parameter_c = value_c;
更容易维护复杂 SoC 的平台配置。
但必须注意:
使用 DTS 语法,不代表它就是 Linux Device Tree。
决定一份 DTS 性质的,不是文件后缀,而是:
谁读取它
什么时候读取
遵循什么Binding
由什么工具处理
最终生成什么
可以类比为:
JSON 既可以保存应用程序设置,也可以描述网络协议。格式相同,不代表内容、消费者和生命周期相同。
六、applet_t264_sigheader.bin.encrypt 又是什么?
它与 BCT 不是同一类文件。
br_bct_BR.bct
是配置数据。
而:
applet_t264_sigheader.bin.encrypt
是经过启动安全工具链处理的可执行固件镜像。
文件名可以分成三部分理解:
applet_t264
└── Applet可执行程序
sigheader
└── 添加了启动认证相关头部
encrypt
└── 经过签名/加密处理流程生成的产物
Applet 通常参与 RCM 刷机阶段:
Host上的TegraFlash
│
│ USB Recovery/RCM
▼
发送Applet到目标SoC
│
▼
Applet在早期环境中运行
│
├── 读取芯片信息
├── 读取Fuse和RAM Code
├── 获取板级信息
└── 协助后续刷机流程
因此:
| 文件 | 本质 |
|---|---|
br_bct_BR.bct |
Boot ROM使用的配置数据 |
applet_t264_sigheader.bin.encrypt |
经过安全封装的可执行程序 |
mb1_t264_prod.bin |
MB1可执行固件 |
mb2_t264.bin |
MB2可执行固件 |
kernel-*.dtb |
Linux使用的设备树 |
*.dtbo |
Device Tree Overlay |
TegraSign 工具负责生成签名、Hash以及特定模式下的加密数据。不过,仅凭文件名中的 .encrypt,不能直接判断设备是否已经烧写 OEM Key 或启用了特定量产安全状态,最终状态还取决于使用的密钥、Fuse和刷机参数。(NVIDIA Docs)
七、为什么到了 UEFI 又开始使用 Device Tree?
因为运行到 UEFI 时,启动环境已经完全不同了。
在前面的 BCT 和早期固件协助下,系统已经完成:
DRAM初始化
基本电源和时钟初始化
早期Pinmux配置
启动存储访问
内存安全区域建立
UEFI镜像加载和认证
此时 UEFI 已经具备:
可用的外部内存
较完整的执行环境
访问启动存储的能力
解析FDT的能力
加载文件和启动操作系统的能力
所以 UEFI 可以使用更通用的 Device Tree 机制。
Jetson UEFI 中的 Device Tree 主要有两个角色。
1. 服务于 UEFI 自身
UEFI 需要认识当前平台的部分信息,例如:
启动设备
平台配置
固件相关节点
Reserved Memory
板级识别信息
启动模式
这些信息可以通过 UEFI 阶段的 DTB 或 DTBO 提供。
2. 为 Linux 准备 Kernel DTB
Jetson 的 L4tLauncher 负责加载 Kernel 和 Kernel DTB。
UEFI
│
├── 读取启动配置
├── 选择Kernel Image
├── 选择Kernel DTB
├── 应用相关Overlay
▼
将Kernel和最终DTB交给Linux
UEFI 可以根据启动模式和配置选择独立的 Kernel DTB。在部分 Jetson 启动配置中,如果没有找到指定的 Kernel DTB,还可能使用 UEFI 当前持有的 DTB作为后备。(NVIDIA Docs)
所以不能简单地说:
BCT用于Bootloader
Device Tree用于Linux
更准确的说法是:
BCT
负责最早期的平台建立
UEFI Device Tree
服务于固件阶段的平台描述和启动选择
Kernel Device Tree
服务于Linux驱动模型
八、BCT、UEFI DT 和 Kernel DT 是否存在重复配置?
会存在少量重叠,但它们承担的职责不同。
以一个 GPIO 控制的外设复位信号为例:
MB1-BCT
├── 将PAD配置为GPIO
├── 配置Pull
├── 配置Tristate
├── 设置输入输出能力
└── 设置启动早期状态
UEFI Device Tree
└── UEFI需要使用该设备时,描述固件阶段资源
Kernel Device Tree
├── 指定哪个Linux设备使用该GPIO
├── 定义高有效或低有效
└── 由Linux驱动申请并控制
Kernel DTS 中即使写了:
reset-gpios = <&gpio 10 GPIO_ACTIVE_LOW>;
也不能自动替代 MB1-BCT 中的 Pad 和 Pinmux 配置。
如果 PAD 在早期阶段仍然被配置为其他 SFIO 功能,或者处于不正确的 Tristate 状态,那么 Linux 驱动即使成功申请 GPIO,物理引脚也可能无法产生预期电平。
这不是配置重复,而是同一硬件在不同生命周期阶段分别被管理。
九、如何快速判断一个 Jetson BSP 文件属于哪一层?
不要只看 .dts 后缀,建议按照以下顺序判断。
第一步:看文件名和目录
*-br-bct-* → 很可能是BR-BCT源码
*-mb1-bct-* → 很可能是MB1-BCT源码
*-mb2-bct-* → 很可能是MB2-BCT源码
*-sdram-* → 很可能属于Mem-BCT
kernel/*.dts → 很可能属于Kernel Device Tree
uefi/*.dts → 很可能属于UEFI配置或Overlay
文件名只能作为线索,不能作为最终依据。
第二步:看 Board Config 中的引用变量
例如:
BCTFILE
PINMUX_CONFIG
PMIC_CONFIG
UPHY_CONFIG
EMC_BCT
MB2_BCT
SCR_CONFIG
OVERLAY_DTB_FILE
DTB_FILE
这些变量决定配置进入哪条生成链。
第三步:看处理工具
tegrabct_v2 / TegraFlash
→ BCT生成链
dtc / Kernel Build
→ Kernel DTB生成链
EDK2 Build
→ UEFI DTB/DTBO生成链
第四步:看最终产物
.bct
→ 启动配置二进制
.dtb/.dtbo
→ Flattened Device Tree
.bin/.bin.encrypt
→ 固件或可执行镜像
第五步:确认最终消费者
Boot ROM
MB1
MB2
UEFI
Linux Kernel
最终消费者才真正决定这个文件的性质。
十、完整生成关系
将这些文件放在一起,可以得到一条比较清晰的生成链:
板级配置文件
│
├── BR-BCT .dts/.dtsi
├── Mem-BCT .dts/.dtsi
├── MB1-BCT .dts/.dtsi
├── MB2-BCT .dts/.dtsi
│
▼
tegrabct_v2 / TegraFlash
│
├── br_bct*.bct
├── mem_bct*.bct
├── mb1_bct*.bct
└── mb2_bct*.bct
│
▼
签名、Hash和安全封装
│
▼
启动分区或刷机镜像
另一条链是:
UEFI .dts/.dtsi
│
▼
UEFI DTB/DTBO
│
▼
UEFI
Linux 则使用:
Kernel .dts/.dtsi
│
▼
dtc
│
▼
Kernel DTB/DTBO
│
▼
Linux Kernel
三条链都可能使用 DTS 语法,但最终产物和消费者完全不同。
总结
Jetson 使用多个 BCT,并不是因为 Device Tree 能力不足,而是因为最早期启动阶段还没有运行 UEFI 和 Linux,也没有完整的内存、存储及驱动环境。
BR-BCT、Mem-BCT、MB1-BCT 和 MB2-BCT 分别服务于不同启动阶段:
BR-BCT
解决“如何找到并验证后续启动组件”
Mem-BCT
解决“如何让DRAM工作”
MB1-BCT
解决“如何建立SoC和板级硬件的早期状态”
MB2-BCT
解决“如何完成后续平台初始化”
UEFI Device Tree
解决“固件阶段如何认识平台并加载操作系统”
Kernel Device Tree
解决“Linux如何识别和管理硬件”
BCT 之所以也使用 .dts/.dtsi,只是因为 NVIDIA 选择了 DTS 作为结构化配置语言:
DTS决定配置怎么写。
BCT决定配置给哪个启动组件使用。
DTB决定哪棵设备树交给UEFI或Linux。
最准确的理解是:
启动越早,配置越专用、固定并强调安全验证;启动越晚,平台描述越通用、动态,并逐渐交给 UEFI 和 Linux 管理。
因此,BCT 与 Device Tree 并不是相互替代的两套机制,而是 Jetson 分阶段启动架构中的上下游关系:
BCT先建立平台
↓
UEFI组织启动
↓
Kernel Device Tree完成Linux接管
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)