您好,登录后才能下订单哦!
# 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格式,包含代码片段、层级结构和必要的技术细节。
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
开发者交流群:
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
原文链接:https://my.oschina.net/u/4702401/blog/5046024