首先修改task1的代码使其运行一次后进入无限循环
将jmp _task1修改为jmp $
将timer_interrupt修改为:
1 _timer_interrupt:
2 PUSH ds
3 PUSH edx
4 PUSH ecx
5 PUSH ebx
6 PUSH eax
7 ;MOV eax,0x10
8 ;MOV dx,ax
9 in al,0x21 ; ┓
10 or al,(1 << 1) ; ┣ 屏蔽当前中断
11 out 0x21,al ; ┛
12 mov al,0x20 ; ┓置EOI位,其后8259A才能相应新的中断
13 out 0x20,al ; ┛
14 sti ; 允许响应新中断
15 in al,0x60 ; 从0x60端口读出扫描码
16 ;MOV eax,1
17 ;cmp DWORD [current],eax
18 ;je y1
19 ;MOV DWORD [current],eax
20 ;JMP TSS1_SEL : 0
21 ;jmp y2
22 y1:
23 ;MOV DWORD [current],0
24 ;JMP TSS0_SEL : 0
25 ;MOV eax,0x17
26 ;MOV ds,ax
27 ;MOV al,65
28 call write_char ; 这里仅简单的将扫描码作为ANSI码打印出来
29 ;MOV ecx,0xfff
30 y2:
31 cli
32 in al,0x21 ; ┓
33 and al,~(1 << 1) ; ┣ 恢复接受当前中断
34 out 0x21,al ; ┛
35 POP eax
36 POP ebx
37 POP ecx
38 POP edx
39 POP ds
40 IRET
注:因为键盘中断处理过程运行于Ring0,应此可以直接调用内核函数write_char
然后修改IDT表的0x21(0x21对应于IRQ1,表示键盘中断)项的offset_l和offset_h使其指向timer_interrupt中断处理过程.
1 void init_idt()
2 {
3 int i;
4 for(i=0;i<256;i++)
5 {
6 if(0x21 == i || 0x80 == i)
7 {
8 continue;
9 }
10 setup_int_gate((dword)ignore_int,i);
11 }
12 //setup_int_gate((dword)timer_interrupt,0x20);
13 setup_int_gate((dword)timer_interrupt,0x21);
14 setup_trap_gate((dword)system_interrupt,0x80);
15
16 idtr[0] = 8 * 256;
17 idtr[1] = ((dword)&idt_[0] + KERNEL_BASE) & 0xffff;
18 idtr[2] = ((dword)&idt_[0] + KERNEL_BASE)>>16;
19 }
最后启动键盘中断,将8259A主片的IRQ0位设为1,IRQ1位设为0
1 MOV edx,0x21
2 in al,dx
3 AND al,0xFD
4 OUT dx,al
注:0xFD对应二进制码11111101
调试结果:
按下a键输出一个字符,弹起a键输出另一个字符
由于直接将扫描码作为ANSI码输出因此会出现两个乱码字符
完整代码打包下载
posted on 2010-12-11 17:46
lwch 阅读(1971)
评论(5) 编辑 收藏 引用 所属分类:
操作系统