# Linux內核中斷初始化的介紹
## 1. 中斷概述
中斷(Interrupt)是計算機系統中一種重要的機制,它允許硬件設備在需要時打斷處理器的正常執行流程。中斷機制使得CPU不必輪詢設備狀態,從而提高了系統效率。
### 1.1 中斷的分類
Linux內核中的中斷主要分為以下幾類:
1. **硬件中斷(Hardware Interrupt)**:由外部設備產生,如鍵盤、鼠標、網卡等
2. **軟件中斷(Software Interrupt)**:由軟件指令觸發,如系統調用
3. **異常(Exception)**:由CPU內部事件觸發,如除零錯誤、頁錯誤等
### 1.2 中斷處理的特點
- 異步性:中斷可以在任何時候發生
- 優先級:不同類型的中斷有不同的優先級
- 嵌套性:高優先級中斷可以打斷低優先級中斷的處理
## 2. Linux內核中斷子系統架構
Linux內核中斷子系統采用分層設計,主要包含以下組件:
+———————–+ | 驅動層中斷處理 | +———————–+ | 通用中斷處理層 | +———————–+ | CPU架構相關層 | +———————–+ | 硬件中斷控制器 | +———————–+
## 3. 中斷初始化流程
### 3.1 早期初始化(start_kernel階段)
在內核啟動的早期階段(start_kernel函數中),會進行中斷子系統的初步初始化:
```c
// init/main.c
asmlinkage __visible void __init start_kernel(void)
{
...
early_irq_init(); // 早期中斷描述符初始化
init_IRQ(); // 架構相關中斷初始化
tick_init(); // 時鐘中斷初始化
...
}
該函數初始化中斷描述符表(irq_desc數組),為每個可能的中斷號分配一個irq_desc結構:
// kernel/irq/irqdesc.c
int __init early_irq_init(void)
{
struct irq_desc *desc;
int count;
for (count = 0; count < NR_IRQS; count++) {
desc = alloc_desc(count, node, flags, mask, owner);
irq_insert_desc(count, desc);
}
return arch_early_irq_init();
}
該函數是架構相關的,以x86架構為例:
// arch/x86/kernel/irqinit.c
void __init init_IRQ(void)
{
x86_init.irqs.intr_init(); // 調用native_init_IRQ()
}
x86架構特有的中斷初始化:
// arch/x86/kernel/irqinit.c
void __init native_init_IRQ(void)
{
/* 初始化IDT表 */
idt_setup_apic_and_irq_gates();
/* 注冊默認中斷處理函數 */
for (i = 0; i < NR_VECTORS; i++) {
set_intr_gate(i, interrupt[i]);
}
/* 初始化本地APIC */
apic_intr_init();
}
現代系統通常使用高級可編程中斷控制器(APIC):
// arch/x86/kernel/apic/apic.c
void __init apic_intr_init(void)
{
/* 初始化本地APIC */
setup_local_APIC();
/* 初始化IOAPIC */
if (io_apic_init() < 0)
panic("IO APIC initialization failed");
/* 設置中斷親和性 */
setup_irq_affinity();
}
每個中斷都由一個irq_desc結構描述:
// include/linux/irqdesc.h
struct irq_desc {
struct irq_data irq_data;
irq_flow_handler_t handle_irq; // 流處理函數
struct irqaction *action; // 中斷處理鏈表
unsigned int depth; // 禁用計數
unsigned int irq_count; // 中斷計數
const char *name; // 中斷名稱
...
};
設備驅動程序通過request_irq()注冊中斷處理函數:
// kernel/irq/manage.c
int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long flags, const char *name, void *dev)
{
struct irqaction *action;
int retval;
action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
action->handler = handler;
action->flags = flags;
action->name = name;
action->dev_id = dev;
retval = __setup_irq(irq, desc, action);
...
}
// arch/x86/entry/entry_64.S
ENTRY(irq_entries_start)
vector=FIRST_EXTERNAL_VECTOR
.rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
pushq $(~vector+1)
jmp common_interrupt
vector=vector+1
.endr
END(irq_entries_start)
common_interrupt:
SAVE_ALL
movq %rsp, %rdi
call do_IRQ
jmp ret_from_intr
// arch/x86/kernel/irq.c
__visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
{
struct irq_desc *desc;
unsigned vector = ~regs->orig_ax;
desc = __this_cpu_read(vector_irq[vector]);
if (likely(desc != NULL)) {
handle_irq(desc, regs);
}
...
}
Linux支持將中斷處理線程化,減少關中斷時間:
// kernel/irq/manage.c
static int
__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
{
if (new->flags & IRQF_ONESHOT)
irq_setup_forced_threading(new);
...
}
多核系統中可以設置中斷的CPU親和性:
// kernel/irq/proc.c
static ssize_t write_irq_affinity(int fd, const char __user *buffer,
size_t count, loff_t *pos)
{
cpumask_var_t new_value;
alloc_cpumask_var(&new_value, GFP_KERNEL);
cpumask_parse_user(buffer, count, new_value);
irq_set_affinity(irq, new_value);
...
}
內核通過/proc/interrupts提供中斷統計:
$ cat /proc/interrupts
CPU0 CPU1
0: 45 0 IO-APIC 2-edge timer
1: 3 0 IO-APIC 1-edge i8042
8: 1 0 IO-APIC 8-edge rtc0
...
現代Linux內核在中斷初始化方面做了多項優化:
Linux內核中斷初始化是一個復雜的過程,涉及硬件架構、中斷控制器、內核子系統等多個層面的協作。理解中斷初始化流程對于內核開發、驅動開發和系統調優都具有重要意義。隨著硬件技術的發展,Linux中斷子系統也在不斷演進,以支持更高效的中斷處理和更好的實時性能。
”`
這篇文章詳細介紹了Linux內核中斷初始化的各個方面,從基本概念到具體實現,涵蓋了約2250字的內容。文章采用Markdown格式,包含代碼片段、層級結構和必要的技術細節。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。