中断分类
对于Linux内核来说,中断信号通常分为两类:硬件中断和软件中断(异常)。每个中断由0~255之间的一个数字来标识。按照中断用途,可以分以下两类:
1、中断int0~int31(0x00~0x1f),每个中断的功能由Intel公司固定设定或保留用, 属于软件中断,但Intel公司称之为异常;因为这些中断是在CPU执行指令时探测到异常情况而引起的。通常还可分为故障(Fault)和陷阱(traps)两类。
2、中断int32~int255 (0x20~0xff)可以由用户自己设定,在Linux系统中,将int32~int47(0x20~0x2f)对应于8259A中断控制芯片发出的硬件中断请求信号IRQ0~IRQ15,并把程序编程发出的系统调用(system call)中断设置为int128(0x80)。
中断处理
intel CPU收到中断后,通过idt寄存器和中断向量找到相应的中断门函数,根据中断门描述执行一定的处理后(例如关闭中断等等),调用中断门函数,其中idt寄存器指向了中断门描述表的首地址,而中断向量即为表中的偏移。
中断初始化
异常类中断的中断门初始化在arch/x86/kernel/traps.c文件中的trap_init函数中实现,每个中断的中断门函数实现均不同;
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);
/* int3 can be called from all */
set_system_intr_gate_ist(3, &int3, DEBUG_STACK);
/* int4 can be called from all */
set_system_intr_gate(4, &overflow);
set_intr_gate(5, &bounds);
set_intr_gate(6, &invalid_op);
set_intr_gate(7, &device_not_available);
#ifdef CONFIG_X86_32
set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS);
#else
set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK);
#endif
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_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
set_bit(IA32_SYSCALL_VECTOR, used_vectors);
#endif
set_system_trap_gate(SYSCALL_VECTOR, &system_call);
set_bit(SYSCALL_VECTOR, used_vectors);
#endif
}
其他中断的中断门初始化在arch/x86/kernel/irqinit.c文件的native_init_IRQ函数中实现,每个中断对应的中断门函数是interrupt函数数组(每个函数实现均相同,最终调用common_interrupt函数)中的一项;
void __init native_init_IRQ(void)
{
int i;
/* Execute any quirks before the call gates are initialised: */
x86_init.irqs.pre_vector_init();
apic_intr_init();
/*
* Cover the whole vector space, no vector can escape
* us. (some of these will be overridden and become
* 'special' SMP interrupts)
*/
for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) {
/* IA32_SYSCALL_VECTOR could be used in trap_init already. */
if (!test_bit(i, used_vectors))
set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]);
}
if (!acpi_ioapic)
setup_irq(2, &irq2);
#ifdef CONFIG_X86_32
/*
* External FPU? Set up irq13 if so, for
* original braindamaged IBM FERR coupling.
*/
if (boot_cpu_data.hard_math && !cpu_has_fpu)
setup_irq(FPU_IRQ, &fpu_irq);
irq_ctx_init(smp_processor_id());
#endif
}
到此,中断门初始化已经完成,知道了CPU收到中断后的处理入口。还有几个疑问没有解答:
1、int32~int47(0x20~0x2f)对应硬件中断请求信号IRQ0~IRQ15是怎么做到的;
2、是怎么走到中断处理函数的;
转载于:https://blog.51cto.com/fulongshan/1415604