分类: LINUX
2010-04-22 20:56:13
1、entry_armv.S有系统中断向量表
__vectors_start:
swi SYS_ERROR0 b vector_und + stubs_offset ldr pc, .LCvswi + stubs_offset b vector_pabt + stubs_offset b vector_dabt + stubs_offset b vector_addrexcptn + stubs_offset b vector_irq + stubs_offset b vector_fiq + stubs_offset 当有中断到来时会跳到 b vector_irq + stubs_offset处执行,这里是由一个通用的宏来处理,根据发生中断时是在用户态还是内核态分别由__irq_usr或__irq_svc来处理,它们最后都会调用asm_do_IRQ,参数用中断号(通过entry-maro.s中的get_irqnr_and_base获取)、寄存器。注意这时中断可是关闭的也就是cpsr寄予存器的I标志,在调用asm_do_irq之后还会重新调用get_irqnr_and_base去查找是不是还有新的中断,如果有则再次调用asm_do_irq,如果没用才会返回被中断的代码继续执行,在整个过程中cpsr的中断标志一直是禁止的。
2、asm_do_IRQ在arch/arm/kernel/irq.c中:
1)设置当前进程的处理中断标志;
2)按中断号进入相应的中断处理程序,即调用中断描符的成员handle;
3)检查是否有挂起的中断,如果有则处理;
4)去除当前中断处理标志。
5)如果当前不在中断中,且有软中断要处理则处理软中断。
3、上一步说按中断号进入相应的中断处理程序,下面说个个中断处理程序是如何注册的。
1)在main.c中start_kernel->init_IRQ中会首先把中断描述表初始化为bad_irq_desc(就是没意义),再调用平台相关的init_arch_irq(),这是在setup.c里setup_arch赋值的,对应的是mach_smdk2410.c里的smdk2410_init_irq。
2)smdk2410_init_irq首先清中断;然后为每一个中断描符的成员chip设置s3c_irq_level_chip或s3c_irq_chip,这个主要用来设置中断寄存器,用来屏蔽中断等;再为每一个中断描符的成员handle设置
do_level_IRQ或do_edge_IRQ, 这两个的区别是一个来中断时关不关中断;中断描述符表里的action,是个各驱动注册的中断处理程序, do_level_IRQ或do_edge_IRQ这两个函数会调用所有action.
3)这里也有对子中断的处理。
4、软中断处理:
说明一下,软中断就是在中断的下半部来处理的,中断是打开的;定义如下
struct softirq_action softirq_vec[32];从理论上可以有32个软中断,但实际上只用到了前6个,从0到5;每个数组项里有一个要处理的函数,在第3步处理完中断后就会检查softirq_ver的每一项如果有挂起的则处理,如果处理时间太长,就唤醒ksoftirqd内核线程来处理。
5、tasklet,这个就是利用上面的第5个软中断的处理函数来变相处理的,过程如下:
利用open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);这个把第5个软中断也就是tasklet的处理函数注册为tasklet_action;为此定义了一个变量DEFINE_PER_CPU(struct tasklet_head, tasklet_vec) = { NULL };task_vec基本上是一个链表,里面的每一项就是真正的task_let函数,这样tasklet_action调用task_vec链表里的每一个要片处理的task_let函数,这样就实现了task_let.
6、有一点没有搞清,因为在进入中断时cpu的中断位是禁止的,我一直没找到再哪是打开的,不太理解如果是这样,linux是不支持中断嵌套的。
7、工作队列,下面的链接说的很好,http://blog.csdn.net/sailor_8318/archive/2008/07/16/2657294.aspx。
|