[fW]中断处理函数数组interrupt[]初始化
2013-10-18 14:36
281 查看
中断处理函数数组interrupt[]初始化 2011-05-13 15:51:40
分类: LINUX
在系统初始化期间,trap_init()函数将对中断描述符表IDT进行第二次初始化(第一次只是建一张IDT表,让其指向ignore_intr函数),而在这次初始化期间,系统的0~19号中断(用于分NMI和异常的中断向量)均被设置好。与此同时,用于系统调用的0x80号向量也已被设置。
然而,对于外部中断的初始化 却没有在这个函数中进行。而是在函数init_IRQ中。
仔细想一想内核这样做,的确是使代码清晰又有条理。
1)trap_init -----> 内部中断异常和NMI(中断向量号:0~19)
2) init_IRQ -----> 外部可屏蔽中断 (中断向量号:32~127,129~238)
在init_IRQ函数中,对IDT中断描述符表进行了第三次完善(把相应的外部中断对应的中断向量进行填充)
410 for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
411 int vector = FIRST_EXTERNAL_VECTOR + i;
412 if (i >= NR_IRQS)
413 break;
414 if (vector != SYSCALL_VECTOR)
415 set_intr_gate(vector, interrupt[i]);
416 }
上述代码解释:
FIRST_EXTERNAL_VECTOR =0x20;
http://lxr.linux.no/linux+v3.10/arch/x86/include/asm/irq_vectors.h#L35
设置中断向量号32---NR_IRQS相应的中断处理程序地址为数组interrupt[i]的内容。(除去128号中断向量,已经这个向量号已经被用于系统调用)。
我们看一下interrupt数组的定义:这段程序时用汇编写的。
540 .data
541 ENTRY(interrupt)
542 .text
543
544 vector=0
545 ENTRY(irq_entries_start)
546 RING0_INT_FRAME
547 .rept NR_IRQS
548 ALIGN
549 .if vector
550 CFI_ADJUST_CFA_OFFSET -4
551 .endif
552 1: pushl $~(vector)
553 CFI_ADJUST_CFA_OFFSET 4
554 jmp common_interrupt
555 .data
556 .long 1b
557 .text
558 vector=vector+1
559 .endr
上面的代码开起来很乱,我们整理一下,使其更加易读,但是又不失其本质。
.data
ENTRY(interrupt)
.long 1b //注意 如果把数据段放在这里那么1b要改为1f了,而且失去循环执行NR_IRQS次的功能。
//我们只能人为的把他们想象成被循环执行了NR_IRQS次 :)
.text
vector=0
ENTRY(irq_entries_start)
.rept NR_IRQS
1: pushl $~(vector)
jmp common_interrupt
vector=vector+1
我们把数据段放在一起,代码段放在一起。注意这里的代码段是用来初始化数据段的。
我们看到:interrupt作为一个内存标签,其内容为代码段标号1所表示的地址。同时我们也注意到这个interrupt数组的所有项的内容都是一样的:全部为“标号1”的符号地址。
每次外部中断来临时,硬件自动根据PIC或者APIC送出来的中断类型码(中断向量号)去查找中断描述符表的相应项,然后得到interrupt[n]的内容,继而转去执行标号1地址的代码,而标号1的代码仅将中断号取反后压入栈中,后立马跳到common_interupt标号处去执行。至于为什么要把中断向量号取反后压栈,则是由于内核用正的相应号去表示系统调用号,用负号来表示中断号。
细心的你有可能发现了一个问题:上述代码片段只是向interrupt表示的内存地址处存入大量重复的4字节数据,却没有象C语言定义数组那样定义interrupt[NR_IRQS-1],那么set_intr_gate这样的函数是如何确切的指导interrupt是一个数组呢,而且数组的内容是函数指针?
例如:set_intr_gate(vector,interrupt[i]);是如何取interrupt[i]内容呢?
啰嗦了这么半天...
如下一个声明就搞定了。
extern void (*interrupt[NR_IRQS])(void);//函数指针数组
566 common_interrupt:
567 SAVE_ALL
568 TRACE_IRQS_OFF
569 movl %esp,%eax
570 call do_IRQ
571 jmp ret_from_intr
572 CFI_ENDPROC
common_interrupt首先执行宏SAVE_ALL保存中断处理程序可能用到的寄存器(注意:cs eip ss esp由硬件自动保存)然后把栈顶指针传给eax寄存器后(eax寄存器内容将作为do_IRQ函数的参数)调用do_IRQ进行中断处理,返回后
执行ret_from_intr从中断返回。
分类: LINUX
在系统初始化期间,trap_init()函数将对中断描述符表IDT进行第二次初始化(第一次只是建一张IDT表,让其指向ignore_intr函数),而在这次初始化期间,系统的0~19号中断(用于分NMI和异常的中断向量)均被设置好。与此同时,用于系统调用的0x80号向量也已被设置。
然而,对于外部中断的初始化 却没有在这个函数中进行。而是在函数init_IRQ中。
仔细想一想内核这样做,的确是使代码清晰又有条理。
1)trap_init -----> 内部中断异常和NMI(中断向量号:0~19)
2) init_IRQ -----> 外部可屏蔽中断 (中断向量号:32~127,129~238)
在init_IRQ函数中,对IDT中断描述符表进行了第三次完善(把相应的外部中断对应的中断向量进行填充)
410 for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
411 int vector = FIRST_EXTERNAL_VECTOR + i;
412 if (i >= NR_IRQS)
413 break;
414 if (vector != SYSCALL_VECTOR)
415 set_intr_gate(vector, interrupt[i]);
416 }
上述代码解释:
FIRST_EXTERNAL_VECTOR =0x20;
http://lxr.linux.no/linux+v3.10/arch/x86/include/asm/irq_vectors.h#L35
设置中断向量号32---NR_IRQS相应的中断处理程序地址为数组interrupt[i]的内容。(除去128号中断向量,已经这个向量号已经被用于系统调用)。
我们看一下interrupt数组的定义:这段程序时用汇编写的。
540 .data
541 ENTRY(interrupt)
542 .text
543
544 vector=0
545 ENTRY(irq_entries_start)
546 RING0_INT_FRAME
547 .rept NR_IRQS
548 ALIGN
549 .if vector
550 CFI_ADJUST_CFA_OFFSET -4
551 .endif
552 1: pushl $~(vector)
553 CFI_ADJUST_CFA_OFFSET 4
554 jmp common_interrupt
555 .data
556 .long 1b
557 .text
558 vector=vector+1
559 .endr
上面的代码开起来很乱,我们整理一下,使其更加易读,但是又不失其本质。
.data
ENTRY(interrupt)
.long 1b //注意 如果把数据段放在这里那么1b要改为1f了,而且失去循环执行NR_IRQS次的功能。
//我们只能人为的把他们想象成被循环执行了NR_IRQS次 :)
.text
vector=0
ENTRY(irq_entries_start)
.rept NR_IRQS
1: pushl $~(vector)
jmp common_interrupt
vector=vector+1
我们把数据段放在一起,代码段放在一起。注意这里的代码段是用来初始化数据段的。
我们看到:interrupt作为一个内存标签,其内容为代码段标号1所表示的地址。同时我们也注意到这个interrupt数组的所有项的内容都是一样的:全部为“标号1”的符号地址。
每次外部中断来临时,硬件自动根据PIC或者APIC送出来的中断类型码(中断向量号)去查找中断描述符表的相应项,然后得到interrupt[n]的内容,继而转去执行标号1地址的代码,而标号1的代码仅将中断号取反后压入栈中,后立马跳到common_interupt标号处去执行。至于为什么要把中断向量号取反后压栈,则是由于内核用正的相应号去表示系统调用号,用负号来表示中断号。
细心的你有可能发现了一个问题:上述代码片段只是向interrupt表示的内存地址处存入大量重复的4字节数据,却没有象C语言定义数组那样定义interrupt[NR_IRQS-1],那么set_intr_gate这样的函数是如何确切的指导interrupt是一个数组呢,而且数组的内容是函数指针?
例如:set_intr_gate(vector,interrupt[i]);是如何取interrupt[i]内容呢?
啰嗦了这么半天...
如下一个声明就搞定了。
extern void (*interrupt[NR_IRQS])(void);//函数指针数组
566 common_interrupt:
567 SAVE_ALL
568 TRACE_IRQS_OFF
569 movl %esp,%eax
570 call do_IRQ
571 jmp ret_from_intr
572 CFI_ENDPROC
common_interrupt首先执行宏SAVE_ALL保存中断处理程序可能用到的寄存器(注意:cs eip ss esp由硬件自动保存)然后把栈顶指针传给eax寄存器后(eax寄存器内容将作为do_IRQ函数的参数)调用do_IRQ进行中断处理,返回后
执行ret_from_intr从中断返回。
相关文章推荐
- 《c primer pius》第十章第6题,编写一个程序,初始化一个二维double数组,并利用练习2中的任一函数来把这个数组复制到另一个二维数组(因为二维数组是数组的数组,所以可以使用处理一维数组的
- 函数指针数组在ARM异常中断处理中的应用
- 六、线程的代码实现:pcb栈、线程栈、PCB初始化、中断处理函数、调度函数->多线程调度
- 字符串数组初始化、处理函数
- 字符数组的定义、初始化及引用以及一些常用的字符串处理函数
- hihocoder #1068 : RMQ-ST算法 ( RMQ算法 O(nlogn)处理 O(1)查询 *【模板】 1)初始化d数组直接读入+计算k值用数学函数log2()==*节约时间 )
- 中断处理函数和可重入特性
- dojo对数组的处理函数,dojo.forEach、dojo.every、 dojo.some、 dojo.map等
- c语言:创建一个数组,分别实现函数初始化数组、 清空数组、数组元素的逆置
- Linux中断(interrupt)子系统之三:中断流控处理层
- C Primer plus 10.2 初始化一个double类型的数组,然后把该数组的内容拷贝至3个其它的数组中,使用带数组的表示方法的函数进行第一份拷贝,使用带指针表示方法和指针递增的函..
- Linux中断(interrupt)子系统之三:中断流控处理层
- php数组的相关处理函数(上)
- dll回调给java的函数参数需要有字节数组类型参数的处理
- Linux2.6 中断处理函数和申请中断函数的变化
- 数组处理函数(获取字符数组中一定长度的字符,修改字符数组的某个字符)
- C语言:实现函数init()初始化数组、 实现empty()清空数组、 实现reverse()函数完成数组元素的逆置
- 中断处理程序、中断上下文中处理延时及一些函数的调用规则(调IIC中断驱动有感)
- STL数组处理常用函数
- 其他数组处理函数