天天看點

中斷和異常

1、中斷和異常的差別

中斷:一般由外部裝置引起;

異常:cpu執行完某條指令之後,cpu控制單元産生,一般由程式設計錯誤引起。

2、中斷向量

0~255

0~31:異常和不可屏蔽中斷

32~47:可屏蔽中斷

48~255:軟中斷

linux使用一個軟中斷(0x80)作為系統核心函數的系統調用接口。

硬體中斷IRQ0~IRQ15被關聯到了中斷向量32.。。47.

2、中斷描述表

中斷描述符表中,每個向量在表中有相應的中斷或者異常處理程式的入口位址。核心在允許中斷發生前,必須先适當的初始化IDT

中斷描述符表的作用:将中斷向量和中斷處理程式一一對應起來。

IDT表的大小為:256*8.因為linux系統中有256個中斷和異常,是以該表共有256項,每一項有8個位元組。

中斷和異常

16-31是段選擇符,0-15和48-64組合起來形成32位偏移量。

40-43表示描述符的類型:01110中斷描述符;00101任務門描述符,01111陷阱門描述符。在這裡我們主要研究中斷門和陷阱門。而這個描述符也是中斷門和異常門唯一的差別。

DPL:等于0或者3.0是特權模式。使用者态(DPL=3).

目前的執行等級被儲存在CPL寄存器中。控制單元比較CPL和IDT中的DPL字段,如果DPL字段的值較大,則中斷被執行。

中斷描述符表是存在于記憶體中的,是以,怎麼尋址到這張表的呢?

linux中有一個寄存器IDTR(48位)其中32位是段基址,16位是段限。(從這裡我們可以看出,整個IDT表的大小為64k,而每個表項是8位元組,所有最多有8k的表項,但是系統中隻有256個表項被使用)

linux中有一個GDT表,記錄了所有的段基址,段屬性以及段長。

我們是怎麼根據中斷向量号(0~255)找到中斷服務程式的入口位址呢?

在IDT中,每個表項都是一個門。我們首先根據中斷号找到中斷門,然後根據中斷門中的段選擇符(16位:高十三位是索引,最低兩位是DPL),索引到GDT中的相應表項。進而找到該中斷服務程式所在的段基址。然後該段基址和中斷門中的偏移量找到中斷服務程式入口位址。

在這裡有一個安全性的問題。當找到段基址之後,該段基址中有一個DPL,我們需要将目前特權級CPL(存放在cs寄存器中的低兩位)與段描述符(存放在GDT中)的描述符的特權級DPL進行比較,如果CPL比較小,則産生異常。

對于程式設計異常,則做進一步安全檢查,比較CPL與處于IDT中的門描述符中的DPL,如果DPL小,則産生一個“General protection”異常。

對于上面這句話總結一下:意思是在中斷門(異常門)中,有兩個DPL,分别位于段選擇符以及(46,45bit)中。

我們都知道這個段選擇符最終是要裝載到cs寄存器中,而偏移量是要裝載到eip寄存器中。那麼這個中斷到底能不能執行,我們首先要将這個段選擇符中的DPL和目前cs寄存器中的CPL進行比較(低兩位);

如果要還要考慮程式設計異常,那麼該中斷門中的DPL也要進行相應的檢查。

linux中有很多體系結構相關的函數在IDT中插入門:

set_trap_gate(n,addr).

在IDT的第n個表項插入一個陷阱門。門中的段選擇符設定成為核心代碼的段選擇符,偏移量設定為異常程式處理位址(addr),同時DPL字段設定為0.

在linux核心源碼的實作上,idt_descr變量(6個位元組制定了IDT的位置和大小)。idt_table存放了IDT表。

在linux核心中,首先用一個空函數ignore_int來統一初始化中斷處理程式,然後在start_kernel中對IDT進行第二次初始化。trap_init()函數将異常處理程式插入到IDT中。插入的函數包括:

set_trap_gate()(DPL=0),set_intr_gate()(DPL=0),set_system_gate()(DPL=3,陷阱門),set_system_intr_gate()(DPL=3),set_task_gate()(中斷門,門選擇符是TSS全局描述符表的指針,該TSS中包含被激活的函數,偏移量設定為0,DPL=3), 

異常處理程式三個标準的結構:

在核心堆棧中儲存大多數寄存器的内容;

用進階c語言處理異常;

通過ret_from_exception()函數從異常處理程式退出。

分析:int指令發送一個中斷信号,然後,系統就會查找IDT->GDT,找到異常處理程式,執行完之後傳回。

中斷:

IO中斷;時鐘中斷;處理器間中斷;

中斷處理程式的靈活性:

IRQ共享;

IRQ動态配置設定;

中斷處理程式要執行的操作:緊急的;非緊急的;非緊急可延遲的;

IO中斷處理流程:IRQn->IDT[32+N]->interrupt[n]->do_IRQ[n]->中斷服務例程1。。。中斷服務例程n。

每一個中斷向量(中斷門)對應一個irq_desc描述符。

中斷和異常