문제
- 마우스가 안움직이는건 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와 유사하게 설정
'컴퓨터과학 > 컴퓨터, OS' 카테고리의 다른 글
HWSW - 2. 컴파일 (0) | 2020.08.06 |
---|---|
HWSW - 1. MCU (0) | 2020.08.05 |
os만들기 - 24. 변수 표시하고, 마우스 띄우기 (0) | 2020.08.03 |
os만들기 - 23. 문자(열) 처리 (0) | 2020.08.03 |
os만들기 - 22. 부팅정보 가져오기, 구조체, 화살표 연산자 (0) | 2020.08.03 |