为了让鼠标能移动起来,必须使用中断,而要使用中断则必须将GDT和IDT初始化。在此之前,首先要初始化PIC,它的意思是可编程中断控制器。它是将多个中断信号集合成一个中断信号的装置,PIC检测着输入管脚的多个中断信号,只要有一个中断信号过来,就将唯一的输出管脚信号变成ON,并通知给CPU。
其中与CPU直接相连的PIC为主PIC,与主PIC相连的PIC称为从PIC。其中从PIC通过第2号IRQ与主PIC相连。
PIC设定如下:
void init_pic(void)
{
io_out8(PIC0_IMR, 0xff );
io_out8(PIC1_IMR, 0xff );
io_out8(PIC0_ICW1, 0x11 );
io_out8(PIC0_ICW2, 0x20 );
io_out8(PIC0_ICW3, 1 << 2);
io_out8(PIC0_ICW4, 0x01 );
io_out8(PIC1_ICW1, 0x11 );
io_out8(PIC1_ICW2, 0x28 );
io_out8(PIC1_ICW3, 2 );
io_out8(PIC1_ICW4, 0x01 );
io_out8(PIC0_IMR, 0xfb );
io_out8(PIC1_IMR, 0xff );
return;
}
从CPU角度看,PIC是外部设备,CPU使用OUT指令进行操作。
PIC的寄存器都是8位寄存器,其中IMR是中断屏蔽寄存器。ICW是初始化控制数据。ICW有4个,其中ICW1与ICW4与主板配线方式、中断信号的电气特性有关。ICW3是有关主从连接的设定。ICW2则决定哪一号中断通知CPU。至于为什么从INT20开始,原因是0x00~0x1f已经被操作系统所用,当应用程序对操作系统干坏事时,CPU内部会自动产生INT0x00~0x1f,如果IRQ与这些号码重复,则CPU会分不清它到底是IRQ还是CPU的系统保护通知。
初始化完PIC之后就可以来设定鼠标中断和键盘中断了,它们分别对应IRQ12和IRQ1。代码如下:
void inthandler21(int *esp)
{
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
boxfill8(binfo->vram, binfo->scrnx, COL8_000000, 0, 0, 32 * 8 - 1, 15);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, "INT 21 (IRQ-1) : PS/2 keyboard");
for (;;) {
io_hlt();
}
}
void inthandler2c(int *esp)
{
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
boxfill8(binfo->vram, binfo->scrnx, COL8_000000, 0, 0, 32 * 8 - 1, 15);
putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, "INT 2C (IRQ-12) : PS/2 mouse");
for (;;) {
io_hlt();
}
}
有了相关的中断函数,则进行注册,注册语句如下:
set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);
asm_inthandler21注册在idt的第0x21号,如果中断发生,CPU会自动调用asm_inthandler21,2 * 8表示的是asm_inthandler21属于哪一个段,即段号是2,乘以8是因为低3位有别的意思。对于号码段为2的段,有如下设置:
set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
该段涵盖了整个bootpack。最后的AR_INTGATE32将IDT的属性设定为0x008e,表示这是中断处理的有效设定。