查看: 1394|回复: 0

比特世界病虫害防治指南(三):如何判断HardFault的来源

[复制链接]
  • TA的每日心情
    开心
    2024-3-26 15:16
  • 签到天数: 266 天

    [LV.8]以坛为家I

    3300

    主题

    6547

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    32032
    最后登录
    2024-4-26
    发表于 2021-6-3 17:26:44 | 显示全部楼层 |阅读模式
    大家好,咱们又见面了。相信有了前两次的笔谈,读者朋友们对Hard fault的设计理念和初步的事故现场分析已经有了理解,再听到hard fault的大名也不再是那么“动感情”了。这次小编还要给读者朋友们带来更好的消息,就是中高端Cortex-M CPU的另一个贴心的设计:为我们分类了事故的3个大类,15个小类。在M3, M4, M7, M33, M55中都有。


    前两期快速链接:
    比特世界病虫害防治指南(一)


    比特世界病虫害防治指南(二):分析自动压栈的事故现场

    观察CFSR寄存器中列出的细分异常状态


    我们先回顾一下,CPU把fault的细分数据保存在了SCB->CFSR寄存器中。在CMSIS库中,这个寄存器只是定义成了一个32位整数,不方便查看具体的位。而像KEIL这样的IDE则做了比较友善的可视化。
    为了不依赖IDE,小编也“扩写”了”SCB”区寄存器的定义,主要是把寄存器的功能区细分到具体的位和位段,名叫” SCBFine_t”,可以从这里下载:
    code/inc/cmregs_fine.h· 宝木山石/cmdebug - 码云 - 开源中国 (gitee.com)


    使用时,只要定义SCBFine_t类型的指针变量并赋值为SCB的地址就可以了,


    SCBFine_t *g_pSCB =(SCBFine_t*) SCB;


    然后,就可以在Watch窗口中添加这个变量。


    为了防止链接器把它优化掉,记得在程序中装模作样地用它一下啊,比如”g_pSCB =g_pSCB;”这样的。


    SCB中有好几个参与CPU基本控制与状态的寄存器中,和咱们主题fault有关的是核心就是CFSR寄存器中,下图是对它的位段定义:
    1. struct {
    2.         __IOM uint32_t rw1c0001_IAccViol:1;
    3.         __IOM uint32_t rw1c0101_DAccViol:1;
    4.         __IOM uint32_t zz0201_:1;
    5.         __IOM uint32_t rw1c0301_MUnStkErr:1;
    6.         __IOM uint32_t rw1c0401_MStkErr:1;
    7.         __IOM uint32_t rw1c0501_MLSPErr_LazyStatePreserve:1;
    8.         __IOM uint32_t zz0601_:1;
    9.         __IOM uint32_t rw1c0701_MMARValid:1;
    10.         
    11.         __IOM uint32_t rw1c0801_IBusErr:1;
    12.         __IOM uint32_t rw1c0901_PreciseErr:1;
    13.         __IOM uint32_t rw1c1001_ImpreciseErr:1;
    14.         __IOM uint32_t rw1c1101_UnStkErr:1;
    15.         __IOM uint32_t rw1c1201_StkErr:1;
    16.         __IOM uint32_t rw1c1301_LSPErr_LazyStatePreserve:1;
    17.         __IOM uint32_t zz1401_:1;
    18.         __IOM uint32_t rw1c1501_BFARValid:1;
    19.         
    20.         __IOM uint32_t rw1c1601_UndefInstr:1;
    21.         __IOM uint32_t rw1c1701_InvState:1;
    22.         __IOM uint32_t rw1c1801_InvPC:1;
    23.         __IOM uint32_t rw1c1901_NoCP:1;
    24.         __IOM uint32_t zz2004_:4;
    25.         __IOM uint32_t rw1c2401_Unaligned:1;
    26.         __IOM uint32_t rw1c2501_DivByZero:1;
    27.         __IOM uint32_t zz2606_:6;        
    28. } CFSR;
    复制代码
    这里各个位和位段的定义模式为:


    <访问限定><起始位号><位段长度>_助记符。


    访问限定可以是rw, ro, wo, rw1c, zz。分别是读写、只读、只写、读并且写1清除。特殊的"zz"表示位段未定义。


    比如,CFSR寄存器中的rw1c1701_InvState,表示可读,写1清除,起始位序号为15 (1<<15),长度为1个位,名称为InvState。


    又如, wo0201_SysResetReq,表示只写,起始位序号为2(1<<2),长度为1个位,名称为SysResetReq。


    再如,rw0803_PriGroup, 表示可读可写,起始位序号为8(1<<8),长度为3个位,名称为PriGroup。


    最后,zz1104_,表示起始位序号为11,长度为4个位的位段没有定义。


    下面这个图展示了把g_pSCB添加到Watch窗口并展开CFSR寄存器的样子:
    1.png
    在这个图中,可以清楚地看出15号位的”InvState”标志设置了。

    异常状态综述


    在接下来,咱们会扯个劲地唠叨唠叨这15种异常状态(以及它们的组合),结合实例说事。不过在这之前,还是先对它们有些基本的了解。

    总线错误类fault (BusErr)


    这可能是最关键也最常出现的一类了。从名字就能看出,跟总线上访问设备不成功有关,设备既可以是形形色色的真实存储器,也可以是表现成存储器的外设。无论是哪一种,每个设备都在4GB的线性地址空间中开出一个段落安家落户。所以,总线错误的出现肯定是各种访问地址空间的指令导致的,在C语言下,对应的程序就常常是变量赋值,尤其是通过指针变量的赋值,或者memcpy这类API调用。


    4GB的大小对于存储卡虽然已是小到无人问津,但对于32位MCU来说却是个大得可怕的天文数字,而一般来说真正开发的部分,包括内部RAM,寄存器中,以及外面扩展的存储器,只占很小的比例。这样,如果程序中的bug导致访问了错误的地址,很可能就落到了未开发的地址区域,或者落到了禁止访问的区域。在这种情况下,就会产生总线错误。另一方面,程序bug还可能导致CPU从不当的位置取指令。虽然对CPU和程序来说,取指令与取数据是两个非常不同的使用场合,但在总线和总线设备看来都是访问动作。Cortex-M CPU中的错误标志区分了数据访问和指令访问。


    Cortex-M CPU能识别以下5种总线错误,要点总结如下:
    2.png
    存储器管理违章类fault (MemManageErr)


    Cortex-M CPU允许器件选配存储器保护单元(MPU),可以通过编程它的寄存器来给不同的地址范围施加数据和取指访问的限制。当出现了违章的访问时,MPU就会捕获到作奸犯科的指令,并产生一个MemManageErr类型的fault。MPU有多种妙用,既可以隔离不同的应用业务逻辑,隔离应用与系统,也可以检测栈溢出,甚至还能用于筛查遗漏的依赖关系,这个后面咱们再好好说。可以说,MemManageErr类型的fault是最能给我们干活的了,就像是一个忠实的看家狗狗。



    Cortex-MCPU能识别4种存储管理违章,要点总结如下:
    存储器管理违章类fault (MemManageErr)


    Cortex-M CPU允许器件选配存储器保护单元(MPU),可以通过编程它的寄存器来给不同的地址范围施加数据和取指访问的限制。当出现了违章的访问时,MPU就会捕获到作奸犯科的指令,并产生一个MemManageErr类型的fault。MPU有多种妙用,既可以隔离不同的应用业务逻辑,隔离应用与系统,也可以检测栈溢出,甚至还能用于筛查遗漏的依赖关系,这个后面咱们再好好说。可以说,MemManageErr类型的fault是最能给我们干活的了,就像是一个忠实的看家狗狗。



    Cortex-MCPU能识别4种存储管理违章,要点总结如下:
    3.png
    不当使用CPU类(UsageFault)


    相比总线错误和访问违章,其它类型的不当使用CPU都会产生这类用法错误,所以这类错误其实是个大杂烩,既零散又不多见,并且往往难以从直接原因推导出最终根源,分析的难度也就更大。可以说如果谁能准确地洞察UsageFault的原因,谁在Cortex-M CPU的比特世界中就有了一双火眼金睛,这也是小编在追求的境界,但还远远不够。在后面的推文中,小编会以实例来介绍我们曾遇到的几种情况。



    老样子,还是先简单地了解一下Cortex-M CPU能识别哪些不当的使用方式,共6种:
    4.png
    小结


    通过这次的介绍,咱们已经了解了如何查看Cortex-M CPU能识别的三大类15小类具体错误类型,并且对于它们有了初步的了解。在后面的续集中,小编会结合自己和朋友同事们的实际不幸遭遇,提炼出有代表性的简化的段子,来向读者朋友们哭诉,一定要看哦!



    签到签到
    回复

    使用道具 举报

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

    本版积分规则

    关闭

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

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

    GMT+8, 2024-4-27 06:17 , Processed in 0.108066 second(s), 20 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

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