查看: 1624|回复: 2

[原创] 莫名的的复位—Bootable image结构的‘秘密’

[复制链接]

该用户从未签到

656

主题

6312

帖子

0

超级版主

Rank: 8Rank: 8

积分
20127
最后登录
2024-5-3
发表于 2021-1-5 16:27:37 | 显示全部楼层 |阅读模式
本帖最后由 小恩GG 于 2021-1-5 16:39 编辑

莫名的的复位—Bootable image结构的‘秘密’

前提
前段时间,小编使用tensorflow lite库在MIMXRT1050 EVK开发板上部署CNN模型过程中,无意中发现如果工程在使用比较多大的SDRAM空间时,使用MCUBootUtility或MCUXpresso Secure Provisioning工具生成bootable image在MIMXRT1050 EVK开发板上运行过程中,调用CNN模型时会触发莫名的复位现象,通过打印SRC_SRSR寄存器发现是lockup_sysresetreq复位源引发的,但是通过调试工具如Jlink或OpenSDA直接烧录的话,工程代码却能正常运行,最后通过反复比较与测试发现复位现象与bootable image结构有关(不了解bootable image结构的小伙伴,可以通过此博文—《恩智浦i.MX RT1xxx系列MCU启动那些事(6)- Bootable image格式与加载(elftosb/.bd)了解,那我们开始吧。
细节介绍
因为tensorflow lite库运行ML模型需要较大的RAM空间,而i.MX RT1050本身的FlexRAM只有512 byte,远远无法满足需求,所以需要SDRAM来提供充足的RAM空间,这就需要bootable image中添加DCD部分。
下面列出三组bootable image的IVT,Bootable image和DCD部分,分别对应:a) SD 卡的non-XIP启动,b) FlexSPI Nor flash的XIP启动,c) FlexSPI Nor flash的XIP启动,其中a,b项的bootable image是MCUXpresso Secure Provisioning工具生成的,而c项则是通过Jlink直接烧录的。
a) SD 卡的non-XIP启动
2021-01-04_17-37-14.png

图 1

b) FlexSPI Nor flash的XIP启动 (MCUXpresso Secure Provisioning工具生成的)
2021-01-04_17-45-19.png

图 2

c)FlexSPI Nor flash的XIP启动(Jlink直接烧录)
2021-01-04_17-47-38.png

图 3

根据《恩智浦i.MX RT1xxx系列MCU启动那些事(6)- Bootable image格式与加载(elftosb/.bd),上面三组bootable image的IVT,Bootable image和DCD部分都是符合结构规范要求的,那到底是什么原因导致a,b项的bootable image不能正常工作呢?
问题解决
经过多次比较与测试发现,问题与IVT的版本和application code的绝对地址设置有关(IVT的结构如下所示),其中结构体中的par代表版本号,通常为0x40或0x41,entry存储的是application code第一条执行指令的绝对地址,也有两种设置方式,一种是application code存储的首地址,另一种为application code的ResetISR中断函数指针指向的地址。
  1. /** @ref hab_header structure */
  2. typedef struct hab_hdr {
  3.     uint8_t tag;              /**< Tag field */
  4.     uint8_t len[2];           /**< Length field in bytes (big-endian) */
  5.     uint8_t par;              /**< Parameters field */
  6. } hab_hdr_t;

  7. /** @ref ivt structure */
  8. struct hab_ivt_v0 {
  9.     /** @ref hdr with tag #HAB_TAG_IVT0, length and HAB version fields */
  10.     hab_hdr_t hdr;
  11.     /** Absolute address of the first instruction to execute from the image */
  12.     uint32_t entry;
  13.     /** Reserved in this version of HAB: should be NULL. */
  14.     uint32_t reserved1;
  15.     /** Absolute address of the image DCD: may be NULL. */
  16.     uint32_t dcd;
  17.     /** Absolute address of the Boot Data: may be NULL, but not interpreted any further by HAB */
  18.     uint32_t boot_data;
  19.     /** Absolute address of the IVT.*/
  20.     uint32_t self;
  21.     /** Absolute address of the image CSF.*/
  22.     uint32_t csf;
  23.     /** Reserved in this version of HAB: should be zero. */
  24.     uint32_t reserved2;
  25. };
复制代码
本着大胆猜测,小心求证的心态,发现将a,b项bootable image 中的par和entry按照c项格式修改后(如下所示),代码居然能成功地运行了。
a) SD 卡的non-XIP启动
2021-01-05_15-09-18.png

图 4

b) FlexSPI Nor flash的XIP启动 (MCUXpresso Secure Provisioning工具生成的)
2021-01-05_14-17-55.png

图 5

原因探究
跟同事讨论后,发现问题的根本原因与ROM code根据entry值实现跳转的方式有关,跳转函数的具体代码如下所示

  1. void jump_to_entry(uint32_t entry)
  2. {
  3.     typedef void (*application_callback_t)(void);
  4.     static application_callback_t s_app_callback;

  5.     pu_irom_mpu_disable();

  6.     __DMB();
  7.     __DSB();
  8.     __ISB();

  9.     // The entry point is the absolute address of the call back function
  10.     if ((uint32_t)entry & 1)
  11.     {
  12.         s_app_callback = (application_callback_t)entry;
  13.     }
  14.     // The entry point is the base address of vector table
  15.     else
  16.     {
  17.         static uint32_t s_stack_pointer;
  18.         // Ensure Core read vector table for destination instead of register
  19.         volatile uint32_t *vector_table = (volatile uint32_t *)entry;

  20.         s_stack_pointer = vector_table[0];
  21.         s_app_callback = (application_callback_t)vector_table[1];

  22.         // Update Stack pointer
  23.         __set_MSP(s_stack_pointer);
  24.         __set_PSP(s_stack_pointer);
  25.     }

  26.     __DSB();
  27.     __ISB();

  28.     // Jump to user application in the end
  29.     s_app_callback();

  30.     // Should never reach here
  31.     __NOP();
  32.     __NOP();
  33. }
复制代码
当entry值是复位向量(Reset_Handler)函数地址(即奇地址)时,ROM code是直接通过函数调用的方式跳转到复位函数执行,而如果entry值是中断向量表首地址(即偶地址),ROM code会先将当前SP重设到application code指定的栈顶,然后再跳转到复位函数。
但是,MCUXpresso IDE的ResetISR函数没有重设SP的动作,所以当IVT中的entry是复位向量时,ROM code跳转到application code后依旧延用ROM code中的栈,而如果栈空间不足时,application code就会发生程序跑飞或Hard fault等错误。所以解决方法就需要手动在在MCUXpresso IDE的startup流程中加入重设SP操作,具体如下。
  1. __attribute__ ((section(".after_vectors.reset")))
  2. void ResetISR(void) {
  3.     __asm volatile ("cpsid i");

  4.     /* 新增SP重设代码 */
  5.     __asm volatile ("MSR msp, %0" : : "r" (&_vStackTop) : );
  6.     __asm volatile ("MSR psp, %0" : : "r" (&_vStackTop) : );

  7.     SystemInit();

  8.     // ...
  9. }
复制代码
参考IVT里的不同entry设置可能会造成i.MXRT1xxx系列启动App后发生异常跑飞



回复

使用道具 举报

  • TA的每日心情
    开心
    2024-3-26 15:16
  • 签到天数: 266 天

    [LV.8]以坛为家I

    3303

    主题

    6550

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    32059
    最后登录
    2024-4-30
    发表于 2021-1-5 16:56:38 | 显示全部楼层
    支持一下
    签到签到
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    3 天前
  • 签到天数: 597 天

    [LV.9]以坛为家II

    51

    主题

    2230

    帖子

    0

    金牌会员

    Rank: 6Rank: 6

    积分
    7099
    最后登录
    2024-5-4
    发表于 2021-1-6 06:41:24 | 显示全部楼层
    感谢分享学习下
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-5-4 17:54 , Processed in 0.119462 second(s), 21 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表