- 论坛徽章:
- 0
|
这是基于Freebsd2_2版本的中断处理过程,到5.x后好象改成线程了,没有了这些古老的代码.写出来的原因是因为不知是否理解的正确,希望大家批评指正,以后我不会看代码了,一方面是太辛苦,另一方面是没从这些知识中看到前(钱)途,虽然不会没饭吃,工作也很稳定,很闲 ,但对家庭来说还是没有帮助,兴趣将转向厚黑学,哈哈.生活就是这样.
_cpl 其初值是全'0xFFFFFFFF' ,all off 屏蔽所有的中断.系统初始化完成后将调用spl0()从而开放所
有中断,此时cpl将是"0".一个中断进入处理之前会置相应的位为'1' ,同时也要把之前的cpl保存,一般是保存在STACK中到doreti再处理,cpl 中0-15位对应8259A的硬件中断,16-31是软中断用.
_ipending是OS的全局变量是interrupt pending 意思是还没处理的中断,其初值是'0',如果低优先级的中断在高优先级中断开放中断(sti)处理时得到响应会在ipending中相应地方置位,不进行中断服务程序的处理就退回到高优先级中断处理过程.
u_int intr_mask[ICU_LEN] “sets of intrs masked during handling of 1”这是英文注解,对应某一中断的中断屏蔽集,这个变量我是花了不少时间但是还是看不懂,希望有朋友给说说,我只是猜测一个我认为合理的解释.每个硬件中断都应该在ipl中把比它优先级低的中断屏蔽,这样的目的是为了高优先级中断能在适当的时候注意到有低优先级的中断发生了,从而能把低优先级中断挂在ipending中而不至于被低优先级中断,等到高优先级中断结束时低优先级中断得到处理.cpl中从0-31位优先级递增,最高是0,最低是31位对应的中断,硬中断比软中断优先级高,比如中断7的是intr_mask[7]
=0xffffff80,0到6位的优先级比7要高所以是不能屏蔽的,8到31位对应的中断优先级比7低所以会屏蔽.中断7本身也屏蔽,由于中断并不是用完所有的32位,所以为了减少无用的处理,没有和中断联系的位将不会是’1’而是’0’.
中断处理(包括TRAP)一般是通过_doreti退出,在进入doreti前都会在STACK中压入这次中断前的cpl和向量号.
static inthand_t *fastintr[ICU_LEN] = {
&IDTVEC(fastintr0), &IDTVEC(fastintr1),
. . .
&IDTVEC(fastintr14), &IDTVEC(fastintr15)
}
static inthand_t *slowintr[ICU_LEN] = {
&IDTVEC(intr0), &IDTVEC(intr1), &IDTVEC(intr2), &IDTVEC(intr3),
. . .
&IDTVEC(intr12), &IDTVEC(intr13), &IDTVEC(intr14), &IDTVEC(intr15)
}
fastintrXX和intrXX在i386isavectors.s 里定义,象时钟中断,硬盘中断采用FAST_INTR.以下是宏定义和解释.
#define FAST_INTR(irq_num, vec_name, enable_icus)
.text
SUPERALIGN_TEXT
IDTVEC(vec_name)
pushl %eax
pushl %ecx
pushl %edx
pushl %ds 保护现场,快速中断只保护部分现场.
MAYBE_PUSHL_ES
movl $KDSEL,%eax
movl %ax,%ds ds选择符指向系统数据段
MAYBE_MOVW_AX_ES
FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) 可能是时间片的统计,没细看
pushl _intr_unit + (irq_num) * 4 压入中断号做参数
call *_intr_handler + (irq_num) * 4 * 调用中断服务处理程序 *
enable_icus * 使中断控制器进行工作,如选出高优先级中断,但现在CPU不会响应 *
addl $4,%esp 恢复STACK
incl _cnt+V_INTR * 应该是系统的中断统计 *
movl _intr_countp + (irq_num) * 4,%eax *针对某中断的统计*
incl (%eax)
movl _cpl,%eax
notl %eax
andl _ipending,%eax 这个比较的意思是看是否有没被处理的中断
jne 2f
1:
MEXITCOUNT
MAYBE_POPL_ES
popl %ds
popl %edx
popl %ecx
popl %eax
iret
2: 处理挂起的中断,包括硬中断和软中断
cmpb $3,_intr_nesting_level * 限制中断嵌套数,防止栈溢出 *
jae 1b 超过将中断返回
movl _cpl,%eax
movl $HWI_MASK|SWI_MASK,_cpl
incb _intr_nesting_level
sti 开中断,前面enable_icus后中断控制器选出的中断无论优先级如何都得到CPU的响应,但不一定得到处理,可能只是被挂在ipending中.
MAYBE_POPL_ES
popl %ecx
popl %edx
xchgl %eax,4(%esp)
pushal
pushl %ecx
pushl %es
movl $KDSEL,%eax
movl %ax,%es
movl (2+8+0)*4(%esp),%ecx
movl %ecx,(2+6)*4(%esp)
movl (2+8+1)*4(%esp),%eax
pushl %eax
subl $4,%esp
* Sti开中断后到这里的指令是构造一个统一的栈祯(stack frame)以方便进入doreti中 *
MEXITCOUNT 系统的时间片统计.
jmp _doreti
#define INTR(irq_num, vec_name, icu, enable_icus, reg)
IDTVEC(vec_name)
pushl $0
pushl $0
pushal 保存通用寄存器,eax,ebx,ecx,edx,ebp. . .
pushl %ds
pushl %es 到这里所有的寄存器都保存在堆栈中了.
movl $KDSEL,%eax
movl %ax,%ds
movl %ax,%es
以下的四条汇编是为了在8259中把当前中断的中断位 置位以屏蔽当前中断
movb _imen + IRQ_BYTE(irq_num),%al
orb $IRQ_BIT(irq_num),%al
movb %al,_imen + IRQ_BYTE(irq_num)
outb %al,$icu+ICU_IMR_OFFSET
enable_icus 使中断控制器(8259)正常工作以选出优先级最高的中断给CPU
movl _cpl,%eax
testb $IRQ_BIT(irq_num),%reg
jne 2f
跳转的条件是cpl中的相应位被置'1',也就是该中断被屏蔽,因此要把中断挂在ipending,这个被挂起的中断应该是比当前正在处理的中断优先级有低.
incb _intr_nesting_level
__CONCAT(Xresume,irq_num): 被挂起的中断得到处理的时候都是从这里开始的
FAKE_MCOUNT(12*4(%esp))
incl _cnt+V_INTR
movl _intr_countp + (irq_num) * 4,%eax
incl (%eax)
movl _cpl,%eax
pushl %eax 用于传递给doreti
pushl _intr_unit + (irq_num) * 4
orl _intr_mask + (irq_num) * 4,%eax 提升优先级的地方.
movl %eax,_cpl 设置当前中断的cpl
sti 开中断.8259中断控制器选出的中断从这里开始将得到CPU的注意
call *_intr_handler + (irq_num) * 4
cli
以下的四条汇编的目的是把8259中中断进入时被屏蔽的当前中断打开
movb _imen + IRQ_BYTE(irq_num),%al
andb $~IRQ_BIT(irq_num),%al
movb %al,_imen + IRQ_BYTE(irq_num)
outb %al,$icu+ICU_IMR_OFFSET
sti
MEXITCOUNT 时间片计数
jmp _doreti
2:
orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) 把中断挂在ipending中
popl %es
popl %ds
popal
addl $4+4,%esp
iret 中断返回,在这里一般是返回更高优先级的中断,继续高优先级中断的处理.
[ 本帖最后由 bhpang2 于 2005-12-13 13:00 编辑 ] |
|