字符设备驱动笔记——中断方式按键驱动之linux异常处理结构(四)

1.中断方式获取按键值



单片机: 1)按键按下

2)cup发生中断,跳转到异常向量入口执行

3)b 函数

    a.保存被中断的现场

    b.执行中断处理函数

    c.恢复

linux: 1)trap_init()函数构造异常向量

2)vector_irq + stubs_offset 跳转,vector_irq用宏来实现

    a.保存寄存器的值

    b.asm_do_IRQ

    c.恢复
2.linux异常处理结构分析
--------------------------------------------- trap_init()函数构造了异常向量 把__vectors_start代码复制到vectors这个地址中去 --------------------------------------------- 1)
/arch/arm/kernel/traps.c trap_init()
{ memcpy((
void *)vectors, __vectors_start, __vectors_end - __vectors_start);
......
}
vectors
====> CONFIG_VECTORS_BASE 异常向量的地址,可配置项 2)
/arch/arm/kernel/entry-armv.S __vectors_start分析: ------------------------------------------- __vectors_start: ARM( swi SYS_ERROR0 ) THUMB( svc #0 ) THUMB( nop ) W(b) vector_und + stubs_offset @这些都是异常向量 W(ldr) pc, .LCvswi + stubs_offset W(b) vector_pabt + stubs_offset W(b) vector_dabt + stubs_offset W(b) vector_addrexcptn + stubs_offset W(b) vector_irq + stubs_offset W(b) vector_fiq + stubs_offset   ...... ---------------------------------------------- 3)分析vector_und vector_und由vector_stub宏定义而来
vector_stub und, UND_MODE
--------------------------------------------------------- //宏定义 .macro vector_stub, name, mode, correction=0 .align 5 vector_\name: .if \correction sub lr, lr, #\correction .endif   ......

//替换后 .macro vector_stub, name, mode, correction=0 .align 5 vector_und: @定义了一个标号 @ @ 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 | PSR_ISETSTATE) msr spsr_cxsf, r0 ....... .endm ------------------------------------------------------------- 4) .long __und_usr @ 0 (USR_26 / USR_32) //作用:保存寄存器,做处理,恢复寄存器 .long __und_invalid @ 1 (FIQ_26 / FIQ_32) .long __und_invalid @ 2 (IRQ_26 / IRQ_32) .long __und_svc @ 3 (SVC_26 / SVC_32) .long __und_invalid @ 4 .long __und_invalid @ 5 .long __und_invalid @ 6 .long __und_invalid @ 7 .long __und_invalid @ 8 .long __und_invalid @ 9 .long __und_invalid @ a .long __und_invalid @ b .long __und_invalid @ c .long __und_invalid @ d .long __und_invalid @ e .long __und_invalid @ f .align 5 ----------------------------------------------------------------- ==========================================================================
分析vector_irq 1)W(b) vector_irq
+ stubs_offset ----------------------------------------------------------------- 2)vector_stub irq, IRQ_MODE, 4 替换后 .macro vector_stub, name, mode, correction=0 .align 5 vector_irq: //计算返回地址 sub lr, lr, #\correction @ @ 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 | PSR_ISETSTATE) msr spsr_cxsf, r0 @ @ the branch table must immediately follow this code @ and lr, lr, #0x0f THUMB( adr r0, 1f ) THUMB( ldr lr, [r0, lr, lsl #2] ) mov r0, sp ARM( ldr lr, [pc, lr, lsl #2] ) movs pc, lr @ branch to handler in SVC mode ENDPROC(vector_\name) .align 2 @ handler addresses follow this label 1: .endm -----------------------------------------------------------
3)
.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 ------------------------------------------------------ 4)__irq_usr分析: __irq_usr: usr_entry @入口 kuser_cmpxchg_check 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 ARM( strne r0, [r0, -r0] ) THUMB( movne r0, #0 ) THUMB( strne r0, [r0] ) #endif #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_on #endif mov why, #0 b ret_to_user UNWIND(.fnend ) ENDPROC(__irq_usr) .ltorg .align 5 ------------------------------------------------------ usr_entry分析: .macro usr_entry UNWIND(.fnstart ) UNWIND(.cantunwind ) @ don't unwind the user space sub sp, sp, #S_FRAME_SIZE ARM( stmib sp, {r1 - r12} ) @保存寄存器 THUMB( stmia sp, {r0 - 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 ...... .endm ------------------------------------------------------------ irq_handler分析: .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, BSYM(1b) bne asm_do_IRQ @跳转到C程序里面处理 ...... .endm
5) 调用asm_do_IRQ C处理程序

 

你可能感兴趣的:(linux)