6410之异常中断处理

来源:互联网 发布:淘宝网蒸锅小片毕链 编辑:程序博客网 时间:2024/06/07 01:00

单片机中断方式获取键值:

1.按键按下

2.CPU发生中断,跳转到异常向量入口地址执行

3.跳转到中断处理函数

中断处理函数的工作有:

a.保存被中断的现场

b.执行中断处理函数

c.恢复现场


linux中断方式获取键值:

1.异常向量的设置:ARM架构的CPU的异常向量基地之可以在0x00000000(比如之前裸板程序中所说的异常向量基地址就在这里),也可以是0xffff0000(linux内核使用的地址)可以查看trap_init函数进行查看它是如何将异常向量赋值到0xffff0000处的。拷贝的动作如下所示:

void __init early_trap_init(void)
{

   。。。

   memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);

   。。。

}

2.这里vectors,__vectors_start,__vectors_end的定义如下:

vectors:

unsigned long vectors = CONFIG_VECTORS_BASE;    // #define CONFIG_VECTORS_BASE 0xffff0000即为linux的虚拟地址

__vectors_start,__vectors_end定义在entry-armv.S (arch\arm\kernel),定义如下:

.globl __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



.globl __vectors_end
__vectors_end:

从上面可以看到__vectors_start和__vectors_end之间就是异常向量处理跳转列表。

3.取irq为例:

W(b) vector_irq + stubs_offset

vector_irq 的定义如下:

vector_stub irq, IRQ_MODE, 4

展开为:

.macro vector_stub, name, mode, correction=0

        //.macro vector_stub, irq, IRQ_MODE, 4
.align 5


vector_\name:
//vector_irq:
.if \correction

         //.if 4
sub lr, lr, #\correction

        //sub lr, lr, #4   减去4个字节,保证中断返回还是执行的是当前指令
.endif


@
@ 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)

上面做好准备工作就会跳转到下面的列表,下面列表列出的是在各种模式下发生中断所要跳转的中断列表:

.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

比如在用户模式和svc模式下发生了中断,就会跳转到__irq_usr,或__irq_svc去执行。在其他工作模式下不可能发生中断异常,否则使用"__irq_invalid",ARM架构CPU中使用4位数据来表示工作模式(目前只有7中工作模式),所以共有16个跳转分支。

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  //中断处理调用asm_do_IRQ函数,恢复现场 
#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


mov why, #0
b ret_to_user
 UNWIND(.fnend )
ENDPROC(__irq_usr)

原创粉丝点击