关于ARM架构下Linux中断的问题

112 views
Skip to first unread message

fiddle yuan

unread,
Jan 23, 2011, 10:02:14 AM1/23/11
to linux-...@zh-kernel.org
大家好:

前一段时间看了一点Qualcomm MSM平台下中断处理的代码,发现有些基础知识方面的问题非常迷惑,希望各位不吝赐教,先谢谢了~

问题是:
(1). 在MSM平台下(ARM),是否支持中断嵌套?
(2). 如果支持,那么就需要捋清楚整个中断流程
2.1 当IRQ中断来的时候,CPU会自动将CPSR的I位置位,从而禁止新的IRQ中断
2.2 PC会自动设置到0xFFFF0018处
2.3 随后,跳转到vector_irq处执行,此时,处理器处于IRQ模式,vector_irq的代码做了这些操作:修正返回地址(lr),依次将ro,lr,spsr压入栈中(此时的栈应该是IRQ模式下的栈),设置spsr为SVC模式,根据lr计算正确的跳转表项,最后通过更新PC来跳转到相应的跳转表项中(比如,来中断之前处于usr模式,那么就应该跳转到__irq_usr来执行)
2.4 到了__irq_usr中,首先调用usr_entry,把一堆从r0-r15还有一些usr模式下的寄存器压入SVC模式下的栈,然后调用get_thread_info,根据sp找到thread_info,将preempt_count加1,防止内核抢占,再接下来,调用irq_handler来获取中断号,并触发调用asm_do_IRQ(它将调用注册中断时作为参数传进来的中断服务程序),最后,恢复tsk,给why赋值,掉用ret_to_user返回usr模式,结束

以上(2)中的步奏是基于MSM7627平台下,内核版本2.6.32的.问题关健在于整个流程不知道在何处重新将2.1中由CPU自动置位的I位给清掉的?如果没有清掉,显然是无法实现中断嵌套的,并且也不可能没有清掉,否则返回usr模式后岂不是无发接收中断了?可我找来找去,还是没有找到清掉I位的操作.

不知道哪位高人能够指点一二,在此谢谢各位~
_______________________________________________
Linux 内核开发中文邮件列表
Linux-...@zh-kernel.org
http://zh-kernel.org/mailman/listinfo/linux-kernel
Linux 内核开发中文社区: http://zh-kernel.org

Allen Wang

unread,
Jan 24, 2011, 3:39:46 AM1/24/11
to fiddle yuan, linux-...@zh-kernel.org
2011/1/23 fiddle yuan <fiddle...@gmail.com>

> 大家好:
>
> 前一段时间看了一点Qualcomm MSM平台下中断处理的代码,发现有些基础知识方面的问题非常迷惑,希望各位不吝赐教,先谢谢了~
>
> 问题是:
> (1). 在MSM平台下(ARM),是否支持中断嵌套?
>

ARM core only support fiq interrupt irq essentially.
But based the CPU's interrupt controller, you can use high priority
irq interrupt low priority irq to implement nested interrupt.

(2). 如果支持,那么就需要捋清楚整个中断流程
> 2.1 当IRQ中断来的时候,CPU会自动将CPSR的I位置位,从而禁止新的IRQ中断
> 2.2 PC会自动设置到0xFFFF0018处
> 2.3
> 随后,跳转到vector_irq处执行,此时,处理器处于IRQ模式,vector_irq的代码做了这些操作:修正返回地址(lr),依次将ro,lr,spsr压入栈中(此时的栈应该是IRQ模式下的栈),设置spsr为SVC模式,根据lr计算正确的跳转表项,最后通过更新PC来跳转到相应的跳转表项中(比如,来中断之前处于usr模式,那么就应该跳转到__irq_usr来执行)
> 2.4
> 到了__irq_usr中,首先调用usr_entry,把一堆从r0-r15还有一些usr模式下的寄存器压入SVC模式下的栈,然后调用get_thread_info,根据sp找到thread_info,将preempt_count加1,防止内核抢占,再接下来,调用irq_handler来获取中断号,并触发调用asm_do_IRQ(它将调用注册中断时作为参数传进来的中断服务程序),最后,恢复tsk,给why赋值,掉用ret_to_user返回usr模式,结束
>
>
> 以上(2)中的步奏是基于MSM7627平台下,内核版本2.6.32的.问题关健在于整个流程不知道在何处重新将2.1中由CPU自动置位的I位给清掉的?如果没有清掉,显然是无法实现中断嵌套的,并且也不可能没有清掉,否则返回usr模式后岂不是无发接收中断了?可我找来找去,还是没有找到清掉I位的操作.
>

kernel/irq/handle.c:
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
irqreturn_t ret, retval = IRQ_NONE;
unsigned int status = 0;

if (!(action->flags & IRQF_DISABLED))
local_irq_enable_in_hardirq();
.......

fiddle yuan

unread,
Jan 28, 2011, 3:50:05 AM1/28/11
to Allen Wang, linux-...@zh-kernel.org
2011/1/24 Allen Wang <elendi...@gmail.com>:

>
>
> 2011/1/23 fiddle yuan <fiddle...@gmail.com>
>>
>> 大家好:
>>
>> 前一段时间看了一点Qualcomm MSM平台下中断处理的代码,发现有些基础知识方面的问题非常迷惑,希望各位不吝赐教,先谢谢了~
>>
>> 问题是:
>> (1). 在MSM平台下(ARM),是否支持中断嵌套?
>
> ARM core only support fiq interrupt irq essentially.
> But based the CPU's interrupt controller, you can use high priority
> irq interrupt low priority irq to implement nested interrupt.
Linux的中断不是不分优先级别的么?你说的这个应该是ARM中断控制器的优先级别吧?如果想实现嵌套的中断,个人认为必须要使得CPSR在中断没有退出之前就清0,否则不算严格意义上的中断"嵌套"吧?这实际上就是问题2了。


>>
>> (2). 如果支持,那么就需要捋清楚整个中断流程
>> 2.1 当IRQ中断来的时候,CPU会自动将CPSR的I位置位,从而禁止新的IRQ中断
>> 2.2 PC会自动设置到0xFFFF0018处
>> 2.3
>> 随后,跳转到vector_irq处执行,此时,处理器处于IRQ模式,vector_irq的代码做了这些操作:修正返回地址(lr),依次将ro,lr,spsr压入栈中(此时的栈应该是IRQ模式下的栈),设置spsr为SVC模式,根据lr计算正确的跳转表项,最后通过更新PC来跳转到相应的跳转表项中(比如,来中断之前处于usr模式,那么就应该跳转到__irq_usr来执行)
>> 2.4
>> 到了__irq_usr中,首先调用usr_entry,把一堆从r0-r15还有一些usr模式下的寄存器压入SVC模式下的栈,然后调用get_thread_info,根据sp找到thread_info,将preempt_count加1,防止内核抢占,再接下来,调用irq_handler来获取中断号,并触发调用asm_do_IRQ(它将调用注册中断时作为参数传进来的中断服务程序),最后,恢复tsk,给why赋值,掉用ret_to_user返回usr模式,结束
>>
>>
>> 以上(2)中的步奏是基于MSM7627平台下,内核版本2.6.32的.问题关健在于整个流程不知道在何处重新将2.1中由CPU自动置位的I位给清掉的?如果没有清掉,显然是无法实现中断嵌套的,并且也不可能没有清掉,否则返回usr模式后岂不是无发接收中断了?可我找来找去,还是没有找到清掉I位的操作.
>
>
> kernel/irq/handle.c:
> irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
> {
> irqreturn_t ret, retval = IRQ_NONE;
> unsigned int status = 0;
> if (!(action->flags & IRQF_DISABLED))
> local_irq_enable_in_hardirq();
> .......
> }
>

简单看了一下你说的这个流程,应该是这样:假如中断初始化的时候设置了电平触发方式:
handle_level_irq调用handle_IRQ_event,而handle_IRQ_event又调用了local_irq_enable_in_hardirq,是么?

在kernel/include/linux/interrupt.h中,local_irq_enable_in_hardirq是一个宏,定义成了local_irq_enable
#define local_irq_enable_in_hardirq() local_irq_enable()

在kernel/include/linux/irqflags.h中,local_irq_enable又进一步定义成:
#define local_irq_enable() \
do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0)

再跟下去,在kernel/arch/arm/include/asm/irqflags.h中:
#if __LINUX_ARM_ARCH__ >= 6
#define raw_local_irq_enable() __asm__("cpsie i @ __sti" : : : "memory", "cc")
......
#else
#define raw_local_irq_enable() \
({ \
unsigned long temp; \
__asm__ __volatile__( \
"mrs %0, cpsr @ local_irq_enable\n" \
" bic %0, %0, #128\n" \
" msr cpsr_c, %0" \
: "=r" (temp) \
: \
: "memory", "cc"); \
})
......

实在是有点惭愧,接触Linux时间不长,这个就是传说中的AT&T格式的汇编么?
而且如果对于ARM11,就是if分支,只有一个cpsie,就可以搞定么?
如果对于ARM9,则是else分支,这个里面貌似格式不太懂,呵呵~有什么参考文档么?

以上是我依据你的提示看到的代码,不知道正确与否,同时还有汇编格式的疑问,如果可以,麻烦您再抽空指导一下,谢谢了~

Peter Chen

unread,
Jan 29, 2011, 3:20:25 AM1/29/11
to fiddle yuan, linux-...@zh-kernel.org
2011/1/28 fiddle yuan <fiddle...@gmail.com>:
这个函数就是允许arm的中断,在最新的代码里,已经没有这行了,也就是中断禁止被打断,也就是不允许中断嵌套。
arm体系结构也在不断的更新,会有一些新的有用的指令出来,来执行一些过去需要很多很多指令才能执行的东西。

>>>
>>> 不知道哪位高人能够指点一二,在此谢谢各位~
>>> _______________________________________________
>>> Linux 内核开发中文邮件列表
>>> Linux-...@zh-kernel.org
>>> http://zh-kernel.org/mailman/listinfo/linux-kernel
>>> Linux 内核开发中文社区: http://zh-kernel.org
>>
> _______________________________________________
> Linux 内核开发中文邮件列表
> Linux-...@zh-kernel.org
> http://zh-kernel.org/mailman/listinfo/linux-kernel
> Linux 内核开发中文社区: http://zh-kernel.org

--
BR,
Peter Chen

Reply all
Reply to author
Forward
0 new messages