A Linux exception handling architecture/framework
General exception handling mechanism
Two linux kernel for abnormal settings (P397)
The summary of the following analysis:
(1) __vector_start
Copy the code at the start address of the exception vector to the vectors
address
(2) Once an interrupt occurs, it will jump to the vector_irq
beginning code; the code is implemented in the form of a macro
(3) Macro: return from calculation Address -> save the scene -> call the c function of interrupt processing -> restore the scene
- The trap_init function analysis
code is as follows:
Among them: where:,
vectors=0xffff0000
__vectors_start=异常代码存储地址
this code is a jump instruction,
for example
LINE1064:出现未定义的指令
LINE1069:中断跳转指令
- Tracking
vector_und
variables
Continue to track thevector_und
variables in the figure above , but we can’t find the code even though we searched through the code...actually the variable is a macro definition. (For detailed description, please refer to: Vector_stub Macro Analysis of Linux Exception System )
The code in the figure below isvector_stub
a reference to the macro :
the figure below isvector_stub
the definition of the macro in the code :
- Tracking
vector_irq
variables
The following code isvector_stub
a reference to the macro .
According to the macro definition, you can get the following actual code:
/*
* Interrupt dispatcher
*/
/*
vector_stub irq, IRQ_MODE, 4
*/
/*
. macro vector_stub, name, mode, correction=0
参数赋值:
name=irq
mode=IRQ_MODE
correction=4
*/
.align 5
vector_irq:
@计算返回地址,与单片机程序一致
sub lr, lr, #4
@
@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
@ (parent CPSR)
@
stmia sp, {r0, lr} @ save r0, lr
mrs lr, spsr
str lr, [sp, #8] @ save spsr
@
@ Prepare for SVC32 mode. IRQs remain disabled.
@转换到管理模式
mrs r0, cpsr
eor r0, r0, #(\mode ^ SVC_MODE)
msr spsr_cxsf, r0
@
@ the branch table must immediately follow this code
@向下面的列表跳转
and lr, lr, #0x0f
mov r0, sp
ldr lr, [pc, lr, lsl #2]
movs pc, lr @ branch to handler in SVC mode
.long __irq_usr @ 0 (USR_26 / USR_32)-用户模式下发生中断的时候跳到这里来
.long __irq_invalid @ 1 (FIQ_26 / FIQ_32)
.long __irq_invalid @ 2 (IRQ_26 / IRQ_32)
.long __irq_svc @ 3 (SVC_26 / SVC_32)-管理模式下发生中断的时候跳到这里来
.long __irq_invalid @ 4
.long __irq_invalid @ 5
.long __irq_invalid @ 6
.long __irq_invalid @ 7
.long __irq_invalid @ 8
.long __irq_invalid @ 9
.long __irq_invalid @ a
.long __irq_invalid @ b
.long __irq_invalid @ c
.long __irq_invalid @ d
.long __irq_invalid @ e
.long __irq_invalid @ f
- Track the
__irq_usr
corresponding code
__irq_usr:
usr_entry
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_off
#endif
get_thread_info tsk
#ifdef CONFIG_PREEMPT
ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
add r7, r8, #1 @ increment it
str r7, [tsk, #TI_PREEMPT]
#endif
irq_handler
#ifdef CONFIG_PREEMPT
ldr r0, [tsk, #TI_PREEMPT]
str r8, [tsk, #TI_PREEMPT]
teq r0, r7
strne r0, [r0, -r0]
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_on
#endif
mov why, #0
b ret_to_user
.ltorg
.align 5
Which usr_entry
is also a macro, defined as follows:
//功能:保存现场
.macro usr_entry
sub sp, sp, #S_FRAME_SIZE
stmib sp, {r1 - r12}
ldmia r0, {r1 - r3}
add r0, sp, #S_PC @ here for interlock avoidance
mov r4, #-1 @ "" "" "" ""
str r1, [sp] @ save the "real" r0 copied
@ from the exception stack
#if __LINUX_ARM_ARCH__ < 6 && !defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)
#ifndef CONFIG_MMU
#warning "NPTL on non MMU needs fixing"
#else
@ make sure our user space atomic helper is aborted
cmp r2, #TASK_SIZE
bichs r3, r3, #PSR_Z_BIT
#endif
#endif
@
@ We are now ready to fill in the remaining blanks on the stack:
@
@ r2 - lr_<exception>, already fixed up for correct return/restart
@ r3 - spsr_<exception>
@ r4 - orig_r0 (see pt_regs definition in ptrace.h)
@
@ Also, separately save sp_usr and lr_usr
@
stmia r0, {r2 - r4}
stmdb r0, {sp, lr}^
@
@ Enable the alignment trap while in kernel mode
@
alignment_trap r0
@
@ Clear FP to mark the first stack frame
@
zero_fp
.endm
Among them, it irq_handler
is also a macro, defined as follows
/*
* Interrupt handling. Preserves r7, r8, r9
*/
.macro irq_handler
get_irqnr_preamble r5, lr
1: get_irqnr_and_base r0, r6, r5, lr
movne r1, sp
@
@ routine called with r0 = irq number, r1 = struct pt_regs *
@最终调用了函数asm_do_IRQ
adrne lr, 1b
bne asm_do_IRQ
...
.endm
Then, the trace function asm_do_IRQ
is the interrupt handler function