启动内核函数:
init/main.c
start_kernel 函数
里面有
trap_init(); //设置异常处理向量,包括中断,某些linux 版本是 setup_arch——early_trap_init
init_IRQ(); //初始化中断
我们看下 early_trap_init
中间我们省略了很多,我们可以看到
void __init early_trap_init(void)
{
//对于arm 架构来说,异常向量基地址可以是 0 ,也可以是 0xffff0000,linux 是 0xffff0000
unsigned long vectors = CONFIG_VECTORS_BASE;
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
//这里把数组内容拷贝到 CONFIG_VECTORS_BASE ,也就是 0xffff0000
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
}
事实上,__vectors_start 存放在 arch\arm\kernel\entry-armv.S
==========================================================
__vectors_start:
ARM( swi SYS_ERROR0 )
THUMB( svc #0 )
THUMB( nop )
W(b) vector_und + stubs_offset
W(ldr) pc, .LCvswi + stubs_offset
W(b) vector_pabt + stubs_offset
W(b) vector_dabt + stubs_offset
W(b) vector_addrexcptn + stubs_offset
W(b) vector_irq + stubs_offset
W(b) vector_fiq + stubs_offset
.globl __vectors_end
__vectors_end:
==========================================================
实际就是一条 b 指令
irq 最终跳转到 asm_do_IRQ 函数处理
arch\arm\kernel\irq.c
最终它会调用其它文件注册的终端处理函数
看下调用过程
asm_do_IRQ
generic_handle_irq
generic_handle_irq_desc(irq, irq_to_desc(irq));
desc->handle_irq(irq, desc);
desc 是一个结构体 irq_desc,最终调用 handle_irq 函数处理
我们先看下 init_IRQ
init_IRQ 主要就是要注册好 desc
最终调用 set_irq_handler(irq, handle_simple_irq);
去设置好 irq_desc[irq]的 handle_irq
例如上面就是注册为 handle_simple_irq
我们进去看看,中间被我删除掉一些代码
void handle_simple_irq(unsigned int irq, struct irq_desc *desc)
{
......
action_ret = handle_IRQ_event(irq, action);
......
}
可以看到最终使用 handle_IRQ_event 去处理我们注册的中断处理函数,我们再进去看看
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
do {
trace_irq_handler_entry(irq, action);
//最终要的函数,这里使用 action 的 handler 去处理
ret = action->handler(irq, action->dev_id);
trace_irq_handler_exit(irq, action, ret);
switch (ret) {
case IRQ_WAKE_THREAD:
ret = IRQ_HANDLED;
if (unlikely(!action->thread_fn)) {
warn_no_thread(irq, action);
break;
}
if (likely(!test_bit(IRQTF_DIED,
&action->thread_flags))) {
set_bit(IRQTF_RUNTHREAD, &action->thread_flags);
wake_up_process(action->thread);
}
/* Fall through to add to randomness */
case IRQ_HANDLED:
status |= action->flags;
break;
default:
break;
}
retval |= ret;
action = action->next;
} while (action);
}
此次我们可以总结如下:
中断发生的时候:
asm_do_IRQ
generic_handle_irq
generic_handle_irq_desc(irq, irq_to_desc(irq));
desc->handle_irq(irq, desc);
handle_IRQ_event(irq, action);
do {action->handler(irq, action->dev_id);}while(action)
那么 action 是什么呢?他是一个 struct irqaction 结构体
这里我们就要引入另外一个地方了,注册中断
事实上我们的中断处理函数呢,我们都可以去注册它
request_irq(unsigned int irq,irq_handler_t handler,unsigned long flags,const char * devname,void * dev_id)
注意
request_threaded_irq——后面会有这样的一个注册函数,
而 request_irq 实际也是调用 request_threaded_irq
=====================================================
int request_threaded_irq(unsigned int irq, irq_handler_t handler,
irq_handler_t thread_fn, unsigned long irqflags,
const char *devname, void *dev_id)
{
struct irqaction *action;
struct irq_desc *desc;
int retval;
/*
* handle_IRQ_event() always ignores IRQF_DISABLED except for
* the _first_ irqaction (sigh). That can cause oopsing, but
* the behavior is classified as "will not fix" so we need to
* start nudging drivers away from using that idiom.
*/
if ((irqflags & (IRQF_SHARED|IRQF_DISABLED)) ==
(IRQF_SHARED|IRQF_DISABLED)) {
pr_warning(
"IRQ %d/%s: IRQF_DISABLED is not guaranteed on shared IRQs\n",
irq, devname);
}
if ((irqflags & IRQF_SHARED) && !dev_id)
return -EINVAL;
desc = irq_to_desc(irq);
if (!desc)
return -EINVAL;
if (desc->status & IRQ_NOREQUEST)
return -EINVAL;
if (!handler) {
if (!thread_fn)
return -EINVAL;
handler = irq_default_primary_handler;
}
action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
if (!action)
return -ENOMEM;
action->handler = handler;
action->thread_fn = thread_fn;
action->flags = irqflags;
action->name = devname;
action->dev_id = dev_id;
chip_bus_lock(irq, desc);
//这里add 进去
retval = __setup_irq(irq, desc, action);
chip_bus_sync_unlock(irq, desc);
if (retval)
kfree(action);
#ifdef CONFIG_DEBUG_SHIRQ
}
======================================================
可以看到,当我们使用 request_threaded_irq 注册后,内核中断产生时,就会跑下面额流程:
asm_do_IRQ
generic_handle_irq
generic_handle_irq_desc(irq, irq_to_desc(irq));
desc->handle_irq(irq, desc);
handle_IRQ_event(irq, action);
do {action->handler(irq, action->dev_id);}while(action)
——这里就会调用我们通过 request_threaded_irq 注册的中断处理函数了。