Linux kernel的中斷子系統之(一) 綜述

2021-07-25 13:17:27 字數 4380 閱讀 8721

一、前言

乙個合格的linux驅動工程師需要對kernel中的中斷子系統有深刻的理解,只有這樣,在寫具體driver的時候才能:

1、正確的使用linux kernel提供的的api,例如最著名的request_threaded_irq(request_irq)介面

2、正確使用同步機制保護驅動**中的臨界區

3、正確的使用kernel提供的softirq、tasklet、workqueue等機制來完成具體的中斷處理

基於上面的原因,我希望能夠通過一系列的文件來描述清楚linux kernel中的中斷子系統方方面面的知識。一方面是整理自己的思緒,另外一方面,希望能夠對其他的驅動工程師(或者想從事linux驅動工作的工程師)有所幫助。

二、中斷系統相關硬體描述

中斷硬體系統主要有三種器件參與,各個外設、中斷控制器和cpu。各個外設提供irq request line,在發生中斷事件的時候,通過irq request line上的電氣訊號向cpu系統請求處理。外設的irq request line太多,cpu需要乙個小夥伴幫他,這就是interrupt controller。interrupt controller是連線外設中斷系統和cpu系統的橋梁。根據外設irq request line的多少,interrupt controller可以級聯。cpu的主要功能是運算,因此cpu並不處理中斷優先順序,那是interrupt controller的事情。對於cpu而言,一般有兩種中斷請求,例如:對於arm,是irq和fiq訊號線,分別讓arm進入irq mode和fiq mode。對於x86,有可遮蔽中斷和不可遮蔽中斷。

本章節不是描述具體的硬體,而是使用了hw block這樣的概念。例如cpu hw block是只arm core或者x86這樣的實際硬體block的乙個邏輯描述,實際中,可能是任何可能的cpu block。

1、hw中斷系統的邏輯block圖

我對hw中斷系統之邏輯block diagram的理解如下圖所示:

系統中有若干個cpu block用來接收中斷事件並進行處理,若干個interrupt controller形成樹狀的結構,匯集系統中所有外設的irq request line,並將中斷事件分發給某乙個cpu block進行處理。從介面層面看,主要有兩類介面,一種是中斷介面。有的實現中,具體中斷介面的形態就是乙個硬體的訊號線,通過電平訊號傳遞中斷事件(arm以及gic組成的中斷系統就是這麼設計的)。有些系統採用了其他的方法來傳遞中斷事件,比如x86+apic(advanced programmable interrupt controller)組成的系統,每個x86的核有乙個local apic,這些local apic們通過icc(interrupt controller communication)bus連線到io apic上。io apic收集各個外設的中斷,並翻譯成匯流排上的message,傳遞給某個cpu上的local apic。因此,上面的紅色線條也是邏輯層面的中斷訊號,可能是實際的pcb上的銅線(或者soc內部的銅線),也可能是乙個message而已。除了中斷介面,cpu和interrupt controller之間還需要有控制資訊的交流。interrupt controller會開放一些暫存器讓cpu訪問、控制。

2、多個interrupt controller和多個cpu之間的拓撲結構

interrupt controller有的是支援多個cpu core的(例如gic、apic等),有的不支援(例如s3c2410的中斷控制器,x86平台的pic等)。如果硬體平台中只有乙個gic的話,那麼通過控制該gic的暫存器可以將所有的外設中斷,分發給連線在該interrupt controller上的cpu。如果有多個gic呢(或者級聯的interrupt controller都支援multi cpu core)?假設我們要設計乙個非常複雜的系統,系統中有8個cpu,有2000個外設中斷要處理,這時候你如何設計系統中的interrupt controller?如果使用gic的話,我們需要兩個gic(乙個gic最多支援1024個中斷源),乙個是root gic,另外乙個是secondary gic。這時候,你有兩種方案:

(1)把8個cpu都連線到root gic上,secondary gic不接cpu。這時候原本掛接在secondary gic的外設中斷會輸出到某個cpu,現在,只能是(通過某個cpu inte***ce的irq signal)輸到root gic的某個spi上。對於軟體而言,這是乙個比較簡單的設計,secondary gic的cpu inte***ce的設定是固定不變的,永遠是從乙個固定的cpu inte***ce輸出到root gic。這種方案的壞處是:這時候secondary gic的ppi和sgi都是沒有用的了。此外,在這種設定下,所有連線在secondary gic上的外設中斷要送達的target cpu是統一處理的,要麼送去cpu0,要麼cpu 5,不能單獨控制。

(2)當然,你也可以讓每個gic分別連線4個cpu core,root gic連線cpu0~cpu3,secondary gic連線cpu4~cpu7。這種狀態下,連線在root gic的中斷可以由cpu0~cpu3分擔處理,連線在secondary gic的中斷可以由cpu4~cpu7分擔處理。但這樣,在中斷處理方面看起來就體現不出8核的威力了。

注:上一節中的邏輯block示意圖採用的就是方案一。

3、interrupt controller把中斷事件送給哪個cpu?

毫無疑問,只有支援multi cpu core的中斷控制器才有這種幸福的煩惱。一般而言,中斷控制器可以把中斷事件上報給乙個cpu或者一組cpu(包括廣播到所有的cpu上去)。對於外設型別的中斷,當然是送到乙個cpu上就ok了,我看不出來要把這樣的中斷送給多個cpu進行處理的必要性。如果送達了多個cpu,實際上,也應該只有乙個handler實際和外設進行互動,另外乙個cpu上的handler的動作應該是這樣的:發現該irq number對應的中斷已經被另外乙個cpu處理了,直接退出handler,返回中斷現場。ipi的中斷不存在這個限制,ipi更像乙個cpu之間通訊的機制,對這種中斷廣播應該是毫無壓力。

實際上,從使用者的角度看,其需求是相當複雜的,我們的目標可能包括:

(1)讓某個irq number的中斷由某個特定的cpu處理

(2)讓某個特定的中斷由幾個cpu輪流處理

……當然,具體的需求可能更加複雜,但是如何區分軟體和硬體的分工呢?讓硬體處理那麼複雜的策略其實是不合理的,複雜的邏輯如果由硬體實現,那麼就意味著更多的電晶體,更多的功耗。因此,最普通的做法就是為interrupt controller支援的每乙個中斷設定乙個target cpu的控制介面(當然應該是以暫存器形式出現,對於gic,這個暫存器就是interrupt processor target register)。系統有多個cpu,這個控制介面就有多少個bit,每個bit代表乙個cpu。如果該bit設定為1,那麼該interrupt就上報給該cpu,如果為0,則不上報給該cpu。這樣的硬體邏輯比較簡單,剩餘的控制內容就交給軟體好了。例如如果系統有兩個cpu core,某中斷想輪流由兩個cpu處理。那麼當cpu0相應該中斷進入interrupt handler的時候,可以將interrupt processor target register中本cpu對應的bit設定為0,另外乙個cpu的bit設定為1。這樣,在下次中斷發生的時候,interupt controller就把中斷送給了cpu1。對於cpu1而言,在執行該中斷的handler的時候,將interrupt processor target register中cpu0的bit為設定為1,disable本cpu的位元位,這樣在下次中斷發生的時候,interupt controller就把中斷送給了cpu0。這樣軟體控制的結果就是實現了特定中斷由2個cpu輪流處理的演算法。

4、更多的思考

面對這個hw中斷系統之邏輯block diagram,我們其實可以提出更多的問題:

(1)中斷控制器傳送給cpu的中斷是否可以收回?重新分發給另外乙個cpu?

(2)系統中的中斷如何分發才能獲得更好的效能呢?

(3)中斷分發的策略需要考慮哪些因素呢?

……很多問題其實我也沒有答案,慢慢思考,慢慢逼近真相吧。

二、中斷子系統相關的軟體框架

linux kernel的中斷子系統相關的軟體框架圖如下所示:

由上面的block圖,我們可知linux kernel的中斷子系統分成4個部分:

(1)硬體無關的**,我們稱之linux kernel通用中斷處理模組。無論是哪種cpu,哪種controller,其中斷處理的過程都有一些相同的內容,這些相同的內容被抽象出來,和hw無關。此外,各個外設的驅動**中,也希望能用乙個統一的介面實現irq相關的管理(不和具體的中斷硬體系統以及cpu體系結構相關)這些「通用」的**組成了linux kernel interrupt subsystem的核心部分。

(2)cpu architecture相關的中斷處理。 和系統使用的具體的cpu architecture相關。

(3)interrupt controller驅動** 。和系統使用的interrupt controller相關。

(4)普通外設的驅動。這些驅動將使用linux kernel通用中斷處理模組的api來實現自己的驅動邏輯。

linux kernel中的中斷處理流程

2 linux kernel arm64的中斷函式處理流程 1 linux kernel arm32的中斷函式處理流程 我們從irq handler巨集函式看起 1 irq handler巨集 注意config multi irq handler巨集表示 允許每台機器在執行時指定它自己的irq處理程...

關於linux kernel的死法

最近在除錯linux核心驅動,宕機無數次。關於linux的死法也有些心得。1 嘎嘣兒脆型。特點 啥提示也沒有,說宕就宕,var log messages 裡邊啥提示資訊也沒有。原因 八成是你自己沒玩兒好,在kernel裡邊記憶體越界了。還有兩成是超過了linux核心棧8k的限制。2 半死不活型。特點...

Linux kernel 關機的底層操作

linux關機相關命令如 halt,shutdown,poweroff和reboot 其實它們底層都是呼叫名為reboot的system call,其具體實現是在核心目錄的kernel sys.c中的 syscall define4 reboot,int,magic1,int,magic2,unsi...