ARM异常处理模式
ARM有七种异常中断类型,优先级、工作模式(有七种工作模式)、地址、功能都不一样。如其中软件中断SWI优先级为6,工作模式管理模式,异常向量地址为0x00000008,功能是用户定义的中断指令,可用于用户模式下的程序调用特权操作。

当中断产生后,除了复位中断立即中止当前指令外,其余情况都是处理器完成当前指令后,才去执行异常处理程序。
-
将CPSR的值保存到将要执行的异常中断对应的各自SPSR中,以实现对处理器当前状态、中断屏蔽及各标志位的保护。
-
设置当前状态寄存器CPSR的相应位。设置CPSR中的M4~M0的5位,进入相应工作模式,设置I=1禁止IRQ中断,如果进入复位模式或FIQ模式,还要设置F=1以禁止FIQ中断。
-
将引起异常指令的下一条地址(断点地址)保存到新异常工作模式的LR(R14)中,使异常处理程序执行完后正确返回原来程序处继续向下执行。
-
给程序计数器PC强制赋值,转入向量地址,以便执行相应的处理程序。
每种中断异常模式对应两个寄存器SP和LR。
从中断返回。如果是复位异常,系统自动从0x00000000开始重新执行程序,无需返回。
-
首先恢复原来被保护的用户寄存器。
-
将SPSR寄存器复制到CPSR中,使得原来CPSR状态从相应的SOSR中恢复,一恢复被中断的程序状态。
-
根据异常类型将PC值恢复成断点地址,以继续执行用户原来运行着的程序。
-
清除CPSR中的中断禁止标志I和F,开放外部中断和快速中断。
注意:(1)程序状态寄存器及断点地址的恢复必须同时进行。
(2)由于异常随机发生,所以要对异常向量进行初始化,即在异常向量的地址处放置一条跳转指令,跳转到异常处理程序。
前面我们学习ARM工作模式中,处理器模式切换可以通过软件控制进行切换,即修改CPSR模式位,但这是在特权模式(SVC)下,一旦继续往下运行即当我们处于用户模式下,是没有权限实现模式转换的。若想实现模式切换,只能由另一种方法来实现,即通过外部中断或是异常处理过程进行切换。于是ARM指令集中提供了两条产生异常的指令,通过这两条指令可以用软件的方法实现异常,其中一个就是中断指令SWI 。
一、软件中断
软中断是利用硬件中断的概念,用软件方式进行模拟,实现从用户模式切换到特权模式并执行特权程序的机制。
硬件中断是由电平的物理特性决定,在电平变化时引发中断操作,而软中断是通过一条具体指令SWI,引发中断操作,也就是说用户程序里可以通过写入SWI指令来切换到特权模式,当CPU执行到SWI指令时会从用户模式切换到管理模式下,执行软件中断处理。由于SWI指令由操作系统提供的API封装起来,并且软件中断处理程序也是操作系统编写者提前写好的,因此用户程序调用API时就是将操作权限交给了操作系统,所以用户程序还是不能随意访问硬件。
软件中断指令(Software Interrupt, SWI)用于产生软中断,实现从用户模式变换到管理模式,CPSR保存到管理模式的SPSR中,执行转移到SWI向量。在其他模式下也可以使用SWI指令,处理器同样切换到管理模式。
SWI指令格式如下:
SWI{cond} immed_24
其中:immed_24 24位立即数,值为从0――16777215之间的整数。
SWI指令后面的24立即数是干什么用的呢?用户程序通过SWI指令切换到特权模式,进入软中断处理程序,但是软中断处理程序不知道用户程序到底想要做什么?SWI指令后面的24位用来做用户程序和软中断处理程序之间的接头暗号。通过该软中断立即数来区分用户不同操作,执行不同内核函数。如果用户程序调用系统调用时传递参数,根据ATPCSC语言与汇编混合编程规则将参数放入R0~R4即可。通俗一点说就是我软件中断然后我干些什么,就是通过后面的24位立即数来判断,因为软中断我可以写很多个处理程序,最后到底是哪一个中断发生就是通过SWI后面的立即数来切换到相应的处理程序中。下面将如何判断这个立即数做详述。

二、软中断处理
CPU执行到swi xxx执行后,产生软件中断,由异常处理部分知识可知,软中断产生后CPU将强制将PC的值置为异常向量表地址0x08,在异常向量表0x08处安放跳转指令b HandleSWI,这样CPU就跳往我们自己定义的HandleSWI处执行。地址分配从0x00开始。
.text
b reset @0x00 reset
ldr pc,_udef @0x04 udef
ldr pc,_swi_handler @0x08 swi 软中断程序的入口 突破32M空间的限制
ldr pc,_prefech @0x0c prefetch abort
ldr pc,_data_abort @0x10 data abort
nop @0x14 reserved
ldr pc,_irq @0x18 irq
ldr pc,_fiq @0x1c fiq
_udef:
.word _udef
_swi_handler:
.word swi_handler
_prefech:
.word _prefech
_data_abort:
.word _data_abort
_irq:
.word _irq
_fiq:
.word _fiq
swi_handler: @ 0xffff00ff
stmfd sp!,{r0,lr} @进栈保护现场
sub r0,lr,#4
ldr r0,[r0]
bic r0,#0xff000000
bl fun
ldmfd sp!,{r0,pc}^ @出栈恢复现场
fun:
cmp r0,#6 //中断号为6
~~//处理函数
mov pc,lr
reset:
ldr sp,=stack_base @切换到应用程序
msr cpsr,#0x10
mov r0,#3 @保护现场测试
swi 6 @跳转到异常向量表中软中断的入口位置
@保存返回地址到LR
@切换到SVC工作模式
mov r1,r0
b reset
.data
buf:
.space 32
stack_base:
.end
1–保护现场
软中断处理中通过STMFD SP!, {R0, LR} 要保存程序执行现场,将R0通用寄存器数据保存在管理模式下SP栈内,LR由硬件自动保存软中断指令下一条指令的地址(后面利用LR的地址取得SWI指令编码),该寄存器值也保存在SP栈内,将来处理完毕之后返回;
2–获取SWI指令编码
由SWI指令编码知识可知,SWI指令低24位保存有软中断号,通过LDR R0, [LR, #-4]指令,取得SWI指令编码(LR为硬件自动保存SWI xxx指令的下一条指令地址,LR – 4就是SWI指令地址),将其保存在R0寄存器中。通过BIC R0, R0, #0xFF000000 指令将SWI指令高8位清除掉,只保留低24位立即数,取得SWI指令编码;
3–根据SWI指令做出相应操作
根据24位立即数中的软中断号判断用户程序的请求操作。代码中SWI编码为6,则判断R0 中是不是6 在处理相应的程序,根据ATPCS调用规则,R0~R3做为参数传递寄存器,在软中断处理中没有使用这4个寄存器,而是使用R0作为操作寄存器的。
4–返回并恢复现场
执行完系统调用操作之后,将进入软中断处理时保存的返回地址LR的值恢复给PC,实现程序返回,再利用ldmfd sp!,{r0,pc}^ 指令同时还恢复了状态寄存器。切换回用户模式下程序中继续执行。
其实讲到这,会产生一个疑问,什么时候需要我们从用户模式切换到管理模式?我们应该记得系统调用,就是用户态向内核态的切换。
三、系统调用
操作系统的主要功能是为应用程序的运行创建良好的环境,保障每个程序都可以最大化利用硬件资源,防止非法程序破坏其它应用程序执行环境,为了达到这个目的,操作系统会将硬件的操作权限交给内核来管理,用户程序不能随意使用硬件,使用硬件(对硬件寄存器进行读写)时要先向操作系统发出请求,操作系统内核帮助用户程序实现其操作,也就是说用户程序不会直接操作硬件,而是提供给用户程序一些具备预定功能的内核函数,通过一组称为系统调用的(system call)的接口呈现给用户,系统调用把应用程序的请求传给内核,调用相应的内核函数完成所需的处理,将处理结果返回给应用程序。 这好比我们去银行取款,用户自己的银行帐户不可能随意操作,必须要有一个安全的操作流程和规范,银行里的布局通常被分成两部分,中间用透明玻璃分隔开,只留一个小窗口,面向用户的是用户服务区,工作人员所在区域为内部业务操作区,取款时,将银行卡或存折通过小窗口交给业务员,并且告诉他要取多少钱,具体取钱的操作你是不会直接接触的,业务员会将银行帐户里减掉取款金额,将现金给你。上述操作流程可以很好保护银行系统,银行系统的操作全部由业务员来实现,用户只能向业务员提出自己的服务请求。银行里的小窗口就类似与操作系统的系统调用接口,是将用户请求传递给内核的接口。
操作系统里将用户程序运行在用户模式下,并且为其分配可以使用内存空间,其它内存空间不能访问,内核态运行在特权模式下,对系统所有硬件进行统一管理和控制。从前面所学知识可以了解到,用户模式下没有权限进行模式切换,这也就意味着用户程序不可能直接通过切换模式去访问硬件寄存器,如果用户程序试图访问没有权限的硬件,会产生异常。这样用户程序被限制起来,如果用户程序想要使用硬件时怎么办呢?用户程序使用硬件时,必须调用操作系统提供的API接口才可以,而操作系统API接口通过软件中断方式切换到管理模式下,实现从用户模式下进入特权模式。