728x90

문제

- 마우스가 안움직이는건 GDT와 IDT를 설정하지 않음

 

 

 

GDT와 IDT를 다루기 전에

- 이들은 CPU에서 설정하는것 asmhead.nas에서 프로그램을 대충 돌리는 내용만 있지. GDT와 IDT 설정은 안됨.

- 세그먼트와 인터럽트를 다루는게 우선

 

메모리의 사용과 세그먼테이션

- ORG 명령으로 읽을 프로그램이 어디에 있는지 선언하지 않으면, 원하는 프로그램을 읽지 못함

 => ex. ORG 0x1234 하면 프로그램은 메모리의 0x1234번지를 읽어야함

- 여러 프로그램이 돌다가 동일한 번지를 건드릴수 있는데, 막아야함 => 사용중인 메모리 접근 막는 것이 세그먼테이션

 

세그먼테이션

- 총 4GB 메모리를 분할후 각 블록들의 처음 번지를 0으로 다루는 기능

 => 모든 프로그램에서 ORG 0으로 시작. 구분된 블록 하나 하나를 세그먼트라 함.

 

페이징

- 세그먼트는 4GB를 분할하는것이지만 페이징은 4GB를 테스트 수만큼 만들어 메모리 순서를 바꾸어 충돌 막는 방법?

 

 

 

 

 

 

 

 

 

세그먼트 관리

- 세그먼테이션이 세그먼트 1개를 표현하기위한 필요 정보 : 세그먼트 크기, 세그먼트 시작번지, 세그먼트 관리 속성

 => CPU에서 8바이트 데이터로 위 정보들을 표현.

- 세그먼트 설정을 위한 세그먼트 레지스터는 16비트 뿐

 =>그래픽 팔레트와 동일하게, 세그먼트 번호를 세그먼트 레지스터에 담고 세그먼트 번호가 어느 것에 대응하는지 설정

 

 

세그먼트 번호 사용 가능 범위

- 팔레트에서 색번호는 0 ~ 255. 2^8만큼 사용

- 세그먼트 번호는 세그먼트 레지스터가 16비트라 2^16만큼 일것같으나, CPU 성능 상 하위 3비트는 사용불가

  => 사용 가능한 세그먼트 번호는 13비트. 즉,  범위가 0 ~ 8,191

 

 

팔레트와 세그먼트 차이

- 팔레트는 그래픽(외부 장치)를 다루므로 io_out을 사용

- 세그먼트는 CPU 내부만의 레지스터 만으로 정리하므로 필요없음

 

 

세그먼트 정의하기

- 세그먼트 번호는 0 ~ 8,191까지 존재

- 실제 전체 세그먼트는 2^16 => 64KB 요구. 하지만 CPU는 64KB를 기억 불가

 => CPU 대신 메모리에 세그먼트들을 기록은것

 

 

GDT Global (Segment) Descriptor Table

- 전역 세그먼트 기술자 표

- 메모리에 세그먼트들을 나열하고, 세그먼트 맨 앞 번지와 설정할 세그먼트 갯수를 GDTR 레지스터에 설정

 * GDTR : Global (Segment) Descriptor Table Regisor

 

 

IDT Interrupt Descriptor Table

- 인터럽트 기술자 표

- CPU는 외부 상황이나 내부 문제 발생시 잠시 스위칭 함 => 인터럽트 

- 컴퓨터에는 그래픽, 메모리, 키보드, 사운드 등 다양한 처리해야할 장치가 많음

 => 이를 빠르게 처리하기 위해 인터럽트를 사용

 

인터럽트

- 각 장치에 변화가 있을시 발생

- 인터럽트 발생 -> CPU는 기존에 하던일을 멈춤 -> 다시 할수있게 준비 -> 인터럽트 처리 -> 이전작업으로 돌아감

 

 

마우스를 쓰려면

- 인터럽트 설정필요

- IDT는 인터럽트번호 0 ~ 255까지 준비, 특정 번호의 인터럽트가 호출되면 대응되는 콜백함수를 수행함.

- GDT와 IDT 설정을 하자

 

 

 

GDT, IDT 관련 코드들

- SEGMENT_DESCRIPTOR : GDT를 구성하는 8바이트 구조체

- GAST_DESCRIPTOR : IDT를 구성하는 8바이트 구조체

 

struct SEGMENT_DESCRIPTOR {
	short limit_low, base_low;
	char base_mid, access_right;
	char limit_high, base_high;
};

struct GATE_DESCRIPTOR {
	short offset_low, selector;
	char dw_count, access_right;
	short offset_high;
};

void init_gdtidt(void);
void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar);
void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar);
void load_gdtr(int limit, int addr);
void load_idtr(int limit, int addr);






void init_gdtidt(void)
{
	struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) 0x00270000;
	struct GATE_DESCRIPTOR    *idt = (struct GATE_DESCRIPTOR    *) 0x0026f800;
	int i;

	/* GDT 초기화 */
	for (i = 0; i < 8192; i++) {
		set_segmdesc(gdt + i, 0, 0, 0);
	}
	set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, 0x4092);
	set_segmdesc(gdt + 2, 0x0007ffff, 0x00280000, 0x409a);
	load_gdtr(0xffff, 0x00270000);

	/* IDT 초기화 */
	for (i = 0; i < 256; i++) {
		set_gatedesc(idt + i, 0, 0, 0);
	}
	load_idtr(0x7ff, 0x0026f800);

	return;
}

void set_segmdesc(struct SEGMENT_DESCRIPTOR *sd, unsigned int limit, int base, int ar)
{
	if (limit > 0xfffff) {
		ar |= 0x8000; /* G_bit = 1 */
		limit /= 0x1000;
	}
	sd->limit_low    = limit & 0xffff;
	sd->base_low     = base & 0xffff;
	sd->base_mid     = (base >> 16) & 0xff;
	sd->access_right = ar & 0xff;
	sd->limit_high   = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);
	sd->base_high    = (base >> 24) & 0xff;
	return;
}

void set_gatedesc(struct GATE_DESCRIPTOR *gd, int offset, int selector, int ar)
{
	gd->offset_low   = offset & 0xffff;
	gd->selector     = selector;
	gd->dw_count     = (ar >> 8) & 0xff;
	gd->access_right = ar & 0xff;
	gd->offset_high  = (offset >> 16) & 0xffff;
	return;
}

 

GDT, IDT 초기화

- gdt 변수에 0x0027 0000을 대입 -> 0x0027 0000 ~ 0x0027 ffff를 GDT로 하기 위함

- idt 변수에 0x0026 f800 대입 -> 0x0026 f800 ~ 0x26 ffff 번지를 IDT로 함

 

 

- gdt는 2^13 = 8192번까지 세그먼트 설정

 * 하나의 gdt당 8바이트 이므로 아래와 같이 gdt의 다음 번지로 넘어감

0x0027 0000

0x0027 0008

0x0027 0010

0x0027 0018

      ...

0x0026  ffff

- 결국 아래의 그림에서 반복문으로 모든 세그먼트들에 대해서

 gdt의 번지들에 리미트(세그먼트 크기 - 1) 0, 베이스(시작 번지) 0, 엑세스 권한 속성 0으로 설정

 

- 반복문 다음 구문 set_segmdesc로  gdt + 1-> 1번 GDT,  gdt + 2는 2번 GDT

 => 1번은 크기가 0xffff ffff(4GB), 시작 번지 0, 세그먼트속성 0x4092

 => 2번은 크기가 0x0007 ffff(512KB), 시작번지 0x0028 0000, -> bootpack.hrb를 위해 작성

- 마지막으로 load gdtr. C언어에서 GDTR을 다룰수 없어 어셈블러 상에 함수 작성

- IDT는 GDT와 동일한 과정으로 초기화

 

 

 

 

정리

- 이번 시간에는 GDT, IDT 설정하는 과정만 다루고 실제 인터럽트 처리 같은것들을 하지 않아서 동작은 안함.

- 다시 내용을 정리하면 동일한 메모리 번지 사용 충돌을 막기위해 세그먼테이션 사용

- 세그먼테이션은 메모리를 블록으로 분할한 후, 각 블록(세그먼트)들을 처음 번지를 0으로 다룸.

- 세그먼테이션에서 세그먼트 1개가 갖는 정보들 : 세그먼트 크기, 시작번지, 관리속성

- GDT : 수많은 세그먼트 데이터들을 CPU 대신 메모리에 저장해놓은 테이블 Global (Segment) Descriptor Table

- IDT : 인터럽트 기술자 표, 인터럽트 기능을 수행하기 위해 인터럽트 번호와 콜벡함수를 정리한 테이블

- IDT를 쓰기전에 GDT 먼저 설정이 필요

- GDT와 IDT 구조체는 1개당 8바이트

- 소스 코드 상 모든 가능한 GDT들에 대해 크기 0, 시작점 0, 속성 0으로 설정

- 1, 2번 GDT만 별도 설정 수행

- IDT는 GDT와 유사하게 설정

 

300x250

+ Recent posts