很多人在學(xué)習(xí)中斷子系統(tǒng)的過程中,在對基本概念與整體不太了解的情況下,過早的陷入了各種架構(gòu)的實現(xiàn)細(xì)節(jié),如同盲人摸象。這里主要給大家明確中斷的各個基本概念,希望從這個角度能讓大家更好的理解中斷子系統(tǒng)。
什么是中斷
在計算機(jī)科學(xué)中,中斷(英語:Interrupt)是指處理器接收到來自硬件或軟件的信號,提示發(fā)生了某個事件,應(yīng)該被注意,這種情況就稱為中斷。中斷子系統(tǒng)中的中斷指的是其中硬件的一方,后續(xù)中斷均按此理解。
中斷處理的參與對象和流程
中斷處理中有著多個對象的參與,理解每個對象在其中是如何參與是很重要的。以下列舉了中斷處理的參與對象。
中斷事件:指中斷事件本身的抽象。
中斷號:用于硬件和軟件識別并區(qū)分中斷事件,需要注意同一個中斷事件在中斷處理的不同階段未必是同一個中斷號。
中斷源:有中斷事件需要 cpu 處理的硬件。
中斷控制器:非必須,用于解決系統(tǒng)擁有多中斷源場景的硬件;從中斷源接收中斷事件并傳遞到 cpu;可以級聯(lián)。
cpu:收到中斷,cpu 跳轉(zhuǎn)到特定的地址——中斷向量。由中斷向量開始軟件對中斷的處理。
中斷事件在硬件中的流程如下,上一行是中斷事件的體現(xiàn)形式,下一行是所在的硬件:
再把軟件處理結(jié)合起來,形成一個硬件軟件切換的過程:
相鄰的中斷事件體現(xiàn)形式的映射方式可以在所在的對象的連接的實現(xiàn)中找到。
中斷子系統(tǒng)
現(xiàn)在把之前的流程具有的部分對比內(nèi)核中斷子系統(tǒng),可以發(fā)現(xiàn)還多出了一個通用中斷處理層。因為內(nèi)核需要支持各種不同的架構(gòu)與外設(shè),需要解耦架構(gòu)硬件相關(guān)部分(cpu 與中斷控制器)與非架構(gòu)相關(guān)(外設(shè)),使得開發(fā)外設(shè)驅(qū)動并不需要了解架構(gòu)相關(guān)部分。另一方面,系統(tǒng)硬件拓?fù)浣Y(jié)構(gòu)的信息一般由設(shè)備樹源碼 DTS 體現(xiàn)。
硬件封裝層
硬件封裝層包括 cpu 和中斷控制器兩部分。區(qū)分開 cpu 和中斷控制器相當(dāng)重要,希望大家能更明確 cpu 和中斷控制器的概念。軟件在 cpu 方面主要需要按架構(gòu)實現(xiàn)中斷向量的處理,可以看 arch/「/kernel/entry」.S 的匯編實現(xiàn)。另外還需要為通用的開關(guān)中斷方法提供架構(gòu)實現(xiàn):
通用中斷開關(guān)方法 | 具體架構(gòu)中斷開關(guān)實現(xiàn) |
---|---|
local_irq_enable | arch_local_irq_enable |
local_irq_disable | arch_local_irq_disable |
這個 local 指的是 local_cpu,表示的是當(dāng)前 cpu 是否響應(yīng)中斷:當(dāng)前 cpu 關(guān)中斷的情況下,中斷控制器不管怎么玩都是徒勞的。事實上 cpu 對中斷開關(guān)的實現(xiàn)還包含著很多條件,類似特權(quán)態(tài)、非屏蔽中斷 NMI 之類的,可以在后文找下具體分析。軟件對中斷控制器的抽象是 struct irq_chip,體現(xiàn)的是中斷控制器所具體的行為。這里列舉部分重要成員講解:
起因 | struct irq_chip 成員 | 說明 |
---|---|---|
怎么控制中斷控制器是否屏蔽某個中斷事件? | irq_enable/ irq_disable | |
中斷控制器如何配置中斷事件的觸發(fā)方式 | irq_set_type | 控制各個中斷的電氣觸發(fā)條件,例如邊沿觸發(fā)或者是電平觸發(fā)。 |
中斷控制器如何得知中斷事件被 cpu 響應(yīng)? | irq_ack | 中斷控制器在實現(xiàn)中會根據(jù)中斷事件被 cpu 開始響應(yīng)或完成響應(yīng)來決定該中斷事件類型是否會再度通知 cpu 處理。 |
中斷控制器如何得知 cpu 完成處理中斷事件? | irq_eoi | 中斷控制器在實現(xiàn)中會根據(jù)中斷事件被 cpu 開始響應(yīng)或完成響應(yīng)來決定該中斷事件類型是否會再度通知 cpu 處理。 |
在 smp 系統(tǒng)中,中斷事件應(yīng)該通知哪個 cpu? | irq_set_affinity | affinity 表示了中斷事件在中斷控制器中配置的目標(biāo) cpu,根據(jù)具體實現(xiàn)可以是 1 個或多個。 |
此外,當(dāng)多個中斷事件同時發(fā)生,中斷控制器會根據(jù)其優(yōu)先級的實現(xiàn)來決定中斷事件通知給 cpu 的順序,某些實現(xiàn)是可配置的。另一方面,考慮到系統(tǒng)中可能存在多個中斷控制器,使得單一中斷控制器的中斷號不足以區(qū)分中斷事件,所以引入了軟件中斷號的概念。加上硬件中斷號映射中斷號的軟件抽象 struct irq_domain,再看中斷控制器軟件抽象到中斷源軟件抽象的流程:
##中斷流控處理層這一層主要是隱藏了中斷控制器在具體中斷事件處理函數(shù)調(diào)用前后的一些處理邏輯,包括:
何時對中斷控制器發(fā)出 ack 回應(yīng)?
mask_irq 和 unmask_irq 的處理;
中斷控制器是否需要 eoi 回應(yīng)?
何時打開 cpu 的本地 irq 中斷?以便允許 irq 的嵌套;
類似于在用洗衣機(jī)洗衣服的時候,我們不關(guān)心衣服可能要經(jīng)歷過的洗滌多久、脫水多久、漂洗多久諸如此類的步驟細(xì)節(jié),只需要按衣服類型選擇流程;內(nèi)核引入中斷流程的抽象類型 irq_flow_handler_t 屏蔽了中斷事件相關(guān)的 cpu、中斷控制器和中斷源的屬性的不同帶來的處理流程差異。這里舉例部分內(nèi)核實現(xiàn):
handle_simple_irq:用于簡易流控處理。
handle_level_irq:用于電平觸發(fā)中斷的流控處理。
handle_edge_irq:用于邊沿觸發(fā)中斷的流控處理。
handle_fasteoi_irq:用于需要響應(yīng) eoi 的中斷控制器
handle_percpu_irq:用于只在單一 cpu 響應(yīng)的中斷。
驅(qū)動程序 API 與中斷通用邏輯
對于中斷事件本身,內(nèi)核使用 struct irq_desc 進(jìn)行描述,它包含著所有的信息。而對于中斷控制器與中斷源的驅(qū)動來說,關(guān)注的信息都只是其中的一部分。中斷事件從中斷源到中斷控制器的映射的描述一般事先會靜態(tài)定義好并存放在設(shè)備樹源碼里,即中斷源的設(shè)備樹節(jié)點包含著相連的中斷控制器和中斷事件對應(yīng)在中斷控制器中斷號的信息;而作為驅(qū)動程序需要對軟件中斷號 irq 和中斷事件處理函數(shù)建立映射。那么要把設(shè)備樹節(jié)點中的中斷控制器和中斷控制器中斷號轉(zhuǎn)換成軟件中斷號 irq,內(nèi)核給驅(qū)動程序提供了接口:
irq_of_parse_and_map:驅(qū)動由設(shè)備樹節(jié)點獲得 irq。
當(dāng)中斷控制器和中斷控制器中斷號轉(zhuǎn)換成軟件中斷號 irq 映射不存在時,這個接口會申請 irq_desc 并建立映射,根據(jù)連接著的中斷控制器的驅(qū)動提供的硬件中斷號映射中斷號的軟件抽象 irq_domain 完成映射。在映射過程中會包括對 irq_desc 的一些屬性的設(shè)置,如:
irq_set_handler:驅(qū)動選擇 irq_flow_handler。
irq_set_chip:驅(qū)動選擇 irq 連接的中斷控制器。
irq_alloc_desc 系列:驅(qū)動直接申請 irq_desc。
中斷源驅(qū)動獲取到 irq,還需要將 irq 與中斷處理函數(shù)建立映射:
request_irq/request_threaded_irq:驅(qū)動將中斷處理函數(shù)注冊到 irq。
enable_irq & disable_irq:驅(qū)動開關(guān) irq。
接下來將對一些具體的架構(gòu)實現(xiàn)做介紹。這里介紹兩個處理器 armv8 和 x86,以及兩個中斷控制器 arm-gicv3 和 x86-APIC 的實現(xiàn)。希望幫助大家得出諸如“arm 內(nèi)核有中斷嵌套嗎”“arm cpu eoi 是做什么”這類問題的答案。
armv8
arm 核心擁有 2 個外部中斷線,IRQ 和 FIQ;這兩根中斷線連接到中斷控制器上,中斷控制器通過拉高和拉低這兩根中斷線觸發(fā)中斷。一個中斷應(yīng)該觸發(fā) IRQ 還是 FIQ 中斷線,由其 GROUP 屬性和當(dāng)前的特權(quán)級和安全域決定。
GROUP 的定義:
arm 核,軟件可以寫 SCR、HCR 和 PSTATE.DAIF 寄存器以決定響應(yīng)中斷的特權(quán)級和屏蔽中斷;arm 不支持 NMI。arm 核由于中斷控制器的實現(xiàn),同時只會有一個需要被響應(yīng)的中斷,因此不限制 IRQ/FIQ 響應(yīng)順序的實現(xiàn)。arm 核上處于觸發(fā)狀態(tài)的中斷線需要結(jié)合 SCR、HCR 和 PSTATE.DAIF 寄存器判斷是否觸發(fā)中斷,不論當(dāng)前是否處于中斷。在中斷觸發(fā)時,arm 核心根據(jù) VBAR 系列寄存器的基地址,會按具體情況選擇偏移跳轉(zhuǎn)到對應(yīng)的地址。
x86
Intel x86 架構(gòu)提供 INTR 和 NMI 兩個中斷引腳,他們通常與 Local APIC 相連, 用于接收 Local APIC 傳遞的中斷信號。一個中斷應(yīng)該觸發(fā) INTR 還是 NMI 中斷線由 Local APIC 實現(xiàn)。
x86,中斷都在 ring0 響應(yīng)。x86 上軟件使用 CLI 指令將本 CPU 的 EFLAGS 寄存器的 IF 位清 0,阻止接收中斷;STI 指令將 IF 位置為 1,允許接收中斷。這兩條指令都只對當(dāng)前 CPU 起作用,而不影響平臺上的其他 CPU。x86 中斷線的實現(xiàn)原生支持 NMI。x86 核上同時只會有一個需要被響應(yīng)的中斷,它由 Local APIC 從 IRR 中選擇;當(dāng) Local APIC 不使能時,優(yōu)先響應(yīng) NMI 中斷線。不論當(dāng)前是否處于中斷,x86 核上若 INTR 處于觸發(fā)且未屏蔽中斷即會觸發(fā)中斷;NMI 處于觸發(fā)則直接觸發(fā)中斷。中斷觸發(fā)時,x86 核根據(jù)寄存器 IDTR 記錄的基址和中斷控制器的寄存器 ISR 提供的中斷向量號找到 IDT 表中對應(yīng)的 Interrupt Gate 表項,跳轉(zhuǎn)到相應(yīng)的地址。
arm-gicv3
從邏輯視圖上看,gicv3 的核外部分統(tǒng)稱 IRI,由 Distributor、ITS、Redistributor 這 3 種組件組成;gicv3 核內(nèi)部分是 CPU interface,PE 可以理解為 cpu;IRI 與 CPU interface 通過 GIC Stream Protocol interface 交互。
不同的中斷在 gic 上對應(yīng)著不同的 INTID;gic 把中斷類型分為 LPI、PPI、SPI、SGI,約束 INTID 取值對應(yīng)的中斷類型。SGI 指由 CPU 直接寫對應(yīng)的寄存器觸發(fā)中斷;PPI 指中斷為特定一個 CPU 私有/專用,同一中斷號的 PPI 在不同 CPU 可以指不同的中斷源;SPI 對應(yīng) PPI,是所有 CPU 全局共享的,同一中斷號的 SPI 在不同 CPU 均指相同的中斷源;LPI 的區(qū)分是中斷路由上的不同,主要是在 IRI 中由 ITS 路由的中斷,其余 3 種中斷均不經(jīng)過 ITS;某些實現(xiàn)下還有直接在 Redistributor 觸發(fā)的 LPI 中斷。
一個外部中斷從在外設(shè)上產(chǎn)生,依次經(jīng)過 IRI、CPU interface 并最終通過中斷線到達(dá) PE;PE 產(chǎn)生的中斷需要先經(jīng)過 CPU interface 到 IRI,再到目標(biāo)的 CPU interface 和 PE。邏輯上,IRI 可以對應(yīng)多個 PE,因此對于需要被一個特定目標(biāo) PE 響應(yīng)的中斷,gicv3 通過引入 affinity routing 機(jī)制解決這種路由問題。同一時間,CPU interface 上只能存在一個待處理的中斷,對于多個中斷被發(fā)送到 CPU interface 上,gic 引入優(yōu)先級的機(jī)制來決定如何選擇保留的中斷;這個優(yōu)先級的機(jī)制還被運(yùn)用在 IRI 上,優(yōu)先級更高的中斷會被優(yōu)先發(fā)送到 CPU interface。另外,CPU interface 還負(fù)責(zé)將這個待處理的中斷按照 GROUP 屬性和當(dāng)前的特權(quán)級和安全域決定觸發(fā) IRQ 還是 FIQ 中斷線;并且當(dāng) PE 當(dāng)前處于中斷時,CPU interface 還需要通過中斷優(yōu)先級分組的機(jī)制判斷待處理的中斷是否需要被通知給 PE,即搶占。
x86-APIC
從邏輯視圖上看,APIC 的核外部分是 I/O APIC,核內(nèi)部分是 Local APIC。I/O APIC 根據(jù)內(nèi)部 PRT table 中的 RTE 發(fā)送中斷消息給 Local APIC。I/O APIC 中 PRT table 由 24 個 RTE 項組成,每一項對應(yīng)一個 IRQ 引腳。I/O APIC 可以有多個,當(dāng)多個 I/O APIC 存在時,使用 GSI 代表每個 I/O APIC 管腳的編號:例如 I/O APIC1 有 24 個 IRQ,I/O APIC2 也有 24 個 IRQ,則 I/O APIC2 的 GSI 是從 24 開始,GSI = 24 + IRQ(I/O APIC2)。I/O APIC 的 24 個管腳沒有優(yōu)先級之分。一個外部中斷經(jīng)過 I/O APIC 再到 Local APIC,最后由 Local APIC 控制中斷線在 CPU 上觸發(fā)中斷;CPU 內(nèi)部的中斷源由 Local APIC 管理,不需要經(jīng)過 I/O APIC;IPI 也由 Local APIC 管理,同樣不需要經(jīng)過 I/O APIC。
Local APIC 支持 0-255 的中斷向量號,它們可以同時存在于寄存器 IRR 上,引入中斷優(yōu)先級進(jìn)行選擇:優(yōu)先級 = 中斷向量號 / 16因為 32 以下的中斷向量號是保留的,所以可用中斷優(yōu)先級范圍為 2-15,數(shù)字越大優(yōu)先級越高;當(dāng)優(yōu)先級高于寄存器 PPR 的情況下會操作 INTR 中斷線,若當(dāng)前已經(jīng)處于中斷則可能出現(xiàn)搶占。中斷向量號的低 4 位會在當(dāng) PPR 改變的情況下,ISR 從 IRR 上選擇中斷向量號的比較中使用,同樣也是數(shù)字越大優(yōu)先級越高。
審核編輯 :李倩
-
處理器
+關(guān)注
關(guān)注
68文章
18926瀏覽量
227218 -
控制器
+關(guān)注
關(guān)注
112文章
15884瀏覽量
175354
原文標(biāo)題:openEuler Kernel 技術(shù)解讀 | 內(nèi)核中斷子系統(tǒng)介紹
文章出處:【微信號:openEulercommunity,微信公眾號:openEuler】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論