历史上的今天
返回首页

历史上的今天

今天是:2024年09月28日(星期六)

2021年09月28日 | ARM的异常处理过程分析(异常向量/工作模式)

2021-09-28 来源:eefocus

ARM的7种工作模式:

        1、用户模式(Usr):用于正常执行程序;

        2、快速中断模式(FIQ):用于高速数据传输;

        3、外部中断模式(IRQ):用于通常的中断处理;

        4、管理模式(svc):操作系统使用的保护模式;

        5、数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于虚拟存储以及存储保护;

        6、系统模式(sys):运行具有特权的操作系统任务;

        7、未定义指令中止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件;

 

除用户模式外,其余6种工作模式都属于特权模式;

特权模式中除了系统模式以外的其余5种模式称为异常模式;

大多数程序运行于用户模式;

进入特权模式是为了处理中断、异常、或者访问被保护的系统资源;


++++++++++++++++++++++++++++++++++++

转载自:http://blog.chinaunix.net/uid-20937170-id-3220124.html

uC/OS-II官网给出来的ARM7-ARM9移植手册(AN-104),分析了在ARM中移植的问题,想想从来没有认真的学习过ARM的汇编,趁着这个机会复习复习吧。其实底层的东西才是创造力的心脏。


其中的移植代码中存在的很多问题比如中断的关闭和开启,任务级别的情景切换,中断到任务的情景切换都是我们在平时移植中讲到,我也不在此强调了。在官网中提供的移植过程中存在异常处理机制,这个本不是在移植过程中考虑的,但是文档中确实提供了一个比较好的处理方式。我在此对这一段时间的学习做一个总结。


首先需要了解ARM的异常处理机制,异常是每一种处理器都必须考虑的问题之一,关键在于如何让处理,返回地址在什么位置都是需要考虑的,


ARM中支持7种异常,其中包括复位、未定义指令异常、软中断异常、预取指令中止、数据中止、IRQ、IFQ。每一种异常运行在特定的处理器模式下。我在此逐一的分析。


一般异常发生后,CPU都会进行一系列的操作,这些操作有一部分是CPU自动完成,有一部分是需要我们程序员完成。


首先说明CPU会自动完成的部分,用ARM结构手册中的代码描述如下:

R14_ = return link                //这个可以参看寄存器的说明,两个作用

SPSR_< exception_mode > = CPSR

CPSR[4:0] = exception mode number //设置工作模式

CPSR[5] = 0 ;                     //ARM指令

If ==Reset or Fiq then    //只有在复位和FIQ模式下才会关闭FIQ中断

        CPSR[6] = 1 ;

CPSR[7] = 1 ;                            //任何异常模式下都会关闭IRQ中断

PC = exception vector address

从上面的代码中我们可以发现CPU自动处理的过程包括如下:

1、拷贝CPSR到SPSR_

2、设置适当的CPSR位:改变处理器状态进入ARM状态;改变处理器模式进入相应的异常模式;设置中断禁止位禁止相应中断。

3、更新LR_,这个寄存器中保存的是异常返回时的链接地址

4、设置PC到相应的异常向量

以上的操作都是CPU自动完成,异常的向量表如下:


返回地址问题

异常的返回地址也是需要我们注意的地方,不同的异常模式返回地址也是存在差异的,这主要是因为各种异常产生的机理存在差别所导致的。这样我们的需要在异常进入处理函数之前或者在返回时调整返回地址,一般采用进入异常处理函数前进行手动调整。下面每一种异常R14保存的值都给了出来,其中也包含了CPU自动处理的部分,根据保存的R14就可以知道怎样实现地址的返回。


复位异常:

可以看出该模式下的先对来说返回地址也比较简单,不需要做太多的描述。

未定义的指令异常:

返回的方式也比较简单:

       MOVS  PC, R14

预取指令中止异常:

返回需要做下面的调整:

SUBS      PC, R14, #4

数据中止

返回地址需要做下面的调整:

如果需要重新访问数据则:

SUBS      PC, R14, #8

如果不需要重新访问数据则:

SUBS      PC, R14, #4

IRQ中断的处理过程:

返回地址需要做下面的调整:

       SUBS PC,R14,#4

IFQ中断:

返回地址需要做下面的调整:

       SUBS  PC, R14 ,#4

从上面的代码可以知道,对于每一种异常,保存的返回地址都是不一样的,一般都需要我们手动的跳转,当然调整的时机也需要我们选择,是在进入处理前跳转还是返回时调整都是需要我们程序员控制的。

在ARM Developer Suite Developer Guide中对ARM处理器的异常处理操作提供能更加详细的解释,每一种异常下的处理方式如下文描述:

异常返回时另一个非常重要的问题是返回地址的确定,在前面曾提到进入异常时处理器会有一个保存LR的动作,但是该保存值并不一定是正确的返回地址,下面以一个简单的指令执行流水状态图来对此加以说明。

我们知道在ARM架构里,PC值指向当前执行指令的地址加8处,也就是说,当执行指令A(地址0x8000)时,PC等于指令C的地址(0x8008)。假如指令A是“BL”指令,则当执行该指令时,会把PC(=0x8008)保存到LR寄存器里面,但是接下去处理器会马上对LR进行一个自动的调整动作:LR=LR-0x4。这样,最终保存在 LR里面的是 B指令的地址,所以当从 BL返回时,LR里面正好是正确的返回地址。同样的调整机制在所有LR自动保存操作中都存在,比如进入中断响应时,处理器所做的LR保存中,也进行了一次自动调整,并且调整动作都是LR=LR-0x4。


下面,我们对不同类型的异常的返回地址依次进行说明:

假设在指令A处(地址0x8000)发生了异常,进入异常响应后,LR上经过调整保存的地址值应该是B的地址0x8004。


1、如果发生的是软件中断,即A是“SWI”指令

异常是由指令本身引起的,从 SWI中断返回后下一条执行指令就是B,正好是LR寄存器保存的地址,所以只要直接把LR恢复给PC。


MOVS pc, lr

2、发生的是Undefined instruction异常

异常是由指令本身引起的,从异常返回后下一条执行指令就是B,正好是LR寄存器保存的地址,所以只要直接把LR恢复给PC。

MOVS pc, lr


3、发生的是IRQ或FIQ中断

因为指令不可能被中断打断,所以A指令执行完以后才能响应中断,此时PC已更新,指向指令D的地址(地址0x800C),LR上经过调整保存的地址值是C的地址0x8008。中断返回后应该执行B指令,所以返回操作是:

SUBS pc, lr, #4


4、发生的是Prefetch Abort异常

该异常并不是处理器试图从一个非法地址取指令时触发,取出的指令只是被标记为非法,按正常处理流程放在流水线上,在执行阶段触发Prefetch Abort异常,此时LR上经过调整保存的地址值是B的地址0x8004。异常返回应该返回到A指令,尝试重新取指令,所以返回操作是:

SUBS pc, lr, #4


5、发生的是“Data Abort”

CPU访问存储器时触发该异常,此时PC指向指令D的地址(地址0x800C),LR上经过调整保存的地址值是C的地址0x8008。异常返回后,应回到指令A,尝试重新操作存储器,所以返回操作是:

SUBS pc, lr, #8


以上就是ARM异常的CPU操作部分,接下来就是程序员应该完成的操作。

1.由于CPU会自动跳转到对应的异常向量中,因此只需要在在各个异常向量中存放对应的操作,最简单的都是存放一个B指令跳转到对应的异常处理函数的操作即可。但由于B指令的跳转返回只有+-32M,而异常处理函数的地址可能会超过+-32M,因此可以采用另一种方式实现方式:在异常向量中保存一条指令LDR PC [addr],其中的addr中就保存了异常处理函数的地址,当然addr的相对地址要小于+-32M。这样也就解决了跳转范围的问题。


2.接下来就是异常处理函数对应的操作,可以在进入异常处理之前就进行返回地址的调整,这样后面就不用进行处理啦,当然也可以在返回过程中再调整。一般都是在这个过程中进行调整。进行压栈操作,保存对应的环境变量。调用实际的处理过程等。


3.出栈,恢复CPU的状态和寄存器的值。由于第一步中已经调整好返回地址,这一步不需要再次调整。当然如果之前没有调整,这里则需要进行相应的调整。


在uC/OS-II的官网移植中采用通用异常处理函数的方式实现异常的处理,下面我们来分析其中的部分代码:


首先是处理器部分的移植,包括异常向量、异常的ID号,存储异常处理函数地址的地址等:


/*ARM的异常ID号,支持7种类型的异常,每一种异常都存在一个ID号*/

#define  OS_CPU_ARM_EXCEPT_RESET        0x00

#define  OS_CPU_ARM_EXCEPT_UNDEF_INSTR 0x01

#define  OS_CPU_ARM_EXCEPT_SWI          0x02

#define  OS_CPU_ARM_EXCEPT_PREFETCH_ABORT 0x03

#define  OS_CPU_ARM_EXCEPT_DATA_ABORT     0x04

#define  OS_CPU_ARM_EXCEPT_ADDR_ABORT     0x05

#define  OS_CPU_ARM_EXCEPT_IRQ               0x06

#define  OS_CPU_ARM_EXCEPT_FIQ               0x07

#define  OS_CPU_ARM_EXCEPT_NBR              0x08

/*异常向量地址*/

#define  OS_CPU_ARM_EXCEPT_RESET_VECT_ADDR              (OS_CPU_ARM_EXCEPT_RESET          * 0x04 + 0x00)           //0x00

#define  OS_CPU_ARM_EXCEPT_UNDEF_INSTR_VECT_ADDR        (OS_CPU_ARM_EXCEPT_UNDEF_INSTR    * 0x04 + 0x00)         //0x04

#define  OS_CPU_ARM_EXCEPT_SWI_VECT_ADDR                (OS_CPU_ARM_EXCEPT_SWI            * 0x04 + 0x00)             //0x08

#define  OS_CPU_ARM_EXCEPT_PREFETCH_ABORT_VECT_ADDR     (OS_CPU_ARM_EXCEPT_PREFETCH_ABORT * 0x04 + 0x00)         //0x0c

#define  OS_CPU_ARM_EXCEPT_DATA_ABORT_VECT_ADDR         (OS_CPU_ARM_EXCEPT_DATA_ABORT     * 0x04 + 0x00)                            //0x10

/*这个异常是ARM中不支持的异常*/

#define  OS_CPU_ARM_EXCEPT_ADDR_ABORT_VECT_ADDR         (OS_CPU_ARM_EXCEPT_ADDR_ABORT     * 0x04 + 0x00)                            //0x14

#define  OS_CPU_ARM_EXCEPT_IRQ_VECT_ADDR                (OS_CPU_ARM_EXCEPT_IRQ            * 0x04 + 0x00)                           //0x18

#define  OS_CPU_ARM_EXCEPT_FIQ_VECT_ADDR             (OS_CPU_ARM_EXCEPT_FIQ            * 0x04 + 0x00)                       //0x1c

/*存储异常处理函数地址的地址*/

/* ARM exception handlers addresses                  */

#define  OS_CPU_ARM_EXCEPT_RESET_HANDLER_ADDR           (OS_CPU_ARM_EXCEPT_RESET          * 0x04 + 0x20)                            //0x20

#define  OS_CPU_ARM_EXCEPT_UNDEF_INSTR_HANDLER_ADDR     (OS_CPU_ARM_EXCEPT_UNDEF_INSTR    * 0x04 + 0x20)           //0x24

#define  OS_CPU_ARM_EXCEPT_SWI_HANDLER_ADDR             (OS_CPU_ARM_EXCEPT_SWI            * 0x04 + 0x20)        //0x28

#define  OS_CPU_ARM_EXCEPT_PREFETCH_ABORT_HANDLER_ADDR  (OS_CPU_ARM_EXCEPT_PREFETCH_ABORT * 0x04 + 0x20)     //0x2c

#define  OS_CPU_ARM_EXCEPT_DATA_ABORT_HANDLER_ADDR      (OS_CPU_ARM_EXCEPT_DATA_ABORT     * 0x04 + 0x20)            //0x30

#define  OS_CPU_ARM_EXCEPT_ADDR_ABORT_HANDLER_ADDR      (OS_CPU_ARM_EXCEPT_ADDR_ABORT     * 0x04 + 0x20)           //0x34

#define  OS_CPU_ARM_EXCEPT_IRQ_HANDLER_ADDR             (OS_CPU_ARM_EXCEPT_IRQ            * 0x04 + 0x20)           //0x38

#define  OS_CPU_ARM_EXCEPT_FIQ_HANDLER_ADDR             (OS_CPU_ARM_EXCEPT_FIQ            * 0x04 + 0x20)           //0x3c

推荐阅读

史海拾趣

Atlanta Micro公司的发展小趣事

近年来,电子行业经历了快速的发展和变革,新技术、新产品层出不穷。面对这一形势,Atlanta Micro积极应对挑战,不断调整战略和业务模式。公司加强了与产业链上下游企业的合作,共同应对市场变化;同时,也加大了对新兴技术的研发投入,力求在新技术领域取得突破。这些努力使得Atlanta Micro在激烈的市场竞争中保持了稳健的发展态势。

以上便是关于Atlanta Micro在电子行业发展的5个故事。这些故事展示了公司从创业初期到逐渐发展壮大的过程,以及面对挑战和变革时所采取的应对策略。虽然这些故事只是公司发展历程中的一部分,但它们足以体现出Atlanta Micro在电子行业中的坚韧和拼搏精神。

DC Components公司的发展小趣事

为了进一步扩大市场份额,DC Components公司积极开拓国际市场。公司通过与全球客户的合作,将产品出口到多个国家和地区,实现了全球化布局。这种市场拓展策略不仅提升了公司的品牌影响力,还为公司的未来发展打开了更广阔的空间。

光磊(GL)公司的发展小趣事

为了进一步扩大市场份额,DC Components公司积极开拓国际市场。公司通过与全球客户的合作,将产品出口到多个国家和地区,实现了全球化布局。这种市场拓展策略不仅提升了公司的品牌影响力,还为公司的未来发展打开了更广阔的空间。

Cressall Power Resistors公司的发展小趣事

为了确保产品质量和稳定供应,Cressall投入大量资源建设质量管理体系。公司引入了先进的质量管理方法和工具,对生产过程中的每一个环节进行严格把控。同时,公司还建立了完善的质量检测体系,确保出厂产品的合格率。这些措施有效提升了公司的产品质量和客户满意度,为公司的长远发展奠定了坚实的基础。

Alan Industries Inc公司的发展小趣事

Alan Industries Inc.自创立之初,就以其对技术研发的不懈追求而闻名。在公司成立的早期,其研发团队成功开发出一款高效能、低功耗的芯片,这一创新产品在市场上引起了巨大反响。随后,公司不断投入研发资源,推出了一系列具有竞争力的电子产品,逐渐在行业中树立了技术领先的地位。这些产品不仅满足了消费者对电子产品性能的需求,还为公司带来了可观的利润,为公司的快速发展奠定了坚实基础。

东科半导体(DK)公司的发展小趣事

东科半导体(DK)公司一直将技术创新作为发展的核心驱动力。公司投入大量资金和资源用于研发,先后开发出AC/DC、同步整流、第三代半导体氮化镓芯片等先进技术。其中,东科半导体的同步整流芯片研发成功,其独特的两引脚封装技术为全球首创,为公司赢得了行业内的独家竞争优势。这一技术的成功应用,不仅提升了公司产品的性能,也进一步巩固了东科在电源管理芯片市场的领先地位。

问答坊 | AI 解惑

RFID将广泛应用于纺织品物流管理和防伪

[摘要]法国一些大型服装品牌连锁店已经计划装备RFID技术,对商店和仓库的库存进行清点管理。由于RFID技术还可以检测各种物质的化学成分和惰性金属,因此可用于纺织品防伪鉴别。      据法国《纺织报》消息,一种被称 ...…

查看全部问答>

元件模特秀--图文并茂、简单易懂

无意间发现一篇很有创意的介绍元件的原理、外形、封装、功能的文章---元件模特秀。 原作者是“爱因迪生”。在这里我转帖过来,大家一起欣赏 文件比较大,还有很多图片,发帖比较麻烦,我直接先传PDF文档得了。这个是我从网上下来后做的PDF,希望 ...…

查看全部问答>

测量系统中的误差分析及解决方法

测量系统中的误差分析及解决方法…

查看全部问答>

我要动态加载一个流驱动,总是不成功,why?

        HANDLE device=ActivateDevice(_T(\"\\\\HKEY_LOCAL_MACHINE\\\\Drivers\\\\HGPIOs\"),NULL);         if(device==0)         {           &nbs ...…

查看全部问答>

ad转换器

请问AD转换器可以和PC直接相连么,可以的话推荐一款…

查看全部问答>

!!请问Windows中的缺页中断处理是在那个中断级别啊,是APC_LEVEL吗 ???

我看到一篇文章写道:“APC_LEVEL当一个asynchsonous procedure call产生时,processor进入到APC_LEVEL。在这个level上,会无视其他的APC,屏蔽APC LEVEL的中断,比如,一些I/O completion APC。可以访问pagable memory。系统在APC_LEVEL处理缺页中 ...…

查看全部问答>

请教 惠普 ProBook 4411s(VA045PA) 多少钱可以买到手?

惠普 ProBook 4411s(VA045PA)  报价 5999元 我随便问了下老板多少钱,他说5200. 多少钱可以买到手?…

查看全部问答>

电子产品焊接工艺

电子产品焊接工艺…

查看全部问答>

怎么样将应用层的数据传到IAP中?

   ST的IAP方案需要按键,可是我设计的板子没有按键,只是通过串口实现控制。这样话IAP就没法工作了。所以想从用户层跳到IAP层进行IAP编程,可是需要从应用层传递一个变量。怎么样传递变量呢?   …

查看全部问答>

用Keil MDK的兄弟请注意,发现MDK好像有点问题

俺用的是V4.20最新的Keil MDK,最近几天调试发现有点问题: 1. Keil串口软件Debug没有问题,在硬件上运行却出现问题,不能正常运行。涉及到发送中断的应用,在Debug的Serial Window里收发正常,但是上了硬件就发送不好使,害的我痛苦了几天。 2. ...…

查看全部问答>