저번에 Interrupt Descriptor Table에 대해서 대충(?) 알아봤다. 그래서 이번에는 구현해 보기로 했다. 막상 구현하려고 하니 뭘 해야 할지 답답… ㅎㅎㅎ 우선 저번에 간단하게 작성해 놓은 IDT 구조체 다시 한번 작성해 놓고..
typedef struct _IDTDesc { unsigned short Offset_low; unsigned short Selector; unsigned char Unused; unsigned char Access; unsigned short Offset_high; } IDTDesc;
음… 이제… 이 구조체가 여러개 존재 한다고 하니… 배열로… 구성해서…근데 몇개??? 몇개를 해야 하지??? 음… 그냥 1바이트 255개..ㅡㅡ;;;;; 대충해 보자.. 그래….
#define MAX_IDT 255 IDTDesc IDT[MAX_IDT];
음…그리고….에.. 그러니까.. 테이블을 만들었으니까 GDT 처럼 GDTR 이라는 레지스터에 이 테이블 주소를 넣어주는 …아.. 그래 IDTR에 이 테이블 주소를 넣어줘야지!!! ㅎㅎㅎ
그러면 IDTR 구조.
32bit | 16bit 0bit |
IDT의 메모리상에서 위치 | IDT의 크기 |
뭐… 별거 없다.. GDTR 구조와 같다…그러면..
typedef struct _IDTRegistor { unsigned short Size; unsigned int Address; } IDTRegistor; IDTRegistor IDTR;
음… 이렇게 만들었으면 예외상황 인터럽트, 하드웨어 인터럽트, 시스템콜 들을 등록 하라고 하는데 ….. ??? 어떻게 하지?? 검색해 보자…!!!!!!…………………………………………………………
저번에 포스팅한 예외상황 인터럽트 번호 0 부터 … 채울 수 있을 때까지 채우란다.. 시스템콜들은 뭐라뭐라 하는데 그냥 건너뛰고… 예외상황 하고 하드웨어 입력….!!! 그런데 말이다…. IDT 각각의 항목이 뭔지를 알아야 채우지~~~
Offset_low(2Byte)
Offset_high(2Byte)
요 두 놈들은 인터럽트 발생 시 인터럽트가 해야 할 (ISR이라고 저번에 적었지!~~^^ 잊어버렸었다.) 작업 위치 란다. 즉, 해당 함수의 메모리 상 위치.
Selector(2Byte)
요놈은 보호모드 진입시 GDT 테이블에 적어 놓은 CODE, DATA 셀렉터를 입력하는 놈이라는 데… 난 아직도 CODE와 DATA가 어떤 의미인지 모르겠다.. 그냥, CODE 셀렉터… 음… GDT 테이블에서 0x08 가 CODE 니까.. 저긴 0x08로 입력하는 걸로.
Unused(1Byte)
요넘은 사용 안하니 패쓰하고
Access(1Byte)
요놈은 그러니까… 전번에 한번 적었던 기억이 나는데…...http://manggong.org/41 여기…
P, DPL, S, TYPE 요렇게 되어 있고. P는 1로 하라고 하니 1. DPL 특권 레벨에 대한 것이라고 하고 레벨 0, 유저는 3이라고 하는데 0. S는 그냥 0.
TYPE은 여러 종류가 있는 것 같은데 보호 모드로 진입해서 32비트 라고 하고 Trap Gate는 소프트웨어 인터럽트나 예외 인터럽트, Interrupt Gate는 하드웨어 인터럽트. 그러면 0xE 아니면 0xF 인것 같다.
자, 그러면 Access 이놈한테 줄 수 있는 값은 10001110(0x8E : 소프트웨어 인터럽트, 예외인터럽트), 또는 10001111(0x8F : 하드웨어 인터럽트)
흠.. 이제 IDT를 채워보자.
아… 그러고 보니 Offset_low, high에 입력 해 줄 인터럽트 서비스 루틴(ISR) 함수가 없다.. 음… 더미 함수 하나 만들어 보고……근데 그냥 만들면 되나??? ……….이거 뭐 하나 쉽게 진행이 안되니…
http://wiki.osdev.org/Interrupt_Service_Routines에 의하면
void _declspec(naked) interrupt_handler() { _asm pushad; /* do something */ _asm{ popad iretd } }
이런식으로 만들면 된다고 한다. 그래 그냥 저 함수 저대로 쓰자~~ ^^
자 그러면.. 입력!
void Init_IDT() { int i; unsigned int high, low; for(i = 0; i < MAX_IDT; i++ ) { IDT[i].Selector = 0x08; if( i < 0x14 ) IDT[i].Access = 0x8E; // 예외 인터럽트 else IDT[i].Access = 0x8F; // 하드웨어 IDT[i].Unused = 0x00; low = (unsigned int)&interrupt_handler; low = low & 0xFFFF; high = (unsigned int)&interrupt_handler; high = (high >> 16); IDT[i].Offset_high = (unsigned short)high; IDT[i].Offset_low = (unsigned short)low; } }
그리고 내친김에 IDTR도…
IDTR.Address = (unsigned int)&IDT; IDTR.Size = MAX_IDT * sizeof( IDTDesc );
다 입력했다… 마지막으로 이제 어셈블리어 LIDT 로 IDTR을 로딩시켜 주면…~~~~~~~ 된다고 하는데 … 어셈은 어려워 ㅠㅠ … 대충 해보자….
void LoadIDTR(unsigned int addr) { _asm { mov eax, [addr] lidt [eax] sti } }
ㅎㅎㅎㅎ lidt에 idtr 주소 넣어 주고 sti 명령어로 인터럽트를 활성화 시켜주면 된다고 한다. 자…. 한번 해볼까??
void InitPIC(); void Init_IDT(); void interrupt_handler(); void LoadIDTR(unsigned int addr); unsigned char Read_port_byte(unsigned short port); void Write_port_byte(unsigned short port, unsigned char data); typedef struct _IDTDesc { unsigned short Offset_low; unsigned short Selector; unsigned char Unused; unsigned char Access; unsigned short Offset_high; } IDTDesc; typedef struct _IDTRegistor { unsigned short Size; unsigned int Address; } IDTRegistor; #define MAX_IDT 255 IDTDesc IDT[MAX_IDT]; IDTRegistor IDTR; unsigned char *Screen = (unsigned char*)0xB8000; #define KEY_F1 0x80 #define KEY_F2 (KEY_F1 + 1) #define KEY_F3 (KEY_F2 + 1) #define KEY_F4 (KEY_F3 + 1) #define KEY_F5 (KEY_F4 + 1) #define KEY_F6 (KEY_F5 + 1) #define KEY_F7 (KEY_F6 + 1) #define KEY_F8 (KEY_F7 + 1) #define KEY_F9 (KEY_F8 + 1) #define KEY_F10 (KEY_F9 + 1) #define KEY_F11 (KEY_F10 + 1) #define KEY_F12 (KEY_F11 + 1) #define KEY_INS 0x90 #define KEY_DEL (KEY_INS + 1) #define KEY_HOME (KEY_DEL + 1) #define KEY_END (KEY_HOME + 1) #define KEY_PGUP (KEY_END + 1) #define KEY_PGDN (KEY_PGUP + 1) #define KEY_LFT (KEY_PGDN + 1) #define KEY_UP (KEY_LFT + 1) #define KEY_DN (KEY_UP + 1) #define KEY_RT (KEY_DN + 1) #define KEY_PRNT (KEY_RT + 1) #define KEY_PAUSE (KEY_PRNT + 1) #define KEY_LWIN (KEY_PAUSE + 1) #define KEY_RWIN (KEY_LWIN + 1) #define KEY_MENU (KEY_RWIN + 1) static const unsigned char kbd_scancode[] = { 0, 0x1B, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\b', '\t', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', 0, 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', '`', 0, '\\', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 0, 0, ' ', 0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10,0, 0, KEY_HOME, KEY_UP, KEY_PGUP,'-', KEY_LFT,'5', KEY_RT, '+', KEY_END, KEY_DN, KEY_PGDN,KEY_INS,KEY_DEL,0, 0, 0, KEY_F11, KEY_F12 }; void printf( char *msg ) { while(*msg != '\0') { *Screen++ = *msg++; *Screen++ = 7; } } void putc(char Code) { *Screen++ = Code; *Screen++ = 7; } int StartKernel(int argc, char *argv[]) { char *hello = "Hello OS!"; char *complete = "complete."; unsigned char* vidmem = (unsigned char*)0xB8000; unsigned char data = 0; int b = 5; int c = 0; printf(hello); InitPIC(); Init_IDT(); while(1) ; return 0; } unsigned char Read_port_byte(unsigned short port) { unsigned char KeyCode = 0; __asm { mov dx, port xor eax, eax in ax, dx lea ebx, KeyCode mov [ebx], al } return KeyCode; } void Write_port_byte(unsigned short port, unsigned char data) { __asm { mov dx, [ebp+8] mov al, [ebp+12] out dx, al } } void InitPIC() { Write_port_byte(0x20, 0x11); Write_port_byte(0x21, 0x20); Write_port_byte(0x21, 0x04); Write_port_byte(0x21, 0x01); Write_port_byte(0x21, 0xFF); Write_port_byte(0xA0, 0x11); Write_port_byte(0xA1, 0x28); Write_port_byte(0xA1, 0x02); Write_port_byte(0xA1, 0x01); Write_port_byte(0xA1, 0xFF); } void _declspec(naked) interrupt_handler() { _asm pushad; _asm { popad iretd } } void Init_IDT() { int i; unsigned int high, low; for(i = 0; i < MAX_IDT; i++ ) { IDT[i].Selector = 0x08; if( i < 0x14 ) IDT[i].Access = 0x8E; // 예외 인터럽트 else IDT[i].Access = 0x8F; // 하드웨어 IDT[i].Unused = 0x00; low = (unsigned int)&interrupt_handler; low = low & 0xFFFF; high = (unsigned int)&interrupt_handler; high = (high >> 16); IDT[i].Offset_high = (unsigned short)high; IDT[i].Offset_low = (unsigned short)low; } IDTR.Address = (unsigned int)&IDT; IDTR.Size = MAX_IDT * sizeof( IDTDesc ); LoadIDTR((unsigned int)&IDTR); } void LoadIDTR(unsigned int addr) { _asm { mov eax, [addr] lidt [eax] sti } }
예전에 키보드 입력 받았던 코드에서 PIC를 초기화 해주고…!!! (하드웨어 인터럽트 발생해야 하니깐…) 컴파일 해서 확인!!!
아무 반응 없다…
뭐… 재부팅 안된것만 해도 다행이다.
키보드 입력을 받았으면 좋겠는데… 피곤해서 오늘은 그냥 여기까지…
다음시간에는 키보드 입력 루틴까지..
'프로그래밍 > OS 만들기' 카테고리의 다른 글
OS 만들기 #19 키보드 처리 및 쉬어가기. (0) | 2015.08.16 |
---|---|
OS 만들기 #18 IDT - 3 (0) | 2015.08.12 |
OS 만들기 #16 IDT - 1 (0) | 2015.07.30 |
OS 만들기 #15 커널-키보드 입력 (0) | 2015.02.09 |
OS 만들기 #14 PE 재배치 (0) | 2014.03.28 |