首先异常向量表的代码如下:
__exception_handlers:
#ifdef CYGSEM_HAL_ROM_RESET_USES_JUMP
// Assumption: ROM code has these vectors at the hardware reset address.
// A simple jump removes any address-space dependencies [i.e. safer]
b reset_vector // 0x00
#else
ldr pc,.reset_vector // 0x00
#endif
ldr pc,.undefined_instruction // 0x04
ldr pc,.software_interrupt // 0x08 start && software int
ldr pc,.abort_prefetch // 0x0C
ldr pc,.abort_data // 0x10
#ifdef CYGNUM_HAL_ARM_VECTOR_0x14
.word CYGNUM_HAL_ARM_VECTOR_0x14
#else
.word 0 // unused
#endif
ldr pc,.IRQ // 0x18
ldr pc,.FIQ // 0x1C
对于undefined/software/abort/prefech异常来说,依次眺望以下标号位置:
.code 32
undefined_instruction:
ldr sp,.__undef_exception_stack // get good stack
stmfd sp!,{r0-r5} // save some supervisor regs
mrs r1,spsr
tst r1,#CPSR_THUMB_ENABLE
subeq r0,lr,#4 // PC at time of interrupt (ARM)
subne r0,lr,#2 // PC at time of interrupt (thumb)
mov r2,#CYGNUM_HAL_EXCEPTION_ILLEGAL_INSTRUCTION
mov r3,sp
b call_exception_handler
.code 32
software_interrupt:
stmfd sp!,{r8}
ldr r8,.__undef_exception_stack // get good stack
stmfd r8!,{r0-r5} // save some supervisor regs
mov r3,r8
ldmfd sp!,{r8}
mrs r1,spsr
tst r1,#CPSR_THUMB_ENABLE
subeq r0,lr,#4 // PC at time of SWI (ARM)
subne r0,lr,#2 // PC at time of SWI (thumb)
mov r2,#CYGNUM_HAL_EXCEPTION_INTERRUPT
b call_exception_handler
.code 32
abort_prefetch:
ldr sp,.__undef_exception_stack // get good stack
stmfd sp!,{r0-r5} // save some supervisor regs
sub r0,lr,#4 // PC at time of interrupt
mrs r1,spsr
mov r2,#CYGNUM_HAL_EXCEPTION_CODE_ACCESS
mov r3,sp
b call_exception_handler
.code 32
abort_data:
ldr sp,.__undef_exception_stack // get good stack
stmfd sp!,{r0-r5} // save some supervisor regs
sub r0,lr,#4 // PC at time of interrupt
mrs r1,spsr
mov r2,#CYGNUM_HAL_EXCEPTION_DATA_ACCESS
mov r3,sp
b call_exception_handler
对于IRQ和FIQ的处理如下:
1、发生FIQ或者IRQ时首先跳转到异常向量表对应类型的向量跳转指令,对于IRQ和FIQ而言,处理过程基本一致,FIQ会多一点处理,所以以下分析从FIQ中断开始;
2、首先检查中断发生前的处理器模式;
// We can get here from any non-user mode.
mrs r8,spsr // CPSR at time of interrupt
and r9,r8,#CPSR_MODE_BITS // isolate pre-interrupt mode
cmp r9,#CPSR_IRQ_MODE
bne 1f
3、如果在IRQ中发生FIQ中断,则关闭FIQ中断,并立刻返回继续处理之前的IRQ中断;
// If FIQ interrupted IRQ mode, just return with FIQ disabled.
// The common interrupt handling takes care of the rest.
orr r8,r8,#CPSR_FIQ_DISABLE
msr spsr,r8
subs pc,lr,#4
4、如果在其他模式中发生FIQ中断,则保存中断发生前的CPSR和PC地址保存到临时堆栈中,禁止IRQ和FIQ,进入IRQ模式,把先前临时堆栈中的CPSR和PC地址恢复到IRQ模式下对应的SP和LR寄存器中;
IRQ模式 SP寄存器 = FIQ中断发生前的处理器CPSR
LR寄存器 = FIQ中断发生前的处理器运行地址
SPSR = FIQ中断发生前的处理器CPSR
说明:由于FIQ中断保存的中断前处理器CPSR和PC地址已经转移到IRQ模式下保存起来了,所以以下的处理对于FIQ和IRQ都一样;
===================================================================
5、将中断发生前的R0-R5状态存入临时堆栈,因为后面的处理需要占用这些寄存器;然后依次初始化R1-R5如下:
R0 = 中断发生时的PC地址
R1 = 中断发生时的CPSR
R2 = 中断向量index
R3 = 临时堆栈指针
R4 = 当前中断模式下的CPSR
R5 = ??
6、切换到Supervisor Mode,在该模式下禁止FIQ中断,将当前模式的svc_sp,、当前模式的svc_lr、中断向量index、中断发生时的CPSR、中断发生时的PC地址依次压入堆栈,注意此时的堆栈为Supervisor Mode已经初始化的地址;
Supervisor Mode下的堆栈寄存器
Supervisor Mode下的链接寄存器
中断向量index
中断发生时的CPSR
中断发生时的PC地址 <===SP
7、如果中断前处于USER模式,则需要往堆栈中继续保存其他寄存器,包括r8-r12, sp, lr;Supervisor Mode下堆栈的数据分布如下:
Supervisor Mode下的堆栈寄存器
Supervisor Mode下的链接寄存器
中断向量index
中断发生时的CPSR
中断发生时的PC地址
User mode下的LR寄存器
User mode下的SP寄存器
User mode下的R12-R8寄存器 <===SP
8、如果中断前不是处于USER模式,则将Supervisor Mode下的SP和CPSR分别暂存到R0和R2中;然后切换回中断前的模式(需要禁止FIQ和IRQ,ARM状态);
R0 = Supervisor Mode下的SP寄存器
R2 = Supervisor Mode下的CPSR寄存器
在中断前的模式下,把r8-r12,sp,lr保存到Supervisor Mode下的堆栈空间;然后切换回Supervisor Mode,同时要更新当前模式下堆栈指针;
Supervisor Mode下的堆栈寄存器
Supervisor Mode下的链接寄存器
中断向量index
中断发生时的CPSR
中断发生时的PC地址
中断前mode下的LR寄存器
中断前mode下的SP寄存器
中断前mode下的R12-R8寄存器 <===SP
10、无论中断前是否处于USER模式,都会跳到此步骤;将之前保存到临时堆栈的R0-R5以及没有改动的R6/R7一起保存到Supervisor Mode下的堆栈中;此时当前模式堆栈内容如下排列:
Supervisor Mode下的堆栈寄存器
Supervisor Mode下的链接寄存器
中断向量index
中断发生时的CPSR
中断发生时的PC地址
中断前mode下的LR寄存器
中断前mode下的SP寄存器
中断前mode下的R12-R0寄存器 <===SP
11、