Linux 中斷子系統(tǒng):GIC 中斷控制器
GIC 是 ARM 公司給 Cortex-A/R 內(nèi)核提供的一個中斷控制器,類似 Cortex-M 內(nèi)核(STM32)中的 NVIC。
- GIC:Generic Interrupt Controller,通用中斷控制器。
- NVIC:Nested Vectored Interrupt Controller,嵌套中斷向量控制器。
目前 GIC 有 4 個版本:V1~V4,V1 是最老的版本,已經(jīng)被廢棄了。V2~V4 目前正在大量的使用。GIC V2 是給 ARMv7-A 架構(gòu)使用的,比如 Cortex-A7、Cortex-A9、Cortex-A15 等, V3 和 V4 是給 ARMv8-A/R 架構(gòu)使用的,也就是 64 位芯片使用的。
我們使用的是 IP 核,也就是 gic400、gic500、gic600。支持對應(yīng)的架構(gòu)。
gic400,支持 GIC-v2 架構(gòu)。
gic500,支持 GIC-v3 架構(gòu)。
gic600,支持 GIC-v3 和 GIC-v4 架構(gòu)。
GIC-v2
GIC V2 最多支持 8 個核。ARM 會根據(jù) GIC 版本的不同研發(fā)出不同的 IP 核,半導(dǎo)體廠商直接購買對應(yīng)的 IP 核即可,比如 ARM 針對 GIC V2 就開發(fā)出 了 gic400 這個中斷控制器 IP 核。
當(dāng) GIC 接收到外部中斷信號以后就會報給 ARM 內(nèi)核,但是 ARM 內(nèi)核只提供了四個信號給 GIC 來匯報中斷情況:VFIQ、VIRQ、FIQ 和 IRQ:
VFIQ:虛擬快速 IRQ。
VIRQ:虛擬 IRQ。
FIQ:快速 IRQ。
IRQ::Interrupt ReQuest。
VFIQ 和 VIRQ 是針對虛擬化的,我們不討論虛擬化中斷,剩下的就是 FIQ 和 IRQ 了。一般我們只使用 IRQ,所以相當(dāng)于 GIC 最終向 ARM 內(nèi)核就上報一個 IRQ 信號。
下圖來源于ARM官方手冊,是 GIC-v2 的框圖:
左側(cè)部分就是中斷源,中間部分就是 GIC 控制器,最右側(cè)就是中斷控制器向 處理器內(nèi)核發(fā)送中斷信息。我們重點(diǎn)要看的肯定是中間的 GIC 部分,GIC 將眾多的中斷源分為 分為三類:
①、SPI(Shared Peripheral Interrupt),共享外設(shè)中斷,該中斷來自于外設(shè),所有 Core 共享的中斷。比如按鍵中斷、串口中斷等等,這些中斷所有的 Core 都可以處理,不限定特定 Core。
②、PPI(Private Peripheral Interrupt),私有外設(shè)中斷,該終端來自于外設(shè),被特定的核處理。GIC 是支持多核的,每個核有自己獨(dú)有的中斷。
③、SGI(Software-generated Interrupt),軟中斷,由軟件觸發(fā)引起的中斷,通過向寄存器 GICD_SGIR 寫入數(shù)據(jù)來觸發(fā),系統(tǒng)會使用 SGI 中斷來完成多核之間的通信。
中斷源有很多,為了區(qū)分這些不同的中斷源肯定要給他們分配一個唯一 ID,這些 ID 就是中斷 ID。GIC-v2中每一個 CPU 最多支持 1020 個中斷 ID,中斷 ID 號為 ID0~ID1019。這 1020 個 ID 包 含了 PPI、SPI 和 SGI。這 1020 個 ID 分 配如下:
ID0~ID15:這 16 個 ID 分配給 SGI。每個CPU核都有自己的16個。
ID16~ID31:這 16 個 ID 分配給 PPI。每個CPU核都有自己的16個。
ID32~ID1019:這 988 個 ID 分配給 SPI,像 GPIO 中斷、串口中斷等這些外部中斷 ,至于具體到某個 ID 對應(yīng)哪個中斷那就由半導(dǎo)體廠商根據(jù)實際情況去定義了。
GIC-v2 架構(gòu)分為了兩個邏輯塊:Distributor 和 CPU Interface,也就是分發(fā)器端和 CPU 接口端。
Distributor(分發(fā)器端):中間那個框框,此邏輯塊負(fù)責(zé)處理各個中斷事件的分發(fā)問題,也就是中斷事件應(yīng)該發(fā)送到哪個 CPU Interface 上去。分發(fā)器收集所有的中斷源,可以控制每個中斷的優(yōu)先級,它總是將優(yōu)先級最高的中斷事件發(fā)送到 CPU 接口端。分發(fā)器端要做的主要 工作如下:
①、全局中斷使能控制。
②、控制每一個中斷的使能或者關(guān)閉。
③、設(shè)置每個中斷的優(yōu)先級。
④、設(shè)置每個中斷的目標(biāo)處理器列表。
⑤、設(shè)置每個外部中斷的觸發(fā)模式:電平觸發(fā)或邊沿觸發(fā)。
⑥、設(shè)置每個中斷屬于組 0 還是組 1。
CPU Interface(CPU 接口端):CPU 接口端聽名字就知道是和 CPU Core 相連接的,因此在圖中每個 CPU Core 都可以在 GIC 中找到一個與之對應(yīng)的 CPU Interface。CPU 接口端 就是分發(fā)器和 CPU Core 之間的橋梁,CPU 接口端主要工作如下:
①、使能或者關(guān)閉發(fā)送到 CPU Core 的中斷請求信號。
②、應(yīng)答中斷。
③、通知中斷處理完成。
④、設(shè)置優(yōu)先級掩碼,通過掩碼來設(shè)置哪些中斷不需要上報給 CPU Core。
⑤、定義搶占策略。
⑥、當(dāng)多個中斷到來的時候,選擇優(yōu)先級最高的中斷通知給 CPU Core。
GIC-v2 支持 bypass 功能,當(dāng)左上角 CFGSDISABLE 信號為高,外部來的 IRQ 和FIQ 不經(jīng)過 GIC 仲裁,直連 CPU core 的 IRQ 和 FIQ 引腳。此場景可能用在啟動階段,一般不用。
右上角有 GICD_ 、GICC_ 、GICV_ 、GICH_ 系列寄存器,因為不討論虛擬中斷,所以我們一般只關(guān)心 GICD_ 、GICC_ 開頭的寄存器, GICD_ 代表 Distributor 分配器的寄存器, GICC_ 代表 CPU interface 的寄存器。
有一點(diǎn)需要說明:不管 GIC 如何對中斷進(jìn)行分類,對 CPU core 來講,只分為 IRQ、FIQ、VIRQ、VFIQ,一般所有的外部中斷對CPU core來講都屬于IRQ:
即便在 GIC 內(nèi)部分為了 SPI、SGI、PPI,但是最后都會到 CPU interface,CPU interface 再給 CPU core ,CPU core 只認(rèn)為有四種中斷類型,普通都是 IRQ。
GIC-v3
GIC-v3 架構(gòu)有改變,中斷號也變多了,不過還是向后兼容 GIC-v2 的。
GIC-v3支持超多核,以 xxx.xxx.xxx.xxx 命名,不止8核,GIC-v2 只支持 8 核,命名為 0-7 。
GIC-v3將 CPU interface 從GIC側(cè)移到了CPU側(cè),因為處理中斷會頻繁訪問 CPU interface 的寄存器,移到 CPU 側(cè)加快訪問速度,中斷處理就會加快。
GIC-v3 的架構(gòu)變化如下:以前 SPI、PPI、SGI 都?xì)w Distributor(分發(fā)器端) 管,現(xiàn)在只有 SPI 歸 Distributor管,PPI、SGI、LPI 都?xì)w Redistributor 管,作用還是一樣的。
寄存器分布,不同東西的寄存器開頭不一樣:
GIC-v 3的中斷號規(guī)定如下,來源于ARM官方文檔。
最主要的區(qū)別就是增加了 LPI 這個中斷類型,是基于消息的中斷。
一般 IRQ 和 FIQ 都會有一個物理線,會給 CPU 核一個物理信號,代表中斷到來。LPI 不一樣,它是基于消息的機(jī)制,寫寄存器就會發(fā)一個消息中斷,是 ARM 在為未來布局,以后會出一些 server 的產(chǎn)品,獨(dú)享中斷號。
GIC-v3 邏輯圖總結(jié)如下:
GIC -v2 架構(gòu)寄存器:
來源于 GIC-v2 手冊最后幾頁:
這里的 alias 別名很有意思,說明了這個寄存器是干嘛的:
GIC -v3的寄存器不一樣,是 ICC_ 、ICV_ 、ICH_ 系列寄存器。