|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
ARM异常处理:
2 k- m& r( T. M; W3 w只要正常的程序流被暂时中止,处理器就进入异常模式。例如响应一个来自外设的中断。在处理异常之前,ARM内核保存当前的处理器状态,这样当处理程序结束是可以恢复执行原来的程序。
2 s! ^+ j. w5 x6 e注意:如果同时发生两个或更多异常,那么将按照固定的顺序来处理异常 。' T; \; U* x% N) m
ARM支持的异常种类:' x: U5 p1 w" g7 F4 z
一、异常的进入与退出
8 ?5 r1 X; l8 l/ f. z% Z& u6 F/ `/ ^当一种异常发生时,硬件就会自动执行如下动作:
* X6 b. S5 K1 X5 a- T1 p( P! r(1)将CPSR保存到相应异常模式下的SPSR中
2 `2 n# m* }; e9 ], W& ~(2)把PC寄存器保存到相应异常模式下的LR中
" H+ {: p* @ x) m! |2 b(3)将CPSR设置成相应的异常模式
3 Z# N# u% [0 a, u, `(4)设置PC寄存器的值为相应处理程序的入口地址. n5 F8 R* T. L) I
可以总结如下:6 T, G2 K6 M/ p) u7 m. D
在这里我们需要重点研究的是,异常产生后,最后PC会指到哪里去呢?这个事情实际不需要我们操心,ARM核在设计的时候就已经确定好了,也就是经常我们所说的异常向量表。异常向量表:. j) p' j4 G, o" Z$ P$ V3 s
在ARM7,ARM9/10等处理器,异常向量表可以存放在以 0x00000000或0xffff00000其始的地址。默认是以零地址开始存放的。可能有些同学还是有些晕,我们来举个例子说明一下。
% x! q# v! R) E例如:ARM处理器正在执行指令,此时外部硬件产生了一个中断。此时将产生IRQ异常,然后ARM核就会自动完成我们上面说的4步。完成前3步后,ARM核会强制将pc的值修改为0x18。修改完成后,处理器就开始从0x18这个地址取指令执行。7 t' [7 ^9 d- l% o8 T
从上图可以知道,不同的异常产生时,ARM核修改的PC值不一样。例如:如果是swi指令引起的异常,ARM核最后就会修改pc的值为0x08。2 q/ J" w' m7 ^- Y
是不是异常向量表,一定要放在0x00000000或0xffff00000其始的地址呢?答案:不是,现在cortex-A系列的处理器可以将异常向量表放在任何位置,拿ARM核收到异常后,它怎么知道应该将pc的值修改为多少呢?这就需要我们通过协处理指令告诉它了。
9 v- c& ^6 p; q) D' J: [5 q, u例如:在cortex-A8上,我们可以操作如下协处理指令,来告诉ARM核异常向量表的位置。- \8 m( _7 J$ Y0 [; P6 S
cortex-A8官方手册:3.2.68节有详细说明: ]/ t+ Q/ T% u3 r: T. [# x
如将告诉ARM核,异常向量表存放在0x20008000/ Q; N. t8 s; x
ldr r0,=0x20008000 b2 R" p3 |: D1 ^
mcr p15,0,r0,c12,c0,07 B' R0 s6 H! J4 _5 e! R3 J
好了,到这里大家已经知道了异常是什么,当异常产生的时候,ARM核都会自动做那些事情。当然,当异常产生的时候,我们应该对异常做出处理,处理完之后,要返回异常产生之前的场景继续运行。就像,有些时候,我们在做事情的时候,生病了,我们就需要到医生那里去治疗一下,等治疗完成之后,就必须把生病前的事情接着后面干。6 w' l4 g; ~. C7 I; C/ k0 l* d
有些人,肯定忍不住了,我知道了异常,也知道异常产生后,pc会指向异常向量表,那异常向量表中,到底放什么东西呀,我该怎么处理我的异常呢?
0 n7 ^0 y, D+ ?* R3 `2 T) q首先,回答第一个问题,异常向量表中存放的就是去医生的火箭。坐上火箭就可以到医生哪了,这叫一个字"快"。医生,火箭.....- T$ h3 K- W T4 [5 R" x
呵呵,别折磨大家了,我们公布答案吧!看下面
6 [' I, | v4 s* ~9 u. J! d从上面我们可以知道,异常向量表里面存放的都是跳转指令。有些时直接通过b指令实现的,有些时通过修改pc值实现的。这也就是刚刚我说到的"火箭"。跳转的目的是跳到一个地方对异常进行处理。也就是我说到的到医生那里去"治疗"。; N' c; c; s- [, a* z+ T/ _
我们以irq异常为例子,来说明我们需要干的事情
' X6 t* c4 J/ w1 r5 E6 iirq :! M/ \/ t7 D* M( J* R. K# s- v9 @
SUB LR,LR,#4 ;计算返回地址
1 j5 h6 t$ c; J! a6 j S% `0 ASTMFD SP!,{R0-R3,LR} ;保存使用到的寄存器- ~! y4 A5 V6 L. z* R" [: u
干里你想干的事情
0 ^/ X/ Y- n) c$ B9 W.....
5 ?3 W3 ?7 r4 H: {LDMFD SP!,{R0-R3,PC}^ ;中断返回
* U8 @7 S$ z8 U, S. X! r注意:当异常结束时,异常处理程序必须:
9 f: X- m8 D( |7 W- ?1.将LR中的值减去偏移量后存入PC,偏移量根据异常的类型而有所不同;
+ K) v4 |' V: ^- j u t9 E2.将SPSR的值复制回CPSR;
& {* I! i( S+ K5 I# ~! c/ f: C3.清零中断禁止标志。
. M K- Z7 g/ F) {& [& e L注:恢复CPSR的动作会将T、F和I位自动恢复为异常发生前的值。! P/ q3 a6 N# T6 n. R* l# a; O% k
" v3 s% U! l; D; k- X
- d# m2 B6 w+ S# q哎,终于说完了异常。下面我们用一句话总结一下:异常产生需要保存现场(ARM核已经自动为我们做了),异常返回的时候需要恢复现场(需要程序员自动完成)。
: `4 f% z X+ H. e% @: {- E' k__________________________________________________________________________________________________________* n) ~5 C' x( y9 i, ^
下面我们来详细说明异常产生的原因,以及异常返回时,异常模式的lr应该保存的值是多少。最后我们会以软中断实验,来给大家强化对异常的理解。! B+ z4 f( d! ~$ l# j |, m! I
重要基础知识:R15(PC)总是指向“正在取指”的指令,而不是指向“正在执行”的指令或正在“译码”的指令。一般来说,人们习惯性约定将“正在执行的指令作为参考点”,称之为当前第一条指令,因此PC总是指向第三条指令。当ARM状态时,每条指令为4字节长,所以PC始终指向该指令地址加8字节的地址,即:PC值=当前程序执行位置+8;0 Q4 I8 |1 z+ s5 q3 }
注意:不管是几级流水线都统一按照三级流水线来分析,这一点已经向ARM官方求证过。- d( m% t6 y6 k& v5 Y" l
(1)快速中断异常
% W6 I# b9 ]) ~) d快速中断请求(FIQ)适用于对一个突发事件的响应,这得益于在ARM状态中,快速中断模式有8个专用的寄存器可用来满足寄存器保护的需要(这可以加速上下文切换的速度)。
% L6 R' p7 q# i, a/ N不管异常入口是来自ARM状态还是Thumb状态,FIQ处理程序都会通过下面的指令从中断返回:
: k6 j& G2 y) U2 uSUBS pc,R14_fiq,#4! v2 l m7 a3 P% s q( E/ S8 `
在一个特权模式中,可以通过置位CPSR中的F位来禁止FIQ异常。" [5 {) y4 w3 j" d5 N
(2)中断请求异常# M3 h& [7 h6 h$ i3 l+ l Q3 p, c+ J
中断请求(IRQ)异常是一个由nIRQ输入端的低电平所产生的正常中断(在具体的芯片中,nIRQ由片内外设拉低,nIRQ是内核的一个信号,对用户不可见)。IRQ的优先级低于FIQ。对于FIQ序列它是被屏蔽的。任何时候在一个特权模式下,都可通过置位CPSR中的I 位来禁止IRQ。" U; J8 j. r" f
不管异常入口是来自ARM状态还是Thumb状态,FIQ处理程序都会通过执行下面的指令从中断返回:; D0 Q) C8 R3 s
SUBS PC,R14_fiq,#4
0 X0 O& C6 C2 q分析IRQ 和 FIQ异常中断处理的返回:
l' r2 Y0 A+ j2 t+ R2 q指令地址 对应于PC) S7 E0 B4 |3 @6 j6 g; V
A PC-8 执行此指令完成后(!)查询IRQ及FIQ,如果有中断请求则产生中断.
. e1 T) k4 Y9 ?5 ?( ?+ C Q& F! kA+4 PC-4
6 _% Q9 G3 \3 a; j! z0 MA+8 PC ;lr!
4 Q3 |/ A( V& I* K. J/ [ (此时PC的值已经更新,指向A+12.将当前PC-4(即A+8)* I, ~1 V! w0 b2 Y' @ U" a
保存到LR.返回时,要接着执行A+4(LR-4)处的指令,所以返回指令为' X4 l* r* N* g+ o D3 i( F+ `
SUBS PC, LR,#4(PC=A+4=LR-4)
/ L5 ^0 a& m2 t( g( g2 z白话解释:对于普中断和快中断异常:+ r, _ l3 Y9 i! z$ ?
中断必须在一条指令执行完以后被检测到,如正在执行指令甲时发生了中断,不等指令甲执行完是不
, t$ |# n" J; f4 S+ \0 X9 k& {; m会处理该中断的,发生异常时pc已经更新(A+12);0 i. b( M' h6 V8 C, b+ p) R
lr = pc – 4(这时处理器决定的,无法更改!)即A+8" e u' h2 m `. y H3 Q6 M
返回后,应执行被中断而没有执行的指令(上面的A+4),所以返回时,pc = lr-4: ]6 Y' C* |, W/ p0 C' {
(3)中止7 z' b# Q6 u* q) u' Q0 [. ?
中止发生在对存储器的访问不能完成时,中止包含两种类型:
4 S* U& M9 ^- o+ U) y- F* H8 C预取中止 : 发生在指令预取过程中
2 J, P8 U( N @2 X' [: ~ U1 _2 P数据中止 : 发生在对数据访问时
% H* F. d% Y. Z Y( H HA.预取中止5 ^' c+ g5 `. \4 [
当发生预取中止时,ARM核将预取的指令标记为无效,但在指令达到流水线的执行阶段时才进入异常。如果指令在流水线中因为发生分支而没有被执行,中止将不会发生。
, l* \" A7 Q- h- k! P! B5 m# U/ v在处理中止的原因之后,不管处于哪种处理器操作状态,处理程序都会执行下面的指令恢复PC和CPSR并重试被中止的指令:
/ P% C% A K& a6 _6 _! ]% a9 fSUBS PC,R14_abt,#4
+ g. s( V+ @7 ]. I3 K分析指令预取中止异常中断处理的返回:( ~5 z) M" M4 d) g4 a
指令地址
& L( _# t! t' P; N9 \0 DA PC-8 执行本指令时发生异常, 5 q* a# ^/ V$ E% E1 ~% S7 w, \# Q
A+4 PC-4 处理器将A+4(PC-4)保存到LR. ;lr!
3 n" R3 H9 W; e! i5 \0 z! o( ?& qA+8 PC
V+ G( f& Y6 j( F" ]返回时,发生指令预取中止的指令A(PC-8)处重新执行,所以返回指令为
* k, e* Y+ a7 }8 _& @SUBS PC, LR,#4(PC=A=LR-4) B) c9 |5 X. F0 E
白话解释:对于预取指令中止异常:
. z/ L6 ~# E O3 p 发生预取指令异常时,是在执行时发生的异常,pc未更新,即pc = A+82 V# X+ @/ N$ _* }
lr = pc – 4(这时处理器决定的,无法更改!)即A+4
: h# r" a& @6 h; w5 n 由于这类异常返回后应重新执行异常的那个指令(A),所以返回时,pc = lr-4
/ N( T, N& H& R4 L7 \B.数据中止$ A: G. x: L. c1 {
指令地址5 @ Z" O0 K8 O" h0 @3 p/ S2 ?; }
A PC-8 本指令访问有问题的数据,产生中断时,PC的值已经更新 0 l! b# C4 k3 }0 P
A+4 PC-4 中断发生时PC=A+12,处理器将A+8(PC-4)保存到LR.
, X3 A0 u" K( n5 v4 W) \6 zA+8 PC ;lr!7 S8 p5 R2 H" m3 }8 @- E R
返回时,要返回到A处继续执行,所以指令为SUBS PC, LR,#8.(PC=A=LR-8)5 P0 r* l2 ^8 n" i% L
白话解释:对于数据访问中止异常:
* W& m* I A' Y; n5 t; o 发生数据访问中止异常时,是在执行时访问数据错误导致的异常,pc已经更新,即pc = A+12
- w8 Z- Y b2 R9 E2 J4 }3 H2 t: A% \ lr = pc – 4(这时处理器决定的,无法更改!)即A+8& V. ^+ ` o/ @3 Z' e: ]7 M
由于这类异常返回后应重新执行异常的那个指令(A),所以返回时,pc = lr-8
7 ]% B' E: j) G; g) e(4)软件中断指令( m6 g% j' s- s x; v
所有的任务都是运行在用户模式下的,因此任务只能读CPSR而不能写SPSR。任务切换到特权模式下唯一的途径就是使用一个SWI指令调用,SWI指令强迫处理器从用户模式切换到SVC管理模式,并且IRQ自动关闭,所以软件中断方式常被用于系统调用。) c- i0 P# D# U9 f# z6 F
(5)未定义指令异常
0 Q9 ?1 x/ f. [(1)当ARM在对一条未定义指令进行译码时,发现这是一条自己和系统内任何协处理器都无法执行的指令时,就会发生未定义指令异常;
$ t% s( e+ L* M8 K" u(2)由于是在对未定义指令译码时发生异常,所以PC的值等于未定义指令的地址+4(即刚好为中断返回地址),因此R14保存的值是 中断返回地址 ,所以当异常要返回时可执行以下指令:
4 J9 ?* `: t v% c3 O( g- [: e" DMOVS PC,R14_und 0 U d. ~/ l. A c W( t* N
分析:SWI和和未定义指令异常中断的返回:7 a P$ E1 ?! `! n6 s
指令地址: D/ ]1 C- ^5 o; o; C" b m
A PC-8 当前指令为SWI或未定义指令 此时发生异常PC的值还没有更新.
/ h. _; q% D( u) Z1 H& B& k: O1 IA+4 PC-4 中断时处理器将PC-4保存到LR ;lr!9 f9 r( ?/ l3 C7 @4 n! d, e2 q3 q: P2 ]
A+8 PC $ n' {! @* o: p; c3 m8 Y
返回时,从发生中断的指令A(PC-8)的下一条指令A+4(PC-4)处开始执行,所以直接
- I2 b5 Y% S! G: m' x5 f9 v把LR的值赋给PC就行了,具体指令为MOVPC,LR (PC=A+4=LR). y3 i" p9 i( J$ A0 m- p/ x
白话解释:对于SWI和未定义指令异常:
& b+ }* k4 y+ l% ?+ d( x 发生异常时pc没有更新,根据ARM的三级流水线原理,pc没有更新,仍然等于(A+8);
9 P# t* v: @" A lr = pc – 4(这时处理器决定的,无法更改!)即A+4% ~4 v: }+ C" ]
由于这类异常返回后应执行下一条指令(A+4),所以返回时,pc = lr即可
* ~# x$ v. z! N. O" G6 Q最后我们来总结一下:; j& r( e8 F+ n3 Q8 q- ~+ Z& y
引起PC更新的原因一种是数据中止,还有就是中断了.
7 l; ^( c v1 m3 ^8 z! W' d5 z; ~ 中断必须是在一条指令执行完毕后才能被检测到,所以它中断的只是还未执行的那条指令(pc - 8),
) f+ R M1 y5 T所以pc = lr – 4;
, I5 i/ Z& W8 d) q3 W/ {0 |; X' V 与中断相同,SWI和未定义指令异常也是返回到下一条指令(pc - 4),只是他们在执行时,PC的值并没
% K- [6 {# n3 ?3 s) P- v: ~- B有更新,所以pc = lr;
: p" N& D( |' N& Z% ^( q 预取指令中止异常,也没有发生pc更新,但它还得重新执行发生异常的那条指令,所以pc = lr – 4;
5 j9 i( d0 Y+ o 数据访问中止异常,发生了pc更新,并且它也需要重新执行发生异常的那条指令,所以pc = lr – 8;3 Z6 u( {2 X S. @, W; ~' x
当多个异常同时发生时,一个固定的优先级系统决定它们被处理的顺序: ~+ E6 g, `0 O5 m0 @
______________________________________________________________________________________________________________________
! D/ H: q8 a! p! m! R二、SWI 实验5 [# I3 y$ G) Z# \% i& m
(1)swi指令
" `; x3 _8 X* H* u0 k) S9 b; W, V7 ?4 f( c1 c4 F' J4 p
2 o: V: B, F0 W* m9 ?- U% T
SWI指令用于产生软中断,从而实现在从户模式变换到管理模式,并且将CPSR保存到管理模式的SPSR中,然后程序跳转到SWI异常入口。在其它模式下也可使用SWI指令,处理器同样地切换到管理模式。8 r0 I2 r: X" G9 }; S2 \
该指令主要用于用户程序调用操作系统的系统服务,操作系统在SWI异常处理程序中进行相应的系统服务。/ `; D: w, b, O# \% K4 z9 J; b+ z
注意:6 e+ v: h3 H; q# I
ARM 内核不提供直接传递软中断(SWI)号到处理程序的机制:
4 Q( g: a* A- l" \" m1 ?# w1 z: cSWI 处理程序必须定位SWI 指令,并提取SWI指令中的常数域
$ n6 N+ M2 |6 e8 K为此, SWI 处理程序必须确定SWI 调用是在哪一种状态(ARM/Thumb).
3 s0 a, s) j! {) H' J) L+ t检查 SPSR 的 T-bit
4 X8 U* T% Q1 R& RSWI 指令在ARM 状态下在 LR-4 位置, Thumb 状态下在LR-2位置
3 o. i2 _& t' s# w" L1 U a: YSWI 指令按相应的格式译码:
# @! W- \$ j+ C1 c) S例如: c' h: H6 O) D$ B* s
4 L$ V. E& t0 ?2 p" B7 u& e y
SWI 13
& P: |% {9 v& O! ^$ a9 b) u, W8 W, i思考,当软中断产生后,怎么获取它的软中断号呢?) Y# s8 Y2 ? d% X! A# ?) r
实验的核心代码如下:
1 R" l ^8 `; M* n7 F: C; R
' V/ h: i0 Y& A' Esoftware_interrupt:# l/ `# i+ t& v8 E# i. y3 o: @3 A Z
@设置软中断所在模式的栈
0 D3 n6 Z" f% j; u# @7 V7 i) jldr sp,=0x34000
1 l; O3 h. |" t! Y+ I@保存用到的寄存器# E3 @1 j5 v& Y+ B% R
stmfd sp!,{r0-r2,lr}) f: z% ?3 q! M) v9 [5 D
@获取swi指令对应的机器码) l' s5 W8 s' S# V& N$ D
ldr r0,[lr,#-4]
8 v$ A' {7 ~% k' y@获取软中断号2 V. W' n# \' V
bic r0,r0,#0xff000000
4 ?- H% Z @1 G0 w1 V2 x@调用C处理函数,求累加和" C5 U V2 \* ^" d9 d
bl calc_sum
% y/ Y5 J) ^4 h- c5 G4 `& k/ Y@获得函数返回值,存放在r1
+ E3 P' \! r1 W: @mov r1,r0( G' c, q" U* y% D7 \' P; T8 E% @- w& I
@恢复现场,^表示目标寄存器是pc时,传递数据给pc,同时更新CPSR7 ]# i( t; y5 l& {+ w, r
ldmfd sp!,{r0-r2,pc}^
' ]% V7 r/ Y& w2 N0 H J! } |
|