异常的介绍
概念
异常会导致处理器暂停程序执行以处理事件,例如外部生成的中断或试图执行未定义的指令。异常可以由内部和外部源生成,通常,当出现异常时,处理器状态会在处理异常之前立即保存。这意味着,当事件被处理后,可以从发生异常的地方恢复原始状态并恢复程序执行。
可能会同时生成多个异常,并且在处理器处理异常时可能会生成一个新的异常(异常也可以嵌套)
下图为ARM所用工作模式的介绍
他的中断又分为以下这些
我们4412的板子的异常向量表在0XFFFF 0000这个位置,所以我们首先要开启MMU,才可以去访问这个异常向量表,这时候我们就需要用到汇编来定义
.align 2
.text
.global _start
_start: //全局向量表
b reset @0x0
ldr pc, _Undefined_Instruction @0x4
ldr pc, _Supervisor_Call @0x8
ldr pc, _Prefetch_Abort @0xc
ldr pc, _Data_Abort @0x10
ldr pc, _Not_Used @0x14
ldr pc, _IRQ_interrupt @0x18
ldr pc, _FIQ_interrupt @0x1c
//异常的跳转
_Undefined_Instruction:
.word Undefined_Instruction
_Supervisor_Call:
.word Supervisor_Call
_Prefetch_Abort:
.word Prefetch_Abort
_Data_Abort:
.word Data_Abort
_Not_Used:
.word Not_Used
_IRQ_interrupt:
.word IRQ_interrupt
_FIQ_interrupt:
.word FIQ_interrupt
reset:
mov ip, sp
push {fp, ip, lr, pc}
sub fp, ip, #4
bl clr_bss
bl main
sub sp, fp, #12
ldm sp, {fp, sp, pc}
Undefined_Instruction:
mov sp, #0x76000000
stmfd sp!, {r0-r12, lr}
bl do_unde
ldmfd sp!, {r0-r12, pc}^
Supervisor_Call:
stmfd sp!, {r0-r12, lr}
sub r0, lr, #4
ldr r0, [r0]
bic r0, r0, #0xff000000
bl do_svc
ldmfd sp!, {r0-r12, pc}^
Prefetch_Abort:
Data_Abort:
ldr sp, =0x76e00000 //将一个地址装载到sp中
sub lr, lr, #4
stmfd sp!, {r0-r12, lr} //lr已经在产生异常时被设置为 pc -4 pc-4正好是C的下一行
bl do_abt_data //跳转到异常函数
ldmfd sp!, {r0-r12, pc}^ //^的作用是手动将SPSR返还给CPSR
Not_Used:
IRQ_interrupt:
FIQ_interrupt:
excep_sec:
excep_start:
.word _start
excep_end:
.word excep_sec
.globl excep_start //声明起始地址为全局变量
.globl excep_end //声明结束地址为全局变量
__start_bss:
.word _bss_start
__end_bss:
.word _bss_end
这时候我们需要将物理地址映射到虚拟地址,同时把我们的在汇编中写好的表放到0XFFFF0000这个位置,这时候我们在汇编中声明这全局变量.globl excep_start和
excep_end,并在c语言中定义他,主要的编码为下面
extern u32 excep_start[],u32 excrp_end //用数组的首地址来记录在汇编中的的位置
init_global_map(TTB);//mmu初始化
CREATE_DESCRIPTOR(TTB, 0xffff0000, 0x75000000); //映射0xffff0000
enable_mmu(TTB); //使能mmu
memcpy((void *)0xffff0000, (void *)excep_start, excep_end - excep_start)
//将表防入0xffff0000
这样子我们就搭建好了一个最近基本的异常框架,我们可以在c语言中修改异常函数来做我们想做的处理