linux arm中断进程,ARM Linux对中断的处理

用户模式下的中断处理

先来回顾一下中断发生时系统的处理过程。当中断发生时,系统跳转到vector_irq处执行,它获得返回地址,在sp指针(中断模式下的栈,临时性的)所指的地方保存r0、lr和spsr,之后进入SVC模式,并根据中断产生时CPU的模式,以模式的低4位值为索引,来取相应的处理程序的地址,从而进入中断的处理过程。r0中保存中断时中断模式的SP的值。还是在这里补充一点ARM的CPU模式的东西好。ARM处理器的最低5位用来指示处理当前所在的模式。各模式对应的模式值如下(在arch/arm/include/asm/ptrace.h中):

#define USR_MODE   0x00000010

#define FIQ_MODE   0x00000011

#define IRQ_MODE   0x00000012

#define SVC_MODE   0x00000013

#define ABT_MODE   0x00000017

#define UND_MODE   0x0000001b

#define SYSTEM_MODE   0x0000001f

中断发生时,CPU处于用户模式下,则当然会调用__irq_usr例程,

.align 5

__irq_usr:

usr_entry//宏,保存各寄存器,便于返回的时候恢复

kuser_cmpxchg_check

get_thread_info tsk//获取保存当前task信息的地址

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

先来看usr_entry,在arch/arm/kernel/entry-armv.S中:

.macro usr_entry

UNWIND(.fnstart   )

UNWIND(.cantunwind   )  @ don't unwind the user

space

sub   sp, sp, #S_FRAME_SIZE

// stmib,每次传送前地址加四

ARM( stmib sp, {r1 - r12}  )

THUMB(  stmia sp, {r0 - r12}  )

//把r0指向的地址处的值传给r1到r13,即r1=r0,r2=lr,r3=spsr。

ldmia r0, {r1 - r3}

add   r0, sp, #S_PC      @

here for interlock avoidance

mov   r4, #-1         @  ""

""     ""        ""

// r1存放的是实际r0的值,这里就是存储实际的r0

str   r1, [sp]    @

save the "real" r0 copied

@

from the exception stack

@

@

We are now ready to fill in the remaining blanks on the stack:

@

@  r2 - lr_, already fixed up

for correct return/restart

@  r3 - spsr_

@  r4 - orig_r0 (see pt_regs definition in

ptrace.h)

@

@

Also, separately save sp_usr and lr_usr

@

//存储返回地址,现场状态等(被中断代码处的)

stmia r0, {r2 - r4}

//存储用户模式下的sp,lr,ARM体系结构中用户模式和系统模式共用同一个

// SP和LR

ARM( stmdb r0, {sp, lr}^         )

THUMB(  store_user_sp_lr

r0, r1, S_SP - S_PC )

@

@

Enable the alignment trap while in kernel mode

@

alignment_trap

r0

@

@

Clear FP to mark the first stack frame

@

zero_fp

asm_trace_hardirqs_off

.endm

这个宏和svc_entry一样,主要也是保存各个寄存器值到栈上相应的位置。__irq_usr中间的代码和__irq_svc一样,这里就不再赘述了。__irq_usr处理完中断后,调用ret_to_user来返回到用户模式,这个例程在arch/arm/kernel/entry-common.S下定义:

ENTRY(ret_to_user)

ret_slow_syscall:

disable_irq           @ disable interrupts

ldr   r1, [tsk, #TI_FLAGS]@获取thread_info中flags域的值

tst   r1, #_TIF_WORK_MASK@判断task是否被阻塞

bne   work_pending@根据需要进行进程的切换。

no_work_pending:

/*

perform architecture specific actions before user return */

//宏,空的在arch/arm/mach-s3c2410/include/mach/entry-macro.S中

//定义

arch_ret_to_user r1, lr

restore_user_regs

fast = 0, offset = 0

ENDPROC(ret_to_user)

宏restore_user_regs在arch/arm/kernel/entry-header.S中定义:

.macro restore_user_regs, fast = 0, offset = 0

//获取被中断代码处的状态(cpsr)

ldr   r1, [sp, #\offset + S_PSR]  @ get calling cpsr

ldr   lr, [sp, #\offset + S_PC]!  @ get pc

// spsr里保存好被中断代码处的状态(cpsp)

msr   spsr_cxsf, r1         @

save in spsr_svc

#if defined(CONFIG_CPU_32v6K)

clrex              @ clear the exclusive monitor

#elif defined (CONFIG_CPU_V6)

strex r1, r2, [sp]       @

clear the exclusive monitor

#endif

.if   \fast

ldmdb sp, {r1 - lr}^        @

get calling r1 - lr

.else

ldmdb sp, {r0 - lr}^        @

get calling r0 - lr

.endif

@栈地址恢复,避免多个中断后溢出

add   sp, sp, #S_FRAME_SIZE - S_PC

//返回被中断代码处继续执行,并把spsr赋给cpsr,即恢复被中断处

//的现场状态。这样CPU又可以从被中断的地方继续执行了,而且这个

//时候所有的寄存器值(r0到r12),包括状态寄存器值(cpsr)都是源

//码被中断时的值。

movs  pc, lr         @ return & move spsr_svc into cpsr

.endm

恢复寄存器,完成中断处理,回到用户模式。

顺便看下work_pending,在arch/arm/kernel/entry-common.S中:

work_pending:

tst r1,

#_TIF_NEED_RESCHED  @判断是否需要调度进程

bne work_resched            @进程调度

tst r1,

#_TIF_SIGPENDING|_TIF_NOTIFY_RESUME

beq no_work_pending    @无需调度,返回

mov r0,

sp            @ 'regs'

mov r2,

why              @ 'syscall'

bl  do_notify_resume

b   ret_slow_syscall     @ Check work again

work_resched:

bl  schedule

由该汇编代码可知,如果在用户模式下产生中断的话,在返回的时候,会根据需要进行进程调度,而从代码可知,如果中断发生在管理等内核模式下的话是不会进行进程调度的。

Ok,中断的流程大体就是这样的,c函数里的中断流程在系统模式下的中断处理里已经说的很多了,这里不再赘述。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值