对于ARM平台而言,我们推荐使用第一种方法,因为从逻辑上讲,中断处理就是需要根据当前的硬件中断系统的状态,转换成一个IRQ number,然后调用该IRQ number的处理函数即可。通过get_irqnr_and_base这样的宏定义来获取IRQ是旧的ARM SOC系统使用的方法,它是假设SOC上有一个中断控制器,硬件状态和IRQ number之间的关系非常简单。但是实际上,ARM平台上的硬件中断系统已经是越来越复杂了,需要引入interrupt controller级联,irq domain等等概念,因此,使用第一种方法优点更多。
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
一个task的thread info数据结构定义如下(只保留和本场景相关的内容):
struct thread_info {
unsigned long flags; /* low level flags */
int preempt_count; /* 0 => preemptable, <0 => bug */
……
};
flag成员用来标记一些low level的flag,而preempt_count用来判断当前是否可以发生抢占,如果preempt_count不等于0(可能是代码调用preempt_disable显式的禁止了抢占,也可能是处于中断上下文等),说明当前不能进行抢占,直接进入恢复现场的工作。如果preempt_count等于0,说明已经具备了抢占的条件,当然具体是否要抢占当前进程还是要看看thread info中的flag成员是否设定了_TIF_NEED_RESCHED这个标记(可能是当前的进程的时间片用完了,也可能是由于中断唤醒了优先级更高的进程)。
保存现场的代码和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的现场
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-76601-10.html
吃吃喝喝打打几十块输赢的小麻将
是解决途径之一
加油