Linux x86_64内核中断初始化

中断分类

Linux系统中,中断分为:

  • 硬中断:由外部设备或者执行异常产生的需要快速处理的中断。如缺页中断、定时器硬件中断。

    根据内部产生还是外部产生,分为:
    1. 异常:异常是内部产生的中断,不可屏蔽。
    2. 外部中断:外部中断是由外部设备产生的,可以屏蔽。
  • 软中断:

    ​ 软中断是Linux系统中断处理的底半处理部分,是Linux模拟的中断。为了加快硬件中断的处理,防止数据的丢失,Linux对中断处理分为顶半处理和底半处理两部分,顶半处理程序快速处理硬件事件,把不是那么紧急的逻辑放到底半处理程序中,可以简单的认为硬终端处理程序为顶半处理程序,软中断处理程序为底半处理程序。软中断一般在硬中断处理程序执行后才会执行。但是当硬中断嵌套的时候,软中断会在所有的硬中断处理完毕后才会处理,当软中断太多,会放到ksoftirqd线程中处理。

内核初始化-中断

intel处理器有256个硬中断号。其中前32个中断号为异常使用,在内核初始化的时候进行初始化。内核初始化的代码流程如下:
可以看到首先初始化异常处理,再初始化部分外部中断,再初始化一部分软中断处理。


asmlinkage void __init start_kernel(void)
{
     
    lock_kernel();
    ...
     //初始化调度模块
    sched_init();

    ...
    sort_main_extable();
    // 初始化异常处理。
    trap_init();
    ...
    // 初始化外部中断
    init_IRQ();
    ...
    // 初始化定时器模块,同时,会注册定时器的软中断处理函数。
    init_timers();
    
    // 初始化软中断)
    softirq_init();
    time_init();
    ...
    // 初始化
    acpi_early_init();
}

异常中断初始化

异常中断在内核中称为trap,异常中断初始化代码为

//门初始化。初始化中断向量表。系统有固定的256个硬件中断向量。
void __init trap_init(void)
{
    
    set_intr_gate(0,&divide_error);
    set_intr_gate_ist(1,&debug,DEBUG_STACK);
    set_intr_gate_ist(2,&nmi,NMI_STACK);
    set_intr_gate(3,&int3);
    set_system_gate(4,&overflow);   /* int4-5 can be called from all */
    set_system_gate(5,&bounds);
    set_intr_gate(6,&invalid_op);
    set_intr_gate(7,&device_not_available);
    set_intr_gate_ist(8,&double_fault, DOUBLEFAULT_STACK);
    set_intr_gate(9,&coprocessor_segment_overrun);
    set_intr_gate(10,&invalid_TSS);
    set_intr_gate(11,&segment_not_present);
    set_intr_gate_ist(12,&stack_segment,STACKFAULT_STACK);
    set_intr_gate(13,&general_protection);
    set_intr_gate(14,&page_fault);
    set_intr_gate(15,&spurious_interrupt_bug);
    set_intr_gate(16,&coprocessor_error);
    set_intr_gate(17,&alignment_check);
#ifdef CONFIG_X86_MCE
    set_intr_gate_ist(18,&machine_check, MCE_STACK); 
#endif
    set_intr_gate(19,&simd_coprocessor_error);

#ifdef CONFIG_IA32_EMULATION
    set_system_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
#endif
       
    set_intr_gate(KDB_VECTOR, call_debug);
       
    /*
     * Should be a barrier for any external CPU state.
     */
    cpu_init();
}

总结如下:

中断向量号异常事件Linux的处理程序
0除法错误Divide_error
1调试异常Debug
2NMI中断Nmi
3单字节,int 3Int3
4溢出Overflow
5边界监测中断Bounds
6无效操作码Invalid_op
7设备不可用Device_not_available
8双重故障Double_fault
9协处理器段溢出Coprocessor_segment_overrun
10无效TSSIncalid_tss
11缺段中断Segment_not_present
12堆栈异常Stack_segment
13一般保护异常General_protection
14页异常Page_fault
15Spurious_interrupt_bug
16协处理器出错Coprocessor_error
17对齐检查中断Alignment_check
0x80系统调用ia32_syscall
0xf9内核调试call_debug

上述中断处理函数都是汇编语言编写。一部分汇编直接处理完毕,一部分通过调用C函数帮助处理。
汇编代码在linux/arch/x86_64/entry.S中,大部分都是调用C函数do_中断处理函数名处理。
整理如下:

中断向量号异常事件Linux汇编调用c函数处理结果
0除法错误Divide_errordo_divide_error发送SIGFPE信号
1调试异常Debugdo_debug发送SIGTRAP信号
2NMI中断Nmido_nmi
3单字节,int 3Int3do_int3发送SIGTRAP信号
4溢出Overflowdo_overflow发送SIGSEGV信号
5边界监测中断Boundsdo_bounds发送SIGSEGV信号
6无效操作码Invalid_opdo_invalid_op发送SIGILL信号
7设备不可用Device_not_availablemath_state_restore发送SIGSEGV信号
8双重故障Double_faultdo_double_fault
9协处理器段溢出Coprocessor_segment_overrundo_coprocessor_segment_overrun发送SIGFPE信号
10无效TSSInvalid_tssdo_invalid_TSS发送SIGSEGV信号
11缺段中断Segment_not_presentdo_segment_not_present发送SIGBUS信号
12堆栈异常Stack_segmentdo_stack_segment
13一般保护异常General_protectiondo_general_protection
14页异常Page_faultdo_page_fault处理缺页中断
15Spurious_interrupt_bugdo_spurious_interrupt_bug
16协处理器出错Coprocessor_errordo_coprocessor_error发送SIGFPE信号
17对齐检查中断Alignment_checkdo_alignment_check发送SIGBUS信号
0x80系统调用ia32_syscall
0xf9内核调试call_debugdo_call_debug

外部中断初始化

中断控制器硬件APIC分为两种:本地APIC和全局APIC。本地APIC集成在CPU内部,每个CPU都有一个,用于处理本地中断请求,CPU可以通过APIC向其他CPU发送中断,现在主要用于CPU之间的通信(IPI)。全局APIC主要是连接外部设备,用于外部设备的中断。在内核中断初始化的时候,会初始化三个与IPI相关中断。

void __init init_IRQ(void)
{
    int i;
    /**
    * 该函数主要是初始化硬件
    * 1. 初始化本地APIC控制芯片
    * 2. 初始化8259A芯片
    /
    init_ISA_irqs();
    /*
     * 清空32以后的中断向量表。(除了系统调用和内核调试用的中断号)
     */
    for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
        int vector = FIRST_EXTERNAL_VECTOR + i;
        if (i >= NR_IRQS)
            break;
        if (vector != IA32_SYSCALL_VECTOR && vector != KDB_VECTOR) { 
            set_intr_gate(vector, interrupt[i]);
    }
    }
// 多处理器通信中断
#ifdef CONFIG_SMP

    set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
    set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
    set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
    set_intr_gate(CALL_FUNCTION_VECTOR, call_function_interrupt);
#endif  
// 本地APIC中断
#ifdef CONFIG_X86_LOCAL_APIC
    /* self generated IPI for local APIC timer */
    set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
    set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
    set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);
#endif
    setup_timer();

    if (!acpi_ioapic)
        setup_irq(2, &irq2);
}

总结如下:

中断向量号中断名异常事件中断处理函数调用c函数处理结果
0xfcRESCHEDULE_VECTOR处理器间中断, 用于cpu之间同学,其他cpu要求重新调度reschedule_interruptsmp_reschedule_interrupt将线程调度标志置为需要重新调度。之后内核检查标志的时候会重新调度线程
0xfdINVALIDATE_TLB_VECTOR处理器间中断, 用于cpu之间通信,其他cpu要求TLB缓存失效invalidate_interruptsmp_invalidate_interruptcpu刷新TLB
0xfaCALL_FUNCTION_VECTOR处理器间中断, 用于cpu之间通信,让另外的cpu调用某个函数call_function_interruptsmp_call_function_interrupt函数数据通过call_data_struct传送,cpu会调用该函数
0xefLOCAL_TIMER_VECTORAPIC定期器中断apic_timer_interruptsmp_apic_timer_interrupt触发定时器的软中断
0xffSPURIOUS_APIC_VECTOR伪中断spurious_interruptsmp_spurious_interrupt忽略
0xfeERROR_APIC_VECTORAPIC错误error_interruptsmp_error_interrupt打印错误

0xfa中断说明:
当cpu需要另一个cpu执行某个函数时,只需要初始化

struct call_data_struct {
    void (*func) (void *info);
    void *info;
    atomic_t started;
    atomic_t finished;
    int wait;
};

的结构体,然后发出一个0xfa中断即可。

软中断初始化

软中断初始化分为两部分:

  1. 初始化定时器时,会打开TIMER_SOFTIRQ的软中断,并设置中断处理函数为run_timer_softirq。
  2. softirq_init函数执行,会打开TASKLET_SOFTIRQ和HI_SOFTIRQ,处理函数分别为 tasklet_action和 tasklet_hi_action。

软中断的线程处理机制就不说了。

转载于:https://www.cnblogs.com/stonehat/p/8681639.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值