中断门初始化(init_IRQ)

来源:互联网 发布:淘宝网店计划 编辑:程序博客网 时间:2024/06/06 16:38
1,中断门的设置是在init_IRQ中完成
linux-2.6.11.12\init\main.c:start_kernel->init_IRQ


2,init_IRQ(linux-2.6.11.12\arch\i386\kernel\i8259.c)

1)for循环用于设置中断门,但跳过用于设置系统调用的陷阱门中断向量(SYSCALL_VECTOR,在trap_init中初始化),并跳过CPU使用的0~19异常和非屏蔽中断向量(用于设置陷阱门的中断向量,由trap_init初始化)以及Intel保留的20~31向量。即设置中断门从设置断向量FIRST_EXTERNAL_VECTOR(0x20=32)开始,共NR_IRQS(当没有定义CONFIG_X86_IO_APIC时,只利用了从32号开始的15个(与 8259A中的15个IRQ相对应),即NR_IRQS=15);
2)interrupt[i]为中断处理函数,在linux-2.6.11.12\arch\i386\kernel\entry.S中定义:
     
分析如下:
首先342行和352行都处于.data段,虽然看起来它们是隔开的,但实际上被gcc安排在了连续的数据段内存 中,同理在代码段内存中,354行与350行的指令序列也是连续存储的。另外,348-354行会被gcc展开NR_IRQS次,因此每次352行都会存储一个新的指针,该指针指向每个349行展开的新对象。最后在代码段内存中连续存储了NR_IRQS个代码片断,首地址由 irq_entries_start指向。而在数据段内存中连续存储了NR_IRQS个指针,首址存储在interrupt这个全局变量中。这样,例如 IRQ号是0 (从init_IRQ()调用,它对应的中断向量是FIRST_EXTERNAL_VECTOR)的中断通过中断门后会触发 interrput[0],从而执行:
pushl 0-256
jmp common_interrupt
的代码片断,进入到Linux内核安排好的中断入口路径。

3) set_intr_gate这是中断门,14表示0b1110,即表示中断门;0表示设置dpl=0(用于硬件中断,DPL为0,不允许用户态直接使用int指令访问);idt_table+n表示中断向量n对应的idt表中的位置;__KERNEL_CS表示内核代码段。
     
4),调用pre_intr_init_hook()函数来初始化16个可屏蔽中断的 irq_desc结构体(在Linux之中对于每一个中断有两个重要的数据结构与之对应,他们分别是中断门描述符idt_table和中断请求描述符irq_desc,所谓的中断初始化也就是对这两个数据结构进行初始化);
Linux支持多个外设共享一个IRQ,为了维护中断向量和中断服务例程(ISR)之间的映射关系,Linux用一个irq_desc_t数据结构来描述,叫做IRQ描述符。

status描述中短线状态:
#define IRQ_INPROGRESS  1   /* 正在执行这个IRQ的一个处理程序*/
#define IRQ_DISABLED    2    /* 由设备驱动程序已经禁用了这条IRQ中断线 */
#define IRQ_PENDING     4    /* 一个IRQ已经出现在中断线上,且被应答,但还没有为它提供服务 */
#define IRQ_REPLAY      8    /* 当Linux重新发送一个已被删除的IRQ时 */
#define IRQ_AUTODETECT  16  /* 当进行硬件设备探测时,内核使用这条IRQ中断线 */
#define IRQ_WAITING     32   /*当对硬件设备进行探测时,设置这个状态以标记正在被测试的irq */
#define IRQ_LEVEL       64    /* IRQ level triggered */
#define IRQ_MASKED      128    /* IRQ masked - shouldn't be seen again */
#define IRQ_PER_CPU     256     /* IRQ is per CPU */

handler:指向hw_interrupt_type描述符,这个描述符是对中断控制器的描述。
action:指向一个单向链表的指针,这个链表就是对中断服务例程进行描述的irqaction结构。
depth:如果启用这条IRQ中断线,depth则为0,如果禁用这条IRQ中断线不止一次,则为一个正数。每当调用一次disable_irq(),该函数就对这个域的值加1,如果depth等于0,该函数就禁用这条IRQ中断线。相反,每当调用enable_irq()函数时,该函数就对这个域的值减1;如果depth变为0,该函数就启用这条IRQ中断线。
lock:保护该数据结构的自旋锁。

irqaction结构(next指向下一个irqaction结构):

handler:指向一个具体I/O设备的中断服务例程。这是允许多个设备共享同一中断线的关键域。
flags:用一组标志描述中断线与I/O设备之间的关系。
SA_INTERRUPT
中断处理程序必须以禁用中断来执行
SA_SHIRQ
该设备允许其中断线与其他设备共享,注意在同一个给定线上注册的每个处理程序必须制定这个标志,否则,在每条线上只能有一个中断处理程序。
SA_SAMPLE_RANDOM
可以把这个设备看作是随机事件发生源;因此,内核可以用它做随机数产生器。(用户可以从/dev/random 和/dev/urandom设备文件中取得随机数而访问这种特征)
SA_PROBE
内核在执行硬件设备探测时正在使用这条中断线。
name:I/O设备名(通过读取/proc/interrupts文件,可以看到,在列出中断号时也显示设备名。)
dev_id:指定I/O设备的主设备号和次设备号。当一个中断处理程序需要从一个中断线上注册(dev_id作为注册函数
request_irq的入参)或释放时,dev_id将提供唯一的标示。如删除中断程序时,将会删除dev_id指定的这一个,如果没有这个参数,内核不可能知道在给定的中断线上到底要删除哪一个处理程序。如果无需共享中短线,那么将参数赋值为NULL就可以了。
next:指向irqaction描述符链表的下一个元素。共享同一中断线的每个硬件设备都有其对应的中断服务例程,链表中的每个元素就是对相应设备及中断服务例程的描述。
irq:IRQ线。



由上述代码可知,初始化时让所有的中断线都处于禁用状态,每条中断线上还没有任何中断服务例程(action为0,即链表为空),因为中断线被禁用,因此depth为1。当调用request_irq注册中断时,将覆盖掉这些初始值。
0 0
原创粉丝点击