响应中断是操作系统最重要的任务之一,所以要写操作系统,就要知道如何设置中断处理程序,以及中断处理程序的编写。
x86CPU在实模式下,中断是通过中断向量表来转发的,这个中断向量表是固定在物理地址0 - 3FF处。大致来说,就是x86CPU可以处理256个中断,每个中断的中断处理程序用四个字节表示,因此总共占用1K个字节。具体的细节就不再这里写了。这里主要是讲怎么进行中断处理。
第一步:
设置硬件,也就是设置8259中断控制器。在目前这一步,先不用设置,直接采用DOS的设置。
第二步:
设置中断处理程序。也就是用自己编写的程序来替换原来的中断处理程序。为此,要编写一个设置用的程序,这个程序使用汇编语言。
; dword_t Ivt_set(int id,dword_t handle)
_Ivt_set:
mov bx, sp
push di
mov cx,[bx + 4];
mov di,[bx + 6];
mov ax,4
mov dx,[bx + 2];
mul dx;
mov bx,ax
push es
push 0
pop es
mov ax,es:[bx ]
mov dx,es:[bx + 2];
cli
mov es:[bx],cx
mov es:[bx+2],di
sti
pop es
pop di
ret
这个程序比较简单,关键就是在于更换了ES寄存器
第三步:
编写具体的中断处理程序。
这里用时钟中断作为例子,编写中断处理程序要注意保存寄存器,在完成中断处理后,在用保存的值恢复寄存器。中断处理程序一般都是用汇编语言编写
_Irq_clock:
push ax
push bx
push cx
push dx
push si
push di
push es
push ds
pop es
mov al,020h
out 020h,al
call do_irq_clock
pop es
pop di
pop si
pop dx
pop cx
pop bx
pop ax
iret
这里说明一下do_irq_clock,这是一个变量,里面保存有具体中断处理程序地址,这么做是为了方便的替换具体的处理程序。在需要替换中断处理程序时,用下面的程序
_Irq_clock_set:
mov bx,sp;
mov ax,do_irq_clock;
mov dx,[bx + 2];
mov do_irq_clock,dx
ret
到这里,中断处理的几步就完成了。测试一下,
测试代码如下
volatile static uint32_t ticks = 0;
void Clk_msg(void)
{
char msg[40];
sprintf(msg,"lenix ticks: %8ld",ticks);
Con_write_string(50,0,msg);
}
void Clk_do_clock(void)
{
ticks++;
Clk_msg();
}
void Clk_initial(void)
{
word_t tcs;
dword_t handle;
ticks = 0;
Irq_clock_set(Clk_do_clock);
asm{
mov ax,cs
mov tcs,ax
}
handle = ((dword_t)tcs) * 0x10000 | (word_t)Irq_clock;
Ivt_set(0x8,handle);
}
void main(void)
{
Clk_initial();
for(;;);
}
这一段测试的主要在于程序执行后,进入死循环。由于时钟中断已经替换,因此在出现时钟中断时,就会在屏幕的右上角显示一个tick值,这个值记录了发生中断的次数。
运行截图:


被折叠的 条评论
为什么被折叠?



