资讯详情

TF-M Secure 启动流程

📅 2026/11/6 3:48:42 | 华诺云谱 👁 阅读
TF-M Secure 启动流程
文章目录MPS2 AN521 tfm_s 启动流程向量表和复位入口Reset_HandlerC 运行时初始化Secure main设置架构保护配置 Secure 和 Non-Secure 边界初始化平台、串口和中断初始化 OTP 和 provisioning配置架构扩展和校验启动数据SPM 初始化启动 Non-Secure Agent调用链MPS2 AN521 tfm_s 启动流程BL2 通过校验tfm_s镜像后跳转到 Secure 镜像的向量表。本文从tfm_s的Reset_Handler开始说明 TF-M Secure 如何完成 C 运行时初始化、平台安全配置、分区加载以及 Non-Secure 启动。当前构建使用的主要源码如下platform/ext/target/arm/mps2/an521/cmsis_core/startup_an521.c platform/ext/target/arm/mps2/an521/cmsis_core/system_core_init.c secure_fw/partitions/lib/runtime/crt_start.c secure_fw/spm/core/main.c secure_fw/spm/core/spm_ipc.c secure_fw/spm/core/backend_sfn.c platform/ext/target/arm/mps2/an521/tfm_hal_isolation.c生成的 Secure 链接脚本是build_an521_ninja/generated/platform/ext/common/gcc/tfm_isolation_s.ld向量表和复位入口startup_an521.c将__VECTOR_TABLE放入.vectors段。链接脚本把这个段收集到.TFM_VECTORS并将它放在 Secure 镜像的起始位置。当前镜像带有0x400字节的 MCUboot image header所以向量表地址是0x10080400。constVECTOR_TABLE_Type __VECTOR_TABLE[]__VECTOR_TABLE_ATTRIBUTE{(VECTOR_TABLE_Type)(__INITIAL_SP),Reset_Handler,NMI_Handler,HardFault_Handler,/* 其余异常和外部中断处理函数 */};向量表的第一个 word 是初始 MSP第二个 word 是Reset_Handler。Cortex-M33 复位时由硬件读取这两个值然后从Reset_Handler开始执行。ENTRY(Reset_Handler)位于生成的tfm_isolation_s.ld中。Reset_HandlervoidReset_Handler(void){#ifdefined(__ARM_FEATURE_CMSE)(__ARM_FEATURE_CMSE3U)__disable_irq();#endif__set_PSP((uint32_t)(__INITIAL_SP));__set_MSPLIM((uint32_t)(__STACK_LIMIT));__set_PSPLIM((uint32_t)(__STACK_LIMIT));#ifdefined(__ARM_FEATURE_CMSE)(__ARM_FEATURE_CMSE3U)__TZ_set_STACKSEAL_S((uint32_t*)(__STACK_SEAL));#endifSystemInit();__PROGRAM_START();}__INITIAL_SP和__STACK_LIMIT由链接脚本提供。msp_stack段位于 Secure RAM 中__INITIAL_SP指向栈顶__STACK_LIMIT指向栈底。Secure 构建下Reset_Handler完成以下工作关闭中断避免 C 运行时和隔离配置尚未完成时进入异常处理。设置 PSP并设置 MSP、PSP 的栈边界寄存器。在 Cortex-M33 TrustZone 构建中写入 Secure stack seal。调用SystemInit()设置 Secure 向量表和时钟变量。调用__PROGRAM_START()进入 C 运行时入口。SystemInit()位于platform/ext/target/arm/mps2/an521/cmsis_core/system_core_init.c。它将SCB-VTOR指向__VECTOR_TABLE并初始化SystemCoreClock和PeripheralClock。C 运行时初始化GCC 构建中__PROGRAM_START在 CMSIS 的cmsis_gcc_m.h中展开为__cmsis_start。该函数使用链接脚本生成的表初始化 RAMfor(__copy_table_tconst*pTable__copy_table_start__;pTable__copy_table_end__;pTable){for(uint32_ti0u;ipTable-wlen;i){pTable-dest[i]pTable-src[i];}}for(__zero_table_tconst*pTable__zero_table_start__;pTable__zero_table_end__;pTable){for(uint32_ti0u;ipTable-wlen;i){pTable-dest[i]0u;}}_start();第一段把带初值的.data从 Flash 复制到 RAM第二段清零.bss。完成后调用secure_fw/partitions/lib/runtime/crt_start.c中的_start()。crt_start.c对main的声明是main(int argc, char **argv)而 TF-M SPM 中的定义是main(void)。当前两个函数都使用 C 符号main_start()传入的两个参数也不会被 SPM 的main(void)读取因此链接和调用可以正常工作。当前实际编译命令使用 GCC未定义__clang_major__所以执行crt_start.c的 GCC 分支void_start(void){main(0,NULL);while(1);}main()返回后不会回到调用方继续执行_start()会停在死循环中。正常情况下main()内的BACKEND_SPM_INIT()已经把 Secure 分区和 Non-Secure 启动流程接管。Secure mainTF-M Secure 的main()位于secure_fw/spm/core/main.c。当前 AN521 构建使用 SFN backend配置由生成文件build_an521_ninja/generated/interface/include/config_impl.h中的CONFIG_TFM_SPM_BACKEND_SFN 1表示。intmain(void){#ifdefCONFIG_TFM_ENABLE_PROFILINGPROFILING_INIT();#endifFIH_DECLARE(fih_rc,FIH_FAILURE);tfm_arch_config_branch_protection();tfm_arch_set_msplim(SPM_BOOT_STACK_TOP);fih_delay_init();FIH_CALL(tfm_core_init,fih_rc);if(FIH_NOT_EQ(fih_rc,SPM_SUCCESS)){tfm_core_panic();}tfm_arch_set_secure_exception_priorities();BACKEND_SPM_INIT();return0;}设置架构保护tfm_arch_config_branch_protection()配置架构相关的分支保护。随后tfm_arch_set_msplim(SPM_BOOT_STACK_TOP)将启动期间使用的 MSP 限制在链接脚本分配的 Secure 启动栈范围内。fih_delay_init()初始化 Fault Injection Hardening 使用的延时状态。配置 Secure 和 Non-Secure 边界tfm_core_init()首先调用tfm_hal_set_up_static_boundaries()。AN521 的实现位于platform/ext/target/arm/mps2/an521/tfm_hal_isolation.c主要完成配置 SAU 和 IDAU划分 Secure、Non-Secure 以及 Non-Secure Callable 区域。初始化 SRAM1、SRAM2 的 MPC。配置外设 PPC。当前隔离级别启用内存保护时配置 Secure MPU 区域并启用 MPU。生成 SPM 的静态边界句柄供后续分区边界绑定使用。当 FIH 校验配置启用时tfm_hal_verify_static_boundaries()会再次检查 SAU/IDAU、MPC、PPC 以及 MPU 配置。任何一步失败都会返回错误main()随后调用tfm_core_panic()不会继续加载分区。初始化平台、串口和中断tfm_core_init()接着调用平台实现的tfm_hal_platform_init()。AN521 的实现位于platform/ext/target/arm/mps2/an521/tfm_hal_platform.c调用顺序如下enable_fault_handlers();system_reset_cfg();init_debug();__enable_irq();stdio_init();nvic_interrupt_target_state_cfg();nvic_interrupt_enable();这里开启 Secure Fault、Bus Fault、MemManage Fault 和 Usage Fault设置 Secure 复位请求和调试权限打开中断并把 MPC、PPC 相关中断配置为 Secure 处理。日志后端也在这里初始化所以 TF-M 版本信息从此处开始输出。初始化 OTP 和 provisioning平台初始化成功后tfm_core_init()调用tfm_plat_otp_init();tfm_plat_provisioning_is_required(provisioning_required);tfm_plat_otp_init()初始化 AN521 使用的 OTP/NV counter 存储区域。随后 TF-M 从 OTP 读取生命周期状态判断是否需要 provisioning。需要时调用tfm_plat_provisioning_perform()完成后调用tfm_plat_provisioning_check_for_dummy_keys()检查当前设备是否使用 dummy key。当前 QEMU 配置启用了 dummy provisioning因此启动日志会出现[INF] Beginning TF-M provisioning [WRN] TFM_DUMMY_PROVISIONING is not suitable for production! This device is NOT SECURE [WRN] This device was provisioned with dummy keys. This device is NOT SECURE配置架构扩展和校验启动数据provisioning 检查完成后tfm_core_init()调用tfm_arch_config_extensions()然后输出隔离级别。最后调用tfm_core_validate_boot_data()检查 BL2 传递给 Secure 镜像的启动数据。该阶段完成后Secure 平台和隔离边界已经建立。SPM 初始化回到main()后TF-M 设置 Secure 异常优先级使 Non-Secure 代码不能抢占 Secure SVC 或 SecureFault。FIH 配置启用时还会再次验证异常优先级。当前配置是 SFN backend所以#defineBACKEND_SPM_INIT()tfm_spm_init()tfm_spm_init()位于secure_fw/spm/core/spm_ipc.c即使使用 SFN backend分区加载的公共入口仍然是这个函数。它依次完成初始化连接空间和 Non-Secure 上下文。从链接脚本的TFM_SP_LOAD_LIST区域读取分区加载信息。按load_order把分区插入 SPM 分区链表。为每个分区加载服务信息和中断信息。调用tfm_hal_bind_boundary()为分区建立平台隔离边界。调用backend_init_comp_assuredly()初始化分区运行时对象和栈水印。调用backend_system_run()进入第一个运行分区。AN521 当前生成的 Secure 分区包括 Crypto、Platform、Protected Storage 和 Internal Trusted Storage。Non-Secure Agent TZ 作为系统中的特殊分区保存在分区链表中SFN backend 会先准备它然后由backend_system_run()接管执行。启动 Non-Secure Agentbackend_system_run()位于secure_fw/spm/core/backend_sfn.c。它从平台接口读取 Non-Secure 镜像的入口地址param(void*)tfm_hal_get_ns_entry_point();tfm_hal_get_ns_entry_point()读取 Non-Secure 向量表第二个 word。随后 backend 为 Non-Secure Agent 分配的栈设置 PSP 和 PSPLIM调用arch_clean_stack_and_launch()arch_clean_stack_and_launch(param,(uintptr_t)spm_init_function,pldi-entry,SPM_BOOT_STACK_BOTTOM);这里的param是 Non-Secure 镜像的复位入口pldi-entry是 Non-Secure Agent 的入口spm_init_function负责按顺序执行 SFN 分区的初始化入口。完成栈切换后处理器从 Secure SPM 的启动栈切换到分区栈并进入 Non-Secure Agent。调用链Secure 向量表Reset_HandlerSystemInitC 运行时初始化_startSecure maintfm_core_init配置隔离边界平台和中断初始化OTP 和 provisioning校验启动数据设置 Secure 异常优先级tfm_spm_init加载分区信息绑定分区边界backend_system_run切换栈并启动Non-Secure Agent当前tfm_s.map可以看到关键符号的实际关系Reset_Handler startup_an521.o _start crt_start.o main secure_fw/spm/libtfm_spm.a(main.o) tfm_core_init secure_fw/spm/libtfm_spm.a(main.o) tfm_spm_init secure_fw/spm/libtfm_spm.a(spm_ipc.o) backend_system_run secure_fw/spm/libtfm_spm.a(backend_sfn.o)
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑