深入剖析Linux中斷機制_第1頁
深入剖析Linux中斷機制_第2頁
深入剖析Linux中斷機制_第3頁
深入剖析Linux中斷機制_第4頁
深入剖析Linux中斷機制_第5頁
已閱讀5頁,還剩42頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、深入剖析Linux中斷機制中斷概述【摘要】本文詳解了Linux內(nèi)核的中斷實現(xiàn)機制。首先介紹了中斷的一些基本概念,然后分析了面向?qū)ο蟮腖inux中斷的組織形式、三種主要數(shù)據(jù)結(jié)構(gòu)及其之間的關(guān)系。隨后介紹了Linux處理異常和中斷的基本流程,在此基礎(chǔ)上分析了中斷處理的詳細流程,包括保存現(xiàn)場、中斷處理、中斷退出時的軟中斷執(zhí)行及中斷返回時的進程切換等問題。最后介紹了中斷相關(guān)的API,包括中斷注冊和釋放、中斷關(guān)閉和使能、如何編寫中斷ISR、共享中斷、中斷上下文中斷狀態(tài)等。【關(guān)鍵字】中斷,異常,hw_interrupt_type,irq_desc_t,irqaction,asm_do_IRQ,軟中斷,進程切

2、換,中斷注冊釋放request_irq,free_irq,共享中斷,可重入,中斷上下文1 中斷概述1.1 為什么需要中斷?處理器的速度跟外圍硬件設(shè)備的速度往往不在一個數(shù)量級上,因此,如果內(nèi)核采取讓處理器向硬件發(fā)出一個請求,然后專門等待回應(yīng)的辦法,顯然差強人意。既然硬件的響應(yīng)這么慢,那么內(nèi)核就應(yīng)該在此期間處理其他事務(wù),等到硬件真正完成了請求的操作之后,再回過頭來對它進行處理。想要實現(xiàn)這種功能,輪詢(polling可能會是一種解決辦法??梢宰寖?nèi)核定期對設(shè)備的狀態(tài)進行查詢,然后做出相應(yīng)的處理。不過這種方法很可能會讓內(nèi)核做不少無用功,因為無論硬件設(shè)備是正在忙碌著完成任務(wù)還是已經(jīng)大功告成,輪詢總會周期性

3、地重復(fù)執(zhí)行。更好的辦法是由我們來提供一種機制,讓硬件在需要的時候再向內(nèi)核發(fā)出信號(變內(nèi)核主動為硬件主動。這就是中斷機制。1.2 中斷的表示形式硬件設(shè)備生成中斷的時候并不考慮與處理器的時鐘同步換句話說就是中斷隨時可以產(chǎn)生。因此,內(nèi)核隨時可能因為新到來的中斷而被打斷。從物理學(xué)的角度看,中斷是一種電信號,由硬件設(shè)備生成,并直接送入中斷控制器的輸入引腳上。然后再由中斷控制器向處理器發(fā)送相應(yīng)的信號。處理器一經(jīng)檢測到此信號,便中斷自己的當(dāng)前工作轉(zhuǎn)而處理中斷。此后,處理器會通知操作系統(tǒng)已經(jīng)產(chǎn)生中斷,這樣,操作系統(tǒng)就可以對這個中斷進行適當(dāng)?shù)奶幚砹恕2煌脑O(shè)備對應(yīng)的中斷不同,而每個中斷都通過一個惟一的數(shù)字標識。

4、因此,來自鍵盤的中斷就有別干來自硬盤的中斷,從而使得操作系統(tǒng)能夠?qū)χ袛噙M行區(qū)分,并知道哪個硬件設(shè)備產(chǎn)生了哪個中斷。這樣,操作系統(tǒng)才能給不同的中斷提供不同的中斷處理程序。這些中斷值通常被為中斷請求(IRQ線。通常IRQ都是一些數(shù)值量。例如在PC上,IRQ0是時鐘中斷,而IRQ 1是鍵盤中斷。但并非所有的中斷號都是這樣嚴格定義的。例如,對于連接在PCI總線上的設(shè)備而言,中斷是動態(tài)分配的。而在嵌入式系統(tǒng)中,由于中斷線有限,一般外設(shè)和中斷都是一一匹配的,很少有動態(tài)分配中斷的。不管怎樣,重點在于特定的中斷總是與特定的設(shè)備相關(guān)聯(lián),并且內(nèi)核要知道這些信息。1.3 異常在操作系統(tǒng)中,討論中斷就不能不提及異常。

5、廣義的中斷可分為同步(synchronous)中斷和異步(asynchronous)中斷:同步中斷:是當(dāng)指令執(zhí)行時由 CPU 控制單元產(chǎn)生,之所以稱為同步,是因為只有在一條指令執(zhí)行完畢后 CPU 才會發(fā)出中斷,而不是發(fā)生在代碼指令執(zhí)行期間,比如系統(tǒng)調(diào)用。異步中斷:是指由其他硬件設(shè)備依照 CPU 時鐘信號隨機產(chǎn)生,即意味著中斷能夠在指令之間發(fā)生,例如鍵盤中斷。一般由處理器本身產(chǎn)生的同步中斷稱為異常(exception),異步中斷被稱為中斷(interrupt)。中斷可分為可屏蔽中斷(Maskable interrupt)和非屏蔽中斷(Nomaskable interrupt)。異??煞譃楣收希╢

6、ault)、陷阱(trap)、終止(abort)三類。表 1:中斷類別及其行為類別原因異步/同步返回行為中斷來自I/O設(shè)備的信號異步總是返回到下一條指令陷阱有意的異常同步總是返回到下一條指令故障潛在可恢復(fù)的錯誤同步返回到當(dāng)前指令終止不可恢復(fù)的錯誤同步不會返回在處理器執(zhí)行到由于編程失誤而導(dǎo)致的錯誤指令(例如被0除的時候,或者是在執(zhí)行期間出現(xiàn)特殊情況(例如缺頁,必須靠內(nèi)核來處理的時候,處理器就會產(chǎn)生一個異常。因為許多處理器體系結(jié)構(gòu)處理異常與處理中斷的方式類似,因此,內(nèi)核對它們的處理也很類似。通過軟中斷實現(xiàn)系統(tǒng)調(diào)用,那就是陷人內(nèi)核,然后引起一種特殊的異常系統(tǒng)調(diào)用處理程序異常。你將會看到,中斷的工作方

7、式與之類似,其差異只在于中斷是由硬件而不是軟件引起的。1.4 中斷處理程序在響應(yīng)一個特定中斷的時候,內(nèi)核會執(zhí)行一個函數(shù),該函數(shù)叫做中斷處理程序(interrupt handler或中斷服務(wù)例程(interrupt service routine, ISR。產(chǎn)生中斷的每個設(shè)備都有一個相應(yīng)的中斷處理程序。在Linux中,中斷處理程序看起來就是普普通通的C函數(shù)。只不過這些函數(shù)必須按照特定的類型聲明,以便內(nèi)核能夠以標準的方式傳遞處理程序的信息。中斷處理程序與其他內(nèi)核函數(shù)的真正區(qū)別在于:中斷處理程序是被內(nèi)核調(diào)用來響應(yīng)中斷的,而它們運行于我們稱之為中斷上下文的特殊上下文中。中斷可能隨時發(fā)生,因此中斷處理程

8、序也就隨時可能執(zhí)行。所以必須保證中斷處理程序能夠快速執(zhí)行,這樣才能保證盡可能快地恢復(fù)中斷代碼的執(zhí)行。因此,盡管對硬件而言,迅速對其中斷進行服務(wù)非常重要,但對系統(tǒng)的其他部分而言,讓中斷處理程序在盡可能短的時間內(nèi)完成運行也同樣重要。即使是最精簡版的中斷服務(wù)程序,它也要與硬件進行交互,告訴該設(shè)備中斷已被接收。我們可以考慮一下網(wǎng)絡(luò)設(shè)備的中斷處理程序面臨的挑戰(zhàn)。該處理程序除了要對硬件應(yīng)答,還要把來自硬件的網(wǎng)絡(luò)數(shù)據(jù)包拷貝到內(nèi)存,對其進行處理后再交給合適的協(xié)議?;驊?yīng)用程序。顯而易見,這種工作量不會太小,尤其對于如今的千兆比特和萬兆比特以太網(wǎng)卡而言。因此我們一般把中斷處理切為兩個部分或兩半。中斷處理程序是上半

9、部 (top half接收到一個中斷,它就立即開始執(zhí)行,但只做有嚴格時限的工作,例如對接收的中斷進行應(yīng)答或復(fù)位硬件,這些工作都是在所有中斷被禁止的情況下完成的。能夠被允許稍后完成的工作會推遲到下半部(bottom half去。此后,在合適的時機,下半部會被開中斷執(zhí)行。以網(wǎng)卡作為實例,當(dāng)網(wǎng)卡接收流入網(wǎng)絡(luò)的數(shù)據(jù)包時,需要通知內(nèi)核數(shù)據(jù)包到了。網(wǎng)卡需要立即完成這件事,從而優(yōu)化網(wǎng)絡(luò)的吞吐量和傳輸周期,以避免超時。因此,網(wǎng)卡立即發(fā)出中斷:嘀,內(nèi)核,我這里有最新數(shù)據(jù)包了。內(nèi)核通過執(zhí)行網(wǎng)卡已注冊的中斷處理程序來做出應(yīng)答。中斷開始執(zhí)行,應(yīng)答硬件,拷貝最新的網(wǎng)絡(luò)數(shù)據(jù)包到內(nèi)存,然后讀取網(wǎng)卡更多的數(shù)據(jù)包。這些都是重要

10、、緊迫而又與硬件相關(guān)的工作。處理和操作數(shù)據(jù)包的其他工作在隨后的下半部中進行。深入剖析Linux中斷機制之二Linux中斷的組織形式【摘要】本文詳解了Linux內(nèi)核的中斷實現(xiàn)機制。首先介紹了中斷的一些基本概念,然后分析了面向?qū)ο蟮腖inux中斷的組織形式、三種主要數(shù)據(jù)結(jié)構(gòu)及其之間的關(guān)系。隨后介紹了Linux處理異常和中斷的基本流程,在此基礎(chǔ)上分析了中斷處理的詳細流程,包括保存現(xiàn)場、中斷處理、中斷退出時的軟中斷執(zhí)行及中斷返回時的進程切換等問題。最后介紹了中斷相關(guān)的API,包括中斷注冊和釋放、中斷關(guān)閉和使能、如何編寫中斷ISR、共享中斷、中斷上下文中斷狀態(tài)等?!娟P(guān)鍵字】中斷,異常,hw_interr

11、upt_type,irq_desc_t,irqaction,asm_do_IRQ,軟中斷,進程切換,中斷注冊釋放request_irq,free_irq,共享中斷,可重入,中斷上下文1 Linux中斷的組織形式1.1 IRQ描述符irq_desc對于每個IRQ中斷線,Linux都用一個irq_desc_t數(shù)據(jù)結(jié)構(gòu)來描述,我們把它叫做IRQ描述符,NR_IRQS個IRQ形成一個全局數(shù)組irq_desc,其定義在/include/linux/irq.h中:struct irq_desc 中斷描述符148struct irq_desc 149 irq_flow_handler_t handle_ir

12、q;150 struct irq_chip *chip;151 void *handler_data;152 void *chip_data;153 struct irqaction *action; /* IRQ action list */154 unsigned int status; /* IRQ status */155156 unsigned int depth; /* nested irq disables */157 unsigned int wake_depth; /* nested wake enables */158 unsigned int irq_count; /*

13、For detecting broken IRQs */159 unsigned int irqs_unhandled;160 spinlock_t lock;161#ifdef CONFIG_SMP162 cpumask_t affinity;163 unsigned int cpu;164#endif171 const char *name;172 _cacheline_aligned;173174extern struct irq_desc irq_descNR_IRQS;handle_irq:上層的通用中斷處理函數(shù)指針,如果未設(shè)置則默認為_do_IRQ(。通常針對電平觸發(fā)或者邊沿觸發(fā)有

14、不同的處理函數(shù)。每個中斷線可分別設(shè)置;chip:底層中斷的各種控制訪問方法集合,各個CPU實現(xiàn)的都不同,這屬于面向?qū)ο蟮闹袛嗵幚矸绞街凶畹讓拥囊徊糠?;handler_data:附加參數(shù),用于handle_irq;chip_data:平臺相關(guān)的附加參數(shù),用于chip;action:指向一個單向鏈表的指針,這個鏈表就是對中斷服務(wù)例程進行描述的irqaction結(jié)構(gòu);status:中斷當(dāng)前的狀態(tài);depth:中斷關(guān)閉打開的層數(shù)。如果啟用這條IRQ中斷線,depth則為0,如果禁用這條IRQ中斷線不止一次,則為一個正數(shù)。如果depth等于0,每當(dāng)調(diào)用一次disable_irq( ,該函數(shù)就對這個域的值

15、加1,同時該函數(shù)就禁用這條IRQ中斷線。相反,每當(dāng)調(diào)用enable_irq( 函數(shù)時,該函數(shù)就對這個域的值減1;如果depth變?yōu)?,該函數(shù)就啟用這條IRQ中斷線。Lock:此中斷描述符為全局共享暑假,對于SMP需要互斥訪問Dir: /proc/irq/ 入口Name: /proc/interrupts 中顯示的中斷名稱“_cacheline_aligned”表示這個數(shù)據(jù)結(jié)構(gòu)的存放按32字節(jié)(高速緩存行的大?。┻M行對齊,以便于將來存放在高速緩存并容易存取157void _init init_IRQ(void158159 int irq;160161 for (irq = 0; irq <

16、 NR_IRQS; irq+162 irq_descirq.status |= IRQ_NOREQUEST | IRQ_DELAYED_DISABLE |163 IRQ_NOPROBE;164165#ifdef CONFIG_SMP166 bad_irq_desc.affinity = CPU_MASK_ALL;167 bad_irq_desc.cpu = smp_processor_id(;168#endif169 init_arch_irq(;1701.2 中斷控制器描述符irq_chip 由于CPU不同,故每個處理器對于中斷的處理方式不一樣。Linux為了實現(xiàn)統(tǒng)一的中斷處理,提供了底層的

17、中斷處理抽象接口,對于每個平臺都需要實現(xiàn)底層的接口函數(shù)。這樣對于上層的中斷通用處理程序就無需任何改動。struct irq_chip 片級的中斷描述符94struct irq_chip 95 const char *name;96 unsigned int (*startup(unsigned int irq;97 void (*shutdown(unsigned int irq;98 void (*enable(unsigned int irq;99 void (*disable(unsigned int irq;100101 void (*ack(unsigned int irq;102

18、void (*mask(unsigned int irq;103 void (*mask_ack(unsigned int irq;104 void (*unmask(unsigned int irq;105 void (*eoi(unsigned int irq;106107 void (*end(unsigned int irq;108 void (*set_affinity(unsigned int irq, cpumask_t dest;109 int (*retrigger(unsigned int irq;110 int (*set_type(unsigned int irq, u

19、nsigned int flow_type;111 int (*set_wake(unsigned int irq, unsigned int on;121 const char *typename;122;Name:用于/proc/interruptsStartup:默認為enable if NULLShutdown:默認為 disable if NULLEnable:允許中斷,默認為unmask if NULLDisable:禁止中斷,默認為mask if NULLAck:響應(yīng)一個中斷Mask:mask 一個中斷源,通常是關(guān)閉中斷mask_ack:響應(yīng)并mask中斷源unmask:unma

20、sk中斷源set_type:設(shè)置中斷觸發(fā)方式IRQ_TYPE_LEVEL大多數(shù)控制方法都是重復(fù)的,基本上只要有中斷響應(yīng)、中斷屏蔽、中斷開啟、中斷觸發(fā)類型設(shè)置等方法就可以滿足要求了。其他各種方法基本上和這些相同。提供了中斷響應(yīng)、打開、關(guān)閉、設(shè)置觸發(fā)類型等底層方法的接口static struct irq_chip at91_aic_chip = .name = "AIC",.ack = at91_aic_mask_irq,.mask = at91_aic_mask_irq,.unmask = at91_aic_unmask_irq,.set_type = at91_aic_se

21、t_type,.set_wake = at91_aic_set_wake,;124/*125 * Initialize the AIC interrupt controller.126 */127void _init at91_aic_init(unsigned int priorityNR_AIC_IRQS128129 unsigned int i;130131 /*132 * The IVR is used by macro get_irqnr_and_base to read and verify.133 * The irq number is NR_AIC_IRQS when a sp

22、urious interrupt has occurred.134 */135 for (i = 0; i < NR_AIC_IRQS; i+ 136 /* Put irq number in Source Vector Register: */137 at91_sys_write(AT91_AIC_SVR(i, i;138 /* Active Low interrupt, with the specified priority */139 at91_sys_write(AT91_AIC_SMR(i, AT91_AIC_SRCTYPE_LOW | priorityi;140141 set

23、_irq_chip(i, &at91_aic_chip;142 set_irq_handler(i, do_level_IRQ;143 set_irq_flags(i, IRQF_VALID | IRQF_PROBE;144145 /* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */146 if (i < 8147 at91_sys_write(AT91_AIC_EOICR, 0;148 149150 /*151 * Spurious Interrupt ID in Spu

24、rious Vector Register is NR_AIC_IRQS152 * When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU153 */154 at91_sys_write(AT91_AIC_SPU, NR_AIC_IRQS;155156 /* No debugging in AIC: Debug (Protect Control Register */157 at91_sys_write(AT91_AIC_DCR, 0;158159 /* Disa

25、ble and clear all interrupts initially */160 at91_sys_write(AT91_AIC_IDCR, 0xFFFFFFFF;161 at91_sys_write(AT91_AIC_ICCR, 0xFFFFFFFF;162163以下這些宏定義都是為保持兼容性而設(shè)置的,后續(xù)版本中將徹底刪除47#define do_level_IRQ handle_level_irq48#define do_edge_IRQ handle_edge_irq49#define do_simple_IRQ handle_simple_irq50#define irqdes

26、c irq_desc51#define irqchip irq_chip55#define SA_INTERRUPT IRQF_DISABLED57#define SA_SHIRQ IRQF_SHARED6061#define SA_TRIGGER_LOW IRQF_TRIGGER_LOW62#define SA_TRIGGER_HIGH IRQF_TRIGGER_HIGH63#define SA_TRIGGER_FALLING IRQF_TRIGGER_FALLING64#define SA_TRIGGER_RISING IRQF_TRIGGER_RISING65#define SA_TRI

27、GGER_MASK IRQF_TRIGGER_MASKlinux/kernel/irq/chip.chandle_level_irq1.3 中斷服務(wù)例程描述符irqaction在IRQ描述符中我們看到指針action的結(jié)構(gòu)為irqaction,它是為多個設(shè)備能共享一條中斷線而設(shè)置的一個數(shù)據(jù)結(jié)構(gòu),代表了每個注冊中斷對應(yīng)的信息。在include/linux/interrupt.h中定義如下:67typedef irqreturn_t (*irq_handler_t(int, void *;6869struct irqaction 70 irq_handler_t handler;71 unsign

28、ed long flags;72 cpumask_t mask;73 const char *name;74 void *dev_id;75 struct irqaction *next;76 int irq;77 struct proc_dir_entry *dir;78;Handler:指向一個具體I/O設(shè)備的中斷服務(wù)例程。這是允許多個設(shè)備共享同一中斷線的關(guān)鍵域,中斷線可以相同,但處理函數(shù)可以不一樣。Flags:用一組標志描述中斷線與I/O設(shè)備之間的關(guān)系。SA_INTERRUPT 中斷處理程序必須以禁用中斷來執(zhí)行。此標志表明給定的中斷處理程序是一個快速中斷處理程序(fast interru

29、pt handler。過去,Linux將中斷處理程序分為快速和慢速兩種。那些可以迅速執(zhí)行但調(diào)用頻率可能會很高的中斷服務(wù)程序,會被貼上這樣的標簽。通常這樣做需要修改中斷處理程序的行為,使它們能夠盡可能快地執(zhí)行?,F(xiàn)在,加不加此標志的區(qū)別只剩下一條了:在本地處理器上,快速中斷處理程序在禁止所有中斷的情況下運行。這使得快速中斷處理程序能夠不受其他中斷干擾,得以迅速執(zhí)行。而默認情況下(沒有這個標志,除了正運行的中斷處理程序?qū)?yīng)的那條中斷線被屏蔽外,其他所有中斷都是激活的。除了時鐘中斷外,絕大多數(shù)中斷都不使用該標志。SA_SHIRQ 此標志表明可以在多個中斷處理程序之間共享中斷線。在同一個給定線上注冊的每

30、個處理程序必須指定這個標志:否則,在每條線上只能有一個處理程序。各項該中斷線的每一個例程都需要設(shè)置此標志。Name:I/O設(shè)備名(通過讀取/proc/interrupts文件,可以看到,在列出中斷號時也顯示設(shè)備名。)dev_id:對于共享中斷,此特定值用來區(qū)分各中斷。當(dāng)一個中斷處理程序需要釋放時,dev_id將提供惟一的標志信息(cookie,以便從共享中斷線的諸多中斷處理程序中刪除指定的那一個。如果沒有這個參數(shù),那么內(nèi)核不可能知道在給定的中斷線上到底要刪除哪一個處理程序。如果無需共享中斷線,那么將該參數(shù)賦為空值(NULL就可以了,但是,如果中斷線是被共享的,那么就必須傳遞惟一的信息。另外,內(nèi)

31、核每次調(diào)用中斷處理程序時,都會把這個指針傳遞給它。實踐中往往會通過它傳遞驅(qū)動程序的設(shè)備結(jié)構(gòu):這個指針是惟一的,而且有可能在中斷處理程序內(nèi)及設(shè)備模式中被用到。Next:指向irqaction描述符鏈表的下一個元素。共享同一中斷線的每個硬件設(shè)備都有其對應(yīng)的中斷服務(wù)例程,鏈表中的每個元素就是對相應(yīng)設(shè)備及中斷服務(wù)例程的描述。Irq:對應(yīng)的中斷號dir:proc文件系統(tǒng)對應(yīng)的入口1.4 三者的關(guān)系三個主要的數(shù)據(jù)結(jié)構(gòu)包含了與 IRQ 相關(guān)的所有信息:hw_interrupt_type、irq_desc_t 和 irqaction,下圖解釋了它們之間是如何關(guān)聯(lián)的。中斷服務(wù)例程ISR是irqaction 的H

32、andler成員。中斷的處理是一種面向?qū)ο蟮臋C制,通過三個數(shù)據(jù)結(jié)果實現(xiàn)了三層結(jié)構(gòu),底層是和具體硬件相關(guān)的中斷處理響應(yīng)等,中間層是統(tǒng)一的中斷處理流程,最上層是特定的中斷處理例程。IRQ 結(jié)構(gòu)之間的關(guān)系深入剖析Linux中斷機制之三Linux對異常和中斷的處理Sailor_forever sailing_9806 轉(zhuǎn)載請注明【摘要】本文詳解了Linux內(nèi)核的中斷實現(xiàn)機制。首先介紹了中斷的一些基本概念,然后分析了面向?qū)ο蟮腖inux中斷的組織形式、三種主要數(shù)據(jù)結(jié)構(gòu)及其之間的關(guān)系。隨后介紹了Linux處理異常和中斷的基本流程,在此基礎(chǔ)上分析了中斷處理的詳細流程,包括保存現(xiàn)場、中斷處理、中斷退出時的軟中

33、斷執(zhí)行及中斷返回時的進程切換等問題。最后介紹了中斷相關(guān)的API,包括中斷注冊和釋放、中斷關(guān)閉和使能、如何編寫中斷ISR、共享中斷、中斷上下文中斷狀態(tài)等?!娟P(guān)鍵字】中斷,異常,hw_interrupt_type,irq_desc_t,irqaction,asm_do_IRQ,軟中斷,進程切換,中斷注冊釋放request_irq,free_irq,共享中斷,可重入,中斷上下文1 Linux對異常和中斷的處理1.1 異常處理Linux利用異常來達到兩個截然不同的目的:² 給進程發(fā)送一個信號以通報一個反常情況² 管理硬件資源對于第一種情況,例如,如果進程執(zhí)行了一個被0除的操作,CP

34、U則會產(chǎn)生一個“除法錯誤”異常,并由相應(yīng)的異常處理程序向當(dāng)前進程發(fā)送一個SIGFPE信號。當(dāng)前進程接收到這個信號后,就要采取若干必要的步驟,或者從錯誤中恢復(fù),或者終止執(zhí)行(如果這個信號沒有相應(yīng)的信號處理程序)。內(nèi)核對異常處理程序的調(diào)用有一個標準的結(jié)構(gòu),它由以下三部分組成:² 在內(nèi)核棧中保存大多數(shù)寄存器的內(nèi)容(由匯編語言實現(xiàn))² 調(diào)用C編寫的異常處理函數(shù)² 通過ret_from_exception(函數(shù)從異常退出。1.2 中斷處理當(dāng)一個中斷發(fā)生時,并不是所有的操作都具有相同的急迫性。事實上,把所有的操作都放進中斷處理程序本身并不合適。需要時間長的、非重要的操作應(yīng)該推

35、后,因為當(dāng)一個中斷處理程序正在運行時,相應(yīng)的IRQ中斷線上再發(fā)出的信號就會被忽略。另外中斷處理程序不能執(zhí)行任何阻塞過程,如I/O設(shè)備操作。因此,Linux把一個中斷要執(zhí)行的操作分為下面的三類:² 緊急的(Critical)這樣的操作諸如:中斷到來時中斷控制器做出應(yīng)答,對中斷控制器或設(shè)備控制器重新編程,或者對設(shè)備和處理器同時訪問的數(shù)據(jù)結(jié)構(gòu)進行修改。這些操作都是緊急的,應(yīng)該被很快地執(zhí)行,也就是說,緊急操作應(yīng)該在一個中斷處理程序內(nèi)立即執(zhí)行,而且是在禁用中斷的狀態(tài)下。² 非緊急的(Noncritical)這樣的操作如修改那些只有處理器才會訪問的數(shù)據(jù)結(jié)構(gòu)(例如,按下一個鍵后,讀掃描碼

36、)。這些操作也要很快地完成,因此,它們由中斷處理程序立即執(zhí)行,但在啟用中斷的狀態(tài)下。² 非緊急可延遲的(Noncritical deferrable)這樣的操作如,把一個緩沖區(qū)的內(nèi)容拷貝到一些進程的地址空間(例如,把鍵盤行緩沖區(qū)的內(nèi)容發(fā)送到終端處理程序的進程)。這些操作可能被延遲較長的時間間隔而不影響內(nèi)核操作,有興趣的進程會等待需要的數(shù)據(jù)。所有的中斷處理程序都執(zhí)行四個基本的操作:² 在內(nèi)核棧中保存IRQ的值和寄存器的內(nèi)容。² 給與IRQ中斷線相連的中斷控制器發(fā)送一個應(yīng)答,這將允許在這條中斷線上進一步發(fā)出中斷請求。² 執(zhí)行共享這個IRQ的所有設(shè)備的中斷服務(wù)

37、例程(ISR)。² 跳到ret_to_usr( 的地址后終止。1.3 中斷處理程序的執(zhí)行流程現(xiàn)在,我們可以從中斷請求的發(fā)生到CPU的響應(yīng),再到中斷處理程序的調(diào)用和返回,沿著這一思路走一遍,以體會Linux內(nèi)核對中斷的響應(yīng)及處理。假定外設(shè)的驅(qū)動程序都已完成了初始化工作,并且已把相應(yīng)的中斷服務(wù)例程掛入到特定的中斷請求隊列。又假定當(dāng)前進程正在用戶空間運行(隨時可以接受中斷),且外設(shè)已產(chǎn)生了一次中斷請求,CPU就在執(zhí)行完當(dāng)前指令后來響應(yīng)該中斷。中斷處理系統(tǒng)在Linux中的實現(xiàn)是非常依賴于體系結(jié)構(gòu)的,實現(xiàn)依賴于處理器、所使用的中斷控制器的類型、體系結(jié)構(gòu)的設(shè)計及機器本身。設(shè)備產(chǎn)生中斷,通過總線把

38、電信號發(fā)送給中斷控制器。如果中斷線是激活的,那么中斷控制器就會把中斷發(fā)往處理器。在大多數(shù)體系結(jié)構(gòu)中,這個工作就是通過電信號給處理器的特定管腳發(fā)送一個信號。除非在處理器上禁止該中斷,否則,處理器會立即停止它正在做的事,關(guān)閉中斷系統(tǒng),然后跳到內(nèi)存中預(yù)定義的位置開始執(zhí)行那里的代碼。這個預(yù)定義的位置是由內(nèi)核設(shè)置的,是中斷處理程序的入口點。對于ARM系統(tǒng)來說,有個專用的IRQ運行模式,有一個統(tǒng)一的入口地址。假定中斷發(fā)生時CPU運行在用戶空間,而中斷處理程序?qū)儆趦?nèi)核空間,因此,要進行堆棧的切換。也就是說,CPU從TSS中取出內(nèi)核棧指針,并切換到內(nèi)核棧(此時棧還為空)。若當(dāng)前處于內(nèi)核空間時,對于ARM系統(tǒng)來

39、說是處于SVC模式,此時產(chǎn)生中斷,中斷處理完畢后,若是可剝奪內(nèi)核,則檢查是否需要進行進程調(diào)度,否則直接返回到被中斷的內(nèi)核空間;若需要進行進程調(diào)度,則svc_preempt,進程切換。190 .align 5191_irq_svc:192 svc_entry197#ifdef CONFIG_PREEMPT198 get_thread_info tsk199 ldr r8, tsk, #TI_PREEMPT get preempt count200 add r7, r8, #1 increment it201 str r7, tsk, #TI_PREEMPT202#endif203204 irq_

40、handler205#ifdef CONFIG_PREEMPT206 ldr r0, tsk, #TI_FLAGS get flags207 tst r0, #_TIF_NEED_RESCHED208 blne svc_preempt209preempt_return:210 ldr r0, tsk, #TI_PREEMPT read preempt value211 str r8, tsk, #TI_PREEMPT restore preempt count212 teq r0, r7213 strne r0, r0, -r0 bug(214#endif215 ldr r0, sp, #S_

41、PSR irqs are already disabled216 msr spsr_cxsf, r0221 ldmia sp, r0 - pc load r0 - pc, cpsr222223 .ltorg當(dāng)前處于用戶空間時,對于ARM系統(tǒng)來說是處于USR模式,此時產(chǎn)生中斷,中斷處理完畢后,無論是否是可剝奪內(nèi)核,都調(diào)轉(zhuǎn)到統(tǒng)一的用戶模式出口ret_to_user,其檢查是否需要進行進程調(diào)度,若需要進行進程調(diào)度,則進程切換,否則直接返回到被中斷的用戶空間。404 .align 5405_irq_usr:406 usr_entry407411 get_thread_info tsk412#ifdef

42、 CONFIG_PREEMPT413 ldr r8, tsk, #TI_PREEMPT get preempt count414 add r7, r8, #1 increment it415 str r7, tsk, #TI_PREEMPT416#endif417418 irq_handler419#ifdef CONFIG_PREEMPT420 ldr r0, tsk, #TI_PREEMPT421 str r8, tsk, #TI_PREEMPT422 teq r0, r7423 strne r0, r0, -r0 bug(424#endif428429 mov why, #0430 b

43、ret_to_user432 .ltorg105/*106 * SVC mode handlers107 */108115 .macro svc_entry116 sub sp, sp, #S_FRAME_SIZE117 SPFIX( tst sp, #4 118 SPFIX( bicne sp, sp, #4 119 stmib sp, r1 - r12120121 ldmia r0, r1 - r3122 add r5, sp, #S_SP here for interlock avoidance123 mov r4, #-1 "" "" "

44、;" ""124 add r0, sp, #S_FRAME_SIZE "" "" "" ""125 SPFIX( addne r0, r0, #4 126 str r1, sp save the "real" r0 copied127 from the exception stack128129 mov r1, lr130131 132 We are now ready to fill in the remaining blanks on the stack:133

45、 134 r0 - sp_svc135 r1 - lr_svc136 r2 - lr_ , already fixed up for correct return/restart 137 r3 - spsr_ 138 r4 - orig_r0 (see pt_regs definition in ptrace.h139 140 stmia r5, r0 - r4141 .endm因為C的調(diào)用慣例是要把函數(shù)參數(shù)放在棧的頂部,因此pt- regs結(jié)構(gòu)包含原始寄存器的值,這些值是以前在匯編入口例程svc_entry中保存在棧中的。18 .macro get_irqnr_and_base, irqnr

46、, irqstat, base, tmp19 ldr base, =(AT91_VA_BASE_SYS base virtual address of SYS peripherals20 ldr irqnr, base, #AT91_AIC_IVR read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt21 ldr irqstat, base, #AT91_AIC_ISR read interrupt source number22 teq irqstat, #0 ISR is 0 when no

47、 current interrupt, or spurious interrupt23 streq tmp, base, #AT91_AIC_EOICR not going to be handled further, then ACK it now.24 .endm26/*27 * Interrupt handling. Preserves r7, r8, r928 */29 .macro irq_handler301: get_irqnr_and_base r0, r6, r5, lr31 movne r1, sp32 33 routine called with r0 = irq num

48、ber, r1 = struct pt_regs *34 35 adrne lr, 1b36 bne asm_do_IRQ58 .endm中斷號的值也在irq_handler初期得以保存,所以,asm_do_IRQ可以將它提取出來。這個中斷處理程序?qū)嶋H上要調(diào)用do_IRQ(,而do_IRQ(要調(diào)用handle_IRQ_event(函數(shù),最后這個函數(shù)才真正地執(zhí)行中斷服務(wù)例程(ISR)。下圖給出它們的調(diào)用關(guān)系:asm_do_IRQdo_IRQ(handle_IRQ_event(中斷服務(wù)例程1例程中斷服務(wù)例程2例程中斷處理函數(shù)的調(diào)用關(guān)系112asmlinkage void asm_do_IRQ(un

49、signed int irq, struct pt_regs *regs113114 struct pt_regs *old_regs = set_irq_regs(regs;115 struct irqdesc *desc = irq_desc + irq;116121 if (irq >= NR_IRQS122 desc = &bad_irq_desc;123124 irq_enter(; /記錄硬件中斷狀態(tài),便于跟蹤中斷情況確定是否是中斷上下文125126 desc_handle_irq(irq, desc;/desc_handle_irq33static inline v

50、oid desc_handle_irq(unsigned int irq, struct irq_desc *desc3435 desc->handle_irq(irq, desc; /通常handle_irq指向_do_IRQ36/desc_handle_irq130131 irq_exit(; /中斷退出前執(zhí)行可能的軟中斷,被中斷前是在中斷上下文中則直接退出,這保證了軟中斷不會嵌套132 set_irq_regs(old_regs;133157 * _do_IRQ - original all in one highlevel IRQ handler167fastcall unsig

51、ned int _do_IRQ(unsigned int irq168169 struct irq_desc *desc = irq_desc + irq;170 struct irqaction *action;171 unsigned int status;172173 kstat_this_cpu.irqsirq+;186187 spin_lock(&desc->lock;188 if (desc->chip->ack /首先響應(yīng)中斷,通常實現(xiàn)為關(guān)閉本中斷線189 desc->chip->ack(irq;190 194 status = desc-&

52、gt;status & (IRQ_REPLAY | IRQ_WAITING;195 status |= IRQ_PENDING; /* we _want_ to handle it */196201 action = NULL;202 if (likely(!(status & (IRQ_DISABLED | IRQ_INPROGRESS 203 action = desc->action;204 status &= IRQ_PENDING; /* we commit to handling */205 status |= IRQ_INPROGRESS; /* w

53、e are handling it */206 207 desc->status = status;208215 if (unlikely(!action216 goto out;217218 /*219 * Edge triggered interrupts need to remember220 * pending events.227 */228 for (; 229 irqreturn_t action_ret;230231 spin_unlock(&desc->lock;/解鎖,中斷處理期間可以響應(yīng)其他中斷,否則再次進入_do_IRQ時會死鎖233 action_

54、ret = handle_IRQ_event(irq, action;237 spin_lock(&desc->lock;238 if (likely(!(desc->status & IRQ_PENDING239 break;240 desc->status &= IRQ_PENDING;241 242 desc->status &= IRQ_INPROGRESS;243244out:249 desc->chip->end(irq;250 spin_unlock(&desc->lock;251252 retur

55、n 1;253該函數(shù)的實現(xiàn)用到中斷線的狀態(tài),下面給予具體說明:#define IRQ_INPROGRESS 1 /* 正在執(zhí)行這個IRQ的一個處理程序*/#define IRQ_DISABLED 2 /* 由設(shè)備驅(qū)動程序已經(jīng)禁用了這條IRQ中斷線 */#define IRQ_PENDING 4 /* 一個IRQ已經(jīng)出現(xiàn)在中斷線上,且被應(yīng)答,但還沒有為它提供服務(wù) */#define IRQ_REPLAY 8 /* 當(dāng)Linux重新發(fā)送一個已被刪除的IRQ時 */#define IRQ_WAITING 32 /*當(dāng)對硬件設(shè)備進行探測時,設(shè)置這個狀態(tài)以標記正在被測試的irq */#define IR

56、Q_LEVEL 64 /* IRQ level triggered */#define IRQ_MASKED 128 /* IRQ masked - shouldn't be seen again */#define IRQ_PER_CPU 256 /* IRQ is per CPU */這8個狀態(tài)的前5個狀態(tài)比較常用,因此我們給出了具體解釋。經(jīng)驗表明,應(yīng)該避免在同一條中斷線上的中斷嵌套,內(nèi)核通過IRQ_PENDING標志位的應(yīng)用保證了這一點。當(dāng)do_IRQ(執(zhí)行到for (;循環(huán)時,desc->status 中的IRQ_PENDING的標志位肯定為0。當(dāng)CPU執(zhí)行完handle_IRQ_event(函數(shù)返回時,如果這個標志位仍然為0,那么循環(huán)就此結(jié)束。如果這個標志位變?yōu)?,那就說明這條中斷線上又有中斷產(chǎn)生(對單CPU而言),所以循環(huán)又執(zhí)行一次。通過這種循環(huán)方式,就把可能發(fā)生在同一中斷線上的嵌套循環(huán)化解為“串行”。在循環(huán)結(jié)束后調(diào)用desc->handler->end(函數(shù),具體來說,如果沒有設(shè)置IRQ_DISABLED標志位,就啟用這條中斷線。當(dāng)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論