Linux中斷處理流程
????????在Linux內核中,中斷控制器管理硬件中斷號到Linux中斷號的映射,并通過中斷描述符(struct irq_desc
)進行管理。存儲這種映射關系的方式取決于中斷編號的連續性,具體實現如下:
1.?數組存儲(連續中斷號)
適用場景:當中斷號是連續的且數量有限時,內核使用靜態數組存儲映射關系。
實現方式:
定義一個全局數組?
irq_desc[NR_IRQS]
,其中?NR_IRQS
?是內核支持的最大中斷號數量。每個中斷號直接對應數組的索引。例如,中斷號?
n
?的描述符為?irq_desc[n]
。初始化時,所有描述符預分配并填充默認值(如?
handle_bad_irq
、depth=1
?等),確保未使用的中斷號也有有效描述符。優點:訪問速度快(O(1)時間復雜度),內存連續,適合密集且連續的編號。
缺點:若中斷號稀疏或范圍較大(如存在空洞或超大編號),會導致內存浪費。
2.?基數樹存儲(稀疏中斷號)
適用場景:當中斷號不連續或范圍較大時,使用基數樹(Radix Tree)動態管理映射。
實現方式:
內核配置需開啟?
CONFIG_SPARSE_IRQ
。基數樹按需分配節點,僅存儲實際使用的中斷號及其對應的?
irq_desc
。Linux中斷號由內核動態分配,與硬件中斷號解耦,避免靜態數組的限制。
優點:節省內存,支持稀疏或超大中斷號。
缺點:訪問復雜度略高(接近 O(log n)),動態分配需要額外開銷。
1.中斷描述符
1. 作用
struct irq_desc
?是Linux內核中用于管理單個中斷源的核心數據結構。每個硬件中斷號(或虛擬中斷號)在內核中對應一個?irq_desc
?實例,負責記錄中斷的狀態、處理函數、鎖機制以及關聯的設備處理動作。它是中斷子系統的基礎,確保中斷能夠被正確路由和處理。
2. 核心字段
以下是?
struct irq_desc
?中最重要的字段及其作用:
字段名 類型 說明 irq_data
struct irq_data
存儲與中斷控制器相關的底層信息,如硬件中斷號、觸發方式(邊沿/電平)、中斷芯片等。 handle_irq
irq_flow_handler_t
指向中斷流處理函數(如? handle_edge_irq
?或?handle_level_irq
),負責處理中斷的上下半部。action
struct irqaction *
指向? irqaction
?鏈表的頭節點,表示注冊到該中斷的所有設備處理函數。lock
spinlock_t
自旋鎖,保護中斷描述符的并發訪問。 depth
unsigned int
中斷禁用計數器: depth > 0
?表示中斷被禁用。status
unsigned int
中斷狀態標志(如? IRQ_DISABLED
、IRQ_INPROGRESS
)。
2.irq_desc、irq_chip和irq_domain的區別
1. 核心區別
組件 作用 層級 核心職責 irq_desc
管理單個中斷源的處理邏輯和狀態,包括中斷處理函數、設備注冊信息、鎖機制等。 高層抽象 中斷的軟件管理(狀態、處理流程) irq_chip
定義中斷控制器的硬件操作接口(如使能、禁用、確認中斷),屏蔽不同中斷控制器的差異。 底層硬件抽象 直接操作中斷控制器的硬件行為 irq_domain
管理硬件中斷號(HW IRQ)到Linux虛擬中斷號(IRQ)的映射關系,支持復雜中斷拓撲結構。 中間抽象層 中斷號映射與多中斷控制器的協調
2. 關鍵結構與功能
(1)?
irq_desc
:中斷描述符
核心字段:
irq_data
:關聯底層硬件信息(如?irq_chip
?和?irq_domain
)。
handle_irq
:中斷流處理函數(如?handle_edge_irq
)。
action
:設備驅動注冊的中斷處理函數鏈表(irqaction
)。
lock
:保護并發訪問的自旋鎖。作用:記錄中斷狀態、處理流程和設備注冊信息,是中斷管理的核心單元。
(2)?
irq_chip
:中斷控制器抽象
核心操作函數:
struct irq_chip {void (*enable)(struct irq_data *data); // 使能中斷void (*disable)(struct irq_data *data); // 禁用中斷void (*ack)(struct irq_data *data); // 確認中斷處理完成int (*set_type)(struct irq_data *data, unsigned int type); // 設置觸發類型(邊沿/電平) };
作用:為不同中斷控制器(如PIC、APIC、GIC)提供統一硬件操作接口,實現硬件無關性。
(3)?
irq_domain
:中斷域
核心功能:
將硬件中斷號(HW IRQ)映射到Linux虛擬中斷號(IRQ)。
支持多種映射方式(線性映射、樹形映射、動態分配)。
管理多級中斷控制器的級聯關系(如GPIO控制器級聯到主中斷控制器)。
關鍵方法:
struct irq_domain_ops {int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hwirq);void (*unmap)(struct irq_domain *d, unsigned int virq);// 其他方法(如分配、釋放中斷號) };
3. 層級關系與協作流程
層級關系:
irq_domain → irq_desc → irq_chip
irq_domain
:負責硬件中斷號到Linux中斷號的映射,生成對應的?irq_desc
。
irq_desc
:通過?irq_data
?關聯到?irq_domain
?和?irq_chip
。
irq_chip
:通過?irq_data
?獲取硬件上下文,執行具體的中斷控制器操作。協作流程示例(以中斷觸發為例):
硬件中斷觸發:設備產生硬件中斷號?
hwirq
。映射到Linux中斷號:
irq_domain
?將?hwirq
?轉換為Linux虛擬中斷號?virq
。獲取中斷描述符:通過?
virq
?找到對應的?irq_desc
。處理中斷:
調用?
irq_desc->handle_irq
?執行中斷流處理。遍歷?
irq_desc->action
?鏈表,執行設備驅動注冊的中斷處理函數。操作硬件:通過?
irq_desc->irq_data->irq_chip
?調用?ack()
?或?disable()
?等函數,操作中斷控制器。
4. 設計意義與應用場景
組件 設計目標 典型應用場景 irq_desc
統一管理中斷狀態和流程 所有中斷處理場景(如設備驅動注冊中斷) irq_chip
抽象不同中斷控制器的硬件操作 適配不同硬件平臺(如ARM GIC、x86 APIC) irq_domain
解決復雜中斷號映射問題 多級中斷控制器、動態中斷分配(如PCI設備)
多級中斷控制器:
例如,GPIO控制器級聯到主中斷控制器時,每個控制器有自己的?irq_domain
,irq_domain
?負責級聯中斷號的映射。動態中斷分配:
PCI設備的中斷號可能動態變化,irq_domain
?使用基數樹動態分配Linux中斷號。
5. 總結對比
特性 irq_desc
irq_chip
irq_domain
核心職責 中斷狀態管理與處理流程 中斷控制器的硬件操作 硬件中斷號到Linux中斷號的映射 依賴關系 通過? irq_data
?關聯?irq_chip
?和?irq_domain
由? irq_data
?提供硬件上下文獨立管理中斷號映射,生成? irq_desc
典型操作 注冊中斷處理函數、管理中斷禁用計數 使能/禁用中斷、確認中斷 分配/釋放中斷號、處理多級中斷控制器級聯 設計目標 統一中斷處理邏輯 屏蔽硬件差異 解決復雜中斷拓撲的映射問題
6. 關聯示意圖
硬件中斷 (hwirq)│▼ irq_domain(映射 hwirq → virq)│▼ irq_desc(virq對應的描述符)│▼ irq_chip(操作中斷控制器硬件)
通過?
irq_domain
、irq_desc
?和?irq_chip
?的分工協作,Linux內核實現了對中斷的全面管理:
irq_domain
?解決中斷號的動態映射問題,支持復雜硬件拓撲。
irq_chip
?屏蔽硬件差異,使上層代碼無需關心具體中斷控制器。
irq_desc
?統一管理中斷狀態和處理流程,為設備驅動提供簡潔接口。
3.處理流程詳解
在 ARM64 架構下,在異常級別 1 的異常向量表中,中斷的入口有 3 個:
- 如果處理器處在內核模式(異常級別 1),中斷的入口是 el1_ira;
- 如果處理器處在用戶模式(異常級別 0)下執行 64 位應用程序,中斷的入口函數是 el0_irq;
- 如果處理器正在用戶模式(異常級別 0)下執行 32 位應用程序,中斷的入口函數是 el0_irq_compat。
以網卡接收數據觸發中斷的處理流程為例詳解:?
一、硬件中斷觸發:網卡 → GIC → CPU
網卡硬件動作
網卡接收到網絡數據后,通過內部電路觸發物理中斷引腳(該引腳連接到 GIC 的輸入線)。例如,網卡中斷引腳連接到 GIC 的
SPI 99
(硬件中斷號hwirq=99
)。此時,網卡通過硬件信號告知 GIC 有中斷事件發生。GIC 處理
GIC 的
Distributor
模塊檢測到中斷請求后,借助irq_chip
提供的操作方法(如ack
確認中斷),完成對中斷的初步處理:
- 通過
irq_chip
的ack
方法(如 GIC 的gic_ack
函數),將中斷號寫入 GIC 特定寄存器,標記中斷已被 CPU 接收。- 將中斷路由到目標 CPU 核。此時調用
handle_arch_irq
函數,進入 GIC 的中斷處理函數(如gic_handle_irq
),正式啟動內核中斷處理流程。二、中斷號映射與分發
獲取硬件中斷號
GIC 處理函數從寄存器讀取硬件中斷號(如
hwirq=99
),并判斷其范圍:
- 若
16 ≤ hwirq < 1020
(屬于外部設備中斷范圍),執行以下操作:
- 將中斷號寫入 GIC 的 “中斷結束寄存器”,標記中斷處理開始。
- 調用
handle_domain_irq
,進入中斷號映射流程。
irq_domain
映射中斷號
handle_domain_irq
通過irq_domain
結構體(負責管理硬件中斷號到 Linux 中斷號的映射),執行irq_find_mapping
函數:
irq_domain
根據硬件中斷號hwirq=99
,查找預定義的映射關系,得到對應的 Linux 虛擬中斷號(假設映射結果為linux_irq=128
)。這一步確保內核用統一的 Linux 中斷號管理硬件中斷。三、定位中斷描述符
irq_desc
內核根據映射得到的 Linux 虛擬中斷號
linux_irq=128
,索引到全局數組irq_desc[128]
。irq_desc
存儲該中斷的核心信息:
- 1.中斷處理函數鏈表(
irqaction
鏈表):用于管理共享此中斷號的所有設備的中斷處理函數。若多個設備共享linux_irq=128
,每個設備的irqaction
會通過鏈表組織。
鏈表的構成與用途
?irqaction
?鏈表是存儲在?irq_desc
?結構體中的一個鏈表,用于管理共享同一中斷號的多個設備的中斷處理函數。在系統中,多個設備可能會共享同一個中斷號,每個設備都會有自己對應的?irqaction
?結構體,這些結構體通過鏈表的形式組織起來。當該中斷號對應的中斷發生時,內核會依次遍歷這個鏈表,調用每個?irqaction
?結構體中的中斷處理函數。鏈表的管理與操作
注冊:當設備驅動程序初始化時,會調用?
request_irq
?函數來注冊中斷處理函數。該函數會創建一個?irqaction
?結構體,并將其添加到對應?irq_desc
?的?irqaction
?鏈表中。例如,網卡驅動在初始化時會注冊自己的?irqaction
?結構體:static irqreturn_t nic_irq_handler(int irq, void *dev_id) {// 中斷處理邏輯return IRQ_HANDLED; }struct irqaction nic_irqaction = {.handler = nic_irq_handler,.flags = IRQF_SHARED, // 表示該中斷是共享的.name = "nic_irq",.dev_id = &nic_device, };request_irq(nic_irq, &nic_irqaction);
當中斷發生時,內核會調用?
generic_handle_irq_desc
?函數,該函數會遍歷?irqaction
?鏈表,依次調用每個?irqaction
?結構體中的?handler
?函數。每個?handler
?函數需要通過?dev_id
?來判斷是否是自己設備產生的中斷,并進行相應的處理。- 2.中斷控制器操作方法(通過
irq_chip
關聯):irq_desc
中包含指向irq_chip
的指針,通過irq_chip
定義的方法(如mask
、unmask
、eoi
等),實現對 GIC 的底層控制。
irq_chip
?結構體的作用
irq_chip
?結構體定義了一系列用于操作中斷控制器的方法,這些方法封裝了對中斷控制器硬件的底層操作,如中斷的確認、使能、屏蔽、結束等。irq_desc
?結構體中包含一個指向?irq_chip
?的指針,通過這個指針可以調用?irq_chip
?中定義的方法來控制中斷控制器。常見的操作方法
ack
?方法:用于確認中斷。當中斷控制器接收到中斷請求并通知 CPU 后,CPU 需要通過調用?ack
?方法來告訴中斷控制器已經開始處理該中斷。例如,GIC 的?ack
?方法會將中斷號寫入特定的寄存器,標記中斷處理開始。static void gic_ack(struct irq_data *d) {// 將中斷號寫入GIC的中斷確認寄存器writel_relaxed(d->irq, gic_dist_base + GIC_DIST_ACK); }
mask
?方法:用于屏蔽中斷。在某些情況下,需要暫時禁止某個中斷的觸發,此時可以調用?mask
?方法。例如,在進行一些關鍵操作時,為了避免中斷干擾,可以屏蔽網卡中斷。static void gic_mask(struct irq_data *d) {// 設置GIC的中斷屏蔽寄存器writel_relaxed(1 << (d->irq & 31), gic_dist_base + GIC_DIST_ENABLE_CLEAR); }
四、執行中斷處理函數
1.觸發?
handle_irq
?入口函數? ? ? ? 內核在初始化中斷控制器(如 GIC)時,會根據硬件中斷號范圍(<32 或≥32)設置 irq_desc 的 handle_irq 函數指針。
irq_desc[linux_irq].handle_irq
?根據硬件中斷號是否小于 32,被設置為不同的函數:
- 硬件中斷號 < 32:
handle_percpu_devid_irq
(用于早期的單 CPU 中斷)。- 硬件中斷號 ≥ 32:
handle_fasteoi_irq
(用于現代多核中斷)。? ? ? ? 比如在網卡接收數據的這個案例中處理邏輯如下:
void handle_fasteoi_irq(struct irq_desc *desc) {// 快速EOI中斷處理流程desc->irq_data.chip->ack(&desc->irq_data);generic_handle_irq_desc(desc); // 遍歷irqaction鏈表desc->irq_data.chip->eoi(&desc->irq_data); }
2.遍歷
irqaction
鏈表?
irq_desc[128]
維護irqaction
鏈表。調用generic_handle_irq
,最終觸發generic_handle_irq_desc
,遍歷鏈表:
- 若鏈表中存在網卡驅動注冊的
irqaction
,則調用其.handler
函數(如nic_irq_handler
)。3.網卡驅動的
irqaction
工作網卡驅動注冊的
irqaction
包含:
.handler
:中斷處理函數(如nic_irq_handler
)。.dev_id
:網卡設備標識,用于區分共享中斷的不同設備。
nic_irq_handler
執行:
- 讀取數據:通過寄存器操作,讀取網卡接收緩沖區數據。
- 數據封裝與提交:將數據封裝成網絡協議幀,提交給上層網絡協議棧(如 Linux 網絡子系統)。
- 清除中斷狀態:清除網卡中斷狀態寄存器,準備下次中斷接收。
中斷下半部(軟中斷)處理
- 觸發軟中斷:在中斷處理函數中,若有耗時操作(如協議處理)不適合在中斷處理函數中完成,因此引入了中斷下半部分(軟中斷)的機制,軟中斷可以在中斷處理函數返回后,在合適的時機(如系統空閑時)執行,從而避免影響系統的實時性。通過
netif_rx
等函數觸發軟中斷(如NET_RX_SOFTIRQ
)。
- 網卡驅動的中斷處理函數(
nic_irq_handler
)作為中斷上半部分,主要完成一些緊急的操作,如讀取網卡接收緩沖區的數據,并將數據傳遞給軟中斷處理函數。static irqreturn_t nic_irq_handler(int irq, void *dev_id) {// 讀取網卡接收緩沖區的數據struct sk_buff *skb = nic_read_rx_buffer();if (skb) {// 將數據傳遞給軟中斷處理函數netif_rx(skb);}return IRQ_HANDLED; }
- 軟中斷處理函數:系統在合適時機(如
do_softirq
執行時),調用軟中斷處理函數(如net_rx_action
):
- 從接收隊列取出數據,進行詳細解析、協議處理(如 IP 層、TCP 層處理),最終將數據傳遞給應用層。
static void net_rx_action(struct softirq_action *h) {struct sk_buff *skb;while ((skb = skb_dequeue(&rx_queue))) {// 數據解析、協議處理等操作netif_receive_skb(skb);} }open_softirq(NET_RX_SOFTIRQ, net_rx_action);
五、中斷處理完成
處理函數(含軟中斷)執行完畢后,通過
irq_chip
的.eoi
方法(如gic_eoi
):
- 告知 GIC 中斷處理完成。GIC 更新寄存器,允許后續同類型中斷再次觸發,完成一次完整的中斷處理閉環。
關鍵結構體協作總結
結構體 作用 irq_chip
提供 GIC 操作方法( ack
、eoi
、mask
等),直接控制中斷控制器硬件行為。irq_domain
管理硬件中斷號到 Linux 中斷號的映射,確保內核正確識別中斷來源。 irq_desc
存儲中斷描述符,維護 irqaction
鏈表,是中斷處理的核心管理結構。irqaction
包含網卡驅動的中斷處理函數,執行數據讀取、協議處理等業務邏輯。
?https://github.com/0voice