local APIC 初期化の続き init_IRQ での処理編 (その3)

次は intr_init_hook() の呼び出し。

    /* setup after call gates are initialised (usually add in
     * the architecture specific gates)
     */
    intr_init_hook();

これについては、amazon:Linuxカーネル解析入門にフォローあり。
ソースは arch/i386/mach-default/setup.c との事にて定義は以下。
intr_init_hook()#arch/i386/mach-default/setup.c

void __init intr_init_hook(void)
{
#ifdef CONFIG_X86_LOCAL_APIC
    apic_intr_init();
#endif

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

ちなみにamazon:Linuxカーネル解析入門における apic_intr_init() の解説は p.152 から p.154 に、又、その後の条件分岐の部分については、p.154 から p.155 に解説がある。
ようやくココまでキましたな、との感慨の共に M-. で apic_intr_init() を検索。amazon:Linuxカーネル解析入門にもソースが引用されていますが、以下。
apic_intr_init()#arch/i386/kernel/apic.c

void __init apic_intr_init(void)
{
#ifdef CONFIG_SMP
    smp_intr_init();
#endif
    /* self generated IPI for local APIC timer */
    set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);

    /* IPI vectors for APIC spurious and error interrupts */
    set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
    set_intr_gate(ERROR_APIC_VECTOR, error_interrupt);

    /* thermal monitor LVT interrupt */
#ifdef CONFIG_X86_MCE_P4THERMAL
    set_intr_gate(THERMAL_APIC_VECTOR, thermal_interrupt);
#endif
}

む。現時点でアレなのは

  • smp_intr_init() で何してるんだ
  • set_intr_gate() って何だ

という二点。

早速、掘りサゲる。とりあえずは set_intr_gate() を。

って、結構簡単にめっかったんですが、これはマニュアルの助けが必要ですな。以下にソースを貼っておいてちょっとだけ暇を頂ければ幸いッス。

set_intr_gate()#arch/i386/kernel/traps.c

#define _set_gate(gate_addr,type,dpl,addr,seg) \
do { \
  int __d0, __d1; \
  __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
    "movw %4,%%dx\n\t" \
    "movl %%eax,%0\n\t" \
    "movl %%edx,%1" \
    :"=m" (*((long *) (gate_addr))), \
     "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
    :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
     "3" ((char *) (addr)),"2" ((seg) << 16)); \
} while (0)


/*
 * This needs to use 'idt_table' rather than 'idt', and
 * thus use the _nonmapped_ version of the IDT, as the
 * Pentium F0 0F bugfix can have resulted in the mapped
 * IDT being write-protected.
 */
void set_intr_gate(unsigned int n, void *addr)
{
    _set_gate(idt_table+n,14,0,addr,__KERNEL_CS);
}

これはキアイいるなぁ。とりあえずインライン・アセンブラの引数のナニをもっかい思い出す必要あり。(とほほほ
てか、_set_gate() って難解だぞ。