《Linux核心設計與實現》——中斷和中斷處理

一世豁然發表於2014-11-11

一、中斷

 1、中斷本質上是一種特殊的電訊號,由硬體裝置發向處理器。處理器接收到中斷後,會馬上向作業系統反應此訊號的到來,然後就由作業系統負責處理這些新到來的資料。


 2、不同的裝置對應的中斷不同,而每個中斷都通過一個唯一的數字標誌。這些中斷值通常被稱為中斷請求(IRQ)線,每個IRQ線都會被關聯一個數值量。



二、中斷處理程式

 1、再響應一個特定中斷的時候,核心會執行一個函式,該函式叫做中斷處理程式或中斷服務例程(ISR)。

   1)、產生中斷的每個裝置都有一個相應的中斷處理程式。

   2)、一個裝置的中斷處理程式是它裝置驅動程式的一部分——裝置驅動程式是用於對裝置進行管理的核心程式碼。


 2、中斷處理程式與其他核心函式的真正區別在於:中斷處理程式是被核心呼叫來響應中斷的,而他們執行在中斷上下文中,中斷上下文也稱原子上下文。



三、上半部和下半部的對比

 1、中斷處理切為兩個部分

   1)、中斷處理程式是上半部——接收到一箇中斷,它就立即開始執行,但製作嚴格限時的工作。

   2)、能夠被允許稍後完成的工作會推遲到下半部去。此後,在合適的時機,下半部會被開中斷執行。



四、註冊中斷處理程式

 1、驅動程式可以通過requeset_irq()函式註冊一箇中斷處理程式,並啟用給定的中斷線:

       int  requeset_irq(unsigned  int  irq,  irq_handler_t  handler,

                                       unsigned  long  flags,  const  char  *name,  void  *dev);

       I、引數irq表示要分配的中斷號。

       II、引數handler是一個指標,指向處理這個中斷的實際中斷處理程式。


 2、中斷處理程式標誌

   1)、引數flags可以為0,也可以是一個或多個標誌的位掩碼。

       I、IRQF_DISABLED——該標誌被設定後,意味著核心在處理程式本身期間,要禁止所有的其他中斷。

       II、IRQF_SAMPLE_RANDOM——此標誌表明這個裝置產生的中斷對核心熵池有貢獻。

       III、IRQF_TIMER——此標誌是特別位系統定時器的中斷處理而準備的。

       IV、IRQF_SHARED——此標誌表明可以在多個終端處理程式之間共享中斷線。

   2)、引數name是與中斷有關的的裝置的ASCII文字表示。

   3)、引數dev用於共享中斷線。


 3、一箇中斷例子


 4、釋放中斷處理程式

   1)、解除安裝驅動程式時,需要登出相應的中斷處理程式,並釋放中斷線:

      void  free_irq(unsigned  int  irq,  void  *dev);

      I、如果指定的中斷線不是共享的,那麼,該函式刪除處理程式的同時將禁用這條中斷線。

      II、如果中斷線是共享的,則僅刪除dev所對應的處理程式,而這條中斷線本省只有在刪除了最後一個處理程式時才會被禁用。



五、編寫中斷處理程式

 1、一箇中斷處理程式宣告:

       static  irqreturn_t  intr_hanler(int  irq,  void  *dev);

       I、此函式的型別與request_irq()引數中的healer所要求的引數型別匹配。

       II、第一個引數irq就是處理程式要響應的中斷的中斷號。

       III、第二個引數dev是一個用用指標,它與中斷處理程式註冊時傳遞給request_irq()的引數dev必須一致。

       IV、中斷處理程式的返回值型別是irqreturn_t。中斷處理程式可能返回兩個特殊值:IRQ_NONE和IRQ_HANDLED。


 2、共享的中斷處理程式

   1)、共享的處理程式與非共享的處理程式在註冊和執行方式上比較相似,但差異主要有一下三處:

      I、request_irq()的引數flags必須設定IRQF_SHARED標誌。

      II、對於每個註冊的中斷處理程式來說,dev引數必須唯一。

      III、中斷處理程式必須能夠區分它的裝置是否產生了中斷。

   2)、指定IRQF_SHARED標誌以呼叫request_irq()時,只有在以下兩種情況才能夠成功:

      I、中斷線當前未被註冊。

      II、在該線上的所有已註冊處理程式都指定了IRQF_SHARED。


 3、中斷處理程式例項



六、中斷上下文

 1、當執行一箇中斷處理程式時,核心處於中斷上下文中。


 2、中斷上下文具有較為嚴格的時間限制,因為它打斷了其他的程式碼。中斷上下文中的程式碼應當迅速、簡潔、儘量不要使用迴圈去處理繁重的工作。


 3、中斷處理程式棧是一個配置選項。



七、中斷處理機制的實現

 1、中斷處理系統在Linux中的實現非常依賴於體系結構,實現依賴於處理器、所使用的中斷控制器的型別、體系結構的設計及及機器本身。


 2、中斷從硬體到核心的路由(P100  圖7-1)

   1)、在核心中,中斷開始於預定義的入口點。對於每條中斷線,處理器都會跳到對應的一個惟一的位置。

   2)、初始入口點只是在棧中儲存這個號,並存放當前暫存器的值;然後,核心呼叫函式do_IRQ()。

           unsigend  int  do_IRQ(struct  pt_regs  regs)

   3)、pt_regs結構包含原始暫存器的值。中斷的值也會得以儲存,所以,do_IRQ()可以將它提取出來。

   4)、計算出中斷號之後,do_IRQ()對所接收的中斷進行應答,禁止這條線上的中斷。

   5)、接下來,do_IRQ()需要確保在這條中斷線上有一個有效的處理程式,而且這個程式已經啟動,但是當前並沒有執行。如是如此,do_IRQ()就呼叫handle_IRQ_event()來

             執行為這條中斷線安裝的中斷處理程式。



八、/proc/interrupts

 1、procfs是一個虛擬檔案系統,它只存在核心記憶體中,一般安裝於/proc目錄。在procfs中讀寫檔案都要呼叫核心函式,這些函式模擬從真實檔案中讀寫。



九、中斷控制

 1、禁止和啟用中斷

   1)、用於禁止當前處理器上的本地中斷,隨後又啟用它們的語句為:

       local_irq_disable();

       local_irq_enable();

       I、在X86中,local_irq_disable()僅僅是cli指令,local_irq_enable()僅僅是sti指令。cli和sti分別是對clear和set允許中斷標誌的會變呼叫。

       II、如果在呼叫local_irq_disable()例程之前已經禁止了中斷,那麼該例程往往會帶來潛在的危險;同樣相應的local_irq_enable()例程也存在潛在危險。

   2)、在禁止中斷之前儲存中斷系統的狀態會更加安全一些。相反,在準備啟用中斷時,只需要把中斷恢復到他們原來的狀態:

       unisgend   long  flags;

       local_irq_save(flags);

       /*  .  .  .  */

       local_irq_restore(flags);


 2、禁止指定中斷

   1)、對中斷狀態操作之前禁止裝置中斷的傳遞。LInux提供了四個介面:

      void  disable_irq(unsigned  int  irq);

      void  disable_irq_nosync(unsigned  int  irq);

      void  enable_irq(unsigned  int  irq);

      void  synchronize_irq(unsigned  int  irq);

      I、disable_irq和disable_irq_nosync禁止中斷控制器上指定的中斷線,即禁止給定中斷向系統所有處理器的傳遞。此外函式只有在當前正在執行的所有處理器程式完成

           後,disable_irq才會返回。disable_irq_nosync不會等待當前中斷處理程式執行完畢。

      II、函式synchronize_irq等待一個特定的中斷處理程式的退出。如果該處理程式正在執行,那麼該函式必須退出之後才能返回。

      III、這些函式可以巢狀。但是記住在一條指定的中斷線上,對disable_irq和disable_irq_nosync的每次呼叫,都需要相應的呼叫一次enable_irq。

      IV、以上函式可以從中斷或程式上下文中呼叫,而且不會休眠。但是從中斷上下文中呼叫必須注意。

   2)、禁止多箇中斷處理程式共享的中斷時不合適的。禁止中斷線也就禁止了這條線上所有裝置的中斷傳遞。


 3、中斷系統的狀態

   1)、irqs_disable()定義在<asm/aystem.h>中。如果本地處理器上的中斷系統被禁止,則它返回非0,否則返回0。

   2)、在<linux/hardirq.h>中定義的兩個巨集提供一個用來檢查核心的當前上下文的介面:

      in_interrupt()

      in_irq()

      I、in_interrupt:如果核心處於任何型別的中斷處理中,它返回非0,說明核心此刻正在執行中斷處理程式或正在執行下半部處理程式。

      II、in_irq:只有在核心確實正在執行中斷處理程式時才會返回非0。

   3)、中斷控制方法列表(P106  表7-2)。

相關文章