인터럽트와 예외(키보드 인터럽트 핸들러 구현)
아래와 같이 소스를 짠다. (파일은 이전 장에서 사용하던 파일 중 kernel 만 변경)
책에서는 mov al, 0xFC 로 타이머와 키보드만 유효하게 하나, 실행되지 않으므로 0xFD 키보드만 유효하게 한다.
%include "init.inc"
[org 0x10000]
[bits 32]
PM_Start:
mov bx, SysDataSelector
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
mov ss, bx
lea esp, [PM_Start]
mov edi, 0
lea esi, [msgPMode]
call printf
cld
mov ax, SysDataSelector
mov es, ax
xor eax, eax
xor ecx, ecx
mov ax, 256 ; IDT 영역에 256개의
mov edi, 0 ; 디스크립터를 복사한다.
loop_idt:
lea esi, [idt_ignore]
mov cx, 8 ; 디스크립터 하나는 8바이트 이다.
rep movsb
dec ax
jnz loop_idt
mov edi, 8*0x20
lea esi, [idt_timer]
mov cx, 8
rep movsb
mov edi, 8*0x21 ; 키보드 IDT 디스크립터를 복사한다.
lea esi, [idt_keyboard] ; idt_keyboard는 디스크립터의 포인터 이다.
mov cx, 8
rep movsb
lidt [idtr]
mov al, 0xFD ; 막아두었던 인터럽트 중
out 0x21, al ; 타이머와 키보드만 다시 유효하게 한다.
sti
jmp $
printf:
push eax
push es
mov ax, VideoSelector
mov es, ax
printf_loop:
mov al, byte [esi]
mov byte [es:edi], al
inc edi
mov byte [es:edi], 0x06
inc esi
inc edi
or al, al
jz printf_end
jmp printf_loop
printf_end:
pop es
pop eax
ret
msgPMode db "We are in Protected Mode", 0
msg_isr_ignore db "This is an ignorable interrupt", 0
msg_isr_32_timer db ".This is the timer interrupt", 0
msg_isr_33_keyboard db ".This is the keyboard interrupt", 0
idtr:
dw 256*8-1 ; IDT의 Limit
dd 0 ; IDT의 Base Address
isr_ignore:
push gs
push fs
push es
push ds
pushad
pushfd
mov al, 0x20
out 0x20, al
mov ax, VideoSelector
mov es, ax
mov edi, (80*7*2)
lea esi, [msg_isr_ignore]
call printf
popfd
popad
pop ds
pop es
pop fs
pop gs
iret
isr_32_timer:
push gs
push fs
push es
push ds
pushad
pushfd
mov al, 0x20
out 0x20, al
mov ax, VideoSelector
mov es, ax
mov edi, (80*2*2)
lea esi, [msg_isr_32_timer]
call printf
inc byte [msg_isr_32_timer]
popfd
popad
pop ds
pop es
pop fs
pop gs
iret ; 인터럽트가 발생한 당시의 프로그램의 다음 명령으로 돌아가서 프로그램 재개
isr_33_keyboard: ; 인터럽트 핸들러 루틴
pushad
push gs
push fs
push es
push ds
pushfd
in al, 0x60 ; 키보드에서 어느 키가 눌렸는지 알아내기 위해 사용하는 명령어, 키보드 버퍼에 있는 문자 스
캔코드를 가져온다. 이 스캔코드는 아스키코드와는 다르다. 또한 버퍼에서 문자를 가져오지 않
으면 키보드에서 인터럽트는 발생하지 않는다.
; PIC 리셋 코드
mov al, 0x20 ; 마스터 PIC는 0x20, 0x21 포트를 사용하고, 슬레이브 PIC는 0xA0, 0xA1 포트를 사용한다.
out 0x20, al
mov ax, VideoSelector
mov es, ax
mov edi, (80*4*2)
lea esi, [msg_isr_33_keyboard]
call printf
inc byte [msg_isr_33_keyboard] ; 아스키코드 값이 1씩 추가된다. 여기서 맨 처음 출력되는 것은 '.' 이고
엔터 시 값이 아스키 값이 1씩 증가되어 문자열이 출력된다.
popfd
pop ds
pop es
pop fs
pop gs
popad
iret
idt_ignore:
dw isr_ignore
dw 0x08
db 0
db 0x8E
dw 0x0001
idt_timer:
dw isr_32_timer
dw 0x08
db 0
db 0x8E
db 0x0001
idt_keyboard:
dw isr_33_keyboard
dw 0x08
db 0
db 0x8E
dw 0x0001
times 512-($-$$) db 0
컴파일 후 실행 시 키보드를 누를때, 뗄때마다 맨 앞의 값이 하나 바뀌는것을 알 수 있다.
신기방기 하구만.. 하하..
'OS 커널의 구조와 원리' 카테고리의 다른 글
5장 : Task Switching (0) | 2015.05.07 |
---|---|
4장 : 인터럽트와 예외 - 4 (예외) (0) | 2015.05.06 |
4장 : 인터럽트와 예외 - 2(하드웨어 인터럽트) (0) | 2015.05.06 |
4장 : 인터럽트와 예외 - 1 (0) | 2015.05.04 |
3장 : Protected Mode로 변환 (0) | 2015.05.04 |