STM32N6 启动地址溯源报告
临时文档, 用于梳理"程序头地址 / 向量表地址"是如何被决定的。 依据: UM3234 (How to proceed with boot ROM on STM32N6 MCUs) + 本项目实测二进制。 结论先行:
0x34180400不是芯片硬编码的启动地址, 而是下载缓冲区基址 0x34180000+签名工具填充出的 0x400 偏移。 芯片真正强制的只有一件事: 向量表须 32 字节对齐。
一、问题的界定
本文所说的"启动地址"指 —— 程序映像被搬入 RAM 后, CPU 第一条指令所在的地址, 即向量表的绝对地址,
不是 C 语言的 Reset_Handler, 也不是链接脚本里 _estack 之类的符号。
对 FSBL 而言, 这个值是 0x34180400。对 Appli 而言, 由我们自己定, 当前是 0x34200400。
二、UM3234 中的相关章节索引
| 章节 | 页码 | 内容 | 与启动地址的关系 |
|---|---|---|---|
| §3.2.2.1 IDAU / SAU / MPU | p.7 | "the FSBL code must be aligned on 32-byte addresses (start and end addresses)" | 芯片唯一的硬性对齐要求 |
| §3.2.2.3 / Figure 4 RISAF2 区域配置 | p.7-8 | AXI-SRAM2 被划分为 7 个 RISAF 区域, Download buffer 区从 0x*4180000 起 | 确立 Download buffer 的基址与大小 |
| §3.9.1 / Table 19 固定地址定义 | p.21 | DOWNLOAD_BUFFER_BASE_ADDR / CONTEXT_BASE_ADDR | 给出基址 (该表 0xX4108000 为手册笔误, 见 §四) |
| §3.9.2 / Figure 8 内部 RAM 布局 | p.22 | 安全别名下 0x34180000 起为 Download buffer, 前 512 字节 = Header, 之后为 Code | 确立 基址 + Header 前置 格局 |
| §4.1.1 / Table 32 Base header | p.37 | 偏移 0x68 = Image length, 0x6C = Image entry point, 0x74 = Load address | 给出入口点的存放位置 |
| §5.1 / Figure 11 安全启动总览 | p.40 | "jumps to the FSBL entry point defined in the image header" | 明确跳转目标取自映像头 |
关键: 这五处分散在三个不同章节 (3.2 / 3.9 / 4.1 / 5.1), 没有任何一节的标题含"启动地址"字样,
所以按关键词直接搜索很难命中。§5.1 那一句是唯一一处文字直述跳转机制的地方。
注:
rm0486(参考手册) 不涉及此内容 —— 它描述外设与存储器映射, BootROM 的跳转逻辑不归它管, 全部在 UM3234 中。
三、推理链条 (从手册到 0x34180400)
第 1 步: 确定 Download buffer 基址 = 0x34180000
§3.9.2 / Figure 8 是最可靠的图源, 因为它把安全别名与非安全别名并列画出:
Secure alias AXI-SRAM2 Nonsecure alias
0x341FFFFF
Download buffer (Code) 512 Kbytes
Download buffer (Header)
0x34180200 0x84180200
0x34180000 0x24180000 ← 基址
安全别名 (X = 3) 下为 0x34180000。非安全别名 (X = 2) 下为 0x24180000。
本项目走 FullSecure 上下文, 故取安全别名
0x34180000。
第 2 步: 确认 Header 占前 512 字节 = 0x400
§3.9.2 / Figure 8 明确标注 "Download buffer (Header)" 覆盖 0x34180000 ~ 0x34180200,
即 512 字节。且 §4.1.1 的 Base header 偏移字段最大用到 0x9C, 加上各种扩展头,
512 字节是放得下的。
这是 0x400 这个数字的来源 —— 它本质上是"头部预留空间", 而不是一个神秘的常量。
第 3 步: 确认跳转目标来自映像头, 而非固定常量
§5.1:
If the secure boot succeeds, the boot ROM code stores the address of the boot context in the r0 register and jumps to the FSBL entry point defined in the image header (see Section 4.1).
§4.1.1 / Table 32 定义了该字段:
Name Length Byte offset Description
Image entry point 32 bits 108, 0x6C Entry point of image
所以 BootROM 读取映像偏移 0x6C 处的 32 位值, 然后跳过去。 该值是绝对地址。
第 4 步: 实测我们的 FSBL 映像头
对 FSBL/build/release/DefaultProjectName-trusted.bin (由 STM32_SigningTool_CLI 生成) 做 hexdump:
| 偏移 | 字段 | 实测值 |
|---|---|---|
0x00 | Magic number | "STM2" |
0x64 | Header version | 0x006DA58A |
0x68 | Image length | 0x00020300 = 131840 字节 |
0x6C | Image entry point | 0x0000FA40 |
0x74 | Load address | 0x00000000 |
0x80 | Extension flags | 0x00000000 |
0x34180000 + 0xFA40 = 0x3418FA40
即 BootROM 实际跳转到 0x3418FA40, 该地址落在 FSBL 代码区内 (Reset_Handler 附近)。
注意: 入口点字段是绝对地址, 不是相对基址的偏移。
0xFA40这个数值本身也不等于0x400。
第 5 步: 那么 0x400 到底是谁造成的?
是 STM32_SigningTool_CLI 的 -align 参数。
工具运行时的原始输出:
[Header v2.3] Align the payload to the 0x400 offset by adding padding bytes at the beginning of the payload.
Adding head padding bytes for payload with header v2.3
-align 让签名工具在头部与载荷之间填充字节, 把真正的代码顶到 0x400 边界上。
于是链接脚本按 ORIGIN = 0x34180400 编出来的代码, 搬进去之后恰好落在 0x34180400。
这是一个"工具参数"与"链接脚本"之间的约定, 不是芯片约束。
第 6 步: 反证 —— 去掉 -align 会怎样?
本项目开发过程中真实踩过这个坑:
- 早期
post-build-tasks.cmake缺少-align - 签名工具于是只生成约
0x240字节的头部 - 载荷被顶到
0x240而非0x400 - 链接脚本却按
0x34180400布局, 两者错位0x1C0字节 - 结果: FSBL 起不来, LED 不闪
加上 -align 后立刻恢复正常。 这直接证明 0x400 由工具决定, 改参数它就会变。
四、一处手册笔误
§3.9.1 / Table 19 中:
DOWNLOAD_BUFFER_BASE_ADDR 0xX4108000 Start address of the download buffer in internal AXI SRAM2
CONTEXT_BASE_ADDR 0xX4100000 Start address of the context information structure
0xX4108000 只有 7 位十六进制数字, 而 STM32N6 地址为 32 位 (8 位十六进制)。
对照 §3.9.2 / Figure 8 可确认正确值是 0xX4180000 —— 手册此处漏了一个 0。
AXI-SRAM2 的范围是
0x34100000~0x341FFFFF(1MB)。 若按笔误的0x34108000解读, 会落在 SRAM2 低 32KB 处, 与 Figure 8 的布局图矛盾。 以 Figure 8 为准。
五、结论汇总
| 问题 | 答案 |
|---|---|
0x34180400 由谁决定? | 下载缓冲区基址 (0x34180000) + 签名工具填充偏移 (0x400) |
| 芯片硬编码了吗? | 没有 |
| BootROM 如何知道往哪跳? | 读映像头偏移 0x6C 的 Image entry point (绝对地址) |
| 芯片真正强制的约束? | 向量表须 32 字节对齐 (§3.2.2.1) |
0x400 是谁选的? | STM32_SigningTool_CLI -align 参数 |
| 改变了会怎样? | 改工具参数 / 改链接脚本, 二者必须一致; 不一致则 FSBL 无法启动 |
| 在哪一节能看到机制全貌? | 无单一章节。需拼合 §3.2.2.1 + §3.9.2 + §4.1.1 + §5.1, 其中 §5.1 是唯一的文字直述 |
六、对本项目的实际含义
当前 FSBL 的这条链是自洽的:
┌─ 外部位: XSPI2 Flash 0x70000000
│ (签名后的映像, 前 0x400 为头)
BootROM ───────┤
│ ┌─ 内部位: AXI-SRAM2 Download buffer 0x34180000
└──► │ BootROM 把映像搬到这里
│ 读映像头 0x6C 的入口点
└──► 跳到 0x3418FA40 (FSBL Reset_Handler)
关键联动: .ld 的 ORIGIN = 0x34180400 与签名工具 -align 产生的 0x400 必须恒等。
如果将来调整 EXTMEM_HEADER_OFFSET 或改用非 -align 的签名流程,
.ld 必须同步修改, 否则链接出来的代码会与实际加载位置错位。
Appli 侧不受此约束 —— FSBL 通过
EXTMEM_HEADER_OFFSET = 0x400(stm32_extmem_conf.h:73) 显式告知了自己"头部有多长", 跳转地址由BOOT_GetApplicationVectorTable()=EXTMEM_LRUN_DESTINATION_ADDRESS + EXTMEM_HEADER_OFFSET=0x34200000 + 0x400 = 0x34200400算出。这是我们自己可控的逻辑。