不論是使用者程序還是系統核心都要經常使用中斷或遇到很多異常情況需要處理,如cpu在參與運算過程中,可能會遇到除零錯誤、溢出錯誤、邊界檢查錯誤、缺頁錯誤……免不了需要“異常處理”。中斷技術也是廣泛使用的,系統調用就是利用中斷技術實作的。這些中斷、異常都需要具體的服務程式來執行。trap_init()函數将中斷、異常處理的服務程式與idt進行挂接,逐漸重建中斷服務體系,支援核心、程序在主機中的運算。挂接的具體過程及異常處理類中斷服務程式在idt中所占用的位置如圖2-6所示。
執行代碼如下:
這些代碼的目的就是要拼出第1章1.3.5節講述過的中斷描述符。為了便于閱讀,複制在下面,如圖2-7所示。
上述代碼的執行效果如圖2-8所示。
對比:
set_trap_gate(0,&divide_error)
set_trap_gate(n,addr)
_set_gate(&idt[n],15,0,addr)
_set_gate(gate_addr,type,dpl,addr)
可以看出,n是0;gate_addr是&idt[0],也就是idt的第一項中斷描述符的位址;type是15;dpl(描述符特權級)是0;addr是中斷服務程式divide_error(void)的入口位址,如圖2-9所示。
“movw %%dx,%%axnt”是把edx的低字指派給eax的低字;edx是(char ) (addr),也就是&divide_error;eax的值是0x00080000,這個資料在head.s中就提到過,8應該看成1000,每一位都有意義,這樣eax的值就是0x00080000 + ((char )(addr)的低字),其中的0x0008是段選擇符,含義與第1章中講解過的“jmpi 0,8”中的8一緻。
"movw %0,%%dxnt”是把(short) (0x8000 + (dpl<<13) + (type<<8))指派給dx。别忘了,edx是(char *) (addr),也就是&divide_error。
因為這部分資料是按位拼接的,必須計算精确,我們耐心詳細計算一下:
0x8000就是二進制的1000 0000 0000 0000;
dpl是00,dpl<<13就是000 0000 0000 0000;
type是15,type<<8就是1111 0000 0000;
加起來就是1000 1111 0000 0000,這就是dx的值。edx的計算結果就是(char *) (addr) 的高字即&divide_error的高字 + 1000 1111 0000 0000。
"movl %%eax,%1nt”是把eax的值賦給((char ) (gate_addr)),就是賦給idt[0]的前4位元組。同理,"movl %%edx,%2”是把edx的值賦給(4 + (char ) (gate_addr)),就是賦給idt[0]的前後4位元組。8位元組合起來就是完整的idt[0]。拼接的效果如圖2-10所示。
idt中的第一項除零錯誤中斷描述符初始化完畢,其餘異常處理服務程式的中斷描述符初始化過程大同小異。後續介紹的所有中斷服務程式與idt的初始化基本上都是以這種方式進行的。
set_system_gate(n,addr)與set_trap_gate(n,addr)用的_set_gate(gate_addr,type,dpl,addr)是一樣的;差别是set_trap_gate的dpl是0,而set_system_gate的dpl是3。dpl為0的意思是隻能由核心處理,dpl為3的意思是系統調用可以由3特權級(也就是使用者特權級)
調用。
有關特權級更深入的内容,請參看《intel ia-32 architectures software developer’s manual volume 3.pdf》(可以到intel官方網站下載下傳)。
接下來将idt的int 0x11~int 0x2f都初始化,将idt中對應的指向中斷服務程式的指針設定為reserved(保留)。
設定協處理器的idt項。
允許主8259a中斷控制器的irq2、irq3的中斷請求。
設定并口(可以接列印機)的idt項。
32位中斷服務體系是為适應“被動響應”中斷信号機制而建立的。其特點、技術路線是這樣的:一方面,硬體産生信号傳達給8259a,8259a對信号進行初步處理并視cpu執行情況傳遞中斷信号給cpu;另一方面,cpu如果沒有接收到信号,就不斷地處理正在執行的程式,如果接收到信号,就打斷正在執行的程式并通過idt找到具體的中斷服務程式,讓其執行,執行完後,傳回剛才打斷的程式點繼續執行。如果又接收到中斷信号,就再次進行中斷……
最原始的設計不是這樣,那時候cpu每隔一段時間就要對所有硬體進行輪詢,以檢測它的工作是否完成,如果沒有完成就繼續輪詢,這樣就消耗了cpu處理使用者程式的時間,降低了系統的綜合效率。可見,cpu以“主動輪詢”的方式來處理信号是非常不劃算的。以“被動響應”模式替代“主動輪詢”模式來處理主機與外設的i/o問題,是計算機曆史上的一大進步。