为什么有了 Device Tree,Jetson 还需要 BCT?从 `.dts`、`.bct` 到 UEFI 讲清 Jetson 启动配置

📅2026/7/11 20:16:38 👁️次浏览
为什么有了 Device Tree,Jetson 还需要 BCT?从 `.dts`、`.bct` 到 UEFI 讲清 Jetson 启动配置
B站 嵌入式孙老师博主个人介绍博主书籍-京东购买链接*Yocto项目实战教程加博主微信进技术交流群jerrydev为什么有了 Device TreeJetson 还需要 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 TreeLinux 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-BCTBoot ROM阶段后续组件在哪里、如何加载和验证Mem-BCTMB1DRAM、MC、EMC如何初始化MB1-BCTMB1及相关早期流程Pinmux、GPIO、电源、UPHY、安全等如何配置MB2-BCTMB2MB2阶段的平台与安全配置UEFI DTUEFIUEFI如何认识平台并选择启动资源Kernel DTLinux KernelLinux如何识别和驱动设备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.bctBoot ROM使用的配置数据applet_t264_sigheader.bin.encrypt经过安全封装的可执行程序mb1_t264_prod.binMB1可执行固件mb2_t264.binMB2可执行固件kernel-*.dtbLinux使用的设备树*.dtboDevice Tree OverlayTegraSign 工具负责生成签名、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 DTBJetson 的 L4tLauncher 负责加载 Kernel 和 Kernel DTB。UEFI │ ├── 读取启动配置 ├── 选择Kernel Image ├── 选择Kernel DTB ├── 应用相关Overlay ▼ 将Kernel和最终DTB交给LinuxUEFI 可以根据启动模式和配置选择独立的 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 │ ▼ UEFILinux 则使用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接管