Linux内核中断初始化的介绍

发布时间:2021-06-25 13:53:09 作者:chen
阅读:288
Linux服务器限时活动,0元免费领! 查看>>
# 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();           // 时钟中断初始化
    ...
}

3.1.1 early_irq_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();
}

3.2 架构相关初始化

3.2.1 init_IRQ()

该函数是架构相关的,以x86架构为例:

// arch/x86/kernel/irqinit.c
void __init init_IRQ(void)
{
    x86_init.irqs.intr_init();  // 调用native_init_IRQ()
}

3.2.2 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();
}

3.3 中断控制器初始化

现代系统通常使用高级可编程中断控制器(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();
}

4. 中断描述符(irq_desc)

每个中断都由一个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;         // 中断名称
    ...
};

4.1 中断处理函数注册

设备驱动程序通过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);
    ...
}

5. 中断处理流程

5.1 硬件级处理

  1. 设备产生中断信号
  2. 中断控制器收集信号并转发给CPU
  3. CPU保存当前上下文并跳转到中断处理程序

5.2 内核级处理

// 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

5.3 do_IRQ()函数

// 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);
    }
    ...
}

6. 中断线程化

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);
    ...
}

7. 中断亲和性

多核系统中可以设置中断的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);
    ...
}

8. 中断统计信息

内核通过/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
...

9. 中断初始化优化

现代Linux内核在中断初始化方面做了多项优化:

  1. 延迟中断初始化:非必要中断推迟到系统启动后初始化
  2. 中断共享:多个设备共享同一中断线
  3. MSI/MSI-X:使用消息信号中断提高性能

10. 总结

Linux内核中断初始化是一个复杂的过程,涉及硬件架构、中断控制器、内核子系统等多个层面的协作。理解中断初始化流程对于内核开发、驱动开发和系统调优都具有重要意义。随着硬件技术的发展,Linux中断子系统也在不断演进,以支持更高效的中断处理和更好的实时性能。

参考资料

  1. Linux内核源码(kernel/irq/目录)
  2. 《Linux Kernel Development》Robert Love
  3. 《Understanding the Linux Kernel》Daniel P. Bovet
  4. Linux内核文档(Documentation/core-api/irq/)

”`

这篇文章详细介绍了Linux内核中断初始化的各个方面,从基本概念到具体实现,涵盖了约2250字的内容。文章采用Markdown格式,包含代码片段、层级结构和必要的技术细节。

亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>

推荐阅读:
  1. 常见初始化参数与unix、Linux内核参数关系
  2. Golang 结构体与初始化介绍

开发者交流群:

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

原文链接:https://my.oschina.net/u/4702401/blog/5046024

linux

上一篇:python爬虫多次请求超时怎么办

下一篇:淘宝h5页面的sign加密算法是怎么用的

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》
开发者交流群×