EDA365电子论坛网
标题:
ARM异常处理
[打印本页]
作者:
finishedabc
时间:
2020-5-6 10:29
标题:
ARM异常处理
ARM异常处理:
& N# d7 S1 [, s3 ~
只要正常的程序流被暂时中止,处理器就进入异常模式。例如响应一个来自外设的中断。在处理异常之前,ARM内核保存当前的处理器状态,这样当处理程序结束是可以恢复执行原来的程序。
3 [; k+ s2 l4 T# D
注意:如果同时发生两个或更多异常,那么将按照固定的顺序来处理异常 。
! T8 ]: S4 t) D7 d2 F( V/ z1 n
ARM支持的异常种类:
: Z. T. _+ Y3 V- F# L3 a
一、异常的进入与退出
+ M9 b3 A. i: N
当一种异常发生时,硬件就会自动执行如下动作:
' j1 P& h- u% Q+ D! Z
(1)将CPSR保存到相应异常模式下的SPSR中
1 \- C( F/ c; X6 y% C; b
(2)把PC寄存器保存到相应异常模式下的LR中
5 K1 n2 F2 i4 a5 I
(3)将CPSR设置成相应的异常模式
6 ]: P+ s$ M* ~8 N! N- Y, D
(4)设置PC寄存器的值为相应处理程序的入口地址
3 t) \1 ^4 s% w
可以总结如下:
0 {1 ^5 l0 v2 v H" ^8 H. P
在这里我们需要重点研究的是,异常产生后,最后PC会指到哪里去呢?这个事情实际不需要我们操心,ARM核在设计的时候就已经确定好了,也就是经常我们所说的异常向量表。异常向量表:
8 ~7 ]0 y4 @- w; T' }% x
在ARM7,ARM9/10等处理器,异常向量表可以存放在以 0x00000000或0xffff00000其始的地址。默认是以零地址开始存放的。可能有些同学还是有些晕,我们来举个例子说明一下。
! Q4 n; X# @6 e! Z
例如:ARM处理器正在执行指令,此时外部硬件产生了一个中断。此时将产生IRQ异常,然后ARM核就会自动完成我们上面说的4步。完成前3步后,ARM核会强制将pc的值修改为0x18。修改完成后,处理器就开始从0x18这个地址取指令执行。
7 J; i5 Q% R" t* {) ]
从上图可以知道,不同的异常产生时,ARM核修改的PC值不一样。例如:如果是swi指令引起的异常,ARM核最后就会修改pc的值为0x08。
% F3 V5 X8 i. g8 m1 I' R) V
是不是异常向量表,一定要放在0x00000000或0xffff00000其始的地址呢?答案:不是,现在cortex-A系列的处理器可以将异常向量表放在任何位置,拿ARM核收到异常后,它怎么知道应该将pc的值修改为多少呢?这就需要我们通过协处理指令告诉它了。
5 ~. ^9 D+ ]6 m
例如:在cortex-A8上,我们可以操作如下协处理指令,来告诉ARM核异常向量表的位置。
$ g! e- h) B1 u# `- a
cortex-A8官方手册:3.2.68节有详细说明
! g9 o( |% S8 h, r1 y+ p* G, z
如将告诉ARM核,异常向量表存放在0x20008000
, p% T+ ]- b" b) O. l/ `1 E
ldr r0,=0x20008000
+ X! B$ B p- ?% {' \
mcr p15,0,r0,c12,c0,0
! Z ^! f! f' F0 n+ {; j
好了,到这里大家已经知道了异常是什么,当异常产生的时候,ARM核都会自动做那些事情。当然,当异常产生的时候,我们应该对异常做出处理,处理完之后,要返回异常产生之前的场景继续运行。就像,有些时候,我们在做事情的时候,生病了,我们就需要到医生那里去治疗一下,等治疗完成之后,就必须把生病前的事情接着后面干。
% z& s" R" m4 Z3 \
有些人,肯定忍不住了,我知道了异常,也知道异常产生后,pc会指向异常向量表,那异常向量表中,到底放什么东西呀,我该怎么处理我的异常呢?
* S- N6 B. o* Y
首先,回答第一个问题,异常向量表中存放的就是去医生的火箭。坐上火箭就可以到医生哪了,这叫一个字"快"。医生,火箭.....
/ t8 _5 ]! O/ f0 |! P5 w8 H& m/ _. O
呵呵,别折磨大家了,我们公布答案吧!看下面
" E" P; d; N4 f$ T7 n( c0 ~8 _8 X9 d
从上面我们可以知道,异常向量表里面存放的都是跳转指令。有些时直接通过b指令实现的,有些时通过修改pc值实现的。这也就是刚刚我说到的"火箭"。跳转的目的是跳到一个地方对异常进行处理。也就是我说到的到医生那里去"治疗"。
2 _/ }# m& e$ H! H" V
我们以irq异常为例子,来说明我们需要干的事情
) H9 q/ B% m1 { P4 U! J
irq :
' U' w9 \: i' N# O: }% o
SUB LR,LR,#4 ;计算返回地址
, l T) ~ m4 Z4 {
STMFD SP!,{R0-R3,LR} ;保存使用到的寄存器
/ X w+ {- ^2 E9 J, p
干里你想干的事情
9 g# K b1 o: D. H5 M
.....
* x0 v2 @$ |! J/ t+ m
LDMFD SP!,{R0-R3,PC}^ ;中断返回
0 t- \- J; Y- W
注意:当异常结束时,异常处理程序必须:
' p$ U3 ^9 x/ [! X. l; S& }
1.将LR中的值减去偏移量后存入PC,偏移量根据异常的类型而有所不同;
9 |% f: Z$ [$ Y. P6 w9 Q
2.将SPSR的值复制回CPSR;
4 g: e7 l" K7 m5 x
3.清零中断禁止标志。
n, N+ `9 L7 u. g! a6 V
注:恢复CPSR的动作会将T、F和I位自动恢复为异常发生前的值。
; R4 ?7 h5 x q8 k2 m: Z1 d
0 Y1 D- @: f$ K: W
# \: x$ D! u* J
哎,终于说完了异常。下面我们用一句话总结一下:异常产生需要保存现场(ARM核已经自动为我们做了),异常返回的时候需要恢复现场(需要程序员自动完成)。
$ Y0 {' c# e$ D; J
__________________________________________________________________________________________________________
2 ?. Z- Y; t0 |
下面我们来详细说明异常产生的原因,以及异常返回时,异常模式的lr应该保存的值是多少。最后我们会以软中断实验,来给大家强化对异常的理解。
* S+ l, ~0 Y( k' Z
重要基础知识:R15(PC)总是指向“正在取指”的指令,而不是指向“正在执行”的指令或正在“译码”的指令。一般来说,人们习惯性约定将“正在执行的指令作为参考点”,称之为当前第一条指令,因此PC总是指向第三条指令。当ARM状态时,每条指令为4字节长,所以PC始终指向该指令地址加8字节的地址,即:PC值=当前程序执行位置+8;
1 r/ }6 K4 \: |) o3 o
注意:不管是几级流水线都统一按照三级流水线来分析,这一点已经向ARM官方求证过。
|) X7 c+ k- k5 j, C
(1)快速中断异常
: I5 B6 E6 X. w; [% X4 l
快速中断请求(FIQ)适用于对一个突发事件的响应,这得益于在ARM状态中,快速中断模式有8个专用的寄存器可用来满足寄存器保护的需要(这可以加速上下文切换的速度)。
8 A- J% E( e5 R9 R: N- L
不管异常入口是来自ARM状态还是Thumb状态,FIQ处理程序都会通过下面的指令从中断返回:
5 ]% U4 R0 |) k3 b( H
SUBS pc,R14_fiq,#4
* F% W0 N+ j/ u5 c
在一个特权模式中,可以通过置位CPSR中的F位来禁止FIQ异常。
; e. u; ^; R2 [, i" m
(2)中断请求异常
' k0 W7 V( s1 q2 L
中断请求(IRQ)异常是一个由nIRQ输入端的低电平所产生的正常中断(在具体的芯片中,nIRQ由片内外设拉低,nIRQ是内核的一个信号,对用户不可见)。IRQ的优先级低于FIQ。对于FIQ序列它是被屏蔽的。任何时候在一个特权模式下,都可通过置位CPSR中的I 位来禁止IRQ。
! B- i1 _3 {2 T7 ~ q
不管异常入口是来自ARM状态还是Thumb状态,FIQ处理程序都会通过执行下面的指令从中断返回:
+ ^8 T* q" Z; D$ q9 @ u
SUBS PC,R14_fiq,#4
; [3 W1 e& a4 V. ^
分析IRQ 和 FIQ异常中断处理的返回:
5 O: [; l; _. ^
指令地址 对应于PC
0 x* L/ P% |. o( J$ V" y
A PC-8 执行此指令完成后(!)查询IRQ及FIQ,如果有中断请求则产生中断.
# c j1 g+ K& k0 `: `: D9 ~
A+4 PC-4
8 p$ k- z: D) g4 s @4 D
A+8 PC ;lr!
* q7 l% A6 ^; B1 N& J' w+ N' a
(此时PC的值已经更新,指向A+12.将当前PC-4(即A+8)
7 v( q/ N4 R& ^ _) ~
保存到LR.返回时,要接着执行A+4(LR-4)处的指令,所以返回指令为
( @+ Y7 K5 F5 C0 o
SUBS PC, LR,#4(PC=A+4=LR-4)
$ G) S5 Y; l- s9 y/ l
白话解释:对于普中断和快中断异常:
* `/ Q- U. A: k! Q) L
中断必须在一条指令执行完以后被检测到,如正在执行指令甲时发生了中断,不等指令甲执行完是不
7 w: F- l; S5 R/ g# M, ?' F) T
会处理该中断的,发生异常时pc已经更新(A+12);
$ {9 i {7 ^& P
lr = pc – 4(这时处理器决定的,无法更改!)即A+8
0 {- a. q' s% b
返回后,应执行被中断而没有执行的指令(上面的A+4),所以返回时,pc = lr-4
% e! M' `! w: P
(3)中止
; U8 A( X8 I6 p% @
中止发生在对存储器的访问不能完成时,中止包含两种类型:
/ H( x& o" C D _5 G4 p; \; }1 e
预取中止 : 发生在指令预取过程中
- l, V$ j/ W7 w/ E0 [/ A" f
数据中止 : 发生在对数据访问时
: F2 N0 u, T% i
A.预取中止
4 V* _6 F+ @" X, i) N) r& Z- V+ {% F
当发生预取中止时,ARM核将预取的指令标记为无效,但在指令达到流水线的执行阶段时才进入异常。如果指令在流水线中因为发生分支而没有被执行,中止将不会发生。
1 M, v3 m1 O* m h6 x/ S7 Q0 N2 k
在处理中止的原因之后,不管处于哪种处理器操作状态,处理程序都会执行下面的指令恢复PC和CPSR并重试被中止的指令:
8 _5 y) [4 k! x2 \" r5 z
SUBS PC,R14_abt,#4
$ M O: y- X0 q* W& ~0 w, |
分析指令预取中止异常中断处理的返回:
1 A6 t, L8 p w' i8 w9 q$ A$ m
指令地址
1 y" j$ [$ U' I+ N' Y4 r
A PC-8 执行本指令时发生异常,
y7 Y5 T) v! G& r- a5 `
A+4 PC-4 处理器将A+4(PC-4)保存到LR. ;lr!
$ l% ` C: V; g- [, X
A+8 PC
/ {( }4 d9 f/ ^4 |
返回时,发生指令预取中止的指令A(PC-8)处重新执行,所以返回指令为
! \) I) W i5 K3 x
SUBS PC, LR,#4(PC=A=LR-4)
% F0 \0 h8 v! R2 k3 H9 c
白话解释:对于预取指令中止异常:
a# }4 t$ a, b8 i" O1 ~) D7 f
发生预取指令异常时,是在执行时发生的异常,pc未更新,即pc = A+8
- v7 l7 u! R8 b" j. q, ^
lr = pc – 4(这时处理器决定的,无法更改!)即A+4
, J, |$ Q) e3 a" s ~/ ?6 I( O
由于这类异常返回后应重新执行异常的那个指令(A),所以返回时,pc = lr-4
( z7 ]$ B& w, A5 E. ^
B.数据中止
b; ]- ]0 Q+ x0 i- p# G6 I
指令地址
5 ~ Y6 I3 H$ A- K# Z0 k
A PC-8 本指令访问有问题的数据,产生中断时,PC的值已经更新
" \. x' V& l! L- ^% F: m, c
A+4 PC-4 中断发生时PC=A+12,处理器将A+8(PC-4)保存到LR.
% U1 g" D. r8 i' U: ^8 v6 f" b' _
A+8 PC ;lr!
) m0 [9 ]! O9 @. r* N0 e% c7 Y
返回时,要返回到A处继续执行,所以指令为SUBS PC, LR,#8.(PC=A=LR-8)
2 t1 A) p7 A# R
白话解释:对于数据访问中止异常:
7 Y% j$ A$ n( c7 K
发生数据访问中止异常时,是在执行时访问数据错误导致的异常,pc已经更新,即pc = A+12
$ e8 ~2 z A H# Y! }: V
lr = pc – 4(这时处理器决定的,无法更改!)即A+8
" ~. ^% F; C5 I0 X5 B
由于这类异常返回后应重新执行异常的那个指令(A),所以返回时,pc = lr-8
; y* _3 V3 [8 e! i+ Y4 ~
(4)软件中断指令
4 m d2 y7 D- ]
所有的任务都是运行在用户模式下的,因此任务只能读CPSR而不能写SPSR。任务切换到特权模式下唯一的途径就是使用一个SWI指令调用,SWI指令强迫处理器从用户模式切换到SVC管理模式,并且IRQ自动关闭,所以软件中断方式常被用于系统调用。
~7 F& ~" y4 h* p9 Q( ~
(5)未定义指令异常
* s/ c$ c$ K1 x3 a" L2 i1 c- _2 N
(1)当ARM在对一条未定义指令进行译码时,发现这是一条自己和系统内任何协处理器都无法执行的指令时,就会发生未定义指令异常;
3 F; ~ R# f: r9 j; @
(2)由于是在对未定义指令译码时发生异常,所以PC的值等于未定义指令的地址+4(即刚好为中断返回地址),因此R14保存的值是 中断返回地址 ,所以当异常要返回时可执行以下指令:
7 B: K5 L& ^: F, Z; R
MOVS PC,R14_und
1 ~* R% n3 R* A, V0 o
分析:SWI和和未定义指令异常中断的返回:
* `9 H$ I7 B. E% N3 [" |# I; @
指令地址
4 G0 B3 x1 o$ C5 ?( G( [
A PC-8 当前指令为SWI或未定义指令 此时发生异常PC的值还没有更新.
6 d; d/ F# e, t+ A* F" R/ y
A+4 PC-4 中断时处理器将PC-4保存到LR ;lr!
5 B1 }5 p y: @. {* U
A+8 PC
5 U; t4 \; {9 [* Q, U1 G' E
返回时,从发生中断的指令A(PC-8)的下一条指令A+4(PC-4)处开始执行,所以直接
- |. z+ B7 u5 `) U, ^
把LR的值赋给PC就行了,具体指令为MOVPC,LR (PC=A+4=LR)
/ m- t1 h3 {/ H! o N0 @
白话解释:对于SWI和未定义指令异常:
! ?7 K, L3 V8 N
发生异常时pc没有更新,根据ARM的三级流水线原理,pc没有更新,仍然等于(A+8);
. j7 Y+ w0 N; @; _
lr = pc – 4(这时处理器决定的,无法更改!)即A+4
, M8 o1 o4 e- C3 @4 g- [! N
由于这类异常返回后应执行下一条指令(A+4),所以返回时,pc = lr即可
. @; E/ L( M0 p+ }+ b' G0 B- L% `9 o* d
最后我们来总结一下:
4 q% j0 r6 o. U5 K& q0 `
引起PC更新的原因一种是数据中止,还有就是中断了.
7 y A$ j' f, r
中断必须是在一条指令执行完毕后才能被检测到,所以它中断的只是还未执行的那条指令(pc - 8),
* s( `3 |) v" L
所以pc = lr – 4;
2 a3 W1 V3 a6 E9 h5 O& d, v! e
与中断相同,SWI和未定义指令异常也是返回到下一条指令(pc - 4),只是他们在执行时,PC的值并没
: [" k: n; G) X4 x
有更新,所以pc = lr;
/ U1 m; G* W' y9 q$ l
预取指令中止异常,也没有发生pc更新,但它还得重新执行发生异常的那条指令,所以pc = lr – 4;
: k$ E( x& X2 f; l& D6 T) \
数据访问中止异常,发生了pc更新,并且它也需要重新执行发生异常的那条指令,所以pc = lr – 8;
; _$ D+ M. W3 n; E+ D, W6 Z
当多个异常同时发生时,一个固定的优先级系统决定它们被处理的顺序:
% x6 ~7 B( c9 v- w& ^
______________________________________________________________________________________________________________________
1 n O5 {! R# v! o. z$ h9 _
二、SWI 实验
* ]! W# \; [% ~1 J
(1)swi指令
4 s0 x/ S1 i9 A0 K/ n) ]
# f& Z. v& l! u5 {3 l+ K
6 w/ L+ B1 h7 c5 w; `+ ?
SWI指令用于产生软中断,从而实现在从户模式变换到管理模式,并且将CPSR保存到管理模式的SPSR中,然后程序跳转到SWI异常入口。在其它模式下也可使用SWI指令,处理器同样地切换到管理模式。
( _* b% V8 C n7 |
该指令主要用于用户程序调用操作系统的系统服务,操作系统在SWI异常处理程序中进行相应的系统服务。
! _7 ~$ h$ K1 h6 o: q
注意:
$ e! u# R$ s( U3 L" g( ?
ARM 内核不提供直接传递软中断(SWI)号到处理程序的机制:
" G. j4 G7 W2 K, C. z" v2 E& s; V- X
SWI 处理程序必须定位SWI 指令,并提取SWI指令中的常数域
/ T) @( R) A6 S6 i" w
为此, SWI 处理程序必须确定SWI 调用是在哪一种状态(ARM/Thumb).
. h& ~3 l( t X1 T
检查 SPSR 的 T-bit
0 q& D& v" ]3 q, P& u3 }
SWI 指令在ARM 状态下在 LR-4 位置, Thumb 状态下在LR-2位置
6 q( _! h. ~$ r5 l
SWI 指令按相应的格式译码:
& \% }7 K, ~4 s8 J2 m
例如:
$ K* A5 H" ]5 E3 v
" ^; j( |( F% w' f# F& r
SWI 13
& K" N7 a2 m: W+ @! R4 w
思考,当软中断产生后,怎么获取它的软中断号呢?
; }) W0 p$ L& O
实验的核心代码如下:
, ^( v( v$ }. Y% Q K: X: w
6 Z5 k+ r+ K; Q/ X: l, M
software_interrupt:
8 Z6 e, \. u: c: a+ ~
@设置软中断所在模式的栈
' q4 X3 a5 h* _! g' a5 x
ldr sp,=0x34000
0 ?: {, |' F- N1 D
@保存用到的寄存器
! C2 W+ T: I- S1 L: ~, c P
stmfd sp!,{r0-r2,lr}
/ b# y, C! `* \. F7 i8 M
@获取swi指令对应的机器码
% o' e2 v( g- ?# f( m' {
ldr r0,[lr,#-4]
- W0 p8 @! ^. |6 `
@获取软中断号
! D. z4 R4 B) b
bic r0,r0,#0xff000000
5 s: z) i! P: C2 F0 ?
@调用C处理函数,求累加和
- J" f0 F6 {$ ?7 W
bl calc_sum
: N+ K3 }4 s0 O8 [
@获得函数返回值,存放在r1
* |6 z$ o5 H# F+ r- A
mov r1,r0
4 }5 T0 b3 w( I
@恢复现场,^表示目标寄存器是pc时,传递数据给pc,同时更新CPSR
$ y B$ ?4 P0 v1 D! x; s
ldmfd sp!,{r0-r2,pc}^
$ P/ q9 h6 z7 w' |0 f$ d+ l$ v
作者:
tutututut
时间:
2020-5-6 13:44
ARM异常处理,描述的很详细
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2