微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM linux的中断处理过程

ARM linux的中断处理过程

时间:11-09 来源:互联网 点击:

数指针,这里的汇编指令只需要调用这个machine代码提供的irq handler即可(当然,要准备好参数传递和返回地址设定)。

情况二要稍微复杂一些(而且,看起来kernel中使用的越来越少),代码如下:

.macro arch_irq_handler_default
get_irqnr_preamble r6, lr
1: get_irqnr_and_base r0, r2, r6, lr
movne r1, sp
@
@ asm_do_IRQ 需要两个参数,一个是 irq number(保存在r0)
@ 另一个是 struct pt_regs *(保存在r1中)
adrne lr, BSYM(1b)-------返回地址设定为符号1,也就是说要不断的解析irq状态寄存器

的内容,得到IRQ number,直到所有的irq number处理完毕
bne asm_do_IRQ
.endm

这里的代码已经是和machine相关的代码了,我们这里只是简短描述一下。所谓machine相关也就是说和系统中的中断控制器相关了。get_irqnr_preamble是为中断处理做准备,有些平台根本不需要这个步骤,直接定义为空即可。get_irqnr_and_base 有四个参数,分别是:r0保存了本次解析的irq number,r2是irq状态寄存器的值,r6是irq controller的base address,lr是scratch register。

3、当发生中断的时候,代码运行在内核空间

如果中断发生在内核空间,代码会跳转到__irq_svc处执行:

.align 5
__irq_svc:
svc_entry----保存发生中断那一刻的现场保存在内核栈上
irq_handler ----具体的中断处理,同user mode的处理。

#ifdef CONFIG_PREEMPT--------和preempt相关的处理,本文不进行描述
get_thread_info tsk
ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
ldr r0, [tsk, #TI_FLAGS] @ get flags
teq r8, #0 @ if preempt count != 0
movne r0, #0 @ force flags to 0
tst r0, #_TIF_NEED_RESCHED
blne svc_preempt
#endif

svc_exit r5, irq = 1 @ return from exception

保存现场的代码和user mode下的现场保存是类似的,因此这里不再详细描述,只是在下面的代码中内嵌一些注释。

.macro svc_entry, stack_hole=0
sub sp, sp, #(S_FRAME_SIZE + \stack_hole - 4)----sp指向struct pt_regs中r1的位置
stmia sp, {r1 - r12} ------寄存器入栈。

ldmia r0, {r3 - r5}
add r7, sp, #S_SP - 4 ------r7指向struct pt_regs中r12的位置
mov r6, #-1 ----------orig r0设为-1
add r2, sp, #(S_FRAME_SIZE + \stack_hole - 4)----r2是发现中断那一刻stack的现场
str r3, [sp, #-4]! ----保存r0,注意有一个!,sp会加上4,这时候sp就指向栈顶的r0位置了

mov r3, lr ----保存svc mode的lr到r3
stmia r7, {r2 - r6} ---------压栈,在栈上形成形成struct pt_regs
.endm

五、中断退出过程

1、中断发生在user mode下的退出过程,代码如下:

ENTRY(ret_to_user_from_irq)
ldr r1, [tsk, #TI_FLAGS]
tst r1, #_TIF_WORK_MASK---------------A
bne work_pending
no_work_pending:
asm_trace_hardirqs_on ------和irq flag trace相关,暂且略过

/* perform architecture specific actions before user return */
arch_ret_to_user r1, lr----有些硬件平台需要在中断返回用户空间做一些特别处理
ct_user_enter save = 0 ----和trace context相关,暂且略过

restore_user_regs fast = 0, offset = 0------------B
ENDPROC(ret_to_user_from_irq)
ENDPROC(ret_to_user)

A:thread_info中的flags成员中有一些low level的标识,如果这些标识设定了就需要进行一些特别的处理,这里检测的flag主要包括:

#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | _TIF_NOTIFY_RESUME)

这三个flag分别表示是否需要调度、是否有信号处理、返回用户空间之前是否需要调用callback函数。只要有一个flag被设定了,程序就进入work_pending这个分支。

B:从字面的意思也可以看成,这部分的代码就是将进入中断的时候保存的现场(寄存器值)恢复到实际的ARM的各个寄存器中,从而完全返回到了中断发生的那一点。具体的代码如下:

.macro restore_user_regs, fast = 0, offset = 0
ldr r1, [sp, #\offset + S_PSR] ----r1保存了pt_regs中的spsr,也就是发生中断时的CPSR
ldr lr, [sp, #\offset + S_PC]! ----lr保存了PC值,同时sp移动到了pt_regs中PC的位置
msr spsr_cxsf, r1 ---------赋值给spsr,进行返回用户空间的准备
clrex @ clear the exclusive monitor

.if \fast
ldmdb sp, {r1 - lr}^ @ get calling r1 - lr
.else
ldmdb sp, {r0 - lr}^ ------将保存在内核栈上的数据保存到用户态的r0~r14寄存器
.endif
mov r0, r0 ---------NOP操作,ARMv5T之前的需要这个操作
add sp, sp, #S_FRAME_SIZE - S_PC----现场已经恢复,移动svc mode的sp到原来的位置
movs pc, lr --------返回用户空间
.endm

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top