启动内核函数:

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 注册的中断处理函数了。