嵌入式linux-ARM体系结构及接口技术,七种异常源,异常优先级,异常处理过程,软中断,软中断号获取,异常向量表的建立

文章目录

  • 1,七种异常源
  • 2,异常优先级
  • 3,异常处理过程
    • 3.1,当异常产生时, ARM core会自动完成下面的工作
    • 3.2,异常处理——我们需要完成的部分
      • 3.2.1,例---软中断
  • 4,软中断指令
    • 4.1,例
  • 5,异常向量表的跳转

1,七种异常源

地址偏移量 异常 异常模式 描述
0x00000000 复位 SVC 复位电平有效时,产生复位异常,程序跳转到复位处理程序处执行
0x00000004 未定义指令 Undefined 遇到不能处理的指令时,产生未定义指令异常
0x00000008 软件中断 SVC 执行SWI指令产生,用于用户模式下的程序调用特权操作指令(主要在系统调用时使用)
0x0000000c 预取指异常 Abort中止模式 处理器预取指令的地址不存在,或该地址不允许当前指令访问,产生指令预取中止异常
0x00000010 数据异常 Abort中止模式 处理器数据访问指令的地址不存在,或该地址不允许当前指令访问时 产生数据中止异常
0x00000014 - 未使用 未使用
0x00000018 IRQ IRQ 外部中断请求有效,且CPSR中的I位为0时,产生IRQ异常
0x0000001c FIQ FIQ 快速中断请求引脚有效,且CPSR中的F位为0时,产生FIQ异常

2,异常优先级

  1. 异常在当前指令执行完成之后才被响应
  2. 多个异常可以在同一时间产生
  3. 异常指定了优先级和固定的服务顺序:
    . Reset
    . Data Abort
    . FIQ
    . IRQ
    . Prefetch Abort
    . SWI
    . Undefined instruction

为什么FIQ的响应速度比IRQ快?

  1. FIQs有高于IRQs的优先级
  2. FIQ 向量位于异常向量表的最末. 异常处理程序可从异常量处连续执行
  3. FIQ 模式有5个额外的私有寄存器 (r8-r12) 中断处理必须保护其使用的非私有寄存器

3,异常处理过程

嵌入式linux-ARM体系结构及接口技术,七种异常源,异常优先级,异常处理过程,软中断,软中断号获取,异常向量表的建立_第1张图片

3.1,当异常产生时, ARM core会自动完成下面的工作

1、R14_< exception_mode >  = return link     //确定返回地址,并保存
2、SPSR_< exception_mode > = CPSR
3、修改CPSR相应的位
(1)CPSR[4:0] = exception mode number    //切换到相应异常的工作模式
(2)CPSR[5] = 0 ;                           //进入ARM状态
(3)If ==Reset or Fiq then            //只有在复位和FIQ模式下才会关闭FIQ中断
		CPSR[6] = 1 ;
	CPSR[7] = 1 ;                             //任何异常模式下都会关闭IRQ中断
4、PC = exception vector address        //PC跳到异常向量入口处

3.2,异常处理——我们需要完成的部分

  1. 建立异常向量表
_start:
	b reset
	ldr pc, _undefined_instruction
	ldr pc, _software_interrupt
	ldr pc, _prefetch_abort
	ldr pc, _data_abort
	ldr pc, _not_used
	ldr pc, _irq
	ldr pc, _fiq
_undefined_instruction:
	.long undefined_instruction
_software_interrupt:
	.long software_interrupt
_prefetch_abort:
	.long prefetch_abort
_data_abort:
	.long data_abort
_not_used:
	.long not_used
_irq:
	.long irq
_fiq:
	.long fiq
  1. 异常处理
进栈保存现场
处理异常
出栈恢复现场

3.2.1,例—软中断

	.text	@代码段
	
	@代码一开始先建立异常向量表,将异常处理的入口保护起来(nop表示一条空指令)
	b reset			@0x00	reset
	nop				@0x04 	undefine instruction
	b swi_handle	@0x08	software interrupt 
	nop				@0x0c	prefetch abort
	nop 			@0x10	data abort
	nop				@0x14	(reserved)
	nop				@0x18	irq
	nop				@0x1c	fiq

swi_handle:
	stmfd sp!,{r0,lr}	@进栈保护现场
	mov r0,#6
	ldmfd sp!,{r0,pc}	@出栈恢复现场

reset:
	ldr sp,=stack_base	@给栈顶指针一个合法的内存地址
	mov r0,#3
	swi 2				@程序会跳转到异常向量表中,软中断异常的入口处。
						@同时会把下一条指令的位置保存到lr中
	mov r0,#5
	b reset

	.data	@数据段
buf:
	.space 32
stack_base:	@堆栈进栈后,栈顶指针会递减,所以要在堆栈的位置之前申请一段空间

	.end	@程序结束

4,软中断指令

应用程序通过系统调用访问内核,系统调用要通过软中断来实现。不同的系统调用有不同的软中断号

嵌入式linux-ARM体系结构及接口技术,七种异常源,异常优先级,异常处理过程,软中断,软中断号获取,异常向量表的建立_第2张图片
软中断swi指令执行时,下一条指令地址会存放在lr寄存器中,可以通过

	sub r0,lr,#4	
	ldr r0,[r0]		

获取swi指令

4.1,例

.text	@代码段
	
	@代码一开始先建立异常向量表,将异常处理的入口保护起来(nop表示一条空指令)
	b reset			@0x00	reset
	nop				@0x04 	undefine instruction
	b swi_handle	@0x08	software interrupt
	nop				@0x0c	prefetch abort
	nop 			@0x10	data abort
	nop				@0x14	(reserved)
	nop				@0x18	irq
	nop				@0x1c	fiq

swi_handle:
	stmfd sp!,{r0,lr}	@进栈保护现场
	@获取软中断号
	sub r0,lr,#4		@获取软中断指令的地址
	ldr r0,[r0]			@将软中断指令从其地址中取出
	bic r0,#0xff000000	@只保留软中断号
	
	@软中断号处理
	cmp r0,#2
	moveq r1,#2
	cmp r0,#3
	beq swi_3_function
	
	mov r0,#5
	ldmfd sp!,{r0,pc}^	@出栈恢复现场。'^',表示内核会自动把spsr恢复到cpsr
	
swi_3_function:
	mov r1,#3
	mov pc,lr
swi_3_function_end:

reset:
	ldr sp,=stack_base	@给栈顶指针一个合法的内存地址
	
	@切换到普通用户工作模式下
	mrs r0,cpsr
	ldr r1,=0xffffffe0
	and r0,r0,r1
	orr r0,#0x10
	msr cpsr,r0
	
	mov r0,#2
	swi 2				@程序会跳转到异常向量表中,软中断异常的入口处。
						@同时会把下一条指令的位置保存到lr中
						@同时会切换到svc工作模式下
						
	mov r0,#3
	swi 3
	
	mov r0,#4
	b reset


	.data	@数据段
buf:
	.space 32
stack_base:	@堆栈进栈后,栈顶指针会递减,所以要在堆栈的位置之前申请一段空间

	.end	@程序结束

5,异常向量表的跳转

通过b指令跳转的话会出现如下问题:
若要跳转的地址过大,则b指令会转不下,编译就会出错
所以要进行优化,通过ldr指令来实现

	@代码一开始先建立异常向量表,将异常处理的入口保护起来(nop表示一条空指令)
	b reset			@0x00	reset
	nop				@0x04 	undefine instruction
	b swi_handle	@0x08	software interrupt
	nop				@0x0c	prefetch abort
	nop 			@0x10	data abort
	nop				@0x14	(reserved)
	nop				@0x18	irq
	nop				@0x1c	fiq

swi_handle:
	stmfd sp!,{r0,lr}	@进栈保护现场
	mov r0,#5
	ldmfd sp!,{r0,pc}^	@出栈恢复现场。'^',表示内核会自动把spsr恢复到cpsr
	@代码一开始先建立异常向量表,将异常处理的入口保护起来(nop表示一条空指令)
	b reset							@0x00	reset
	ldr pc,_undefine_instruction	@0x04 	undefine instruction
	ldr pc,_software_interrupt		@0x08	software interrupt
	ldr pc,_prefetch_abort			@0x0c	prefetch abort
	ldr pc,_data_abort 				@0x10	data abort
	ldr pc,_not_use					@0x14	(reserved)
	ldr pc,_irq						@0x18	irq
	ldr pc,_fiq						@0x1c	fiq

_undefine_instruction:
	.word _undefine_instruction
_software_interrupt:
	.word swi_handle
_prefetch_abort:
	.word _prefetch_abort
_data_abort:
	.word _data_abort
_not_use:
	.word _not_use
_irq:
	.word _irq
_fiq:
	.word _fiq

swi_handle:
	stmfd sp!,{r0,lr}	@进栈保护现场
	mov r0,#5
	ldmfd sp!,{r0,pc}^	@出栈恢复现场。'^',表示内核会自动把spsr恢复到cpsr

你可能感兴趣的:(嵌入式linux-ARM体系结构及接口技术,七种异常源,异常优先级,异常处理过程,软中断,软中断号获取,异常向量表的建立)