找回密码
 注册
关于网站域名变更的通知
查看: 439|回复: 1
打印 上一主题 下一主题

ARM异常处理

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-5-6 10:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
ARM异常处理:
& B' q3 ^) S( Y' T只要正常的程序流被暂时中止,处理器就进入异常模式。例如响应一个来自外设的中断。在处理异常之前,ARM内核保存当前的处理器状态,这样当处理程序结束是可以恢复执行原来的程序。* A& u% @1 f& U" R; E4 a/ I
注意:如果同时发生两个或更多异常,那么将按照固定的顺序来处理异常 。
( S6 U" _3 D. k/ V" `& h  fARM支持的异常种类:+ P8 v0 f; q, e3 P; i
一、异常的进入与退出  [" I) T' |, k& K: C( \* M
当一种异常发生时,硬件就会自动执行如下动作:3 E( ~' h# ?# S5 _5 A
(1)将CPSR保存到相应异常模式下的SPSR中
( |) e- t2 B9 I2 O+ E& @(2)把PC寄存器保存到相应异常模式下的LR中' u+ E. b; n* y- y
(3)将CPSR设置成相应的异常模式6 d, g6 U5 _" U2 O! r5 s6 g; t
(4)设置PC寄存器的值为相应处理程序的入口地址
+ Y+ T: J) `( y4 e% _可以总结如下:! ~* i' ^  p8 X7 l) y
   在这里我们需要重点研究的是,异常产生后,最后PC会指到哪里去呢?这个事情实际不需要我们操心,ARM核在设计的时候就已经确定好了,也就是经常我们所说的异常向量表。异常向量表:6 C* V: o5 a0 ^. I, w: |3 d  \
在ARM7,ARM9/10等处理器,异常向量表可以存放在以 0x00000000或0xffff00000其始的地址。默认是以零地址开始存放的。可能有些同学还是有些晕,我们来举个例子说明一下。/ l, U, D- ~2 _5 q/ [# B- f9 O
例如:ARM处理器正在执行指令,此时外部硬件产生了一个中断。此时将产生IRQ异常,然后ARM核就会自动完成我们上面说的4步。完成前3步后,ARM核会强制将pc的值修改为0x18。修改完成后,处理器就开始从0x18这个地址取指令执行。
' X( j* J/ P" E: @5 [! d从上图可以知道,不同的异常产生时,ARM核修改的PC值不一样。例如:如果是swi指令引起的异常,ARM核最后就会修改pc的值为0x08。, s4 o; K1 W6 C) y7 R3 n
是不是异常向量表,一定要放在0x00000000或0xffff00000其始的地址呢?答案:不是,现在cortex-A系列的处理器可以将异常向量表放在任何位置,拿ARM核收到异常后,它怎么知道应该将pc的值修改为多少呢?这就需要我们通过协处理指令告诉它了。
7 \7 y" h* l% v  @  X例如:在cortex-A8上,我们可以操作如下协处理指令,来告诉ARM核异常向量表的位置。
- g' V2 p0 {# x' d6 X8 U5 bcortex-A8官方手册:3.2.68节有详细说明# @2 W, _* x' S1 w) G
如将告诉ARM核,异常向量表存放在0x20008000
! V) B; V, l8 E# e, U) uldr r0,=0x20008000
% ]9 \9 U8 H% i( zmcr p15,0,r0,c12,c0,0
- E- |1 q3 \% V  [4 P( H5 {( K/ k好了,到这里大家已经知道了异常是什么,当异常产生的时候,ARM核都会自动做那些事情。当然,当异常产生的时候,我们应该对异常做出处理,处理完之后,要返回异常产生之前的场景继续运行。就像,有些时候,我们在做事情的时候,生病了,我们就需要到医生那里去治疗一下,等治疗完成之后,就必须把生病前的事情接着后面干。/ U( c" z* o8 n+ `
有些人,肯定忍不住了,我知道了异常,也知道异常产生后,pc会指向异常向量表,那异常向量表中,到底放什么东西呀,我该怎么处理我的异常呢?
/ T% c4 Q: ?  S+ T2 c首先,回答第一个问题,异常向量表中存放的就是去医生的火箭。坐上火箭就可以到医生哪了,这叫一个字"快"。医生,火箭.....
1 T1 Z+ v* A. c4 q呵呵,别折磨大家了,我们公布答案吧!看下面4 |9 ?. `& W* \& x4 x% M- U
从上面我们可以知道,异常向量表里面存放的都是跳转指令。有些时直接通过b指令实现的,有些时通过修改pc值实现的。这也就是刚刚我说到的"火箭"。跳转的目的是跳到一个地方对异常进行处理。也就是我说到的到医生那里去"治疗"。6 a1 ?% K+ l7 h  ~, H7 N, C( a
我们以irq异常为例子,来说明我们需要干的事情
& A! l2 ^' P1 U2 {$ B$ Kirq :
; G$ F; {& ^6 [SUB    LR,LR,#4 ;计算返回地址7 a! ^) ^. d  H5 y/ }
STMFD  SP!,{R0-R3,LR} ;保存使用到的寄存器
8 t  E, [# Q6 y# i  `/ G) x1 |- F干里你想干的事情0 U! Y" v+ A: |
.....
! s$ c! _! M! r$ O: lLDMFD  SP!,{R0-R3,PC}^ ;中断返回9 Q6 ^% K, A9 H) a2 i+ t; h) x
注意:当异常结束时,异常处理程序必须:
. X& x6 L& a; O1 r1.将LR中的值减去偏移量后存入PC,偏移量根据异常的类型而有所不同;; n: }" z4 J- G  X
2.将SPSR的值复制回CPSR;3 t) `+ `+ O' S8 a3 x# m+ P
3.清零中断禁止标志。
# ?. g0 q" r3 w' k" q注:恢复CPSR的动作会将T、F和I位自动恢复为异常发生前的值。
) {" Z5 W3 ~  g# L9 Y8 ^$ J. z6 x% I5 l$ P  ~. S8 m
) E7 D  Y; f0 {7 i9 W4 E9 u6 o
哎,终于说完了异常。下面我们用一句话总结一下:异常产生需要保存现场(ARM核已经自动为我们做了),异常返回的时候需要恢复现场(需要程序员自动完成)。4 R% S6 ^1 c7 N3 F4 q7 [" g
__________________________________________________________________________________________________________, S: T+ ]7 o- H, ^
下面我们来详细说明异常产生的原因,以及异常返回时,异常模式的lr应该保存的值是多少。最后我们会以软中断实验,来给大家强化对异常的理解。
3 k" s- j- x7 a) s* B) h: s" g0 a# O重要基础知识:R15(PC)总是指向“正在取指”的指令,而不是指向“正在执行”的指令或正在“译码”的指令。一般来说,人们习惯性约定将“正在执行的指令作为参考点”,称之为当前第一条指令,因此PC总是指向第三条指令。当ARM状态时,每条指令为4字节长,所以PC始终指向该指令地址加8字节的地址,即:PC值=当前程序执行位置+8;( [0 M  M# H9 j7 j$ |6 g4 B
注意:不管是几级流水线都统一按照三级流水线来分析,这一点已经向ARM官方求证过。. F2 _0 ^, T" \, I8 C6 f
(1)快速中断异常: w3 ~& j$ v# S$ k( {& B# N
快速中断请求(FIQ)适用于对一个突发事件的响应,这得益于在ARM状态中,快速中断模式有8个专用的寄存器可用来满足寄存器保护的需要(这可以加速上下文切换的速度)。
; ^; M/ k! ]) b8 ]1 n8 Q0 F  N( a不管异常入口是来自ARM状态还是Thumb状态,FIQ处理程序都会通过下面的指令从中断返回:
# s7 A9 W# v% r6 TSUBS pc,R14_fiq,#47 [6 g' R+ m3 H& J% n7 u
在一个特权模式中,可以通过置位CPSR中的F位来禁止FIQ异常。6 K" u& [* d; f' ?+ r) L
(2)中断请求异常( h( t4 n. \4 Z5 W% d4 L
中断请求(IRQ)异常是一个由nIRQ输入端的低电平所产生的正常中断(在具体的芯片中,nIRQ由片内外设拉低,nIRQ是内核的一个信号,对用户不可见)。IRQ的优先级低于FIQ。对于FIQ序列它是被屏蔽的。任何时候在一个特权模式下,都可通过置位CPSR中的I 位来禁止IRQ。3 N" H3 @9 I. @3 D8 |3 b8 j
不管异常入口是来自ARM状态还是Thumb状态,FIQ处理程序都会通过执行下面的指令从中断返回:
0 D% K: e1 v! _0 jSUBS    PC,R14_fiq,#48 B1 J; Q  ~% X/ W8 ?1 z- s/ X
分析IRQ 和 FIQ异常中断处理的返回:) {- q, a: G& w% @: _# ?& s0 ^
指令地址  对应于PC
& ^. V) B( Z/ e; V( s! k: dA           PC-8      执行此指令完成后(!)查询IRQ及FIQ,如果有中断请求则产生中断.: ^) S8 f+ X  K0 n' x5 m) L! ?
A+4       PC-44 }7 O( A' I- K+ W5 ~
A+8       PC   ;lr!+ k( ]. l1 \1 t6 d* W6 q
                    (此时PC的值已经更新,指向A+12.将当前PC-4(即A+8)! }+ Z1 _$ @9 Z3 q8 U* M4 t5 d
保存到LR.返回时,要接着执行A+4(LR-4)处的指令,所以返回指令为
: \- l7 p! ^  h- J6 \2 |SUBS PC, LR,#4(PC=A+4=LR-4)4 n9 d1 ~/ N) G% o! W, x
白话解释:对于普中断和快中断异常:
# g9 n# l* @0 H6 p% K9 n" i/ L# e  中断必须在一条指令执行完以后被检测到,如正在执行指令甲时发生了中断,不等指令甲执行完是不, E5 d" |4 }9 H
会处理该中断的,发生异常时pc已经更新(A+12);  T; g- y/ P0 n$ E  q
  lr = pc – 4(这时处理器决定的,无法更改!)即A+8
4 j; ?5 Q7 d: T% T1 E; \3 _! c9 U  返回后,应执行被中断而没有执行的指令(上面的A+4),所以返回时,pc = lr-4( E- c! U% n9 \. i1 i+ L: F
(3)中止) y& p, r$ R3 c, e9 G$ |
中止发生在对存储器的访问不能完成时,中止包含两种类型:
7 B& {( B- }- u) s- p预取中止   :   发生在指令预取过程中
$ r( M1 e$ J8 {4 t6 _7 {# a数据中止   :   发生在对数据访问时
, b% v: X" I8 }2 j- WA.预取中止
+ G! ^; E+ x/ [8 D8 y) l当发生预取中止时,ARM核将预取的指令标记为无效,但在指令达到流水线的执行阶段时才进入异常。如果指令在流水线中因为发生分支而没有被执行,中止将不会发生。& Q- Z, z4 b) d
在处理中止的原因之后,不管处于哪种处理器操作状态,处理程序都会执行下面的指令恢复PC和CPSR并重试被中止的指令:( ~8 E+ i7 t# t$ E5 K5 y' s4 G  [" E
SUBS  PC,R14_abt,#4
- e/ M( z! g* c- O6 L分析指令预取中止异常中断处理的返回:
" B- f! W, {0 W) Q& \0 f) b指令地址, Q' H6 z$ F7 G; Y$ c% b
A       PC-8     执行本指令时发生异常,  ' c/ r+ D5 Y1 f# p0 i
A+4   PC-4     处理器将A+4(PC-4)保存到LR.  ;lr!
# R! k, ^. g6 iA+8   PC
* c6 n+ `- w6 l% M, g' D+ q$ \$ G返回时,发生指令预取中止的指令A(PC-8)处重新执行,所以返回指令为& S+ E& y2 t  H% ~0 k& r
SUBS PC, LR,#4(PC=A=LR-4)
) ]6 j* D0 n/ y' M' ~9 W白话解释:对于预取指令中止异常:/ _: W+ H' T. n5 i& d
  发生预取指令异常时,是在执行时发生的异常,pc未更新,即pc = A+8* m: ]7 d9 y/ s  O0 ^
  lr = pc – 4(这时处理器决定的,无法更改!)即A+4
) |1 g7 r* t. Q4 Y; W: _6 r  由于这类异常返回后应重新执行异常的那个指令(A),所以返回时,pc = lr-4) V8 j/ v6 ~  r6 V
B.数据中止1 o3 k$ j0 }" y0 D3 _4 |
指令地址
! J3 }6 a& Z4 @! L$ B# O9 v! y9 OA           PC-8    本指令访问有问题的数据,产生中断时,PC的值已经更新   0 D* T' X3 M4 r: Z+ [# Y0 Y0 O! ?
A+4        PC-4  中断发生时PC=A+12,处理器将A+8(PC-4)保存到LR.9 I3 M' S- R$ r8 s# O7 v
A+8        PC   ;lr!7 [# h4 z4 L! r* b7 ~5 x
返回时,要返回到A处继续执行,所以指令为SUBS PC,  LR,#8.(PC=A=LR-8)8 r+ K1 f9 A  \" D6 f8 n3 `1 ]2 b
白话解释:对于数据访问中止异常:
0 {7 D* i3 N: u/ Y6 a. `6 ]6 t9 R  发生数据访问中止异常时,是在执行时访问数据错误导致的异常,pc已经更新,即pc = A+12
4 ?2 t6 }4 W; ]. f) w, I" b  lr = pc – 4(这时处理器决定的,无法更改!)即A+8. W; }2 m( T3 n" v4 s1 y
  由于这类异常返回后应重新执行异常的那个指令(A),所以返回时,pc = lr-8; X/ m( o7 D% t+ r. B2 ?2 N
(4)软件中断指令) X9 x. i1 k% p, _1 r7 S8 C
所有的任务都是运行在用户模式下的,因此任务只能读CPSR而不能写SPSR。任务切换到特权模式下唯一的途径就是使用一个SWI指令调用,SWI指令强迫处理器从用户模式切换到SVC管理模式,并且IRQ自动关闭,所以软件中断方式常被用于系统调用。; p- ~, r4 N2 Z$ n0 w
(5)未定义指令异常% Z7 ?, y+ Y4 C3 v
(1)当ARM在对一条未定义指令进行译码时,发现这是一条自己和系统内任何协处理器都无法执行的指令时,就会发生未定义指令异常;
/ c( ~# S0 Q( F( d# E! |) O(2)由于是在对未定义指令译码时发生异常,所以PC的值等于未定义指令的地址+4(即刚好为中断返回地址),因此R14保存的值是 中断返回地址 ,所以当异常要返回时可执行以下指令:
, r" V: U3 t% SMOVS   PC,R14_und   $ N# @+ _( F- f  p
分析:SWI和和未定义指令异常中断的返回:
9 Y. m1 `: j) k% Z指令地址
! I$ h$ h6 {1 g" v4 MA         PC-8 当前指令为SWI或未定义指令 此时发生异常PC的值还没有更新.9 Z* d; t- K* q8 @6 @. v; y
A+4       PC-4 中断时处理器将PC-4保存到LR   ;lr!) u3 h4 ~& ?% _8 |7 P4 u1 y
A+8       PC  0 ^4 X; n. q; L
返回时,从发生中断的指令A(PC-8)的下一条指令A+4(PC-4)处开始执行,所以直接0 j9 L7 K% |; i7 J$ t
把LR的值赋给PC就行了,具体指令为MOVPC,LR  (PC=A+4=LR)  h3 F% S- C' Y+ b/ ?
白话解释:对于SWI和未定义指令异常:6 o3 d5 \7 Z! ^5 s1 z
  发生异常时pc没有更新,根据ARM的三级流水线原理,pc没有更新,仍然等于(A+8);  u: A( n; R/ ~. u) {
  lr = pc – 4(这时处理器决定的,无法更改!)即A+47 C# Q; T2 ~, W
  由于这类异常返回后应执行下一条指令(A+4),所以返回时,pc = lr即可: C2 i3 `# u/ a( b5 X! w" v
最后我们来总结一下:
: g7 Z- Y+ [2 n# A  引起PC更新的原因一种是数据中止,还有就是中断了.
* [0 p) b1 l: Y3 |: {" }! Q: k3 ?  中断必须是在一条指令执行完毕后才能被检测到,所以它中断的只是还未执行的那条指令(pc - 8),) [- p- s; j' |3 u3 ?' P+ _
所以pc = lr – 4;
* c  Q1 H1 h2 I, O0 P  与中断相同,SWI和未定义指令异常也是返回到下一条指令(pc - 4),只是他们在执行时,PC的值并没* k+ Q' |4 I# Y+ t
有更新,所以pc = lr;
* u# b% g* f0 ]! P( w  预取指令中止异常,也没有发生pc更新,但它还得重新执行发生异常的那条指令,所以pc = lr – 4;
7 V/ I0 q5 `3 Q' H* u  数据访问中止异常,发生了pc更新,并且它也需要重新执行发生异常的那条指令,所以pc = lr – 8;; x0 g) e! |+ r/ ]3 u
当多个异常同时发生时,一个固定的优先级系统决定它们被处理的顺序:
; @; L  O% j) B9 a______________________________________________________________________________________________________________________8 h6 l, C! B) x
二、SWI 实验
* O$ y0 ?# n  p) O(1)swi指令
  f& o' Y% [/ S, `7 z1 d
( ?6 h" l$ B" {1 N+ ?, Y0 D5 G6 s+ h) B
SWI指令用于产生软中断,从而实现在从户模式变换到管理模式,并且将CPSR保存到管理模式的SPSR中,然后程序跳转到SWI异常入口。在其它模式下也可使用SWI指令,处理器同样地切换到管理模式。
# _( f9 i4 N2 |8 E该指令主要用于用户程序调用操作系统的系统服务,操作系统在SWI异常处理程序中进行相应的系统服务。/ _0 c8 N9 {# j
注意:
9 u8 ^; z/ j% ~ARM 内核不提供直接传递软中断(SWI)号到处理程序的机制:& R5 M9 q9 c4 Z# }
SWI 处理程序必须定位SWI 指令,并提取SWI指令中的常数域( v2 ]9 p5 T5 d/ k- H
为此, SWI 处理程序必须确定SWI 调用是在哪一种状态(ARM/Thumb).
1 ~6 l) d" U9 ~3 d% D* j6 j检查 SPSR 的 T-bit
+ i0 Z/ C+ E% c9 ~2 \SWI 指令在ARM 状态下在 LR-4 位置, Thumb 状态下在LR-2位置9 {. @# k7 C* k6 ~/ n
SWI 指令按相应的格式译码:
4 e* q" w  C; n7 _1 d0 y; Y例如:+ x% }" V' \) d9 w7 z- Z' L- u

, {- [, F5 c8 h  J, D+ zSWI 133 F) _) [9 k# \) g1 X
思考,当软中断产生后,怎么获取它的软中断号呢?
0 E, G1 B$ t4 |实验的核心代码如下:7 f' y% a+ @; Q8 @5 F5 X) i* \- c
  q3 x! i2 x8 O! [
software_interrupt:+ l2 R* s' V5 y* L$ B! w4 o3 R8 z
@设置软中断所在模式的栈
2 u8 I7 u/ b0 gldr sp,=0x34000
) Q# u: V: f2 ]% I" z* I. @7 F- Y@保存用到的寄存器' k# T- c) O" I
stmfd sp!,{r0-r2,lr}- t+ ?. d' E4 c& z- x: O
@获取swi指令对应的机器码8 f7 M5 S5 t6 U% |& B  l- \' D
ldr r0,[lr,#-4]. r/ G4 v2 h  r/ g
@获取软中断号" @, @9 G! g5 @* k+ [6 N
bic r0,r0,#0xff000000
* p8 L! d; t: f8 a9 ?@调用C处理函数,求累加和2 F7 I  N+ @0 q2 W/ f* b
bl calc_sum
( g8 O: u6 s2 }8 {@获得函数返回值,存放在r1
9 |8 q# f1 p' |" Z4 ~* [mov r1,r0
# M3 L) [: I, R4 n6 j8 F@恢复现场,^表示目标寄存器是pc时,传递数据给pc,同时更新CPSR
4 v6 E+ b7 m- e* ?8 cldmfd sp!,{r0-r2,pc}^

! Q; o8 C6 e" `2 g
  • TA的每日心情
    开心
    2022-12-26 15:46
  • 签到天数: 1 天

    [LV.1]初来乍到

    2#
    发表于 2020-5-6 13:44 | 只看该作者
    ARM异常处理,描述的很详细
    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    关闭

    推荐内容上一条 /1 下一条

    EDA365公众号

    关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

    GMT+8, 2025-11-24 16:26 , Processed in 0.187500 second(s), 24 queries , Gzip On.

    深圳市墨知创新科技有限公司

    地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

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