搜索
bottom↓
回复: 4

请教MPU异常原因分析?

[复制链接]

出0入0汤圆

发表于 2012-8-11 17:57:31 | 显示全部楼层 |阅读模式
本帖最后由 hugeice 于 2012-8-11 17:59 编辑

单片机为LM3S9B92,一个以太网程序运行半小时后会出现usage fault或者bus fault,从异常时的现场来看估计是堆栈被破坏!(栈中的PC为0x20002dff,即下面反汇编的红色代码处)
为了进一步查找原因,配置了MPU对内存进行分类保护,堆栈大小4K,并且在堆栈下方预留的4K的空间,设置为不可读写,用来作为守卫区。具体MPU配置和链接脚本如下:
  1.           /* Init MPU */
  2.           /* ROM: RX */
  3.           MPURegionSet(0, 0x20000000,
  4.                        MPU_RGN_SIZE_32K |
  5.                        MPU_RGN_PERM_EXEC |
  6.                        MPU_RGN_PERM_PRV_RO_USR_NO |
  7.                        MPU_RGN_ENABLE);
  8.           /* SRAM: RW */
  9.           MPURegionSet(1, 0x20008000,
  10.                        MPU_RGN_SIZE_32K |
  11.                        MPU_RGN_PERM_NOEXEC |
  12.                        MPU_RGN_PERM_PRV_RW_USR_NO |
  13.                        MPU_RGN_ENABLE);
  14.           MPURegionSet(2, 0x20010000,
  15.                        MPU_RGN_SIZE_32K |
  16.                        MPU_RGN_PERM_NOEXEC |
  17.                        MPU_RGN_PERM_PRV_RW_USR_NO |
  18.                        MPU_RGN_ENABLE);
  19.           /* stack guard: -- */
  20.           MPURegionSet(3, (unsigned long)pulStack[0],
  21.                        MPU_RGN_SIZE_4K |
  22.                        MPU_RGN_PERM_NOEXEC |
  23.                        MPU_RGN_PERM_PRV_NO_USR_NO |
  24.                        MPU_RGN_ENABLE);
  25.           /* real stack: RW */
  26.           MPURegionSet(4, (unsigned long)pulStack[1],
  27.                        MPU_RGN_SIZE_4K |
  28.                        MPU_RGN_PERM_NOEXEC |
  29.                        MPU_RGN_PERM_PRV_RW_USR_NO |
  30.                        MPU_RGN_ENABLE);
  31.           MPUEnable(MPU_CONFIG_PRIV_DEFAULT /* | MPU_CONFIG_HARDFLT_NMI */);
复制代码
链接脚本:(程序是在内存中调试的,所以所有的地址都为片内地址,LM3S9B92总共有96KB SRAM)
  1. MEMORY
  2. {
  3. /*    FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000 */
  4.     ROM   (rx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
  5.     SRAM  (rw) : ORIGIN = 0x20008000, LENGTH = 0x0000E000
  6.     STACK (rw) : ORIGIN = 0x20016000, LENGTH = 0x00002000
  7. }

  8. SECTIONS
  9. {
  10.     .text :
  11.     {
  12.         _text = .;
  13.         KEEP(*(.isr_vector))
  14.         *(.text*)
  15.         *(.rodata*)
  16. /*        _etext = .; */
  17.     } > ROM
  18.     . = ALIGN(8);
  19.     _etext = .;

  20.     .data : AT(ADDR(.text) + (_etext - _text)/*SIZEOF(.text)*/)
  21.     {
  22.         _data = .;
  23.         *(vtable)
  24.         *(.data*)
  25.         _edata = .;
  26.     } > SRAM
  27.     .bss :
  28.     {
  29.         _bss = .;
  30.         *(.bss*)
  31.         *(COMMON)
  32.         _ebss = .;
  33.     } > SRAM

  34.         .stack :
  35.         {
  36.                 *(.stack);
  37.         } > STACK
  38. }
复制代码
如上配置后,运行程序大约半小时,出现MPU异常,现场如下:
{r = {0xc000000, 0x82f1, 0x0, 0x82f1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x82f1, 0x20017ef4, 0xc000000, 0x20002dff}, xPSR = 0x20017f38, FSR = {CFSR = 0x1, xFSR = {MFSR = 0x1, BFSR = 0x0, UFSR = 0x0}}, HFSR = 0x0, DFSR = 0x0, AFSR = 0x0, AR = {MMAR = 0xffffffff, BFAR = 0xffffffff}}
MMAR地址无效,栈中的PC(0x20002dff)指向如下代码中的红色指令:
  1. /* IP header check sum */
  2. unsigned short ip_check_sum(void *data, int len)
  3. {
  4. 20002de8:       b580            push    {r7, lr}
  5. 20002dea:       b084            sub     sp, #16                                                                                                                                         
  6. 20002dec:       af00            add     r7, sp, #0                                                                                                                                      
  7. 20002dee:       6078            str     r0, [r7, #4]                                                                                                                                    
  8. 20002df0:       6039            str     r1, [r7, #0]                                                                                                                                    
  9. /home/hugeice/Work/judp/lm3s/epiudp/checksum.c:324
  10.         unsigned short chksum;
  11.         chksum = ~check_sum(0, data, len);
  12. 20002df2:       f04f 0000       mov.w   r0, #0                                                                                                                                          
  13. 20002df6:       6879            ldr     r1, [r7, #4]                                                                                                                                    
  14. 20002df8:       683a            ldr     r2, [r7, #0]                                                                                                                                    
  15. 20002dfa:       f7ff fec1       bl      20002b80 <check_sum_opt_c4>
复制代码
栈中PC指向这里:
  1. 20002dfe:       4603            mov     r3, r0
复制代码
  1. 20002e00:       ea6f 0303       mvn.w   r3, r3
  2. 20002e04:       81fb            strh    r3, [r7, #14]                                                                                                                                   
  3. /home/hugeice/Work/judp/lm3s/epiudp/checksum.c:325
  4.         return (0 == chksum) ? 0xffff : chksum;
  5. 20002e06:       89fb            ldrh    r3, [r7, #14]                                                                                                                                   
  6. 20002e08:       2b00            cmp     r3, #0                                                                                                                                          
  7. 20002e0a:       d001            beq.n   20002e10 <ip_check_sum+0x28>
  8. 20002e0c:       89fb            ldrh    r3, [r7, #14]                                                                                                                                   
  9. 20002e0e:       e001            b.n     20002e14 <ip_check_sum+0x2c>
  10. 20002e10:       f64f 73ff       movw    r3, #65535      ; 0xffff                                                                                                                        
  11. /home/hugeice/Work/judp/lm3s/epiudp/checksum.c:326
  12. }
  13. 20002e14:       4618            mov     r0, r3
  14. 20002e16:       f107 0710       add.w   r7, r7, #16                                                                                                                                    
  15. 20002e1a:       46bd            mov     sp, r7
  16. 20002e1c:       bd80            pop     {r7, pc}
  17. 20002e1e:       bf00            nop
复制代码
栈中PC指向调用子函数“check_sum_opt_c4”返回后的下一条指令,但是此指令并没有内存操作(“mov r3, r0”),是否意味着是前一条指令造成的MPU异常?那么是不是前一条指令调用函数在返回阶段造成的MPU异常呢?(比如栈被破坏)
在这种情况下还有什么办法能够更进一步的定位出现问题的地方呢?

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 2012-8-11 18:09:51 | 显示全部楼层
开始怀疑是堆栈溢出,但是我用如下宏测试堆栈的使用情况,发现堆栈需求只有不到300字节,而程序堆栈大小设置为4KByte

下面定义的宏“SPCHK”被插入到各个函数的开始位置,用来探测堆栈的上溢和下溢:
  1. /* pulStack[0] is guard, pulStack[1] is the real stack */
  2. extern unsigned long pulStack[2][1024];
  3. extern unsigned long * g_sp_min;
  4. extern unsigned long * g_sp_max;

  5. #define SPCHK                                                           \
  6.         {                                                               \
  7.                 unsigned long __temp;                                   \
  8.                 if ( &__temp < g_sp_min )                               \
  9.                         g_sp_min = &__temp;                             \
  10.                 if ( &__temp > g_sp_max )                               \
  11.                         g_sp_max = &__temp;                             \
  12.                 if ( g_sp_min <= pulStack[1] )                          \
  13.                         while ( 1 ) {}                                  \
  14.                 if ( g_sp_max > pulStack[2] )                           \
  15.                         while ( 1 ) {}                                  \
  16.         }
复制代码
后来用MPU在真正堆栈的下方设置一个4K的不可读写的警戒区,也没有发现由此触发的MPU异常,说明程序的堆栈并没有下溢,堆栈大小4KByte是足够的;

出0入0汤圆

 楼主| 发表于 2012-8-11 18:17:16 | 显示全部楼层
我感觉好像是程序运行的过程中,堆栈中的数据被篡改了,如果正好是返回地址等关键数据被篡改,则造成函数返回时触发异常,如果返回地址最低位为0,则触发usage fault:试图切入ARM状态,如果返回地址不在有效地址范围内则触发bus fault;
每次出现异常时,栈中的PC都指向上面那条红色的代码“20002dfe:       4603            mov     r3, r0”,可是条指令实在没有什么好怀疑的,倒是其前一条指令“20002dfa:       f7ff fec1       bl      20002b80 <check_sum_opt_c4>”非常可疑,如果是在该函数中造成的堆栈被破坏,但是又没有触发设置的MPU规则,那该如何找到篡改堆栈的真凶呢?

出0入0汤圆

 楼主| 发表于 2012-8-22 09:35:56 | 显示全部楼层
晕死!重新建一个工程专门测试将那个check_sum_opt_c4,发现运行一段时间之后出现死机;然后将这个测试工程放到EK-LM3S8962板子上跑,运行8小时没有出现问题!初步确定是硬件问题!

出0入0汤圆

 楼主| 发表于 2013-3-5 13:05:48 | 显示全部楼层
忘了了解这个帖子了,罪过罪过!

重新做板后程序运行正常!确定是硬件问题!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-6-11 05:26

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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