linux中断的流程,linux中断流程 - 连志安的博客的个人空间 - OSCHINA - 中文开源技术交流社区...

启动内核函数:

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

本文同步分享在 博客“连志安的博客”(CSDN)。

如有侵权,请联系 support@oschina.cn 删除。

本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值