内核部分:内核版本linux 2.6.22.6
1. 从start_kernel() // 在 init/main.c中- start_kernel()
- ...
- trap_init()
- ...
- void __init trap_init(void)
- {
- unsigned long vectors = CONFIG_VECTORS_BASE; //CONFIG_VECTORS_BASE = 0XFFFF0000
- extern char __stubs_start[], __stubs_end[];
- extern char __vectors_start[], __vectors_end[];
- extern char __kuser_helper_start[], __kuser_helper_end[];
- int kuser_sz = __kuser_helper_end - __kuser_helper_start;
-
- /*
- * Copy the vectors, stubs and kuser helpers (in entry-armv.S)
- * into the vector page, mapped at 0xffff0000, and ensure these
- * are visible to the instruction stream.
- */
- memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
- memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
- memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
- ...
- }
trap_init实现的功能是将脚本文件定义的中断向量连接地址映射到0xffff0000为起始的地址中。
2.中断过程分析:以irq中断为例
在main函数执行过程中如果有中断产生那么会跳到中断入口 (entry-asmv.S) - .LCvswi:
- .word vector_swi
- .globl __stubs_end
- __stubs_end:
- .equ stubs_offset, __vectors_start + 0x200 - __stubs_start
- .globl __vectors_start
- __vectors_start:
- swi SYS_ERROR0
- b vector_und + stubs_offset
- ldr pc, .LCvswi + stubs_offset
- b vector_pabt + stubs_offset
- b vector_dabt + stubs_offset
- b vector_addrexcptn + stubs_offset
- b vector_irq + stubs_offset
- b vector_fiq + stubs_offset
- .globl __vectors_end
- __vectors_end:
在内核中,当发生异常是就会进入相应的工作模式,内核是通过一个宏来管理这些模式的。- .macro vector_stub, name, mode, correction=0
- .align 5
- vector_\name:
- .if \correction
- sub lr, lr, #\correction
- .endif
- @
- @ Save r0, lr_ (parent PC) and spsr_
- @ (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
- .endm
1.保存返回地址,r0,lr,spsr寄存器
2.切换到管理模式
3.跳转到相应的入口- vector_stub irq, IRQ_MODE, 4
- .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
- __irq_svc:
- svc_entry
- #ifdef CONFIG_TRACE_IRQFLAGS
- bl trace_hardirqs_off
- #endif
- #ifdef CONFIG_PREEMPT
- get_thread_info tsk
- 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_FLAGS] @ get flags
- tst r0, #_TIF_NEED_RESCHED
- blne svc_preempt
- preempt_return:
- ldr r0, [tsk, #TI_PREEMPT] @ read preempt value
- str r8, [tsk, #TI_PREEMPT] @ restore preempt count
- teq r0, r7
- strne r0, [r0, -r0] @ bug()
- #endif
- ldr r0, [sp, #S_PSR] @ irqs are already disabled
- msr spsr_cxsf, r0
- #ifdef CONFIG_TRACE_IRQFLAGS
- tst r0, #PSR_I_BIT
- bleq trace_hardirqs_on
- #endif
- ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
- .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 *
- @
- adrne lr, 1b
- bne asm_do_IRQ
到这调用asm_do_IRQ函数 传入的参数为 r0 = irq number, r1 = struct pt_regs * 这个是正真的调用异常处理函数 前面都只是一些调用处理函数前的操作,到这里已经传入了2个参数,其中很重要的一个参数就是irq number.我们把这个函数作为分界点。。。
阅读(832) | 评论(0) | 转发(0) |