5.10 初始化中断处理系统
start_kernel接下来要做的事是初始化中断处理系统。整个内核的中断系统的核心就是我们在“初始化中断描述符表”里面设置的那个中断描述符表。而这个表的前19个表项我们已经在“初始化异常服务”中设置为了一些中断和异常的服务。内核接下来会如何设置其余的表项呢?
前面提到过高级可编程中断控制器APIC,这里简单地提一下它的体系结构,简单地说就是由两部分组成:本地高级中断控制器(Local APIC,LAPIC),位于每个CPU中,主要负责传递中断信号到指定的处理器中;I/O高级中断控制器(I/O APIC,)负责搜集来自I/O设备的中断信号并分发给LAPIC,形成一个多级APIC中断分发网络。
接下来的大部分初始化工作都将围绕着LAPIC和IOAPIC这两个东西进行。
5.10.1 设置APIC中断服务
回到start_kernel,由于我们没有配置CONFIG_SPARSE_IRQ,所以605行的early_irq_init()函数是个空函数。606行,调用init_IRQ函数,其本质上是调用x86_init.irqs.intr_init函数,也就是前面“拷贝可用内存区信息”的那个x86_init中看到的那个native_init_IRQ函数,用来初始化LAPIC:
235void __init native_init_IRQ(void) 236{ 237 int i; 238 239 /* Execute any quirks before the call gates are initialised: */ 240 x86_init.irqs.pre_vector_init(); 241 242 apic_intr_init(); 243 244 /* 245 * Cover the whole vector space, no vector can escape 246 * us. (some of these will be overridden and become 247 * 'special' SMP interrupts) 248 */ 249 for (i = FIRST_EXTERNAL_VECTOR; i < NR_VECTORS; i++) { 250 /* IA32_SYSCALL_VECTOR could be used in trap_init already. */ 251 if (!test_bit(i, used_vectors)) 252 set_intr_gate(i, interrupt[i-FIRST_EXTERNAL_VECTOR]); 253 } 254 255 if (!acpi_ioapic) 256 setup_irq(2, &irq2); 257 258#ifdef CONFIG_X86_32 259 /* 260 * External FPU? Set up irq13 if so, for 261 * original braindamaged IBM FERR coupling. 262 */ 263 if (boot_cpu_data.hard_math && !cpu_has_fpu) 264 setup_irq(FPU_IRQ, &fpu_irq); 265 266 irq_ctx_init(smp_processor_id()); 267#endif 268} |
该函数初始化中断向量表中前面一些我们没有设置的表项,首先是240,调用x86_init.irqs.pre_vector_init函数,也就是init_ISA_irqs函数:
101void __init init_ISA_irqs(void) 102{ 103 int i; 104 105#if defined(CONFIG_X86_64) || defined(CONFIG_X86_LOCAL_APIC) 106 init_bsp_APIC(); 107#endif 108 legacy_pic->init(0); 109 110 /* 111 * 16 old-style INTA-cycle interr |