Linux Kernel Interrupt 分析__Linux

來源:互聯網
上載者:User

在之前接觸單片機時就接觸到了中斷這一個名詞,簡單理解,在CPU正常運行程式A時,突然插入了程式B,程式B就可以理解為一個中斷。在linux kernel中也提供中斷機制,用於處理上述突發事件。
一、中斷入口
在linux kernel亦有異常向量表,以linux-2.6.32.50中的ARM架構為例,在arch/arm/kernel/entry-armv.S中存在如下的異常向量表。

 __vectors_start:  ARM(   swi SYS_ERROR0  )  THUMB( svc #0      )  THUMB( nop         )     W(b)    vector_und + stubs_offset     W(ldr)  pc, .LCvswi + stubs_offset     W(b)    vector_pabt + stubs_offset     W(b)    vector_dabt + stubs_offset     W(b)    vector_addrexcptn + stubs_offset     W(b)    vector_irq + stubs_offset     W(b)    vector_fiq + stubs_offset     .globl  __vectors_end __vectors_end:

當中斷產生,將進入vector_irq 中進行中斷處理,對應的代碼如下,其中,vector_stub為宏定義。

/*  * Interrupt dispatcher  */     vector_stub irq, IRQ_MODE, 4     .long   __irq_usr           @  0  (USR_26 / USR_32)     .long   __irq_invalid           @  1  (FIQ_26 / FIQ_32)     .long   __irq_invalid           @  2  (IRQ_26 / IRQ_32)     .long   __irq_svc           @  3  (SVC_26 / SVC_32)     .long   __irq_invalid           @  4     .long   __irq_invalid           @  5     .long   __irq_invalid           @  6     .long   __irq_invalid           @  7     .long   __irq_invalid           @  8     .long   __irq_invalid           @  9     .long   __irq_invalid           @  a     .long   __irq_invalid           @  b     .long   __irq_invalid           @  c     .long   __irq_invalid           @  d     .long   __irq_invalid           @  e     .long   __irq_invalid           @  f

對於管理員模式與使用者模式中發生的中斷,其對應的處理函數不同,分別為__irq_svc與__irq_usr。

二、中斷的調用過程
以__irq_usr為例。
__irq_usr => irq_handler => asm_do_IRQ => generic_handle_irq(irq) => generic_handle_irq_desc() => __do_IRQ(irq) => handle_IRQ_event()

370 irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)371 {372     irqreturn_t ret, retval = IRQ_NONE;373     unsigned int status = 0;374375     if (!(action->flags & IRQF_DISABLED))376         local_irq_enable_in_hardirq();377378     do {379         trace_irq_handler_entry(irq, action);380         ret = action->handler(irq, action->dev_id);381         trace_irq_handler_exit(irq, action, ret);382383         switch (ret) {384         case IRQ_WAKE_THREAD:389             ret = IRQ_HANDLED;395             if (unlikely(!action->thread_fn)) {396                 warn_no_thread(irq, action);397                 break;398             }399408             if (likely(!test_bit(IRQTF_DIED,409                          &action->thread_flags))) {410                 set_bit(IRQTF_RUNTHREAD, &action->thread_flags);411                 wake_up_process(action->thread);412             }413414             /* Fall through to add to randomness */415         case IRQ_HANDLED:416             status |= action->flags;417             break;418419         default:420             break;421         }422423         retval |= ret;424         action = action->next;425     } while (action);426427     if (status & IRQF_SAMPLE_RANDOM)428         add_interrupt_randomness(irq);429     local_irq_disable();430431     return retval;432 }

代碼中380行執行中斷服務程式,該中斷服務程式是由我們編寫並且註冊系統中。通過這樣的一個過程,完成了對外部硬體中斷的響應。

三、中斷服務程式註冊
linux kernel中提供了一組函數用於完成對中斷服務程式的註冊與釋放,request_irq()與free_irq()。

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,        const char *name, void *dev)

該函數有五個參數,其說明如下:
irq—要分配的裝置號
handler—指向實際的中斷服務程式的函數指標

typedef irqreturn_t (*irq_handler_t)(int, void *);

flags—中斷處理常式的標誌。定義在include/linux/interrupt.h
name—中斷名
dev—用於共用中斷線,是handler的參數。如果不用共用中斷線,該參數可設為NULL
中斷服務程式的註冊過程如下:
request_irq() => request_threaded_irq()

1028 int request_threaded_irq(unsigned int irq, irq_handler_t handler,1029              irq_handler_t thread_fn, unsigned long irqflags,1030              const char *devname, void *dev_id)1031 {1032     struct irqaction *action;1033     struct irq_desc *desc;1034     int retval;1035......1081     action->handler = handler;1082     action->thread_fn = thread_fn;1083     action->flags = irqflags;1084     action->name = devname;1085     action->dev_id = dev_id;10861087     chip_bus_lock(irq, desc);1088     retval = __setup_irq(irq, desc, action);1089     chip_bus_sync_unlock(irq, desc);1090......10931113     return retval;1114 }

在代碼1081行中,中斷服務程式handler的地址被儲存在action的handler成員中。結合前面跟蹤的中斷調用流程,在將來中斷產生,將執行我們通過request_irq註冊的中斷服務程式。

一般來說,我們在驅動程式中的init函數中調用request_irq(),將我們編寫的中斷服務程式handler註冊到系統中;當中斷產生後,系統經過一系列的調用,最終將會執行我們的中斷服務程式handler,完成對中斷的響應。
在驅動程式的exit函數中調用free_irq(),將註冊到系統中的中斷服務程式handler移除。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.