首先修改task1的代碼使其運(yùn)行一次后進(jìn)入無限循環(huán)
將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) ; ┣ 屏蔽當(dāng)前中斷
11 out 0x21,al ; ┛
12 mov al,0x20 ; ┓置EOI位,其后8259A才能相應(yīng)新的中斷
13 out 0x20,al ; ┛
14 sti ; 允許響應(yīng)新中斷
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) ; ┣ 恢復(fù)接受當(dāng)前中斷
34 out 0x21,al ; ┛
35 POP eax
36 POP ebx
37 POP ecx
38 POP edx
39 POP ds
40 IRET
注:因?yàn)殒I盤中斷處理過程運(yùn)行于Ring0,應(yīng)此可以直接調(diào)用內(nèi)核函數(shù)write_char
然后修改IDT表的0x21(0x21對應(yīng)于IRQ1,表示鍵盤中斷)項(xiàng)的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位設(shè)為1,IRQ1位設(shè)為0
1 MOV edx,0x21
2 in al,dx
3 AND al,0xFD
4 OUT dx,al
注:0xFD對應(yīng)二進(jìn)制碼11111101
調(diào)試結(jié)果:

按下a鍵輸出一個字符,彈起a鍵輸出另一個字符
由于直接將掃描碼作為ANSI碼輸出因此會出現(xiàn)兩個亂碼字符
完整代碼打包下載
posted on 2010-12-11 17:46
lwch 閱讀(1991)
評論(5) 編輯 收藏 引用 所屬分類:
操作系統(tǒng)