linux中断初始化程序,Linux x86_64 内核中断初始化

Linux x86_64 内核中断初始化

中断分类

Linux 系统中, 中断分为:

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

根据内部产生还是外部产生, 分为:

异常: 异常是内部产生的中断, 不可屏蔽

外部中断: 外部中断是由外部设备产生的, 可以屏蔽

软中断:

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

内核初始化 - 中断

intel 处理器有 256 个硬中断号其中前 32 个中断号为异常使用, 在内核初始化的时候进行初始化内核初始化的代码流程如下:

可以看到首先初始化异常处理, 再初始化部分外部中断, 再初始化一部分软中断处理asmlinkagevoid__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,÷_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);

#ifdefCONFIG_X86_MCE

set_intr_gate_ist(18,&machine_check,MCE_STACK);

#endif

set_intr_gate(19,&simd_coprocessor_error);

#ifdefCONFIG_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)

{

inti;

/**

* 该函数主要是初始化硬件

* 1. 初始化本地 APIC 控制芯片

* 2. 初始化 8259A 芯片

/

init_ISA_irqs();

/*

* 清空 32 以后的中断向量表(除了系统调用和内核调试用的中断号)

*/

for(i=0;i

intvector=FIRST_EXTERNAL_VECTOR+i;

if(i>=NR_IRQS)

break;

if(vector!=IA32_SYSCALL_VECTOR&&vector!=KDB_VECTOR){

set_intr_gate(vector,interrupt[i]);

}

}

// 多处理器通信中断

#ifdefCONFIG_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 中断

#ifdefCONFIG_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 执行某个函数时, 只需要初始化structcall_data_struct{

void(*func)(void*info);

void*info;

atomic_tstarted;

atomic_tfinished;

intwait;

};

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

软中断初始化

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

初始化定时器时, 会打开 TIMER_SOFTIRQ 的软中断, 并设置中断处理函数为 run_timer_softirq

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、付费专栏及课程。

余额充值