![be210bad2b55575ef888d7a9a2b766be.png](https://img-blog.csdnimg.cn/img_convert/be210bad2b55575ef888d7a9a2b766be.png)
在车用系统测试过程中,偶发性的异常复位由于其难以复现的特性,应该是汽车零部件电控开发工程师最为头疼的问题之一了。本文旨在介绍一种系统崩溃时现场保护功能的实现方式,抛砖引玉,供大家参考。
对象:使用英飞凌AURIX系列芯片的系统
参考文献:TriCore V1.6 Core Architecture 32bit Processor Core User Manual
正文:
通常,桌面PC系统崩溃时都会存在DUMP文件供开发工程师去分析。嵌入式系统芯片由于其性能不强且资源有限,同时由于是实时系统,在发生偶发性的单次异常复位后,必须立刻重新根据当前系统状态接管系统控制,所以对于系统崩溃时的现场保护策略以及保存对象,需要大家根据自己的需要进行调整。
保存对象一般包含以下几种:
1.函数调用堆栈(call stack或者call hierarchy )
2.寄存器状态
3.堆栈状态
4.崩溃模块关联RAM状态信息
(这个比较难划分范围,可以更换成车辆信息,不过实际意义不大)
5.RAM整体镜像
现场保护的执行时刻:
1.异常TRAP
2.没想出来(暂时Orz)
定义好了现场保护功能的执行时刻和保存内容,我们可以根据需求来实现各自所需的功能。
假定实现这样一种模式:
在异常TRAP发生时,记录函数调用堆栈+寄存器状态信息+堆栈状态
在实现前,简单介绍下英飞凌AURIX芯片的一些基本概念:
通常情况下,大家对于堆栈的理解是下图这样的
![88d7aec1fcc39300626821d28cf61535.png](https://img-blog.csdnimg.cn/img_convert/88d7aec1fcc39300626821d28cf61535.png)
在TriCore系列芯片中,这个概念和传统的理解有些出入。
硬件初始化时,除了初始化Stack外,还需要初始化一块叫CSA(Context Save Area)的区域。(学计算机的看context应该就知道他是干啥的了)
这块区域是一个64byte*N的区域,当系统发生TRAP,INTERRUPT,FUNCTIONCALL 时,会将函数返回地址及部分寄存器状态信息(总长度64byte)自动存入该区域的一个节点中。N代表这个区域的节点最多可以有N个,当需求的节点个数超过N时,会引发TRAP。
(简单来说,就是假设N是32,如果没有优化的函数嵌套深度超过32个,就会引发TRAP)
这N个节点虽然是一个64byte*N的大数组,其实是通过链表形式进行链接的,所以存在两个指针,一个指向目前未被占用的节点的链表,一个指向当前已使用的节点的列表,这两个队列分别叫做FCX和PCX。这64byte中的前4byte是作为一个叫PCXI的指针,指向前一个节点。
这里新增的名词定义如下:
CSA:64byte存储函数返回地址及部分寄存器状态信息的区域
FCX:Free Context List
PCX:Previous Context List
PCXI:Previous Context Information
寄存器A11:函数返回地址
寄存器A10:堆栈地址
有了这些信息,大家应该就很容易想到实现的思路了。
简单来说,就是当TRAP发生时,通过寄存器中的PCX指向的链表,不断保存每个CSA中必须要的寄存器信息,直到整个PCX链表被遍历结束。
那我们知道搞明白整个PCX链表的链接规则,就知道该怎么实现了,看看是不是很简单?
下面我们来说下该链表的组织结构:
对于PCXI,实际CPU中存在的一个寄存器。可以理解为他就是调用当前函数的函数的CSA的指针(如果是初始化还没有进入任何函数的时候,他就是0x00000000)。
假设我们设置了一个64个CSA的区域,在系统初始化时,每个CSA的首4byte会被初始化成下面的这种形式,CPU的PCXI寄存器应该是0x00000000
![ec71554b89336da3edc5c86042bdfa4f.png](https://img-blog.csdnimg.cn/img_convert/ec71554b89336da3edc5c86042bdfa4f.png)
假设我们有这样一个调用顺序,
启动_startup->main->func1 实际的寄存器信息会如下变化
![503d9c621b0d0b081bac3e706bf4353a.png](https://img-blog.csdnimg.cn/img_convert/503d9c621b0d0b081bac3e706bf4353a.png)
依次类推。
通过这样的方式遍历PCX之后,就可以实现函数调用堆栈的记录,现场寄存器的记录,以及堆栈信息的记录了。
对于需要保存的寄存器的含义以及PCXI的格式,内核手册中都写的很清楚,我就不赘述了。
请大家参考手册的第四章,Task and Functions。
如表述有误,还请大家不吝指点
PS:
原本想好好写下TriCore Autosar OS的实现机制的,发现Flag立的太早,题目太大,目前还是一点点的写比较靠谱点。