字符设备驱动程序之中断方式的按键驱动_Linux异常处理结构(六)


字符设备驱动程序之中断方式的按键驱动_Linux异常处理结构


中断方式获取按键值(单片机)

1、有按键按下

2、CPU发生中断

    强制调到异常向量入口执行(中断是异常的一种)

3、入口函数    跳转指令:b 函数

        a.保存被中断的现场(各种寄存器的值)

        b.执行中断处理函数

        c.恢复被中断的现场





Linux异常向量:

ARM架构CPU的异常向量基址可以是0x00000000,也可以是0xffff0000,Linux内核使用后者。(这个地址0xffff0000并不对应于实际的内存,是一个虚拟地址)。trap_init函数将异常向量复制到0xffff0000处。


使用memcpy把__vectors_start开始,大小为__vectors_end - __vectors_start,拷贝到vectors里。


vectors=CONFIG_VECTORS_BASE,是一个配置项。内核代码里vi .config文件:


CONFIG_VECTORS_BASE=0xffff0000。


__vector_start:(arch\arm\kernel\entry-armv.s)


也是一些跳转指令。



看一个例子,对于中断,发生中断就会跳到b vector_irq + stubs_offset:


vector_stub irq, IRQ_MODE, 4     把它展开。


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

.endm


然后跳转到这里:
.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_usr:


usr_entry:保存寄存器。

irq_handler:最终会调用asm_do_IRQ(用C语言来写的)。





总结:

异常向量最终怎么调用asm_do_irq?

在trap_init构造异常向量,异常向量是把__vectors_start开始,大小为__vectors_end - __vectors_start,拷贝到vectors0xffff0000里。

异常向量:(也是某些跳转)


比如 b vector_irq+subs_offset(vector_irq:链接地址,subs_offset:偏移地址)

vector_irq是用一个宏来实现的vector_stub irq, IRQ_MODE, 4 ,计算返回地址,保存寄存器,调用处理函数。

处理函数:usr_entry保存环境变量、寄存器。调用irq_handler函数。

irq_handler函数:asm_do_IRQ(C函数)。

恢复。


ARM架构Linux内核的异常处理体系结构:


猜你喜欢

转载自blog.csdn.net/xiaodingqq/article/details/80291677