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

ARM异常处理

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
ARM异常处理:$ |9 i% V2 C; W! U1 M' u9 I
只要正常的程序流被暂时中止,处理器就进入异常模式。例如响应一个来自外设的中断。在处理异常之前,ARM内核保存当前的处理器状态,这样当处理程序结束是可以恢复执行原来的程序。
* X' T$ s" v" v- c/ a, k5 D5 q9 J注意:如果同时发生两个或更多异常,那么将按照固定的顺序来处理异常 。) p7 f: Y+ C. r- O3 |
ARM支持的异常种类:
0 l  P4 N' b& {4 q$ S- l一、异常的进入与退出4 U# n6 a1 l0 O  H; d
当一种异常发生时,硬件就会自动执行如下动作:
2 P4 y3 n  I; m/ M9 j" G9 i8 t! D(1)将CPSR保存到相应异常模式下的SPSR中) _1 m+ d: R+ T8 [
(2)把PC寄存器保存到相应异常模式下的LR中5 T1 `% }% U; e+ a1 D8 y/ R' h  n
(3)将CPSR设置成相应的异常模式
3 S  A# u8 ^% {+ G% j) R(4)设置PC寄存器的值为相应处理程序的入口地址# I- E. L# p2 U7 o5 Y. ~: e$ }
可以总结如下:
& P! {, `( D$ Z) g2 j3 k   在这里我们需要重点研究的是,异常产生后,最后PC会指到哪里去呢?这个事情实际不需要我们操心,ARM核在设计的时候就已经确定好了,也就是经常我们所说的异常向量表。异常向量表:
$ w5 @' d, V% R% y9 L- \) x在ARM7,ARM9/10等处理器,异常向量表可以存放在以 0x00000000或0xffff00000其始的地址。默认是以零地址开始存放的。可能有些同学还是有些晕,我们来举个例子说明一下。
, R* G. P) T8 F2 U7 K例如:ARM处理器正在执行指令,此时外部硬件产生了一个中断。此时将产生IRQ异常,然后ARM核就会自动完成我们上面说的4步。完成前3步后,ARM核会强制将pc的值修改为0x18。修改完成后,处理器就开始从0x18这个地址取指令执行。* V3 [' _0 z+ ?* w8 X; I" q+ O
从上图可以知道,不同的异常产生时,ARM核修改的PC值不一样。例如:如果是swi指令引起的异常,ARM核最后就会修改pc的值为0x08。
$ s5 f, ~. {' j是不是异常向量表,一定要放在0x00000000或0xffff00000其始的地址呢?答案:不是,现在cortex-A系列的处理器可以将异常向量表放在任何位置,拿ARM核收到异常后,它怎么知道应该将pc的值修改为多少呢?这就需要我们通过协处理指令告诉它了。
" K. P' X3 }4 O! K6 Q例如:在cortex-A8上,我们可以操作如下协处理指令,来告诉ARM核异常向量表的位置。5 G5 O6 ?  b. G: r  y
cortex-A8官方手册:3.2.68节有详细说明
# H! W3 M# z  M9 h5 d如将告诉ARM核,异常向量表存放在0x20008000
- h9 ]. r, I3 \7 b8 Hldr r0,=0x20008000
' X) N7 b; ?  F9 f, y+ {mcr p15,0,r0,c12,c0,0
$ }" ~* b+ R* @; \' M" k' L* c好了,到这里大家已经知道了异常是什么,当异常产生的时候,ARM核都会自动做那些事情。当然,当异常产生的时候,我们应该对异常做出处理,处理完之后,要返回异常产生之前的场景继续运行。就像,有些时候,我们在做事情的时候,生病了,我们就需要到医生那里去治疗一下,等治疗完成之后,就必须把生病前的事情接着后面干。! i& |  G. z% O+ P
有些人,肯定忍不住了,我知道了异常,也知道异常产生后,pc会指向异常向量表,那异常向量表中,到底放什么东西呀,我该怎么处理我的异常呢?& N) b+ B1 D3 c; ^6 v& D7 r
首先,回答第一个问题,异常向量表中存放的就是去医生的火箭。坐上火箭就可以到医生哪了,这叫一个字"快"。医生,火箭.....' }2 _3 X# q. ~6 \; N2 p0 h/ m) f6 f
呵呵,别折磨大家了,我们公布答案吧!看下面
" b# _/ u4 ?9 W% ]1 v从上面我们可以知道,异常向量表里面存放的都是跳转指令。有些时直接通过b指令实现的,有些时通过修改pc值实现的。这也就是刚刚我说到的"火箭"。跳转的目的是跳到一个地方对异常进行处理。也就是我说到的到医生那里去"治疗"。) i+ X, I! F) {" F. G9 a, ~
我们以irq异常为例子,来说明我们需要干的事情
) q# q! W; l) V. M9 e4 s' mirq :0 }0 c" Q. ~- g- |, D2 O; o3 H, Q
SUB    LR,LR,#4 ;计算返回地址
0 ^+ t/ c2 v7 |: R7 eSTMFD  SP!,{R0-R3,LR} ;保存使用到的寄存器4 @9 t# x! d0 G- W
干里你想干的事情
8 o9 _7 l. e: |) o.....$ Z$ R$ S( Z) ]
LDMFD  SP!,{R0-R3,PC}^ ;中断返回
) l- r9 @" j3 E4 J7 ?注意:当异常结束时,异常处理程序必须:
* _8 S! V( I, I, @# s- i3 m4 Z1.将LR中的值减去偏移量后存入PC,偏移量根据异常的类型而有所不同;- ~) N6 b- n0 @
2.将SPSR的值复制回CPSR;# t. a4 k3 Y! x4 ^6 _5 j
3.清零中断禁止标志。
% Z+ n4 Q! i  T+ }注:恢复CPSR的动作会将T、F和I位自动恢复为异常发生前的值。8 z* ^& F! u( F- Z+ D
( s5 v" b7 i4 q2 k$ b& k3 h

1 @0 \) T4 t  I% m$ C% t哎,终于说完了异常。下面我们用一句话总结一下:异常产生需要保存现场(ARM核已经自动为我们做了),异常返回的时候需要恢复现场(需要程序员自动完成)。
* ?+ A6 M% ^) k__________________________________________________________________________________________________________
2 Y, |. z6 {3 A! ?6 O9 d$ i下面我们来详细说明异常产生的原因,以及异常返回时,异常模式的lr应该保存的值是多少。最后我们会以软中断实验,来给大家强化对异常的理解。( \( o/ g" F" K& A) r. @
重要基础知识:R15(PC)总是指向“正在取指”的指令,而不是指向“正在执行”的指令或正在“译码”的指令。一般来说,人们习惯性约定将“正在执行的指令作为参考点”,称之为当前第一条指令,因此PC总是指向第三条指令。当ARM状态时,每条指令为4字节长,所以PC始终指向该指令地址加8字节的地址,即:PC值=当前程序执行位置+8;# e. l* _: h; \9 t; j
注意:不管是几级流水线都统一按照三级流水线来分析,这一点已经向ARM官方求证过。
7 E2 A1 i) Y6 S/ e; }, Z8 @(1)快速中断异常3 N' I1 i. g  h
快速中断请求(FIQ)适用于对一个突发事件的响应,这得益于在ARM状态中,快速中断模式有8个专用的寄存器可用来满足寄存器保护的需要(这可以加速上下文切换的速度)。
- u( e+ ^7 P! E不管异常入口是来自ARM状态还是Thumb状态,FIQ处理程序都会通过下面的指令从中断返回:
' |2 T& E% h. g% D4 OSUBS pc,R14_fiq,#4
. t1 V1 F# z- `. V6 t# ?; R在一个特权模式中,可以通过置位CPSR中的F位来禁止FIQ异常。
* V- p) ?" s/ e6 r(2)中断请求异常5 u) V: a. H' T
中断请求(IRQ)异常是一个由nIRQ输入端的低电平所产生的正常中断(在具体的芯片中,nIRQ由片内外设拉低,nIRQ是内核的一个信号,对用户不可见)。IRQ的优先级低于FIQ。对于FIQ序列它是被屏蔽的。任何时候在一个特权模式下,都可通过置位CPSR中的I 位来禁止IRQ。( p1 e, n' a' o3 j1 H; g4 ]
不管异常入口是来自ARM状态还是Thumb状态,FIQ处理程序都会通过执行下面的指令从中断返回:
9 b- M) G9 I" X. Y( O* MSUBS    PC,R14_fiq,#4
" A: o  G, e- Q1 _. R0 X8 X- y" w% I分析IRQ 和 FIQ异常中断处理的返回:
, C9 k  V' d: S; _4 {+ `; f指令地址  对应于PC
. g9 ?' z# ~3 U/ G& Q% ~# b/ U) ZA           PC-8      执行此指令完成后(!)查询IRQ及FIQ,如果有中断请求则产生中断.. A- x/ C! L# J: Z; L$ t, S
A+4       PC-4
, ^  W" [" G) B1 T. NA+8       PC   ;lr!* [* Z9 k5 b- R' ^& E
                    (此时PC的值已经更新,指向A+12.将当前PC-4(即A+8)
) X9 C" g2 [4 j4 R) |$ ?保存到LR.返回时,要接着执行A+4(LR-4)处的指令,所以返回指令为
$ B5 z: f' w0 LSUBS PC, LR,#4(PC=A+4=LR-4)8 W9 G* Y" Z( ?2 X# ~9 p
白话解释:对于普中断和快中断异常:
0 g: x/ D; G7 }( K. M8 F8 E  中断必须在一条指令执行完以后被检测到,如正在执行指令甲时发生了中断,不等指令甲执行完是不
6 |+ ~- H* @6 z' A" q8 P& U' H  @会处理该中断的,发生异常时pc已经更新(A+12);
" r9 ^9 x% A  m  lr = pc – 4(这时处理器决定的,无法更改!)即A+8
4 H* h( [7 G' v  V% I$ M  返回后,应执行被中断而没有执行的指令(上面的A+4),所以返回时,pc = lr-44 x0 S. n2 R2 B5 @! i
(3)中止  b' v) G8 J" U( ~
中止发生在对存储器的访问不能完成时,中止包含两种类型:
, @4 G9 x+ |6 {2 E( p7 p预取中止   :   发生在指令预取过程中
& N* a& i5 E4 t6 p1 q0 o; U数据中止   :   发生在对数据访问时% U* y& K, |# T8 ]
A.预取中止
' T: ?) x2 I: X0 s1 _当发生预取中止时,ARM核将预取的指令标记为无效,但在指令达到流水线的执行阶段时才进入异常。如果指令在流水线中因为发生分支而没有被执行,中止将不会发生。7 ?5 E) M% t: ~, |4 N4 H
在处理中止的原因之后,不管处于哪种处理器操作状态,处理程序都会执行下面的指令恢复PC和CPSR并重试被中止的指令:5 Z+ C! ?+ {9 S
SUBS  PC,R14_abt,#42 l& p; _3 P) V6 K3 K
分析指令预取中止异常中断处理的返回:
0 a/ @6 m4 Z) Z7 ^1 J指令地址
+ [! S$ S6 H# c7 NA       PC-8     执行本指令时发生异常,  $ p; [) r  R$ u, u9 q5 _+ {
A+4   PC-4     处理器将A+4(PC-4)保存到LR.  ;lr!
5 f8 ~; y/ O1 b4 ]6 M  Q! sA+8   PC
6 E# ^; S4 I; _/ n7 r返回时,发生指令预取中止的指令A(PC-8)处重新执行,所以返回指令为, |7 h. |3 U5 N+ q( ^/ S+ d
SUBS PC, LR,#4(PC=A=LR-4)  f/ h. {! d2 C6 Q
白话解释:对于预取指令中止异常:
( ?! e1 V0 o; v5 g' o: L! K/ M6 u3 l  ]% a  发生预取指令异常时,是在执行时发生的异常,pc未更新,即pc = A+84 m$ k2 o  K) A1 M' I, Z* J' Q2 t
  lr = pc – 4(这时处理器决定的,无法更改!)即A+4
; z, x; b/ g0 s( r  由于这类异常返回后应重新执行异常的那个指令(A),所以返回时,pc = lr-4% ^2 ^+ Z* C4 @6 n; M" C! A
B.数据中止
: J, O! Z# n, F1 z6 h指令地址$ ]! T) S7 {7 r
A           PC-8    本指令访问有问题的数据,产生中断时,PC的值已经更新   
. F) X1 f( i5 n( IA+4        PC-4  中断发生时PC=A+12,处理器将A+8(PC-4)保存到LR.
- I/ K: W/ b2 R5 h& ^. yA+8        PC   ;lr!
8 i8 i* G% [+ L返回时,要返回到A处继续执行,所以指令为SUBS PC,  LR,#8.(PC=A=LR-8)
" j* ~! N/ G  L$ q- P白话解释:对于数据访问中止异常:( Q4 i5 ]$ ]; e, C% q" D
  发生数据访问中止异常时,是在执行时访问数据错误导致的异常,pc已经更新,即pc = A+12; g, m* Y% k/ M! m
  lr = pc – 4(这时处理器决定的,无法更改!)即A+8
$ H$ @7 D5 V& N0 q- w; w1 s- |( N  由于这类异常返回后应重新执行异常的那个指令(A),所以返回时,pc = lr-8% e& {2 }1 y0 X! L
(4)软件中断指令; v) `3 R8 J. B
所有的任务都是运行在用户模式下的,因此任务只能读CPSR而不能写SPSR。任务切换到特权模式下唯一的途径就是使用一个SWI指令调用,SWI指令强迫处理器从用户模式切换到SVC管理模式,并且IRQ自动关闭,所以软件中断方式常被用于系统调用。' o/ b- f% ]: p1 a
(5)未定义指令异常
( @# r. u! X' I5 `! R4 x(1)当ARM在对一条未定义指令进行译码时,发现这是一条自己和系统内任何协处理器都无法执行的指令时,就会发生未定义指令异常;
3 L) T; a* J$ M(2)由于是在对未定义指令译码时发生异常,所以PC的值等于未定义指令的地址+4(即刚好为中断返回地址),因此R14保存的值是 中断返回地址 ,所以当异常要返回时可执行以下指令:( L9 a$ D( q  a; A0 W+ a8 Y
MOVS   PC,R14_und   6 Z* V# c5 q# u" A- }
分析:SWI和和未定义指令异常中断的返回:
2 ^+ T' A7 w! X, Z6 B6 u" a6 `% [指令地址' |* }/ R5 w/ H. X& U* N# m
A         PC-8 当前指令为SWI或未定义指令 此时发生异常PC的值还没有更新.
& N; ~3 g( P8 [/ J. n; l- CA+4       PC-4 中断时处理器将PC-4保存到LR   ;lr!
0 o+ O6 c6 p4 k" `A+8       PC  
7 X- l. B' f: V# n3 h' O  A5 k% @2 K返回时,从发生中断的指令A(PC-8)的下一条指令A+4(PC-4)处开始执行,所以直接
% S" G* V: n/ I# E+ s把LR的值赋给PC就行了,具体指令为MOVPC,LR  (PC=A+4=LR)
4 P, L& _! z& \5 L- P白话解释:对于SWI和未定义指令异常:
* U+ N4 w3 s7 P0 q/ d  发生异常时pc没有更新,根据ARM的三级流水线原理,pc没有更新,仍然等于(A+8);
7 Q: r$ Y4 s- F4 x: d  lr = pc – 4(这时处理器决定的,无法更改!)即A+4
. ]; J" n8 }4 V4 g# [  由于这类异常返回后应执行下一条指令(A+4),所以返回时,pc = lr即可& c2 W+ [! s0 C: E/ V6 \
最后我们来总结一下:1 T4 b- ~7 W( E8 t3 p) w7 e) Y
  引起PC更新的原因一种是数据中止,还有就是中断了.
* o5 R4 ^4 n( C/ q- t: F* a  中断必须是在一条指令执行完毕后才能被检测到,所以它中断的只是还未执行的那条指令(pc - 8),' ^/ M+ t% @3 R+ _9 }
所以pc = lr – 4;1 L0 ]* t+ q% ]1 r% a) \0 C
  与中断相同,SWI和未定义指令异常也是返回到下一条指令(pc - 4),只是他们在执行时,PC的值并没0 s; ^$ w: _, C5 b7 D4 V9 G8 s6 b
有更新,所以pc = lr;1 s1 U; ?% z& E' D3 I2 Z
  预取指令中止异常,也没有发生pc更新,但它还得重新执行发生异常的那条指令,所以pc = lr – 4;
+ x- j7 p" a% M/ l: c* X  数据访问中止异常,发生了pc更新,并且它也需要重新执行发生异常的那条指令,所以pc = lr – 8;
0 V" N4 O# ^- L当多个异常同时发生时,一个固定的优先级系统决定它们被处理的顺序:
9 C) ~8 R  W( l' w______________________________________________________________________________________________________________________2 m6 I; @0 l3 R- M; f
二、SWI 实验
( N- f- T/ I' w4 y(1)swi指令8 V$ C' T2 R7 Q! X4 `0 b4 C( f+ Y
, D( v) f4 z0 H) I5 N9 n

! |3 s1 c  N- eSWI指令用于产生软中断,从而实现在从户模式变换到管理模式,并且将CPSR保存到管理模式的SPSR中,然后程序跳转到SWI异常入口。在其它模式下也可使用SWI指令,处理器同样地切换到管理模式。) ~8 j% \' t$ F3 |
该指令主要用于用户程序调用操作系统的系统服务,操作系统在SWI异常处理程序中进行相应的系统服务。+ ^4 t! n* C6 ?4 U' A
注意:
! i/ m; h4 }% _" TARM 内核不提供直接传递软中断(SWI)号到处理程序的机制:
7 h" Z0 O/ @- }1 A0 `" lSWI 处理程序必须定位SWI 指令,并提取SWI指令中的常数域6 J  C2 V  H# X+ R4 q1 M. ~
为此, SWI 处理程序必须确定SWI 调用是在哪一种状态(ARM/Thumb).
! H1 t: M! t& m  T5 G检查 SPSR 的 T-bit: F0 J9 y* S9 x
SWI 指令在ARM 状态下在 LR-4 位置, Thumb 状态下在LR-2位置
; @  J+ J* @, s/ K# V- v4 a8 L( zSWI 指令按相应的格式译码:" H+ A; b1 v0 R# r( S4 Y( n
例如:
: |: [) h/ }; J: {/ t# o/ _1 B( F( O5 T8 h# \
SWI 13" ]9 I7 I3 ?5 ]7 A7 X; S8 @
思考,当软中断产生后,怎么获取它的软中断号呢?
& v. _& f: D; j+ D* ~; C实验的核心代码如下:! _3 h/ N( a" @5 i1 A6 }/ `5 N
2 ^8 d, v/ n" p; ~+ h
software_interrupt:! R1 x1 `5 L% H) W+ s5 Q* P
@设置软中断所在模式的栈
2 N5 Z, {! V$ {# w# g5 P) gldr sp,=0x34000
6 i! M5 y! \' D* y; A4 [* m@保存用到的寄存器
3 x: @1 v8 K6 F  m" q% Istmfd sp!,{r0-r2,lr}3 U1 r' {7 i* o/ Y: Q+ G
@获取swi指令对应的机器码
! y5 ^/ t- R7 Q. V- Aldr r0,[lr,#-4]% q( {% t3 x7 Z+ }1 F
@获取软中断号( }! m) a2 Q: V, z' R5 y
bic r0,r0,#0xff000000
# ?; P4 }, R- R/ R8 r@调用C处理函数,求累加和
  Q* ^, s( M+ X0 m) v- W" ybl calc_sum
# P5 J( z, I! @7 j# m@获得函数返回值,存放在r1
; ], }9 s) q$ V/ |6 v% fmov r1,r0* O7 h5 f1 U' K8 v9 }
@恢复现场,^表示目标寄存器是pc时,传递数据给pc,同时更新CPSR8 ?. I% j7 K2 e
ldmfd sp!,{r0-r2,pc}^
9 N. Y9 W5 ^% U  F1 }
  • 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-7-2 20:08 , Processed in 0.062500 second(s), 23 queries , Gzip On.

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

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

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