4. TF-A BL2 镜像签名与加载校验
任务说明
本案例面向ARM Trusted Firmware-A(TF-A)的BL2镜像生成与验证环节。BL2是Trusted Boot流程中的第二级引导加载程序,负责在BL1之后初始化DRAM并加载BL31/BL32/BL33。本案例目标为:使用TF-A源码编译生成BL2镜像文件,并通过解析ELF头与符号表,验证镜像的加载地址(LOAD地址)和入口点(Entry Point)与链接脚本中声明的值一致。
实现方案
采用TF-A标准编译流程生成BL2镜像(bl2.elf与bl2.bin)。随后编写一个独立的Python验证脚本,通过pyelftools库解析bl2.elf,提取以下关键信息:
- ELF文件头中的入口地址(
e_entry) - 第一个LOAD段的虚拟地址(
p_vaddr)与物理地址(p_paddr) - 符号表中
bl2_entrypoint符号的地址
同时从链接脚本(bl2.ld.S)中提取预期的BL2_BASE值,通过编译宏定义传入验证脚本,最终比对四者是否一致。
代码实现
以下为验证脚本verify_bl2.py的完整实现:
#!/usr/bin/env python3
"""
verify_bl2.py - 验证BL2镜像加载地址与入口点
用法: python3 verify_bl2.py <bl2.elf路径> <BL2_BASE值(十六进制, 如0x4020000)>
"""
import sys
from elftools.elf.elffile import ELFFile
def main():
if len(sys.argv) != 3:
print("用法: python3 verify_bl2.py <bl2.elf> <BL2_BASE>")
sys.exit(1)
elf_path = sys.argv[1]
expected_base = int(sys.argv[2], 16)
with open(elf_path, 'rb') as f:
elf = ELFFile(f)
# 1. 从ELF头获取入口点
entry = elf['e_entry']
print(f"[1] ELF入口点 (e_entry) : 0x{entry:08x}")
# 2. 遍历程序头,找到第一个LOAD段
load_vaddr = None
load_paddr = None
for seg in elf.iter_segments():
if seg['p_type'] == 'PT_LOAD':
load_vaddr = seg['p_vaddr']
load_paddr = seg['p_paddr']
print(f"[2] LOAD段虚拟地址 (p_vaddr) : 0x{load_vaddr:08x}")
print(f" LOAD段物理地址 (p_paddr) : 0x{load_paddr:08x}")
break
if load_vaddr is None:
print("错误: 未找到LOAD段")
sys.exit(1)
# 3. 从符号表获取bl2_entrypoint
sym_entry = None
for sec in elf.iter_sections():
if sec['sh_type'] == 'SHT_SYMTAB':
for sym in sec.iter_symbols():
if sym.name == 'bl2_entrypoint':
sym_entry = sym['st_value']
print(f"[3] bl2_entrypoint符号地址 : 0x{sym_entry:08x}")
break
if sym_entry is not None:
break
if sym_entry is None:
print("错误: 符号表中未找到 bl2_entrypoint")
sys.exit(1)
# 4. 与链接脚本期望值比对
print(f"[4] 链接脚本期望BL2_BASE : 0x{expected_base:08x}")
checks = [
("入口点 == BL2_BASE", entry == expected_base),
("LOAD虚拟地址 == BL2_BASE", load_vaddr == expected_base),
("LOAD物理地址 == BL2_BASE", load_paddr == expected_base),
("bl2_entrypoint == BL2_BASE", sym_entry == expected_base),
]
all_pass = True
for name, result in checks:
status = "通过" if result else "失败"
print(f" [{status}] {name}")
if not result:
all_pass = False
if all_pass:
print("\n验证结果: 全部一致,BL2镜像加载地址与入口点正确。")
else:
print("\n验证结果: 存在不一致,请检查链接脚本与编译配置。")
sys.exit(1)
if __name__ == "__main__":
main()
编译与生成
在TF-A源码根目录执行以下命令生成BL2镜像(以FVP平台为例):
make PLAT=fvp BL33=/path/to/bl33.bin DEBUG=1 \
BL2_BASE=0x4020000 \
all -j$(nproc)
编译产物位于build/fvp/debug/bl2/bl2.elf与bl2.bin。其中BL2_BASE=0x4020000为链接脚本中定义的加载地址,需与平台内存映射一致。
验证方法
运行验证脚本,传入生成的ELF文件与编译时使用的BL2_BASE值:
python3 verify_bl2.py build/fvp/debug/bl2/bl2.elf 0x4020000
脚本将依次打印ELF入口点、LOAD段虚拟/物理地址、bl2_entrypoint符号地址,并与期望的BL2_BASE逐一比对。
判定标准
验证通过需同时满足以下条件:
- 脚本输出的四项检查全部显示“通过”;
- ELF入口点、LOAD段虚拟地址、LOAD段物理地址、
bl2_entrypoint符号地址四者数值完全一致,且等于编译时传入的BL2_BASE; - 脚本退出码为0,并打印“全部一致”的结论。
若任一检查失败,说明链接脚本中的地址定义与编译参数不一致,需核对bl2.ld.S中BL2_BASE的赋值及平台内存布局。