Tistory 태그: ,,,,

저번에 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를 초기화 해주고…!!! (하드웨어 인터럽트 발생해야 하니깐…) 컴파일 해서 확인!!!

아무 반응 없다…

뭐… 재부팅 안된것만 해도 다행이다.

키보드 입력을 받았으면 좋겠는데… 피곤해서 오늘은 그냥 여기까지…

다음시간에는 키보드 입력 루틴까지..

 

+ Recent posts