|
本文詳解了Linux內(nèi)核的中斷實(shí)現(xiàn)機(jī)制。首先介紹了中斷的一些基本概念,然后分析了面向?qū)ο蟮腖inux中斷的組織形式、三種主要數(shù)據(jù)結(jié)構(gòu)及其之間的關(guān)系。隨后介紹了Linux處理異常和中斷的基本流程,在此基礎(chǔ)上分析了中斷處理的詳細(xì)流程,包括保存現(xiàn)場(chǎng)、中斷處理、中斷退出時(shí)的軟中斷執(zhí)行及中斷返回時(shí)的進(jìn)程切換等問題。最后介紹了中斷相關(guān)的API,包括中斷注冊(cè)和釋放、中斷關(guān)閉和使能、如何編寫中斷ISR、共享中斷、中斷上下文中斷狀態(tài)等。
1 中斷概述
1.1 為什么需要中斷?
處理器的速度跟外圍硬件設(shè)備的速度往往不在一個(gè)數(shù)量級(jí)上,因此,如果內(nèi)核采取讓處理器向硬件發(fā)出一個(gè)請(qǐng)求,然后專門等待回應(yīng)的辦法,顯然差強(qiáng)人意。既然硬件的響應(yīng)這么慢,那么內(nèi)核就應(yīng)該在此期間處理其他事務(wù),等到硬件真正完成了請(qǐng)求的操作之后,再回過頭來對(duì)它進(jìn)行處理。想要實(shí)現(xiàn)這種功能,輪詢(polling)可能會(huì)是一種解決辦法。可以讓內(nèi)核定期對(duì)設(shè)備的狀態(tài)進(jìn)行查詢,然后做出相應(yīng)的處理。不過這種方法很可能會(huì)讓內(nèi)核做不少無用功,因?yàn)闊o論硬件設(shè)備是正在忙碌著完成任務(wù)還是已經(jīng)大功告成,輪詢總會(huì)周期性地重復(fù)執(zhí)行。更好的辦法是由我們來提供一種機(jī)制,讓硬件在需要的時(shí)候再向內(nèi)核發(fā)出信號(hào)(變內(nèi)核主動(dòng)為硬件主動(dòng))。這就是中斷機(jī)制。
1.2 中斷的表示形式
硬件設(shè)備生成中斷的時(shí)候并不考慮與處理器的時(shí)鐘同步—換句話說就是中斷隨時(shí)可以產(chǎn)生。因此,內(nèi)核隨時(shí)可能因?yàn)樾碌絹淼闹袛喽淮驍唷?br />
從物理學(xué)的角度看,中斷是一種電信號(hào),由硬件設(shè)備生成,并直接送入中斷控制器的輸入引腳上。然后再由中斷控制器向處理器發(fā)送相應(yīng)的信號(hào)。處理器一經(jīng)檢測(cè)到此信號(hào),便中斷自己的當(dāng)前工作轉(zhuǎn)而處理中斷。此后,處理器會(huì)通知操作系統(tǒng)已經(jīng)產(chǎn)生中斷,這樣,操作系統(tǒng)就可以對(duì)這個(gè)中斷進(jìn)行適當(dāng)?shù)奶幚砹恕?br />
不同的設(shè)備對(duì)應(yīng)的中斷不同,而每個(gè)中斷都通過一個(gè)惟一的數(shù)字標(biāo)識(shí)。因此,來自鍵盤的中斷就有別干來自硬盤的中斷,從而使得操作系統(tǒng)能夠?qū)χ袛噙M(jìn)行區(qū)分,并知道哪個(gè)硬件設(shè)備產(chǎn)生了哪個(gè)中斷。這樣,操作系統(tǒng)才能給不同的中斷提供不同的中斷處理程序。
這些中斷值通常被為中斷請(qǐng)求(IRQ)線。通常IRQ都是一些數(shù)值量。例如在PC上,IRQ0是時(shí)鐘中斷,而IRQ 1是鍵盤中斷。但并非所有的中斷號(hào)都是這樣嚴(yán)格定義的。例如,對(duì)于連接在PCI總線上的設(shè)備而言,中斷是動(dòng)態(tài)分配的。而在嵌入式系統(tǒng)中,由于中斷線有限,一般外設(shè)和中斷都是一一匹配的,很少有動(dòng)態(tài)分配中斷的。不管怎樣,重點(diǎn)在于特定的中斷總是與特定的設(shè)備相關(guān)聯(lián),并且內(nèi)核要知道這些信息。
1.3 異常
在操作系統(tǒng)中,討論中斷就不能不提及異常。廣義的中斷可分為同步(synchronous)中斷和異步(asynchronous)中斷:
同步中斷:是當(dāng)指令執(zhí)行時(shí)由 CPU 控制單元產(chǎn)生,之所以稱為同步,是因?yàn)橹挥性谝粭l指令執(zhí)行完畢后 CPU 才會(huì)發(fā)出中斷,而不是發(fā)生在代碼指令執(zhí)行期間,比如系統(tǒng)調(diào)用。
異步中斷:是指由其他硬件設(shè)備依照 CPU 時(shí)鐘信號(hào)隨機(jī)產(chǎn)生,即意味著中斷能夠在指令之間發(fā)生,例如鍵盤中斷。
一般由處理器本身產(chǎn)生的同步中斷稱為異常(exception),異步中斷被稱為中斷(interrupt)。中斷可分為可屏蔽中斷(Maskable interrupt)和非屏蔽中斷(Nomaskable interrupt)。異?煞譃楣收希╢ault)、陷阱(trap)、終止(abort)三類。
表 1:中斷類別及其行為
類別
原因
異步/同步
返回行為
中斷
來自I/O設(shè)備的信號(hào)
異步
總是返回到下一條指令
陷阱
有意的異常
同步
總是返回到下一條指令
故障
潛在可恢復(fù)的錯(cuò)誤
同步
返回到當(dāng)前指令
終止
不可恢復(fù)的錯(cuò)誤
同步
不會(huì)返回
在處理器執(zhí)行到由于編程失誤而導(dǎo)致的錯(cuò)誤指令(例如被0除)的時(shí)候,或者是在執(zhí)行期間出現(xiàn)特殊情況(例如缺頁),必須靠?jī)?nèi)核來處理的時(shí)候,處理器就會(huì)產(chǎn)生一個(gè)異常。因?yàn)樵S多處理器體系結(jié)構(gòu)處理異常與處理中斷的方式類似,因此,內(nèi)核對(duì)它們的處理也很類似。
通過軟中斷實(shí)現(xiàn)系統(tǒng)調(diào)用,那就是陷人內(nèi)核,然后引起一種特殊的異!到y(tǒng)調(diào)用處理程序異常。你將會(huì)看到,中斷的工作方式與之類似,其差異只在于中斷是由硬件而不是軟件引起的。
1.4 中斷處理程序
在響應(yīng)一個(gè)特定中斷的時(shí)候,內(nèi)核會(huì)執(zhí)行一個(gè)函數(shù),該函數(shù)叫做中斷處理程序(interrupt handler)或中斷服務(wù)例程(interrupt service routine, ISR)。產(chǎn)生中斷的每個(gè)設(shè)備都有一個(gè)相應(yīng)的中斷處理程序。
在Linux中,中斷處理程序看起來就是普普通通的C函數(shù)。只不過這些函數(shù)必須按照特定的類型聲明,以便內(nèi)核能夠以標(biāo)準(zhǔn)的方式傳遞處理程序的信息。中斷處理程序與其他內(nèi)核函數(shù)的真正區(qū)別在于:中斷處理程序是被內(nèi)核調(diào)用來響應(yīng)中斷的,而它們運(yùn)行于我們稱之為中斷上下文的特殊上下文中。
中斷可能隨時(shí)發(fā)生,因此中斷處理程序也就隨時(shí)可能執(zhí)行。所以必須保證中斷處理程序能夠快速執(zhí)行,這樣才能保證盡可能快地恢復(fù)中斷代碼的執(zhí)行。因此,盡管對(duì)硬件而言,迅速對(duì)其中斷進(jìn)行服務(wù)非常重要,但對(duì)系統(tǒng)的其他部分而言,讓中斷處理程序在盡可能短的時(shí)間內(nèi)完成運(yùn)行也同樣重要。
即使是最精簡(jiǎn)版的中斷服務(wù)程序,它也要與硬件進(jìn)行交互,告訴該設(shè)備中斷已被接收。我們可以考慮一下網(wǎng)絡(luò)設(shè)備的中斷處理程序面臨的挑戰(zhàn)。該處理程序除了要對(duì)硬件應(yīng)答,還要把來自硬件的網(wǎng)絡(luò)數(shù)據(jù)包拷貝到內(nèi)存,對(duì)其進(jìn)行處理后再交給合適的協(xié)議棧或應(yīng)用程序。顯而易見,這種工作量不會(huì)太小,尤其對(duì)于如今的千兆比特和萬兆比特以太網(wǎng)卡而言。
因此我們一般把中斷處理切為兩個(gè)部分或兩半。中斷處理程序是上半部 (top half)—接收到一個(gè)中斷,它就立即開始執(zhí)行,但只做有嚴(yán)格時(shí)限的工作,例如對(duì)接收的中斷進(jìn)行應(yīng)答或復(fù)位硬件,這些工作都是在所有中斷被禁止的情況下完成的。能夠被允許稍后完成的工作會(huì)推遲到下半部(bottom half)去。此后,在合適的時(shí)機(jī),下半部會(huì)被開中斷執(zhí)行。
以網(wǎng)卡作為實(shí)例,當(dāng)網(wǎng)卡接收流入網(wǎng)絡(luò)的數(shù)據(jù)包時(shí),需要通知內(nèi)核數(shù)據(jù)包到了。網(wǎng)卡需要立即完成這件事,從而優(yōu)化網(wǎng)絡(luò)的吞吐量和傳輸周期,以避免超時(shí)。因此,網(wǎng)卡立即發(fā)出中斷:嘀,內(nèi)核,我這里有最新數(shù)據(jù)包了。內(nèi)核通過執(zhí)行網(wǎng)卡已注冊(cè)的中斷處理程序來做出應(yīng)答。
中斷開始執(zhí)行,應(yīng)答硬件,拷貝最新的網(wǎng)絡(luò)數(shù)據(jù)包到內(nèi)存,然后讀取網(wǎng)卡更多的數(shù)據(jù)包。這些都是重要、緊迫而又與硬件相關(guān)的工作。處理和操作數(shù)據(jù)包的其他工作在隨后的下半部中進(jìn)行。
|
|