c语言interrupt函数,中断处理函数数组interrupt[]初始化
在系統(tǒng)初始化期間,trap_init()函數(shù)將對(duì)中斷描述符表IDT進(jìn)行第二次初始化(第一次只是建一張IDT表,讓其指向ignore_intr函數(shù)),而在這次初始化期間,系統(tǒng)的0~19號(hào)中斷(用于分NMI和異常的中斷向量)均被設(shè)置好。與此同時(shí),用于系統(tǒng)調(diào)用的0x80號(hào)向量也已被設(shè)置。
然而,對(duì)于外部中斷的初始化 卻沒(méi)有在這個(gè)函數(shù)中進(jìn)行。而是在函數(shù)init_IRQ中。
仔細(xì)想一想內(nèi)核這樣做,的確是使代碼清晰又有條理。
1)trap_init -----> 內(nèi)部中斷異常和NMI(中斷向量號(hào):0~19)
2)?init_IRQ?? -----> 外部可屏蔽中斷??(中斷向量號(hào):32~127,129~238)
在init_IRQ函數(shù)中,對(duì)IDT中斷描述符表進(jìn)行了第三次完善(把相應(yīng)的外部中斷對(duì)應(yīng)的中斷向量進(jìn)行填充)
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 = 0x16;
設(shè)置中斷向量號(hào)32---NR_IRQS相應(yīng)的中斷處理程序地址為數(shù)組interrupt[i]的內(nèi)容。(除去128號(hào)中斷向量,已經(jīng)這個(gè)向量號(hào)已經(jīng)被用于系統(tǒng)調(diào)用)。
我們看一下interrupt數(shù)組的定義:這段程序時(shí)用匯編寫(xiě)的。
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
上面的代碼開(kāi)起來(lái)很亂,我們整理一下,使其更加易讀,但是又不失其本質(zhì)。
.data
ENTRY(interrupt)
.long 1b //注意 如果把數(shù)據(jù)段放在這里那么1b要改為1f了,而且失去循環(huán)執(zhí)行NR_IRQS次的功能。???????????????????? //我們只能人為的把他們想象成被循環(huán)執(zhí)行了NR_IRQS次 :)
.text
vector=0
ENTRY(irq_entries_start)
.rept NR_IRQS
1: pushl $~(vector)
jmp common_interrupt
vector=vector+1
我們把數(shù)據(jù)段放在一起,代碼段放在一起。注意這里的代碼段是用來(lái)初始化數(shù)據(jù)段的。
我們看到:interrupt作為一個(gè)內(nèi)存標(biāo)簽,其內(nèi)容為代碼段標(biāo)號(hào)1所表示的地址。同時(shí)我們也注意到這個(gè)interrupt數(shù)組的所有項(xiàng)的內(nèi)容都是一樣的:全部為“標(biāo)號(hào)1”的符號(hào)地址。
每次外部中斷來(lái)臨時(shí),硬件自動(dòng)根據(jù)PIC或者APIC送出來(lái)的中斷類型碼(中斷向量號(hào))去查找中斷描述符表的相應(yīng)項(xiàng),然后得到interrupt[n]的內(nèi)容,繼而轉(zhuǎn)去執(zhí)行標(biāo)號(hào)1地址的代碼,而標(biāo)號(hào)1的代碼僅將中斷號(hào)取反后壓入棧中,后立馬跳到common_interupt標(biāo)號(hào)處去執(zhí)行。至于為什么要把中斷向量號(hào)取反后壓棧,則是由于內(nèi)核用正的相應(yīng)號(hào)去表示系統(tǒng)調(diào)用號(hào),用負(fù)號(hào)來(lái)表示中斷號(hào)。
細(xì)心的你有可能發(fā)現(xiàn)了一個(gè)問(wèn)題:上述代碼片段只是向interrupt表示的內(nèi)存地址處存入大量重復(fù)的4字節(jié)數(shù)據(jù),卻沒(méi)有象C語(yǔ)言定義數(shù)組那樣定義interrupt[NR_IRQS-1],那么set_intr_gate這樣的函數(shù)是如何確切的指導(dǎo)interrupt是一個(gè)數(shù)組呢,而且數(shù)組的內(nèi)容是函數(shù)指針?
例如:set_intr_gate(vector,interrupt[i]);是如何取interrupt[i]內(nèi)容呢?
啰嗦了這么半天...
如下一個(gè)聲明就搞定了。[])(void);//函數(shù)指針數(shù)組
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首先執(zhí)行宏SAVE_ALL保存中斷處理程序可能用到的寄存器(注意:cs eip ss esp由硬件自動(dòng)保存)然后把棧頂指針傳給eax寄存器后(eax寄存器內(nèi)容將作為do_IRQ函數(shù)的參數(shù))調(diào)用do_IRQ進(jìn)行中斷處理,返回后
執(zhí)行ret_from_intr從中斷返回。
總結(jié)
以上是生活随笔為你收集整理的c语言interrupt函数,中断处理函数数组interrupt[]初始化的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 泰拉瑞亚寒冰屏障如何获得
- 下一篇: c语言double root,C语言修仙