- 論壇徽章:
- 0
|
這是基于Freebsd2_2版本的中斷處理過(guò)程,到5.x后好象改成線程了,沒(méi)有了這些古老的代碼.寫出來(lái)的原因是因?yàn)椴恢欠窭斫獾恼_,希望大家批評(píng)指正,以后我不會(huì)看代碼了,一方面是太辛苦,另一方面是沒(méi)從這些知識(shí)中看到前(錢)途,雖然不會(huì)沒(méi)飯吃,工作也很穩(wěn)定,很閑 ,但對(duì)家庭來(lái)說(shuō)還是沒(méi)有幫助,興趣將轉(zhuǎn)向厚黑學(xué),哈哈.生活就是這樣.
_cpl 其初值是全'0xFFFFFFFF' ,all off 屏蔽所有的中斷.系統(tǒng)初始化完成后將調(diào)用spl0()從而開(kāi)放所
有中斷,此時(shí)cpl將是"0".一個(gè)中斷進(jìn)入處理之前會(huì)置相應(yīng)的位為'1' ,同時(shí)也要把之前的cpl保存,一般是保存在STACK中到doreti再處理,cpl 中0-15位對(duì)應(yīng)8259A的硬件中斷,16-31是軟中斷用.
_ipending是OS的全局變量是interrupt pending 意思是還沒(méi)處理的中斷,其初值是'0',如果低優(yōu)先級(jí)的中斷在高優(yōu)先級(jí)中斷開(kāi)放中斷(sti)處理時(shí)得到響應(yīng)會(huì)在ipending中相應(yīng)地方置位,不進(jìn)行中斷服務(wù)程序的處理就退回到高優(yōu)先級(jí)中斷處理過(guò)程.
u_int intr_mask[ICU_LEN] “sets of intrs masked during handling of 1”這是英文注解,對(duì)應(yīng)某一中斷的中斷屏蔽集,這個(gè)變量我是花了不少時(shí)間但是還是看不懂,希望有朋友給說(shuō)說(shuō),我只是猜測(cè)一個(gè)我認(rèn)為合理的解釋.每個(gè)硬件中斷都應(yīng)該在ipl中把比它優(yōu)先級(jí)低的中斷屏蔽,這樣的目的是為了高優(yōu)先級(jí)中斷能在適當(dāng)?shù)臅r(shí)候注意到有低優(yōu)先級(jí)的中斷發(fā)生了,從而能把低優(yōu)先級(jí)中斷掛在ipending中而不至于被低優(yōu)先級(jí)中斷,等到高優(yōu)先級(jí)中斷結(jié)束時(shí)低優(yōu)先級(jí)中斷得到處理.cpl中從0-31位優(yōu)先級(jí)遞增,最高是0,最低是31位對(duì)應(yīng)的中斷,硬中斷比軟中斷優(yōu)先級(jí)高,比如中斷7的是intr_mask[7]
=0xffffff80,0到6位的優(yōu)先級(jí)比7要高所以是不能屏蔽的,8到31位對(duì)應(yīng)的中斷優(yōu)先級(jí)比7低所以會(huì)屏蔽.中斷7本身也屏蔽,由于中斷并不是用完所有的32位,所以為了減少無(wú)用的處理,沒(méi)有和中斷聯(lián)系的位將不會(huì)是’1’而是’0’.
中斷處理(包括TRAP)一般是通過(guò)_doreti退出,在進(jìn)入doreti前都會(huì)在STACK中壓入這次中斷前的cpl和向量號(hào).
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 里定義,象時(shí)鐘中斷,硬盤中斷采用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 保護(hù)現(xiàn)場(chǎng),快速中斷只保護(hù)部分現(xiàn)場(chǎng).
MAYBE_PUSHL_ES
movl $KDSEL,%eax
movl %ax,%ds ds選擇符指向系統(tǒng)數(shù)據(jù)段
MAYBE_MOVW_AX_ES
FAKE_MCOUNT((4+ACTUALLY_PUSHED)*4(%esp)) 可能是時(shí)間片的統(tǒng)計(jì),沒(méi)細(xì)看
pushl _intr_unit + (irq_num) * 4 壓入中斷號(hào)做參數(shù)
call *_intr_handler + (irq_num) * 4 * 調(diào)用中斷服務(wù)處理程序 *
enable_icus * 使中斷控制器進(jìn)行工作,如選出高優(yōu)先級(jí)中斷,但現(xiàn)在CPU不會(huì)響應(yīng) *
addl $4,%esp 恢復(fù)STACK
incl _cnt+V_INTR * 應(yīng)該是系統(tǒng)的中斷統(tǒng)計(jì) *
movl _intr_countp + (irq_num) * 4,%eax *針對(duì)某中斷的統(tǒng)計(jì)*
incl (%eax)
movl _cpl,%eax
notl %eax
andl _ipending,%eax 這個(gè)比較的意思是看是否有沒(méi)被處理的中斷
jne 2f
1:
MEXITCOUNT
MAYBE_POPL_ES
popl %ds
popl %edx
popl %ecx
popl %eax
iret
2: 處理掛起的中斷,包括硬中斷和軟中斷
cmpb $3,_intr_nesting_level * 限制中斷嵌套數(shù),防止棧溢出 *
jae 1b 超過(guò)將中斷返回
movl _cpl,%eax
movl $HWI_MASK|SWI_MASK,_cpl
incb _intr_nesting_level
sti 開(kāi)中斷,前面enable_icus后中斷控制器選出的中斷無(wú)論優(yōu)先級(jí)如何都得到CPU的響應(yīng),但不一定得到處理,可能只是被掛在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開(kāi)中斷后到這里的指令是構(gòu)造一個(gè)統(tǒng)一的棧禎(stack frame)以方便進(jìn)入doreti中 *
MEXITCOUNT 系統(tǒng)的時(shí)間片統(tǒng)計(jì).
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中把當(dāng)前中斷的中斷位 置位以屏蔽當(dāng)前中斷
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)正常工作以選出優(yōu)先級(jí)最高的中斷給CPU
movl _cpl,%eax
testb $IRQ_BIT(irq_num),%reg
jne 2f
跳轉(zhuǎn)的條件是cpl中的相應(yīng)位被置'1',也就是該中斷被屏蔽,因此要把中斷掛在ipending,這個(gè)被掛起的中斷應(yīng)該是比當(dāng)前正在處理的中斷優(yōu)先級(jí)有低.
incb _intr_nesting_level
__CONCAT(Xresume,irq_num): 被掛起的中斷得到處理的時(shí)候都是從這里開(kāi)始的
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 提升優(yōu)先級(jí)的地方.
movl %eax,_cpl 設(shè)置當(dāng)前中斷的cpl
sti 開(kāi)中斷.8259中斷控制器選出的中斷從這里開(kāi)始將得到CPU的注意
call *_intr_handler + (irq_num) * 4
cli
以下的四條匯編的目的是把8259中中斷進(jìn)入時(shí)被屏蔽的當(dāng)前中斷打開(kāi)
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 時(shí)間片計(jì)數(shù)
jmp _doreti
2:
orb $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) 把中斷掛在ipending中
popl %es
popl %ds
popal
addl $4+4,%esp
iret 中斷返回,在這里一般是返回更高優(yōu)先級(jí)的中斷,繼續(xù)高優(yōu)先級(jí)中斷的處理.
[ 本帖最后由 bhpang2 于 2005-12-13 13:00 編輯 ] |
|