本帖最后由 STM新闻官 于 2025-11-2 11:59 编辑
前言
很多客户都有这样一个需求,在MCU中开发一个自己的bootloader程序,通过这个bootloader程序去升级App固件,但是,这个bootloader本身是不能更新的,很多客户但心自己写的bootloader程序可能存在某些bug,无法更新将导致很大的潜在风险,于是有人想到将bootlaoder分为两个阶段,bootloader1, bootloader2, 或者叫做iROT(Immutable Root Of Trust)和uROT(Updatable Root Of Trust), 由前者负责后者的升级(如 :iROT负责uROT的升级),后者负责 APP的升级(如uROT负责APP的升级). 它们的差别是:前者(iROT)是不可修改的,固化的代码,后者(uROT)是可更新的代码。当然它们不仅仅只负责升级,还负责安全启动、信任根的任务。在STM32H573/STM32H533中,iROT已经集成到芯片内部,叫做STiROT, 而uROT则仍然放在片内FLASH,ST官方叫OEMuROT, 它是基于开源项目MCU Boot来做的。
本文档通过一个动手实验, 详细演示了如何在STM32H573上实现一个STiROT+OEMuROT的功能. 旨在针对那些想使用STM32H573芯片内置的STiROT功能而又不知如何开始的开发者. 注:STiROT功能目前只存在于STM32H5系列带安全硬件加速器的型号,如STM32H573/H533。 STM32H563, STM32H503 是不支持STiROT特性的。
1. 准备工作 开发板 : STM32H573-DK(MR1) 软件包 : STM32Cube_FW_H5_V1.5.0 工具: • STM32CubeProgrammer v2.20.0 • Tera Term 串口终端显示 • Trust Package Creator(安装STM32CubeProgrammer 时一并安装, 注意勾选) IDE: STM32CubeIDE v1.18.1
通过STM32CubeProgrammer我们首先确保TrustZone未使能:
3. 烧录并运行一个APP程序 3.1 脚本环境配置 本动手实验基于STM32CubeH5包, 此包必须位于一个没有中文且没有空格的路径下, 于是我们将此包拷贝到C:\cube目录下。在路径STM32Cube_FW_H5_V1.5.0\Projects\STM32H573I-DK\ROT_Provisioning 目录下有一个env.bat文件和一个env.sh文件, 用文本编辑器(如记事本)打开此两个文件:
对应的env.sh文件类似,只不过.sh对应是在git bash下运行的。
检查上面两行, STM32CubeProgrammer_CLI.exe, 以及STM32TrustedPackageCreator_CLI.exe 这两个工具的安装路径是否跟你电脑中的安装路径符合, 如果不符, 则需要进行相应的修改. 同时确保默认配置正确: set stirot_boot_path_project=Applications/ROT/STiROT_Appli set oemirot_boot_path_project=Applications/ROT/OEMiROT_Appli_TrustZone 3.2 运行STiROT_OEMuROT provisioning脚本 再进入到cube包下的STM32Cube_FW_H5_V1.5.0\Projects\STM32H573IDK\ROT_Provisioning\STiROT_OEMuROT 目录下, 有一个名为provisioning.bat 的脚本, 和一个名为provisioning.sh 的脚本 :
接下来取决于你准备用哪个编译器,如果你准备用STM32CubeIDE来编译工程,那么你可用git bash 来运行provisioning.sh 脚本,如果你准备用IAR, 或者Keil MDK来编译工程,那么你可直接双击运行provisioning.bat脚本. 我们使用STM32CubeIDE编译工程来演示 , 于是在git bash下运行provisioning.sh脚本 :
如上图,在此动手实验过程中, 如无特别说明, 此窗口将一直保持。 我们将通过此窗口的提示信息进行每一步的操作。 图中信息提示我们打开TrustedPackageCreator工具, 生成STiROT_Config.obk文件. 3.3 生成STiROT_Config.obk 文件 打开TrustedPackageCreator 工具,切换到OBKey界面,选择xml配置文件: STM32Cube_FW_H5_V1.5.0/Projects/STM32H573IDK/ROT_Provisioning/STiROT_OEMuROT/Config/STiRoT_Config.xml
如上图, 打开TPC, 然后在上图1处点击打开ROT相关界面, 在2处选择OBKey界面, 然后在3处选择OBKey配置xml文件所有路径 : STM32Cube_FW_H5_V1.5.0\Projects\STM32H573IDK\ROT_Provisioning\STiROT_OEMuROT\Config 目录下的 STiRoT_Config.xml 文件, 此文件为生成STiROT对应obk文件的配置文档. 然后下面5处会显示两个密钥对, 从上到下分别为 : • STiRoT_Encryption.pem : OEMuROT 固件加密密钥对应的解包密钥(使用私钥) • STiRoT_Authentication.pem :APPOEMuROT 对应的认证密钥(使用公钥) 这两个密钥实际各自都是一对的。位于Keys目录下. STM32CubeH5包下已经自带了默认的密钥对, 如果你不想使用默认的, 则可以点击上图中的 “Regenerate” 重新生成这两个密钥对. 一旦重新生成, 则需要注意保存这两个密钥对. 接下来就要生成STiROT对应的obk文件了。在右边的输出路径下, 选择一个路径, 比如Binary 目录. 最后点击生成. 则将在Binary目录下生成STiRoT_Config.obk文件. 3.4 生成DA对应的obk文件 回到脚本终端窗口, 输入回车键 :
如上图提示,你须通过TPC工具生成DA_Config.obk文件. 有关如何生成DA_Config.obk文件, 之前已有其它文档讲述, 且STM32CubeH5包下的STM32Cube_FW_H5_V1.5.0\Projects\STM32H573I-DK\ROT_Provisioning\DA\Binary 目录中已经有现存的DA对应的obk文件, 其对应的私钥和证书分别位于上一级目录下的Keys目录和Certificates 目录下, 这些文件均可直接使用, 所以这里不再重复讲述它们的生成过程. 3.5 生成OEMuROT对应的OBK文件 直接按下回车键…
使用TPC配置OEMuROT的OBK :
如上图所示, 在xml file处,选择OEMuROT对应的xml文件 : STM32Cube_FW_H5_V1.5.0\Projects\STM32H573IDK\ROT_Provisioning\STiROT_OEMuROT\Config\OEMuRoT_Config_Keys.xml 然后下面有三对密钥: Authentication secure key: 认证 Secure APP 的密钥对 Authentication non security key: 认证 Non Secure APP 的密钥对 Encription key: APP 加密密钥(这里对应的是私钥,对应解密APP的AES密钥). 按下回车键… 注:若提示错误,请仔细检查路径中是否有空格和中文字符。若有,则将cube包挪移到另一个没有空格没有中文字符的路径,然后重新再来。
3.6 编译OEMiROT_Boot工程
打开STM32Cube_FW_H5_V1.5.0\Projects\STM32H573IDK\Applications\ROT\OEMiROT_Boot 所在的示例工程, 这里我们使用STM32CubeIDE打开. 然后在工程内打开flash_layout.h头文件,按如下修改 :
如上图,我们配置S_APP, NS_APP各自独立升级,且各自带一个data image(应用相关数据).为方便演示,这是可以配置的最大效果. 然而现实情况是,客户自已真实的APP,不管是 S_APP, 还是NS_APP,决大多数情况下都是不带Data image的,此时只需要将这两个宏
MCUBOOT_S_DATA_IMAGE_NUMBER和MCUBOOT_NS_DATA_IMAGE_NUMBER的值均配置为0即可。这里是为了更好的演示才打开的。 然后,编译它.
注:此OEMiROT_Boot工程正是对应了OEMuROT 此时在工程下的Binary目录下会生成三个文件 :
图 14 生成三个文件 随后在窗口内按下回车键…
3.7 编译APP工程
打开并编译OEMiROT_Appli_TrustZone工程… 工程路径: STM32Cube_FW_H5_V1.5.0\Projects\STM32H573IDK\Applications\ROT\OEMiROT_Appli_TrustZone 注:此工程对应用户APP工程(S+NS) 分别编译S_APP,和NS_APP..
随后在窗口内按下回车键… 3.8 生成data数据文件
接下来我们准备生成S_APP对应的data文件。 注: 之前我们在OEMiROT_Boot工程的flash_layout.h头文件中配置了S_APP和NS_APP均带一个data.bin文件,若要分别升级此两个文件,那么这两个文件也必须要加密且签名。这一步,我们需要对它进行打包加密。 在路径STM32Cube_FW_H5_V1.5.0\Projects\STM32H573IDK\ROT_Provisioning\STiROT_OEMuROT\Binary 下,我们可以找到S_APP和NS_APP对应的原始data.bin文件:
这两个data.bin文件是默认的文件,若客户实际情况APP有用到data.bin, 那么需要手动使用一个hex编辑器打开此文件,然后手动按实际需要编辑它。
接下来对其进行打包加密…
如上图所示,使用TPC切换到Image Gen界面,然后在xml文件中选择OEMuROT_S_Data_Image.xml 配置文件, 此文件位于 : STM32Cube_FW_H5_V1.5.0\Projects\STM32H573IDK\ROT_Provisioning\STiROT_OEMuROT\Images 在窗口中按下回车键,此时提示打包加密ns_data.bin文件…
然后也打包加密下ns_data.bin文件:
3.9 预配置provisioning 再按下回车键…
按提示将开关 SW1拨到0的位置后,此时芯片处于OPEN状态。再按下回车键…
如上图所示,脚本在写完FLASH,并配置OB之后,然后提示你要将其最终配置为何种状态… 这里我们输入closed…
输入closed状态后,按下回车键…
如上图所示打印信息,此时表示所有步骤完成。 3.10 使用串口终端连接 我们使用Tera Term这个串口工具连接串口查看程序运行的打印信息 :
到此,整个程序运行流程均正常。且当前App的版本号为 ‘A’. 4. 固件更新 接下来, 我们演示更新固件的过程。首先演示如何升级App. 4.1 修改代码, 并重新编译工程 再次打开OEMiROT_Appli_TrustZone工程下的NS_APP工程,修改版本号为”B”:
const uint8_t UserAppId = 'B'; 然后再编译它。生成新的固件 :
如上图,rot_tz_ns_app_enc_sign.hex 即为我们将要升级的NS_APP固件。 4.2 跳转到芯片内置的bootloader程序 在串口终端中我们输入”1”:
如上图所示, 输入1后, 程序跳转到芯片内置的bootloader中. 此时需要断开Tera Term的串口连接 :
4.3 通过STM32CubeProgrammer下载新固件 打开STM32CubeProgrammer, 并通过串口模式连接芯片:
将新生成NS_APP的加密后的固件rot_tz_ns_app_enc_sign.hex导入到STM32CubeProgrammer 中 (Binary 目录):
如上图点击Start Programming.
4.4 复位后再次运行,查看结果 下载成功后, 断开STM32CubeProgrammer的串口连接, 并使Tera Term重新连接串口 , 然后再重启板子, 于是可以看到如下打印信息 :
如上图所示, 程序运行起来后显示的版本“B”, 这说明新程序已经正常运行起来了。 升级S_APP的过程跟升级NS_APP的过程完全一致,只不过由于这个示例S_APP并无任何打印信息,即使你升级了,在打印中也看不出来。所以这里就不演示了。 4.5 OEMuROT 更新过程 升级OEMuROT的过程也是一样的,不过可以在打印信息中看得出来,所以我们再来看下更新OEMuROT的过程: 打开OEMiROT_Boot工程,在bl2_main.c文件中的main()函数中添加一点打印信息,以区别当前是新版本:
然后编译此OEMiROT_Boot工程… 在此工程的对应Binary目录下会生成新的打包加密文件 :
在Tera Term 界面上输入’1’后,然后断开Tera Term的串口连接 :
按'1',并断开串口连接, 注意这里要断开串口连接。 再使用STM32CubeProgrammer再次通过串口连接并下载新固件 :
点击下载新版本的OEMuROT。
然后断开连接,再次使用Tera Term连接串口终端, 复位并查看打印信息…
如上图所示,从启动过程的打印信息可知,新版本的OEMuROT已经成功更新了。 4.6 更新S_Data, NS_Data 更新S_Data, NS_Data 的过程也是类似的。均是由芯片内置的bootloader来负责将对应固件或者数据写入到对应下载位置, hex文件自带了地址信息,因此只固件或者数据会下载到正确的位置。然后由STiROT来负责安装OEMuROT, 而由OEMuROT负责来安装APP(S_APP, NS_APP). 在Tera Term 打印菜单下,我们按下’2’ 显示NS_Data的内容:
如上图所示,只显示上NS_Data的前两个word :0xb29a551a, 0xaafe09c7, 最后两个word : 0xba1233a9, 0x01c0e3fd. 使用STM32CubeProgrammer查看下原始的ns_data.bin文件内容:
这里完全对得上的。 然后我们使用一个hex文件编辑器修改下,将最后一个字节0xFD改成0x55.
然后再使用TPC进行打包加密:
会新生成ns_data_enc_sign.hex 文件. 接下来就按升级NS_APP一样的流程升级ns_data.bin文件即可。最后再次查看ns_data的内容:
如上图所示,再次查看修改后的ns_data内容,其数据完全对应得上。这说明ns_data升圾成功了。 s_data 的升级跟ns_data升级完全一致,只不过在菜单中并未显示s_data的内容而已。这里我们就不再重复演示。
5. 从代码中跳转到Bootloader的过程 我们来看一下在NS_APP中代码是如何实现跳转到bootloader的:
- /**
- * [url=/u/brief]@brief[/url] Perform Jump to the BootLoader
- * @retval None.
- */
- void LOADER_Run(void)
- {
- printf("\r\n Start config before jumping to the bootloader");
- SECURE_loader_cfg();
- for (int i = 0; i < 16; i++)
- {
- /*SRAM1 -> MPCBB1*/
- GTZC_MPCBB1_NS->SECCFGR[i] = 0;
- }
- uint32_t boot_address = *(uint32_t *)(BOOTLOADER_BASE_NS + 4U);
-
- /*Increment HDPL to HDPL=3*/
- SET_BIT(SBS->HDPLCR, SBS_HDPLCR_INCR_HDPL);
-
- /* change stack limit */
- __set_MSPLIM(0);
-
- __set_MSP((*(uint32_t *)BOOTLOADER_BASE_NS));
-
- SCB->VTOR = BOOTLOADER_BASE_NS;
-
- printf("\r\n Standard Bootloader started");
- printf("\r\n If you want to connect through USART interface, disconnect
- your TeraTerm");
- printf("\r\n Start download with STM32CubeProgrammer through
- supported interfaces (USART/SPI/I2C/USB)\r\n");
- printf("\r\n");
-
- __asm volatile("movs r0, %0\n"
- "bx r0\n" :: "r"(boot_address)); /*jump to non-secure address*/
- }
从上代码可知,在跳转到bootloader之前,代码作了一些配置的,以确保系统bootloader可以正常运行。 除此之外,当程序运行在OEMuROT时,若其未检测到APP的存在,或者按住User按键的情况下按下复位按键时,则会跳转到boot_platform_noimage()函数:
- #if defined(MCUBOOT_EXT_LOADER)
- /**
- * @brief This function manage the jump to boot loader application.
- * [url=/u/NOTE]@NOTE[/url]
- * @retval void
- */
- void boot_platform_noimage(void)
- {
- uint32_t rsslib_sec_jump_HDP_lvl3ns;
-
- BOOT_LOG_INF("Jumping to bootloader");
- BOOT_LOG_INF("Disconnect COM port if used by bootloader");
-
- /* Init RSS jump function descriptor */
- rsslib_sec_jump_HDP_lvl3ns = (uint32_t)(Rss_lib_p->S.JumpHDPLvl3NS);
-
- /* Check Flow control */
- FLOW_CONTROL_CHECK(uFlowProtectValue, FLOW_CTRL_STAGE_2);
- uFlowStage = FLOW_STAGE_CFG;
-
- /* Update run time protections for application execution */
- LL_SECU_UpdateLoaderRunTimeProtections();
-
-
- /* Check Flow control */
- FLOW_CONTROL_CHECK(uFlowProtectValue, FLOW_CTRL_STAGE_3_L);
- uFlowStage = FLOW_STAGE_CHK;
-
- /* Second function call to resist to basic hardware attacks */
- LL_SECU_UpdateLoaderRunTimeProtections();
-
-
- /* Check Flow control */
- FLOW_CONTROL_CHECK(uFlowProtectValue, FLOW_CTRL_STAGE_4_L);
-
- /* Jump into BL through RSS */
- /* last parameter (0U) not used in
- RSSLIB_Sec_JumpHDPL3NS(BOOTLOADER_BASE_NS); */
- boot_jump_to_RSS((uint32_t)&boot_jump_to_RSS,
- rsslib_sec_jump_HDP_lvl3ns, (uint32_t) BOOTLOADER_BASE_NS, 0U);
-
- /* Avoid compiler to pop registers after having changed MSP */
- #if !defined(__ICCARM__)
- __builtin_unreachable();
- #else
- while (1);
- #endif /* defined(__ICCARM__) */
- }
- #endif /* MCUBOOT_EXT_LOADER */
如上代码所示,此时函数会跳转到RSS中,进而进入到系统的bootloader中去. 此时界面的打印信息如下所示:
此时应该断开tera term的串口连接,然后用STM32CubeProgrammer的串口连接方式升级固件或者数据。 6. 调试 调试的方法请参考两个文档: 1> LAT1328 STM32H5 DA之初体验(带TrustZone) 2> LAT1325 调试小技巧之不复位调试 需要结合这两个文档中所提的方法来调试。 6.1 调试OEMuROT工程 我们以STM32CubeIDE来举例调试uROT工程。需要配置一下OEMiROT_Boot工程的STM32CubeIDE 的调试配置:
• 关闭自动编译
• 关闭自动复位, 配置DA
如上图所示,调试时不需要复位,所以要关闭复位。DA配置中我们使用根密钥和根证书。DA操作权限我们选择Level 2 Intrusive Debug, 这个是因为接下来我们准备调试OEMiROT_Boot工程,它是运行在HDPL2下的。
• 关闭检验Flash内容
因为调试是以attach的方式进行调试,并不会重新下载,所以关闭Flash检查。 • 关闭下载Flash,并将main上的断点去掉
如上图所示,我们关闭下载,并将main函数上的断点去掉。
最后点击debug … 调试启动后,在main函数内部设置一个断点,然后手动按下板子上的复位键…
此时可以看到,程序已成功在断点处停下来,接下来你可以继续调试其它内容了。 调试S_APP和NS_APP的工程也类似。 7. 还原 在DA目录下有一个名叫regression.sh,运行它可一键还原…
8. 常见问题 8.1 进入bootloader 后只能用串口连接下载固件或者数据吗 ? 不是的,进入到系统bootloader 后,bootloader 支持的接口均可支持,除了串口外,还支持USB, SPI, I2C, FDCAN 等接口。具体请查看AN2606文档。 下面以USB DFU接口为例 :
如上图所示,当芯片进入到bootloader模式后,将板子上的CN17接口通过USB线连接到PC端,然后在STM32CubeProgrammer上采用USB模式连接,此时是可以连接芯片的。此时可以正常下载hex文件。 8.2 具体是如何使用git bash运行provisioning.sh脚本的 ? 在windows上安装完git GUI后,会同时安装git bash. 安装完后,点击右键,如下图所示,有一个Open Git Bash here 的选项 :
在STM32Cube_FW_H5_V1.5.0\Projects\STM32H573I-DK\ROT_Provisioning 目录下右键选择”Open Git Bash here”, 然后将打开如下窗口 :
然后在窗口内,输入 ./provisioning.sh 即可运行provisioning.sh 脚本. 8.3 我使用STM32CubeIDE编译工程,但是运行provisioning.bat脚本可以吗 ? 可以的。但不建议。使用STM32CubeIDE时,建议使用运行provision.sh脚本,而使用IAR, Keil 编译工程时,建议使用provisioning.bat脚本。
文档中所用到的工具及版本 STM32CubeProgrammer v2.20.0 STM32 Trusted Package Creator v2.20.0 Git v2.50
|
-
|