中断的初始化是在哪里完成的呢?是在start_kernel()中:
512 trap_init();
535 /* init some links before init_ISA_irqs() */
536 early_irq_init();
537 init_IRQ(); //最终调用native_init_IRQ,由它来完成主要工作。
中断向量表的初始化分为两个部分:
(1)对0~19号和0x80号系统保留中断向量的初始化,在trap_init中完成
(2)对其它中断向量的初始化,在init_IRQ中完成。
我们首先来看对系统保留中断向量的初始化,这部分的初始化工作实在trap_init中完成的:
void __init trap_init(void)
{
int i;
#ifdef CONFIG_EISA
void __iomem *p = early_ioremap(0x0FFFD9, 4);
if (readl(p) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24))
EISA_bus = 1;
early_iounmap(p, 4);
#endif
set_intr_gate(0, ÷_error);
set_intr_gate_ist(2, &nmi, NMI_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(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);
/* Reserve all the builtin and the syscall vector: */
for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++)
set_bit(i, used_vectors);
#ifdef CONFIG_IA32_EMULATION
set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall);
set_bit(IA32_SYSCALL_VECTOR, used_vectors);
#endif
#ifdef CONFIG_X86_32
set_system_trap_gate(SYSCALL_VECTOR, &system_call);
set_bit(SYSCALL_VECTOR, used_vectors);
#endif
/*
* Should be a barrier for any external CPU state:
*/
cpu_init();
x86_init.irqs.trap_init(); //这个是什么意思呢?好像跟虚拟机有关,我们不用关注。
}
程序中首先设置中断向量表的头19个陷阱门,这些中断向量表都是CPU保留用于异常处理的。
接着,有这样的操作:
/* Reserve all the builtin and the syscall vector: */ for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) set_bit(i, used_vectors);
系统设置了一个位图used_vectors,来表示每个中断向量表的使用情况,FIRST_EXTERNAL_VECTOR = 20,可以看到,这里是将前20(0~19)个向量表项对应的位图设置为1,表示已经被占用了。
紧接着:
初始化系统调用向量。SYS_CALL_VECTOR = 0x80。这里有一个这样的问题,为什么用的是set_system_trap_gate,而不是像2.4那样用set_system_gate呢?我们可以将系统调用看成是trap,因为它同样要陷入内核空间,可以这样理解,当陷入陷阱时,EIP指向的是下一条指令,而当故障(fault)发生时,EIP指向当前指令,当异常发生时,EIP的指向是不固定的,因此想想系统调用后EIP的变化,它必然是属于陷阱范畴的。set_system_trap_gate(SYSCALL_VECTOR, &system_call);
接下来,看这样一个操作cpu_init()
/* * cpu_init() initializes state that is per-CPU. Some data is already * initialized (naturally) in the bootstrap process, such as the GDT * and IDT. We reloa