CPU会自动识别产生的异常,并将当前的PC值定位到异常向量表的某一个位置,但是由于异常的产生是随机的,我们并不知道什么时间会出现在什么类型的异常,所以需要一个异常向量表(也有说是中断向量表),来完成对不同异常处理函数入口地址的映射。

中断也是异常的一种,中断有硬中断(由硬件产生的中断)和软中断(软件产生的中断)之分。ARM有七种不同的中断源,在中断向量表中对应的地址范围是0X00 ~ 0X1C,本章只介绍软中断。软中断执行由SWI指令产生,用于用户模式下的程序调用特权操作指令。

 

简单实现软中断

我们可以通过软件仿真来查看程序的执行过程,首先硬件复位后,PC指向0X00(异常向量表中的第一个位置),执行跳转rest函数,通过swi触发软中断,CPU帮我们将PC指向0X08这个地址,这里有是一个跳转指令,跳转到swi_hander函数。

所以,只要是异常产生,CPU就会帮我们把PC指针定位到异常向量表中某一个位置,这里实现地址的映射,指向什么函数入口,需要我们自己来实现。

	.text
	.global _start       
_start:
@异常向量表 0X00 - 0X1C
b rest			@0x00	系统复位后的函数入口 rest
nop 			@0x04
b swi_handler 	        @0x08 软中断函数地址入口
nop 			@0x012
nop 			@0x014
nop 			@0x018
nop 			@0x01c
		

swi_handler:
	stmfd sp!,{r0,lr}	@将r0 lr的值进行压栈保存       sp!表示将 sp栈顶指针自动偏移
	mov r0,#5
	ldmfd sp!,{r0,pc}	@栈中的值将分别出栈赋值给 r0,pc

rest:
	ldr sp,=stack_base    @将地址栈底地址装入sp
	mov r0,#3
	swi 2	@swi 触发软中断
	b rest

.data
	.space 32	@栈空间分配
stack_base:		@栈底指针


	.end
	
.global _start    声明全局变量_start,整个工程可见
@ 表示一个函数
swi_handler:
    @...
    @...
    

rest:     
    @...
    @...      
@我们使用栈来做现场的保存与恢复
stmfd sp!,{r0,lr}	@将r0 lr的值进行压栈保存    
@...
@...
ldmfd sp!,{r0,pc}	@栈中的值将分别出栈赋值给 r0,pc

 

 

软中断的进阶使用

做了一些改进

  1. 出栈时恢复现场,同时恢复工作模式
  2. 利用软中断号来实现不同的功能
  3. 解决 b指令的缺陷 -- 无法操作地址长度较大的函数地址

 

由于产生软中断会将工作模式成为SUV模式,如果想要中断结束后恢复之前的模式,需要在出栈ldm后面加上 ^ ; swi 2产生软中断,2是软中断号,存放在这条指令空间中。由于异常发生时,处理器会把当前PC的值保存到LR,所以我们通过LR中的值来拿到软中断号; 一个b指令空间只有4个字节,其中一部分还有存放操作码,一些地址长度比较大的函数就无法实现了,我们用LDR指令来实现跳转。

	.text
	.global _start
_start:

b rest					@0x00	系统复位后的函数入口 rest
nop 					@0x04
ldr pc,_swi_handler 	@0x08 软中断函数地址入口
nop 					@0x012
nop 					@0x014
nop 					@0x018
nop 					@0x01c
		
_swi_handler:
	.word swi_handler  @一个字的空间存放地址

do_swi:
	mov r3, #3
	mov r4,	#4
	mov pc,lr

swi_handler:
	stmfd sp!,{r0,lr}	@将r0 lr的值进行压栈保存
	
	sub r0,lr,#4			@取出软中断号,并且比较软中断号
	ldr r0,[r0]
	bic r0,#0xff000000		@清除高八位数据
	cmp r0,#2
	bleq do_swi				 @处理软中断
	
	ldmfd sp!,{r0,pc}^	@栈中的值将分别出栈赋值给 r0,pc   ^代表出栈恢复入栈时的模式(User)

rest:
	ldr sp,=stack_base		@Suv模式下
	
	mrs   r0,cpsr
	and   r0,r0,#0xFFFFFFE0
	orr   r0,r0,#0x10
	msr   cpsr,r0			@进入User模式
	
	mov r0,#3
	swi 2	@swi 触发软中断 中断号为 2
	b rest

.data
	.space 200	@栈空间分配
stack_base:		@栈底指针


	.end