您的位置:首页 > 其它

关于init_IRQ的函数分析

2010-08-19 18:54 274 查看
init_IRQ() 为xen启动函数 __start_xen中调用初始化中断的函数,其中有一段代码我认为是挺绕的。经过了一些时间的分析,终于弄明白了分享给大家,也给自己做个记录。

for ( vector = FIRST_DYNAMIC_VECTOR; vector < NR_VECTORS; vector++ )
{
if (vector == HYPERCALL_VECTOR || vector == LEGACY_SYSCALL_VECTOR)
continue;
set_intr_gate(vector, interrupt[vector]);
}

这段代码看起来没什么稀奇的,但是想要弄明白interrupt[vector],我却用了些心思。

在 xen/arch/x86/i8295.c文件中有这么个定义:

static void (*interrupt[])(void) = {
IRQLIST_16(0x0), IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)
};

#define IRQLIST_16(x) /
IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), /
IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), /
IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), /
IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)

#define IRQ(x,y) /
IRQ##x##y##_interrupt

那么这个函数 IRQ##x##y##_interrupt 是什么时候定义的呢?

在这个C文件的最顶部有这么一些宏代码

BUILD_COMMON_IRQ()

#define BI(x,y) /
BUILD_IRQ(x##y)

#define BUILD_16_IRQS(x) /
BI(x,0) BI(x,1) BI(x,2) BI(x,3) /
BI(x,4) BI(x,5) BI(x,6) BI(x,7) /
BI(x,8) BI(x,9) BI(x,a) BI(x,b) /
BI(x,c) BI(x,d) BI(x,e) BI(x,f)

BUILD_16_IRQS(0x0) BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)

从名字上看好像是创建与 IRQ有关的什么东西。
跟进看看究竟

#define IRQ_NAME2(nr) nr##_interrupt(void)
#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)

#define BUILD_IRQ(nr) /
asmlinkage void IRQ_NAME(nr); /
__asm__( /
"/n"__ALIGN_STR"/n" /
STR(IRQ) #nr "_interrupt:/n/t" /
"pushq $0/n/t" /
"movl $"#nr",4(%rsp)/n/t" /
"jmp common_interrupt");

到这里可能会发现些什么,原来通过以上三个宏的表述可以得到以下结论

#define BUILD_IRQ(nr) == asmlinkage void IRQ##nr##_interrupt(void),

且在宏#define BUILD_16_IRQS(x) 相当于定义了 256个函数。那么这些函数在那里定义的呢?
看了下面的这段代码我想你就明白了:

#define BUILD_COMMON_IRQ() /
__asm__( /
"/n" __ALIGN_STR"/n" /
"common_interrupt:/n/t" /
STR(SAVE_ALL) /
"movq %rsp,%rdi/n/t" /
"callq " STR(do_IRQ) "/n/t" /
"jmp ret_from_intr/n");

#define IRQ_NAME2(nr) nr##_interrupt(void)
#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)

#define BUILD_IRQ(nr) /
asmlinkage void IRQ_NAME(nr); /
__asm__( /
"/n"__ALIGN_STR"/n" /
STR(IRQ) #nr "_interrupt:/n/t" /
"pushq $0/n/t" /
"movl $"#nr",4(%rsp)/n/t" /
"jmp common_interrupt");

在文件xen/arch/x86/i8295.c的最开始调用了一个宏,BUILD_COMMON_IRQ(),其它的那些BUILD_IRQ的宏,再预编译的时候,就把自己跳转到标号common_interrupt:, 然后走后面的汇编语句,其实到最后是调用do_irq()这个函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: