经常看到网友问:怎么程序跑到了Data Abort或者Prefetch Abort。 俺最近在看AT91SAM7S的手册。里面对Abort问题讲得很清楚。
首先要说,一般我们所说的ARM芯片,是由ARM内核,以及不同厂家扩展的外围模块和逻辑电路组成的。 AT91SAM7S的MC(Memory Controller),就是这样的外围模块。 ARM7内核对系统存储空间(ASB总线)的访问,是通过MC来进行的。 MC要实现总线地址译码,然后去访问真实的存储器。 对于AT91SAM7S来说,真实的存储器包括:片内FLASH、片内RAM、内置外设等,它们都有自己的映射地址。 MC中包含一个Abort状态单元。这个单元会向ARM7内核发出Abort信号。 导致Abort的两种原因: ARM7内核所访问的总线地址不存在(未定义)。因为MC知道哪些地址是空的,不对应真实的存储器。 未对齐的访问。ARM7访问32位数据时地址要四字节对齐;访问16位数据时地址要两字节对齐。
ARM7内核对Abort信号的处理: 如果ARM7内核在访问数据时检测到Abort信号有效,当前指令地址被保存到R14_abt,然后PC会跳转到Data-Abort异常向量(地址0X10)。 如果ARM7内核在指令预取时检测到Abort,预取的指令被标志为无效,但异常(Exception)并不会立刻产生。“如果指令没有被执行,举例来讲,在流水线中的一个分支指令,将不会产生异常,如果指令到流水线的出口并将要被执行时,异常产生”。当前指令地址被保存到R14_abt,PC会跳转到Prefetch-Abort异常向量(地址0X0C)。
MC还能够通过寄存器提供Abort状态信息: 造成Abort的那个访问地址。 请求宽度(32位、16位,还是8位)。 访问类型:数据读、写,还是指令预取。 是未定义地址,还是地址未对齐。 。。。 以上信息,可以帮助定位bug。 用户可以编写Abort异常处理程序来读出这些信息。
另外值得一提的: 除了ARM7访问ASB总线会造成Abort以外,外设DMA控制器访问ASB也会导致Abort。 对于带MMU的arm芯片,操作系统可以通过处理Abort异常来管理虚拟内存。
说回来,什么样的程序错误会导致Abort呢。 俺遇到过的问题是数组访问越界,导致数组外的数据被改写。 例如被改写的恰巧是一个指针变量。 比如堆栈内容被改写,然后又弹出到PC。 比如把0X0C000001,强制转换为指向int的指针,然后再读写这个指针指向的数据。 |