arm对异常(中断)处理过程
1 初始化:
:: a 设置中断源,让它可以产生中断
:: b 设置中断控制器(可以屏蔽某个中断,优先级)
:: c 设置CPU总开关,(使能中断)
2 执行其他程序:正常程序
3 产生中断:按下按键--->中断控制器--->CPU
4 cpu每执行完一条指令都会检查有无中断/异常产生
5 发现有中断/异常产生,开始处理。对于不同的异常,跳去不同的地址执行程序。这地址上,只是一条跳转指令,跳去执行某个函数(地址),这个就是异常向量。如下就是异常向量表,对于不同的异常都有一条跳转指令。 (3-5都是硬件强制做的)
6 这些函数做什么事情?
:: 软件做的:
:: a 保存现场(各种寄存器)
:: b 处理异常(中断):
:::: 分辨中断源
:::: 再调用不同的处理函数
:: c 恢复现场
--------------------------------------异常向量表-------------------------------------
.globl _start _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 //发生中断时,CPU跳到这个地址执行该指令 **假设地址为0x18** ldr pc, _fiq //我们先在0x18这里放 ldr pc ,__irq,于是cpu最终会跳去执行__irq代码 //保护现场,调用处理函数,恢复现场
思考:为什么不用b指令实现中断的跳转?
软中断程序:
示例一:
.text @异常向量表 b reset @0x00 reset nop @0x04 udef b swi_handler @0x08 swi nop @0x0c prefetch abort 指令预取终止 nop @0x10 data abort 数据访问终止 nop @0x14 reserved 保留 nop @0x18 irq nop @0x1c fiq @nop 占空地址;0x00-1c为异常向量表所用,不可被其他语句所占 swi_handler: stmfd sp!,{r0,lr} @将r0,lr进栈,保护现场,sp为堆栈指针 mov r0,#6 ldmfd sp!,{r0,pc} @将原值出栈到r0,pc,恢复现场 reset: mov r0,#3 swi 2 mov r1,r0 b reset
执行压栈和出栈指令后报错
所以在压栈之前,要令堆栈指针sp重新指向一个空间
.text @异常向量表 b reset @0x00 reset nop @0x04 udef b swi_handler @0x08 swi nop @0x0c prefetch abort 指令预取终止 nop @0x10 data abort 数据访问终止 nop @0x14 reserved 保留 nop @0x18 irq nop @0x1c fiq @nop 占空地址;0x00-1c为异常向量表所用,不可被其他语句所占 swi_handler: stmfd sp!,{r0,lr} @将r0,lr进栈,保护现场,sp为堆栈指针 mov r0,#6 ldmfd sp!,{r0,pc} @将原值出栈到r0,pc,恢复现场 reset: ldr sp,=stack_base mov r0,#3 swi 2 mov r1,r0 b reset .data buf: .space 32 @定义内存空间,将空间末地址赋给sp stack_base: @开始压栈,sp递减,入栈sp递增,又会回到此位置 .end
软中断主要用于系统调用,用于从用户空间到内核空间的切换。user--->svc
@异常向量表 b reset @0x00 reset 指令机器码存放的地址空间大小有限制,可以如下单独构造4字节的空间存放 ldr pc,_udef @0x04 udef ldr pc,_swi @0x08 swi 不使用b而使用ldr跳转以突破32M空间限制 ldr pc,_prefetch @0x0c prefetch abort 指令预取终止 ldr pc,_data_abort @0x10 data abort 数据访问终止 nop @0x14 reserved 保留 ldr pc,_irq @0x18 irq ldr pc,_fiq @0x1c fiq @nop 占空地址;0x00-1c为异常向量表所用,不可被其他语句所占 _udef: .word udef_handler _swi: @此标号为地址 .word swi_handler @里面存放了一个数,此数存放了地址,通过ldr将函数地址赋给PC以实现跳转 _prefetch: .word prefetch_handler @未实现 _data_abort: .word data_abort_handler _irq: .word irq_handler _fiq: .word fiq_handler swi_handler: stmfd sp!,{r0,lr} @将r0,lr进栈,保护现场,sp为堆栈指针 sub r0,lr,#4 ldr r0,[r0] bic r0,#0xff000000 bl swi_num_handler ldmfd sp!,{r0,pc}^ @将原值出栈到r0,pc,恢复现场 swi_num_handler: @swith(num) @case 2: @ ..... @case 3: @ ..... reset: ldr sp,=stack_base @切换到应用程序空间 msr cpsr,#0x10 mov r0,#3 @ open read write ioctl ...通过系统调用访问内核数据 @ 2 4 6 7 软中断号 swi 2 @跳转到异常向量表的软中断入口 @保存返回的地址到LR @切换到SVC模式 mov r1,r0 b reset .data buf: .space 32 @定义内存空间,将空间末地址赋给sp stack_base: @开始压栈,sp递减,入栈sp递增,又会回到此位置 .end
来源:https://www.cnblogs.com/y4247464/p/12283480.html