內核中斷號必須要跟硬件中斷號一致嗎

首先說明,答案是否定的,內核中斷號可以與硬件中斷號不一致,但是這是個無聊的問題。。實用價值不大。但是卻可以引起對內核軟件中斷號與硬件中斷號關係的思考。
兩者的關係我覺得可以從中斷的初始化和分發過程來一探究竟。
這裏就從ARM PPC MIPS 3款主流嵌入式處理器架構的內核代碼框架中來分析下他們中斷的初始化和分發過程。

一 中斷的初始化
對於中斷初始化,在系統啓動過程中,這3款處理器架構的內核軟件框架中都會有相應的中斷初始化函數.

內核啓動函數start_kernel中會調用init_IRQ來進行中斷初始化,該函數在不同處理器平臺代碼有不同實現。實現在arch/xxx/kernel/irq.c中。
對於arm處理器,init_IRQ調用對應設備描述符machine_desc的init_irq。
對於ppc處理器,init_IRQ調用對應設備描述符machdep_calls的init_IRQ。
對於mips處理器,init_IRQ調用arch_init_irq。
最終調用的中斷初始化函數是在板級支持包中實現,因爲中斷控制器屬於處理器核的外設。

所以可以看出,中斷初始化的調用關係:
通用函數start_kernel -----> 處理器平臺級函數init_IRQ -----> 板級中斷初始化函數init_irq等


板級中斷初始化函數完成2件事情,其一,中斷控制器初始化。其二,中斷描述符irq_desc的初始化。
中斷控制器初始化就不細說了。這裏我們主要關心軟件上中斷描述符的處理。

內核對於中斷的管理,最關鍵的數據結構就是irq_desc,在kernel/irq/irqdesc.c中:

struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
    [0 ... NR_IRQS-1] = {
        .handle_irq = handle_bad_irq,
        .depth      = 1,
        .lock       = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
    }
};


NR_IRQS由不同處理器平臺的板級支持包來定義,irq_desc數組成員代表每一箇中斷號和相應的處理函數。
所以irq_desc[NR_IRQS]就是硬件中斷控制器中斷號表在內核的表徵。

有個前提,這裏是在不配置CONFIG_SPARSE_IRQ內核選項的情況下,irq_desc[NR_IRQS]用數組形式靜態分配中斷描述符表,編譯時即確定irq_desc數組大小。
如果配置CONFIG_SPARSE_IRQ則動態分配irq_desc以節省內存。這是另一套機制,這裏就不細說了。

板級中斷初始化函數中完成其所使用所有中斷號對應的irq_desc的初始化,主要是設置中斷的一級處理函數。一般是handle_level_irq。函數實現在kernel/irq/chip.c中。
handle_level_irq遍歷該irq_desc的action鏈表,依次執行其action->handler。

各個driver中調用request_irq註冊的中斷處理函數就是irq_desc各個action的handler成員。這裏我們也就明白了內核下共享中斷的實現機制了。

內核中斷的初始化就是這樣。從這裏可以看出,irq_desc[NR_IRQS]內核中斷號表與硬件中斷號表對應。

那麼問題來了,我不讓他們一一對應,硬件中斷號35的處理函數,我想放在irq_desc數組的30號可不可以?
從中斷的初始化來看這樣的修改是沒什麼問題,就是數組成員內容換一下。
但是我們要想到中斷是來幹什麼的,中斷的初始化以及註冊,都是爲了能夠正確的響應中斷進行處理。
所以這個問題的關鍵在於,這樣修改,當產生35號中斷時,內核能不能正常找到在30號irq-desc上的處理函數呢。
也就是在中斷分發過程中內核如何確定軟件中斷號,由硬件35號中斷找到30號irq_desc。

這個我們就需要來看下內核的中斷分發過程了。


二 中斷的分發
中斷是處理器核異常的一種,所以處理器設計中,外設中斷引起處理器異常,處理器跳轉到異常向量表的相應異常入口取指執行。
處理器的異常向量表也是軟硬件結合很有意思的東西,有時間專門寫一篇來記錄,這裏不詳說了。


我們主要來看產生中斷後,處理器跳轉到中斷異常入口後的執行流程。


(1)對於arm處理器,執行流程如下:

vector_irq ---> irq_handler ---> arch_irq_handler_default ---> asm_do_IRQ ---> handle_IRQ
在arch_irq_handler_default中調用get_irqnr_and_base獲取中斷號,傳給asm_do_IRQ作爲參數。
get_irqnr_and_base由板級支持包實現。


(2)對於ppc處理器,執行流程如下:

do_IRQ ---> ppc_md.get_irq ---> handle_one_irq
ppc_md.get_irq是由板級支持包中實現的設備描述符的獲取中斷號函數。


(3)對於mips處理器,執行流程如下:

handle_int ---> plat_irq_dispatch ---> do_IRQ
plat_irq_dispatch由班級支持包中實現。


上述的流程表示由異常入口函數開始,到調用handle_level_irq結束。
對於3款處理器平臺,內核在中斷分發上沒有像中斷初始化那樣由通用函數到處理器平臺函數最後到板級支持函數,而是每種處理器平臺都不一樣。上述函數的實現都在arch/xxx/kernel下,具體實現可以參考代碼。

根據上面的分析可以看出,ARM MIPS PPC在中斷分發中中斷號的獲取都是留給板級支持包來實現的。板級支持包中會讀取中斷控制器中相關寄存器來獲取當前產生的中斷情況,進而返回中斷號。


所以結合中斷初始化部分提出的問題,不管哪款處理器平臺,如果我們想將35號中斷的中斷處理函數在註冊時放在30號irq_desc中(方法是request_irq時中斷號寫30)。

那麼在中斷分發時,獲取中斷號函數中我們也需要進行修改,查詢到中斷控制器寄存器狀態是產生35號中斷,我們返回的中斷號應該是30號!

但是,這樣做並沒有實際的應用意義,因爲在實際開發中還是要儘量保證內核下irq_desc數組與硬件中斷號表一一對應,這樣驅動開發者在操作中斷時就不需要關心內核中斷號和硬件中斷號的關係,而是直接使用硬件中斷號來註冊就可以了。

如果內核中斷號和硬件中斷號不一一對應,驅動開發者在編寫驅動時還需要查找硬件中斷號和內核中斷號的映射表,增大了開發難度。

無論如何,借這個無聊的問題,還是搞清了內核中斷的初始化和分發過程,也是很值得的


但求好事,莫問前程!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章