您的位置:首页 > 其它

6410之异常中断处理

2013-08-13 15:39 204 查看
单片机中断方式获取键值:

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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: