linux中断机制学习整理
来源:互联网 发布:javascript购物车代码 编辑:程序博客网 时间:2024/05/12 21:47
Linux内核源码:2.6.35
irq_chip
irqaction
early_trap_init函数是将异常向量和异常处理的汇编代码拷贝到内存中,其中异常向量是0xffff0000处,关键代码
这里,异常向量地址在arch/arm/kernel/entry-armv.S中,代码摘抄如下
设置个中断号对应的中断状态,关键代码
中断处理流程
一 发生中断时,CPU执行异常向量vector_irq的代码, 即异常向量表中的中断异常的代码,它是一个跳转指令,跳去执行真正的中断处理程序
二 在vector_irq里面,最终会调用中断处理的总入口函数
asm_do_IRQ,调用代码
generic_handle_irq(irq)函数实现在这
再进一步跟踪下去
里面的desc->handle_irq(irq, desc);即调用irq_desc中的handle_irq(不同的中断会有与其对应的irq_desc结构,所以asm_do_IRQ会根据不同的中断号来调用相应的handle_irq),接下去handle_irq会调用chip成员中的函数来进行一些硬件设置,在调用用户在action链表中注册的处理函数
这个函数的实现如下
调用irqaction中的handler,set_irq_handler(timer_irq, handle_level_irq);/*用户注册的中断处理函数*/
函数功能实现代码
里面会根据中断号调用到desc中的handle_irq,desc->handle_irq = handle;
[irq].handle_irq,对于电平触发中断,这个入口通常为handle_level_irq,对于边沿触发中断,这个入口通常为handle_edge_irq
里面 action_ret = handle_IRQ_event(irq, action);
handle_IRQ_event(irq, action)函数里面实现:
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
工具:source insight 3
内核中断机制三大数据结构
irq_desc
struct irq_desc {unsigned int irq;irq_flow_handler_t handle_irq;struct irq_chip *chip;struct irqaction *action; /* IRQ action list */
irq_chip
struct irq_chip {const char *name; void (*ack)(unsigned int irq); void (*mask)(unsigned int irq); void (*mask_ack)(unsigned int irq); void (*unmask)(unsigned int irq); unsigned int (*startup)(unsigned int irq); void (*shutdown)(unsigned int irq); void (*enable)(unsigned int irq); void (*disable)(unsigned int irq);
irqaction
struct irqaction { irq_handler_t handler; unsigned long flags; const char *name; void *dev_id; struct irqaction *next; int irq; struct proc_dir_entry *dir; irq_handler_t thread_fn; struct task_struct *thread; unsigned long thread_flags;};中断处理中,内核会在start_kernel函数中调用init_IRQ(arch/arm/kernel/irq.c)、和early_trap_init(start_kernel内通过调用setup_arch)来设置异常处理函数,early_trap_init函数功能
early_trap_init函数是将异常向量和异常处理的汇编代码拷贝到内存中,其中异常向量是0xffff0000处,关键代码
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start); memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
这里,异常向量地址在arch/arm/kernel/entry-armv.S中,代码摘抄如下
.equ stubs_offset, __vectors_start + 0x200 - __stubs_start .globl __vectors_start__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:init_IRQ函数功能
设置个中断号对应的中断状态,关键代码
for (irq = 0; irq < NR_IRQS; irq++) irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;\\设置中断状态init_arch_irq();/*对应芯片结构的中断初始化函数,每个架构不同*/例如s3c64xx中的初始化函数
void __init s3c64xx_init_irq(u32 vic0_valid, u32 vic1_valid){ printk(KERN_DEBUG "%s: initialising interrupts\n", __func__); /* initialise the pair of VICs */ vic_init(VA_VIC0, IRQ_VIC0_BASE, vic0_valid, 0); vic_init(VA_VIC1, IRQ_VIC1_BASE, vic1_valid, 0); /* add the timer sub-irqs */ s3c_init_vic_timer_irq(IRQ_TIMER0_VIC, IRQ_TIMER0); s3c_init_vic_timer_irq(IRQ_TIMER1_VIC, IRQ_TIMER1); s3c_init_vic_timer_irq(IRQ_TIMER2_VIC, IRQ_TIMER2); s3c_init_vic_timer_irq(IRQ_TIMER3_VIC, IRQ_TIMER3); s3c_init_vic_timer_irq(IRQ_TIMER4_VIC, IRQ_TIMER4); s3c_init_uart_irqs(uart_irqs, ARRAY_SIZE(uart_irqs));}
中断处理流程
一 发生中断时,CPU执行异常向量vector_irq的代码, 即异常向量表中的中断异常的代码,它是一个跳转指令,跳去执行真正的中断处理程序
二 在vector_irq里面,最终会调用中断处理的总入口函数
asm_do_IRQ,调用代码
adrne lr, BSYM(1b) bne asm_do_IRQ三 asm_do_IRQ根据中断号irq来调用相应的irq_desc
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs){ if (unlikely(irq >= NR_IRQS)) { if (printk_ratelimit()) printk(KERN_WARNING "Bad IRQ%u\n", irq); ack_bad_irq(irq); } else { generic_handle_irq(irq); }}
generic_handle_irq(irq)函数实现在这
static inline void generic_handle_irq(unsigned int irq){ generic_handle_irq_desc(irq, irq_to_desc(irq));}
再进一步跟踪下去
static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc){#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ desc->handle_irq(irq, desc);#else if (likely(desc->handle_irq)) desc->handle_irq(irq, desc); else __do_IRQ(irq);#endif}
里面的desc->handle_irq(irq, desc);即调用irq_desc中的handle_irq(不同的中断会有与其对应的irq_desc结构,所以asm_do_IRQ会根据不同的中断号来调用相应的handle_irq),接下去handle_irq会调用chip成员中的函数来进行一些硬件设置,在调用用户在action链表中注册的处理函数
s3c_init_vic_timer_irq(IRQ_TIMER0_VIC, IRQ_TIMER0);
这个函数的实现如下
void __init s3c_init_vic_timer_irq(unsigned int parent_irq, unsigned int timer_irq){ struct irq_desc *desc = irq_to_desc(parent_irq); set_irq_chained_handler(parent_irq, s3c_irq_demux_vic_timer); set_irq_chip(timer_irq, &s3c_irq_timer); set_irq_handler(timer_irq, handle_level_irq); set_irq_flags(timer_irq, IRQF_VALID); desc->handler_data = (void *)timer_irq;}
调用irqaction中的handler,set_irq_handler(timer_irq, handle_level_irq);/*用户注册的中断处理函数*/
函数功能实现代码
__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, const char *name){ struct irq_desc *desc = irq_to_desc(irq); unsigned long flags; if (!desc) { printk(KERN_ERR "Trying to install type control for IRQ%d\n", irq); return; } if (!handle) handle = handle_bad_irq; else if (desc->chip == &no_irq_chip) { printk(KERN_WARNING "Trying to install %sinterrupt handler " "for IRQ%d\n", is_chained ? "chained " : "", irq); /* * Some ARM implementations install a handler for really dumb * interrupt hardware without setting an irq_chip. This worked * with the ARM no_irq_chip but the check in setup_irq would * prevent us to setup the interrupt at all. Switch it to * dummy_irq_chip for easy transition. */ desc->chip = &dummy_irq_chip; } chip_bus_lock(irq, desc); raw_spin_lock_irqsave(&desc->lock, flags); /* Uninstall? */ if (handle == handle_bad_irq) { if (desc->chip != &no_irq_chip) mask_ack_irq(desc, irq); desc->status |= IRQ_DISABLED; desc->depth = 1; } desc->handle_irq = handle; desc->name = name; if (handle != handle_bad_irq && is_chained) { desc->status &= ~IRQ_DISABLED; desc->status |= IRQ_NOREQUEST | IRQ_NOPROBE; desc->depth = 0; desc->chip->startup(irq); } raw_spin_unlock_irqrestore(&desc->lock, flags); chip_bus_sync_unlock(irq, desc);}
里面会根据中断号调用到desc中的handle_irq,desc->handle_irq = handle;
[irq].handle_irq,对于电平触发中断,这个入口通常为handle_level_irq,对于边沿触发中断,这个入口通常为handle_edge_irq
handle_level_irq函数实现
handle_level_irq(unsigned int irq, struct irq_desc *desc){ struct irqaction *action; irqreturn_t action_ret; raw_spin_lock(&desc->lock); mask_ack_irq(desc, irq); if (unlikely(desc->status & IRQ_INPROGRESS)) goto out_unlock; desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); kstat_incr_irqs_this_cpu(irq, desc); /* * If its disabled or no action available * keep it masked and get out of here */ action = desc->action; if (unlikely(!action || (desc->status & IRQ_DISABLED))) goto out_unlock; desc->status |= IRQ_INPROGRESS; raw_spin_unlock(&desc->lock); action_ret = handle_IRQ_event(irq, action); if (!noirqdebug) note_interrupt(irq, desc, action_ret); raw_spin_lock(&desc->lock); desc->status &= ~IRQ_INPROGRESS; if (!(desc->status & (IRQ_DISABLED | IRQ_ONESHOT))) unmask_irq(desc, irq);out_unlock: raw_spin_unlock(&desc->lock);}
里面 action_ret = handle_IRQ_event(irq, action);
handle_IRQ_event(irq, action)函数里面实现:
irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
do { trace_irq_handler_entry(irq, action); ret = action->handler(irq, action->dev_id);/*调用用户注册函数,action是用irqaction类型,等同于irqaction->handler*/ 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);
- linux中断机制学习整理
- Linux 软中断学习资料整理
- arm linux中断机制学习第一篇
- LINUX 中断处理机制的学习
- linux软中断机制
- linux中断机制分析
- linux中断底半部机制
- linux的中断机制
- LINUX中断机制
- linux中断机制
- Linux 中断机制
- linux软中断机制
- linux中断下半部机制
- linux 中断机制浅析
- linux中断处理机制
- linux 中断机制
- LINUX中断机制
- linux 中断机制浅析
- OpenGL 学习资料
- dom操作的优化方法(节选自高性能JavaScript)
- android pc通过wifi调试手机(无需USB连接)
- 观察所得
- 云中的KVM案例分享:Dutch Cloud
- linux中断机制学习整理
- Apache HttpServer与Tomcat7集群Linux版
- node.js 与 redis 与 express 和session协同工作
- android view三个构造函数研究
- 系统时钟和硬件时钟以及date和hwclock命令
- 观察而得
- 2012年年终总结
- [Review]基于OpenGL的计算机图形学之期末复习提纲
- volatile的一段for循环例子