生活随笔
收集整理的這篇文章主要介紹了
中断和异常的区别
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
4.6.7 中斷描述符表
中斷描述符表(Interrupt Descriptor Table,IDT)將每個異常或中斷向量分別與它們的處理過程聯系起來。與GDT和LDT表類似,IDT也是由8字節長描述符組成的一個數組。與GDT 不同的是,表中第1項可以包含描述符。為了構成IDT表中的一個索引值,處理器把異常或中斷的向量號乘以8。因為最多只有256個中斷或異常向量,所以 IDT無需包含多于256個描述符。IDT中可以含有少于256個描述符,因為只有可能發生的異常或中斷才需要描述符。不過IDT中所有空描述符項應該設置其存在位(標志)為0。
IDT表可以駐留在線性地址空間的任何地方,處理器使用IDTR寄存器來定位IDT表的位置。這個寄存器中含有IDT表32位的基地址和16位的長度(限長)值,如圖4-26所示。IDT表基地址應該對齊在8字節邊界上以提高處理器的訪問效率。限長值是以字節為單位的IDT表的長度。
?圖4-26 中斷描述符表IDT和寄存器IDTR
LIDT和SIDT指令分別用于加載和保存IDTR寄存器的內容。LIDT指令用于把內存中的限長值和基地址操作數加載到IDTR寄存器中。該指令僅能由當前特權級CPL是0的代碼執行,通常被用于創建IDT時的操作系統初始化代碼中。SIDT指令用于把IDTR中的基地址和限長內容復制到內存中。該指令可在任何特權級上執行。
如果中斷或異常向量引用的描述符超過了IDT的界限,處理器會產生一個一般保護性異常。
4.6.8 IDT描述符
IDT表中可以存放3種類型的門描述符:中斷門(Interrupt gate)描述符、陷阱門(Trap gate)描述符、任務門(Task gate)描述符。
圖4-27給出了這三種門描述符的格式。中斷門和陷阱門含有一個長指針(即段選擇符和偏移值),處理器使用這個長指針把程序執行權轉移到代碼段中異常或中斷的處理過程中。這兩個段的主要區別在于處理器操作EFLAGS寄存器IF標志上。IDT中任務門描述符的格式與GDT和LDT中任務門的格式相同。任務門描述符中含有一個任務TSS段的選擇符,該任務用于處理異常或中斷。
?圖4-27 中斷門、陷阱門和任務門描述符格式
4.6.9 異常與中斷處理
處理器對異常和中斷處理過程的調用操作方法與使用CALL指令調用程序過程和任務的方法類似。當響應一個異常或中斷時,處理器使用異常或中斷的向量作為IDT表中的索引。如果索引值指向中斷門或陷阱門,則處理器使用與CALL指令操作調用門類似的方法調用異常或中斷處理過程。如果索引值指向任務門,則處理器使用與CALL指令操作任務門類似的方法進行任務切換,執行異常或中斷的處理任務。
異常或中斷門引用運行在當前任務上下文中的異常或中斷處理過程,如圖4-28所示。門中的段選擇符指向GDT或當前LDT中的可執行代碼段描述符。門描述符中的偏移字段指向異常或中斷處理過程的開始處。
?(點擊查看大圖)圖4-28 中斷過程調用
當處理器執行異常或中斷處理過程調用時會進行以下操作:
(1)如果處理過程將在高特權級(如0級)上執行時就會發生堆棧切換操作。堆棧切換過程如下:
處理器從當前執行任務的TSS段中得到中斷或異常處理過程使用的堆棧的段選擇符和棧指針(例如tss.ss0、tss.esp0)。然后處理器會把被中斷程序(或任務)的棧選擇符和棧指針壓入新棧中,如圖4-29所示。
?圖4-29 轉移到中斷處理過程時堆棧的使用方法
接著處理器會把EFLAGS、CS和EIP寄存器的當前值也壓入新棧中。
如果異常會產生一個錯誤號,那么該錯誤號也會被最后壓入新棧中。
(2)如果處理過程將在被中斷任務同一個特權級上運行,那么:
處理器把EFLAGS、CS和EIP寄存器的當前值保存在當前堆棧上。
如果異常會產生一個錯誤號,那么該錯誤號也會被最后壓入新棧中。
為了從中斷處理過程中返回,處理過程必須使用IRET指令。IRET指令與RET指令類似,但IRET還會把保存的寄存器內容恢復到EFLAGS 中。不過只有當CPL是0時才會恢復EFLAGS中的IOPL字段,并且只有當CPL不大于IOPL時,IF標志才會被改變。 如果當調用中斷處理過程時發生了堆棧切換,那么在返回時IRET指令會切換到原來的堆棧。
(1)異常和中斷處理過程的保護
異常和中斷處理過程的特權級保護機制與通過調用門調用普通過程類似。處理器不允許把控制轉移到比CPL更低特權級代碼段的中斷處理過程中,否則將產生一個一般保護性異常。另外,中斷和異常的保護機制在以下方面與一般調用門過程不同:
因為中斷和異常向量沒有RPL,因此在隱式調用異常和中斷處理過程時不會檢查RPL。
只有當一個異常或中斷是由INT n、INT 3或INT 0指令產生時,處理器才會檢查中斷或陷阱門中的DPL。此時CPL必須小于或等于門的DPL。這個限制可以防止運行在特權級3的應用程序使用軟件中斷訪問重要的異常處理過程,例如頁錯誤處理過程,假設這些處理過程已被存放在更高特權級的代碼段中。對于硬件產生的中斷和處理器檢測到的異常,處理器會忽略中斷門和陷阱門中的DPL。
因為異常和中斷通常不會定期發生,因此這些有關特權級的規則有效地增強了異常和中斷處理過程能夠運行的特權級限制。我們可以利用以下技術之一來避免違反特權級保護:
異常或中斷處理程序可以存放在一個一致性代碼段中。這個技術可以用于只需訪問堆棧上數據的處理過程(如除出錯異常)。如果處理程序需要數據段中的數據,那么特權級3必須能夠訪問這個數據段。但這樣一來就沒有保護可言了。
處理過程可以放在具有特權級0的非一致代碼段中。這種處理過程總是可以執行的,與被中斷程序或任務的當前特權級CPL無關。
(2)異常或中斷處理過程的標志使用方式
當通過中斷門或陷阱門訪問一個異常或中斷處理過程時,處理器會在把EFLAGS寄存器內容保存到堆棧上之后清除EFLAGS中的TF標志。清除TF標志可以防止指令跟蹤影響中斷響應。而隨后的IRET指令會用堆棧上的內容恢復EFLAGS的原TF標志。
中斷門與陷阱門唯一的區別在于處理器操作EFLAGS寄存器IF標志的方法。當通過中斷門訪問一個異常或中斷處理過程時,處理器會復位IF標志以防止其他中斷干擾當前中斷處理過程。隨后的IRET指令則會用保存在堆棧上的內容恢復EFLAGS寄存器的IF標志。而通過陷阱門訪問處理過程并不會影響 IF標志。
(3)執行中斷處理過程的任務
當通過IDT表中任務門訪問異常或中斷處理過程時,就會導致任務切換。從而可以在一個專用任務中執行中斷或異常處理過程。IDT表中的任務門引用 GDT中的TSS描述符。切換到處理過程任務的方法與普通任務切換一樣。由于本書討論的Linux操作系統沒有使用這種中斷處理方式,因此這里不再贅述。
4.6.10 中斷處理任務
當通過IDT中任務門來訪問異常或中斷處理過程時就會導致任務切換。使用單獨的任務來處理異常或中斷有如下好處:
被中斷程序或任務的完整上下文會被自動保存。
在處理異常或中斷時,新的TSS可以允許處理過程使用新特權級0的堆棧。在當前特權級0的堆棧已毀壞時如果發生了一個異常或中斷,那么在為中斷過程提供一個新特權級0的堆棧條件下,通過任務門訪問中斷處理過程能夠防止系統崩潰。
通過使用單獨的LDT給中斷或異常處理任務獨立的地址空間,可以把它與其他任務隔離開來。
使用獨立任務處理異常或中斷的不足之處是:在任務切換時必須對大量機器狀態進行保存,使得它比使用中斷門的響應速度要慢,導致中斷延時增加。
IDT中的任務門會引用GDT中的TSS描述符,如圖4-30所示。切換到句柄任務的過程與普通任務切換過程相同。到被中斷任務的反向鏈接會被保存在句柄任務TSS的前一任務鏈接字段中。如果一個異常會產生一個出錯碼,則該出錯碼會被復制到新任務堆棧上。
?圖4-30 中斷處理任務切換
當異常或中斷句柄任務用于操作系統中時,實際上有兩種分派調度任務的機制:操作系統軟件調度和處理器中斷機制的硬件調度。使用軟件調度方法時需要考慮到中斷開啟時采用中斷處理任務。
中斷信號的作用. 使CPU轉而去運行正常控制流之外的代碼.為了它.就要在內核態堆棧保存程序計數器的當前值(eip和cs寄存器).并把與中斷類型相關的一個地址放在程序計數器.中斷處理與進程切換的差異:由中斷或異常處理程序執行的代碼不是一個進程,而是內核控制路徑.代表中斷發生時正在運行的進程執行.其比進程"輕". 中斷和異常 中斷: 可屏蔽中斷(maskable): I/O設備發出的中斷請求(irq)都屬于.可處于兩種狀態:屏蔽的/非屏蔽的.非屏蔽中斷(nonmaskable): 只有幾個危急事件才引起.總是由CPU辨認. 異常: 處理器探測異常:當CPU執行指令時探測到一個反常條件所產生的異常. 根據保存在eip寄存器中的值,分為3種; 1)故障(fault):通常可以被糾正.eip中保存的是引起故障的指令地址.糾正后會重新執行該條指令. ; 2)陷阱(trap):在陷阱指令執行后立刻報告.內核把控制器返回給程序后可以繼續他的執行而不失連貫性. eip保存的是隨后要執行的指令地址.只有當沒有必要重新執行已終止的指令時(通常為了調試程序)時才觸發陷阱. ; 3)異常中止(abort):不能在eip中保存引起異常的指令所在的確切位置.用于報告嚴重的錯誤.異常中止處理程序會強制受影響的進程終止.編程異常: 在編程者發出請求時發生.將其作為陷阱來處理.也叫軟中斷.用途:1)執行系統調用.2)給調試程序通報一個特定的事件. 每個中斷和異常由0~255之間的一個數來標示.稱為向量(vector).只有可屏蔽中斷的向量可以通過編程改變.其余都是固定的. IRQ和中斷:能發出中斷的設備都有一個IRQ的輸出線.所有IRQ線都與一個可編程中斷控制器(PIC)的硬件電路的輸入引腳相連.可以有選擇地禁止每條IRQ線.可對PIC編程從而禁止IRQ.禁止的中斷不丟失.一旦激活,PIC就把他們發送到CPU.該特性運行中斷處理程序逐次處理同一類型的IRQ.為了發揮SMP體系的并行性,能夠把中斷傳遞給每個CPU很重要.所以引入了I/O高級可編程控制器(I/O APIC)的組件.所有CPU都含有一個本地APIC,通過APIC總線(在系統總線上)連接到外部的I/O APIC.還支持CPU產生處理器間中斷(IPI),可以利用它來在CPU之間交換消息.中斷描述符表:IDT是一個系統表,它與每一個中斷或異常向量相聯系.每一個向量在表中有相應的中斷或異常處理程序的入口地址.最多需要256*8=2048字節來存放IDT. idtr寄存器指定IDT的線性基地址及其最大長度,從而使IDT可以位于內存中的任何地方.分為3種類型: 1)任務門:信號發生時,必須取代當前進程的那個進程的TSS選擇符存放在任務門中. ;2)中斷門:包含段選擇符和處理程序的段內偏移量.當CPU控制權轉移到一個適當的斷后,清除IF標志來關閉將來會發生的可屏蔽中斷 ;3)陷阱門:與中斷門相似,但控制權傳遞到一個適合的CPU時不修改IF標志.? Linux利用中斷門處理中斷,利用陷阱門處理異常.注意: "Double fault"異常是唯一由任務們處理的異常.表示一種內核錯誤. 中斷和異常處理程序的嵌套執行. 必須保證中斷處理程序永不阻塞,即中斷處理程序運行期間不能發生進程切換.因為嵌套的內核控制路徑恢復執行時需要的數據都存放在當前線程的內核態堆棧上.一個中斷處理程序可以搶占其他的中斷處理程序和異常處理程序.異常處理程序從不搶占中斷處理程序. 初始化中斷描述符表 過程: 1)在初始化系統時把IDT表的初始地址裝入idtr寄存器,并初始化表中的每一項.; 2)int指令用于在用戶態進程發出一個中斷信號,為了防止模擬非法的中斷,將門描述符的DPL=0.; 3)在用戶態進程必須要能夠發出一個編程異常時,將門的SPL=3。Linux中的分類: 中斷門(DPL=0,所有LInux中斷處理程序都通過中斷門激活,并限制在內核態); 系統門(DPL=3,用來激活3個linux異常處理程序); 系統中斷門(DPL=3,激活int3的異常處理程序); 陷阱門(DPL=0,激活大部分的異常處理程序); 任務門(DPL=0,"Double Fault的異常處理).idt的初始化分為兩步:1)將256個表項用同一個中斷門(即指向ignore_int()中斷處理程序:其是一個空的處理程序)來填充.2)用有意義的陷阱和中斷處理程序來代替空處理程序. 異常處理 大部分異常都解釋成為出錯條件.當異常發生時,內核向引起異常的進程發送一個信號向它通知一個反常條件.特殊情況: 1)"Device not availeble" 2)"Page Fault"該異常推遲給進程分配新的頁框,直到不能再推遲位置.異常處理程序的標準結構: 1)在內核態堆棧中保存大多數寄存器的內容; 2)用C函數處理異常; 3)通過ret_from_exception函數從異常處理程序退出. 中斷處理 由于一個進程被掛起好久后中斷才到達,因此一個完全無關的進程可能正在運行.所以發送信號給當前進程是無用的.中斷處理依賴于中斷類型:1)I/O中斷(查詢設備以確定適當的操作過程); 2)時鐘中斷(該中斷告訴內核一個固定的時間間隔已經過去,作為I/O中斷處理) ;3)處理器間中斷.I/O中斷處理:要能給多個設備同時提供服務.實現: 1)IRQ共享(每個ISR(中斷服務例程)是一個與單獨設備(共享IRQ線)相關的函數,因為無法預知那個特定的設備產生IRQ,所以,中斷處理程序執行多個ISR,以驗證它的設備是否需要關注,如果是,當設備產生中斷時就執行所需的操作); 2)IRQ動態分配(一條IRQ線在可能的最后時刻才與一個設備相關聯.這樣,即使幾個設備并不共享IRQ線,但同一IRQ向量也可以由這幾個設備在不同時刻使用). 一個中斷處理程序正在執行時,相應的IRQ線上發出的信號被暫時忽略; 中斷處理程序所代表的進程必須是出于Task_Running態的; 其不能執行任何阻塞過程.中斷要執行的操作: 1)緊急的(在禁止可屏蔽中斷下立即執行); 2)非緊急的(在開中斷下立即執行); 3)非緊急可延遲的(由獨立的函數執行).步驟:1)在內核態堆棧中保存IRQ的值和寄存器的內容; 2)為正在給IRQ線服務的PIC發送一個應答來允許PIC進一步發出中斷; 3)執行共享這個IRQ的所有設備的ISR; 4)跳到ret_from_intr()的地址后終止.IRQ數據結構: 1)意外中斷:中斷內核沒有處理的中斷.原因是與某個IRQ線相關的ISR不存在或者與某個中斷線相關的所有例程都識別不出來.當一條IRQ線上的意外中斷次數過多時,就禁用這條IRQ線. 2)IRQ在多CPU系統上的分發:對稱多處理器模型(SMP).一般情況下,內核能夠公平地在CPU間分發中斷.但是在某些情況下,Linxu需要使用kirqd的內核線程來糾正IRQ的自動分配.其利用了CPU的IRQ親和力:通過修改I/O APIC的中斷重定向表表項,可以吧中斷信號發送到某個特定的CPU上. CPU間中斷處理:IPI不通過IRQ線傳輸,而是作為信號直接放在連接所有CPU本地APIC總線上. 類型: 1)Call_Function_Vector(發往不包含發送者的所有CPU,強制這些CPU運行發送者傳遞過來的函數). 2)Reschedule_Vector(從中斷返回后,所有的重新調度都自動運行); 3)Invalidate_TLB_Vector(強制TLB無效,來刷新CPU的TLB). 軟中斷及tasklet: 可延遲中斷可以在開中斷的情況下執行.把可延遲中斷從中斷處理程序中抽出來有助于使內核保持較短的響應時間.Linux通過兩種非緊迫,可中斷內核函數:1)可延遲函數;2)通過工作隊列來執行的函數.tasklet是在軟中斷之上實現的.軟中斷的分配是靜態的,tasklet的分配和初始化是在運行時.軟中斷是可重入函數并使用自旋鎖來保護數據,其實可以并行在多CPU上執行的,tasklet總是串行執行,但是不同類型的tasklet可以并發執行,其不必是可重入的.四種操作:1)初始化;2)激活;3)屏蔽;4)執行.激活和執行被綁定在一個CPU上,雖然可以更好地利用CPU的Cache,但是有潛在的危險性(一個CPU很忙,但其他的很閑).軟中斷:使用下標(共6個)來表示優先級.softirq_action[32] ?softirq_vec數組.優先級是下標,所以只有前6元素個有效.另外,thread_info中有一個preempt_count字段來跟蹤內核搶占和內核控制路徑的嵌套.每個CPu都有自己的ksoftirqd/n內核線程.其為了解決以下問題:軟中斷函數可以重新激活自己,軟中斷的連續高流量可能會產生問題.不然就要選擇以下兩種之一的策略:1)忽略do_softirq()運行時新出現的軟中斷,此種情況的等待是不可接受的;2)不斷地重新檢查掛起的軟中斷,這種情況下,do_softirq()函數就會一直不返回,用戶態程序實際上停止執行.解決:do_softirq()函數確定哪些軟中斷是掛起的,并執行他們的韓素華.如果已經執行的軟中斷又被激活,則do_softirq()喚醒內核線程并終止.內核線程有較低的優先級,因此用戶程序有就會運行.但是,如果機器空閑(沒有用戶態程序需要運行時),掛起的軟中斷就很快被執行.tasklet:是I/O驅動程序中實現可延遲函數的首選. 工作隊列 用來代替任務隊列.允許內核函數被激活,而且稍后由一種叫做工作者線程的特殊內核線程來執行.可延遲函數運行在中斷上下文中,而工作隊列中的函數運行在進程上下文中.執行可阻塞函數的方式是在進程上下文中運行,因為在中斷上下文中不可能發生進程切換.兩者都不能訪問進程的用戶態地址空間.
總結
以上是生活随笔為你收集整理的中断和异常的区别的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。