微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > arm linux 下中断流程简要分析中断处理流程

arm linux 下中断流程简要分析中断处理流程

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

是thread_info对象,即该栈拥有者线程的对象,而get_thread_info就是通过把sp低13位清0(8K边界)来获取当前thread_info对象的地址。

arch/arm/kernel/entry-armv.S:

.macroget_thread_info, rd

mov/rd, sp, lsr #13

mov/rd, /rd, lsl #13

.endm

调用该宏后寄存器tsk里存放的就是当前线程的地址了,tsk是哪个寄存器呢,我们在看:

arch/arm/kernel/entry-header.S:

tsk.reqr9@ current thread_info

,tsk只是r9的别名而已, 因此这时r9里保存的就是当前线程的地址。

我们接着看irq_handler:

arch/arm/kernel/entry-armv.S:

.macroirq_handler

1:get_irqnr_and_base r0, r6, r5, lr@平台相关,获取中断号

movner1, sp@如果r0(中断号)不等于0,则r1指向sp所在地址,即pt_regs对象地址(看上图)

@

@ routine called with r0 = irq number, r1 = struct pt_regs *

@

adrnelr, 1b@如果r0(中断号)不等于0,lr(返回地址)等于标号1处,即

@ get_irqnr_and_base r0, r6, r5, lr的那行,即循环处理所有的中断。

bneasm_do_IRQ@处理该中断

#ifdef CONFIG_SMP

/*

* XXX

*

* this macro assumes that irqstat (r6) and base (r5) are

* preserved from get_irqnr_and_base above

*/

test_for_ipi r0, r6, r5, lr

movner0, sp

adrnelr, 1b

bnedo_IPI

#ifdef CONFIG_LOCAL_TIMERS

test_for_ltirq r0, r6, r5, lr

movner0, sp

adrnelr, 1b

bnedo_local_timer

#endif

#endif

.endm

get_irqnr_and_base是平台相关的,这里就不列出来了,对于s3c2410,代码在include/asm-arm/s3c2410/entry-macro.S里,该宏处理完后,r0 =中断号,接下来r1赋值为sp地址(pt_regs对象地址), 最后调用c函数asm_do_IRQ, r0, r1作为参数被传递进去。asm_do_IRQ()处理完后将返回到lr指向的地址处即上面汇编部分标号为1的地址处继续执行。

我们把__irq_usr的汇编部分分析完后再来分析asm_do_IRQ()等c函数。

Arch/arm/kernel/entry-armv.S:

__irq_usr:

……

……

mov why, #0@ why = 0, why是r8的别名,

b ret_to_user@返回到用户模式下

我们看ret_to_user

arch/arm/kernel/entry-common.S:

ENTRY(ret_to_user)

ret_slow_syscall:

disable_irq@ disable interrupts@关中断,

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

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

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

no_work_pending:

@ slow_restore_user_regs

ldrr1, [sp, #S_PSR]@ get calling cpsr获取被中断代码处的状态(cpsp)

ldrlr, [sp, #S_PC]!@ get pc获取返回地址(被中断代码的下条代码处的地址)

msrspsr_cxsf, r1@ save in spsr_svc, spsr里保存好被中断代码处的状态(cpsp)

ldmdbsp, {r0 - lr}^@ get calling r1 – lr从栈上获取用户态下的r0到lr的值

movr0, r0

addsp, sp, #S_FRAME_SIZE - S_PC@栈地址恢复,避免多个中断后溢出

movspc, lr@ return & move spsr_svc into cpsr, 返回被中断代码处继续执行,并把spsr赋给cpsp,即恢复被中断处的现场状态。这样CPU又可以从被中断的地方继续执行了,而且这个时候所有的寄存器值(r0到r12),包括状态寄存器值(cpsr)都是源码被中断时的值。

我们顺便看下work_pending

arch/arm/kernel/entry-common.S:

work_pending:

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

bnework_resched@进程调度

tstr1, #_TIF_NOTIFY_RESUME | _TIF_SIGPENDING

beqno_work_pending@无需调度,返回

movr0, sp@ regs

movr2, why@ syscall

bldo_notify_resume

bret_slow_syscall@ Check work again

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

Ok,中断的流程大体就是这样的,下面我们就开始分析c函数里的中断流程。

先来看asm_do_IRQ

arch/arm/kernel/Irq.c:

/*

* do_IRQ handles all hardware IRQs.Decoded IRQs should not

* come via this function.Instead, they should provide their

* own handler

*/

asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)

{

struct irqdesc *desc = irq_desc + irq; /*获取中断描述符*/

/*

* Some hardware gives randomly wrong interrupts.Rather

* than crashing, do something sensible.

*/

if (irq >= NR_IRQS)/*参数检查*/

desc = &bad_irq_desc;

irq_enter();

desc_handle_irq(irq, desc, regs);/*中断处理*/

/* AT91 specific workaround */

irq_finish(irq);

irq

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

网站地图

Top