IDT系列:(一)初探IDT,Interrupt Descriptor Table,中斷描述符表

IDT,Interrupt Descriptor Table,中斷描述符表是CPU用來處理中斷和程序異常的。

 

一、有關IDT的基本知識

1、中斷時一種機制,用來處理硬件需要向CPU輸入信息的情況。 比如鼠標,鍵盤等。

2、中斷和異常的產生是隨機的,在CPU正常運行過程中隨時可能產生。CPU的中斷處理機制

3、中斷可以由硬件產生(稱爲外部中斷),也可以由軟件產生(稱爲內部中斷),在程序中寫入int n指令可以產生n號中斷和異常(n從0-ffh)。

 

4、同時CPU的中斷異常機制還是重要特性的支持原理,比如程序調試,程序運行過程中的異常處理(如零除數異常、內存分頁錯誤等)。 

5、早期的操作系統甚至是通過中斷來進行內核調用的。int指令是一種c從ring3 進入ring 0的方法。比如windows在xp版本之前使用的int 2e。在x86 CPU提供了sysenter指令後,這種方式才被放棄。

6、每一種中斷對應一箇中斷號。CPU執行中斷指令時,會去IDT表中查找對應的中斷服務程序(interrupt service routine ,ISR)。ISR(爲了表述方便後面用ISR n表示n號中斷的處理程序),x86CPU最大可以支持256種中斷。

 7、中斷是CPU的機制,不管運行的是什麼操作系統,只有是運行於x86架構,IDT結構式必然存在的。IDT表中的ISRs應該有操作系統提供。

8、異常分爲錯誤(Faults)、陷阱(Traps)和終止(Aborts)三種,其區別是“錯誤”允許產生錯誤的程序繼續允許,“陷阱”也可以,但是“錯誤”產生於指令執行後,而“陷阱”需要在產生異常的指令執行後,因此從“錯誤”中返回時繼續執行產生錯誤的指令,而從“陷阱返”回時應當從產生異常的指令後開始執行。終止產生時,處理程序不能得到精確的異常產生的代碼位置,程序不能繼續進行,硬件錯誤會產生“終止”。 例如page faults就是一個faults,mov [eax], ecx,產生了一個分頁錯誤,表面[eax]內存是無效,需要先進行分頁處理從新映射物理內存然後才能繼續進行mov操作;而斷點是一個Trap。

9、Intel指定或保留了前32箇中斷號的作用,操作系統可以指定其餘的中斷號的作用。

10、中斷的過程中可以產生新的中斷。中斷時有優先級的,高優先級的中斷可以“中斷”低優先級的中斷。有的ISR不能被中斷,可以使用STI (set interrupt-enable flag) and CLI(clear interrupt-enable flag)設置IF標誌來啓動和關閉中斷。

 

(更詳細的內容可以參考Intel® 64 and IA-32 Architectures Software Developer’s Manual

 

二、IDT表的結構

中斷處理過程是有CPU直接調用的,CPU有專門的寄存器IDTR來保存IDT在內存中的位置,本文寫爲IDTR.base。IDTR有48爲,前32爲是IDT在內存中的位置(線性地址),後16爲是IDT的大小,本文寫爲IDT.limit。程序可以使用LIDT和SIDT指令來讀寫IDTR。

IDT是一個最大爲256項的表,每個表項爲8字節。稱爲中斷門。CPU通過IDT.base+n*8來尋找門。

根據中斷號對應的異常類型不同(Faults/Traps/Aborts)8個字節的意義也不同。

如上圖所示IDT門中的最後兩個byte是ISR在內存中的高16位,最開始前兩個字節是ISR在內存中地址的低16位。

 

三、使用WinDbg觀察、調試IDT

使用Vmware配置好內核調試環境[link]。

 

WinDbg有支持查看IDT的擴展命令!idt

!idt –a 命令可以看到所有中斷處理函數的地址。
r idtr 參看idtr寄存器中保存的idt表地址。
idt每個表項有8bytes,兩個dword大。

(注意.reload /i 加載符號文件)

kd> !idt -a

Dumping IDT:

00: 8053f19c nt!KiTrap00
01: 8053f314 nt!KiTrap01
02: Task Selector = 0x0058
03: 8053f6e4 nt!KiTrap03
04: 8053f864 nt!KiTrap04
05: 8053f9c0 nt!KiTrap05
06: 8053fb34 nt!KiTrap06
07: 8054019c nt!KiTrap07
08: Task Selector = 0x0050
09: 805405c0 nt!KiTrap09
0a: 805406e0 nt!KiTrap0A
0b: 80540820 nt!KiTrap0B
0c: 80540a7c nt!KiTrap0C
0d: 80540d60 nt!KiTrap0D
0e: 80541450 nt!KiTrap0E
… …


kd> r idtr
idtr=8003f400
kd> db idtr
8003f400  9c f1 08 00 00 8e 53 80-14 f3 08 00 00 8e 53 80  ......S.......S.
8003f410  3e 11 58 00 00 85 00 00-e4 f6 08 00 00 ee 53 80  >.X...........S.
8003f420  64 f8 08 00 00 ee 53 80-c0 f9 08 00 00 8e 53 80  d.....S.......S.
8003f430  34 fb 08 00 00 8e 53 80-9c 01 08 00 00 8e 54 80  4.....S.......T.
8003f440  98 11 50 00 00 85 00 00-c0 05 08 00 00 8e 54 80  ..P...........T.
8003f450  e0 06 08 00 00 8e 54 80-20 08 08 00 00 8e 54 80  ......T. .....T.
8003f460  7c 0a 08 00 00 8e 54 80-60 0d 08 00 00 8e 54 80  |.....T.`.....T.
8003f470  50 14 08 00 00 8e 54 80-80 17 08 00 00 8e 54 80  P.....T.......T.

 

可以看到,這個時候IDT的基地址是在803f400處。
注意觀察其中3號中斷門 e4 f6 08 00 00 ee 53 80 ISR 3 
int 3是trap門,按照之前說的ISR地址構造方法,得到8053f6e4的中斷服務程序地址。

 

 

 

好,我們觀察了IDT表(知道了IDT表的結構,自己寫一個!idt WinDbg擴展也是很簡單的事情),但是,使用windbg調試IDT表式不可能的。WinDbg的工作就要依賴於debuggee系統的中斷向量,如果在ISR 3裏寫個int 3,那麼BSOD是絕對的。Windbg和Debuggee系統是通過com口連接的,當Debuggee系統中產生了int3中斷,系統首先進入到ISR 3中。在ISR 3中判斷存在內核調試器,然後通過com口和WinDbg通行。這個處理過程本身就依賴於Debuggee系統的ISR。如果在ISR 3中又存在一個int 3那麼就無限遞歸了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章