linux系统中断的代码放在内存哪里,中断 - Linux源代码导读报告

pre_intr_init_hook() 调用 init_ISA_irqs(),初始化 irq_desc 数组、status、action、depth。

在循环中,对于所有在 FIRST_EXTERNAL_VECTOR(0x20) 与 NR_VECTOR(0x100)之间的、不是系统中断的 256 - 32 - 1 = 223 项,调用 set_intr_gate(),初始化为中断门。

现在我们关心的是,这些中断门的中断处理程序是什么?在 x86 体系结构下没找到 interrupt 数组的定义,因此使用 64 位体系结构的做说明:// arch/x86/kernel/i8259_64.c

80 static void (*__initdata interrupt[NR_VECTORS - FIRST_EXTERNAL_VECTOR])(void) = {

81 IRQLIST_16(0x2), IRQLIST_16(0x3),

82 IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),

83 IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),

84 IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)

85 };

以上是 interrupt 数组的定义。在下面的代码中,## 是将字符串连接起来,这样宏定义的函数 IRQ(0x4,6) 就是 IRQ0x46_interrupt,生成 224 个这样的函数填入数组。

// arch/x86/kernel/i8259_64.c

70 #define IRQ(x,y) \

71 IRQ##x##y##_interrupt

72

73 #define IRQLIST_16(x) \

74 IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \

75 IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \

76 IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \

77 IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)

那么这 224 个函数在哪里呢?通过下面的宏可以生成一个汇编函数,它调用了 common_interrupt 函数:

// include/asm/hw_irq_64.h

155 #define IRQ_NAME2(nr) nr##_interrupt(void)

156 #define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr)

162 #define BUILD_IRQ(nr) \

163 asmlinkage void IRQ_NAME(nr); \

164 asm("\n.p2align\n" \

165 "IRQ" #nr "_interrupt:\n\t" \

166 "push $~(" #nr ") ; " \

167 "jmp common_interrupt");

common_interrupt 是汇编函数,这个函数最终调用了 do_IRQ,这是我们下章要介绍的核心中断处理函数。

// arch/x86/kernel/entry_32.S

613 common_interrupt:

614 SAVE_ALL

615 TRACE_IRQS_OFF

616 movl %esp,%eax

617 call do_IRQ

618 jmp ret_from_intr

619 ENDPROC(common_interrupt)

看来,只需要调用 BUILD_IRQ 就能生成中断处理函数了。Linux Kernel 正是这样做的:

// arch/x86/kernel/i8259_64.c

37 #define BI(x,y) \

38 BUILD_IRQ(x##y)

39

40 #define BUILD_16_IRQS(x) \

41 BI(x,0) BI(x,1) BI(x,2) BI(x,3) \

42 BI(x,4) BI(x,5) BI(x,6) BI(x,7) \

43 BI(x,8) BI(x,9) BI(x,a) BI(x,b) \

44 BI(x,c) BI(x,d) BI(x,e) BI(x,f)

....................................................

61 BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)

62 BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)

63 BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)

64 BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)

不得不发表一下感慨,Linux Kernel 对 C 语言宏的运用真是炉火纯青。如果是我写代码,很可能不得不先写个代码生成器,用它生成 224 个函数的源码。但 Linux Kernel Source 里出现几百个几乎一模一样的函数太不优雅了,于是利用 C 语言的预处理机制,采用二级宏定义,尽可能降低代码量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值