FreeBSD 5 内核源代码分析之中断处理( 四 )


Xatpic_intr0 至Xatpic_intr15,即为函数名的引用 。而在.s文件中将扩展成
代码:
ALIGN_TEXT;
.globl Xatpic_intr0;
.type Xatpic_intr0,@function;
Xatpic_intr0:

等等,即定义一个全局的函数,也就是说在.c文件中只是引用该函数,真正定义该函数的是
在sys/i386/isa/atpic_vector.s中,该函数实际上就是一个对atpic_handle_intr()
函数的包装,我们后面还将看到该函数 。
代码:
struct atpic_intsrc {
struct intsrc at_intsrc;
int at_irq; /* Relative to PIC base. */
inthand_t *at_intr;
u_long at_count;
u_long at_straycount;
};

static struct atpic_intsrc atintrs[] = {
INTSRC(0),
INTSRC(1),
INTSRC(2),
INTSRC(3),
INTSRC(4),
INTSRC(5),
INTSRC(6),
INTSRC(7),
INTSRC(8),
INTSRC(9),
INTSRC(10),
INTSRC(11),
INTSRC(12),
INTSRC(13),
INTSRC(14),
INTSRC(15),
};

#define INTSRC(irq)
{ { &atpics[(irq) / 8].at_pic }, (irq) % 8,
IDTVEC(atpic_intr ## irq ) }

系统启动时,调用8259A的初始化函数atpic_init(),为非SLAVE IRQ号注册中断源 。
并在i386初始化时调用atpic_startup()函数,注册中断向量
IDTVEC(atpic_intr ## irq ),注意,这只是注册总的包装函数,
具体IRQ号的中断处理函数将由设备驱动通过intr_add_handler()函数来注册 。
代码:
SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND1, atpic_init, NULL)

static void
atpic_init(void *dummy __unused)
{
int i;

/* Loop through all interrupt sources and add them. */
for (i = 0; i < sizeof(atintrs) / sizeof(struct atpic_intsrc); i) {
if (i == ICU_SLAVEID)
continue;
intr_register_source(&atintrs[i].at_intsrc);
}
}

void
init386(first)
int first;
{
......

#ifdef DEV_ISA
atpic_startup();
#endif

......
}

void
atpic_startup(void)
{
struct atpic_intsrc *ai;
int i;

/* Start off with all interrupts disabled. */
imen = 0xffff;
i8259_init(&atpics[MASTER], 0);
i8259_init(&atpics[SLAVE], 1);
atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);

/* Install low-level interrupt handlers for all of our IRQs. */
for (i = 0; i < sizeof(atintrs) / sizeof(struct atpic_intsrc); i) {
if (i == ICU_SLAVEID)
continue;
ai = &atintrs[i];
ai->at_intsrc.is_count = &ai->at_count;
ai->at_intsrc.is_straycount = &ai->at_straycount;
setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase
ai->at_irq, ai->at_intr, SDT_SYS386IGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
}
}


2,IRQ中断的处理过程
代码:
/*
* Macros for interrupt interrupt entry, call to handler, and exit.
*/
#define INTR(irq_num, vec_name)
.text ;
SUPERALIGN_TEXT ;
IDTVEC(vec_name) ;
pushl $0 ; /* dummy error code */
pushl $0 ; /* dummy trap type */
pushal ; /* 8 ints */
pushl %ds ; /* save data and extra segments ... */
pushl %es ;
pushl %fs ;
mov $KDSEL,%ax ; /* load kernel ds, es and fs */
mov %ax,%ds ;
mov %ax,%es ;
mov $KPSEL,%ax ;
mov %ax,%fs ;
;
FAKE_MCOUNT(13*4(%esp)) ; /* XXX late to avoid double count */
pushl $irq_num; /* pass the IRQ */
call atpic_handle_intr ;
addl $4, %esp ; /* discard the parameter */
;
MEXITCOUNT ;
jmp doreti

IRQ产生时,系统根据产生中断的IRQ号找到相应的中断向量入口,即此处的IDT_VEC(vec_name),
再这里,构造好函数atpic_handle_intr()的调用栈后,将转到atpic_handle_intr()进行处理 。
同系统调用一样,这里的调用栈struct intrframe既是atpic_handle_intr()的参数,也是中断
返回时用以恢复现场的寄存器状态 。
代码:
/* Interrupt stack frame */
struct intrframe {
int if_vec;
int if_fs;
int if_es;
int if_ds;
int if_edi;
int if_esi;
int if_ebp;
int :32;
int if_ebx;
int if_edx;

推荐阅读