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
728x90

현황

- 이전 시간에는 폰트 데이터를 만들어 출력해보고, 이를 간편하게하기 위한 putfont8, 문자열을 출력하기위한 putfonts8 함수 등을 구현했습니다.

 

 

문제

- 프로그램 구현시 잘못된 값이 있을것 같을때 해당 변수를 출력해보면 되지만, 지금의 시스템에서는 디버거를 돌릴수도 없고 힘듬

 

방법

- 변수를 출력하기 위해 sprintf() 함수로 출력할 메모리에 원하는 변수 값을 담고, putfons8로 sprintf()로 할당한 변수 공간을 전달해주면 되겠습니다.

 

 

sprintf

- 첫번째 매개변수에 서식에 맞게 값을 대입하여 저장

- sprintf(주소, 서식, 값)

- ex sprintf(s, "%x", 123); 숫자 123을 16진수 형태의 문자열로 변환하여 s 번지에 담는다.

 

 

 

 

매인 함수

- 대부분의 내용은 이전 예제와 동일

- 출력시키고자 하는 변수를 sprintf()함수로 서식에 맞게 문자열로 변환 -> 주소 s에다가 문자열 담음

- 배열 주소 s를 putfonts8로 출력 수행

void HariMain(void)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
	char s[40];

	init_palette();
	init_screen(binfo->vram, binfo->scrnx, binfo->scrny);
	putfonts8_asc(binfo->vram, binfo->scrnx,  8, 8, COL8_FFFFFF, "ABC 123");
	putfonts8_asc(binfo->vram, binfo->scrnx, 31, 31, COL8_000000, "Haribote OS.");
	putfonts8_asc(binfo->vram, binfo->scrnx, 30, 30, COL8_FFFFFF, "Haribote OS.");
	sprintf(s, "scrnx = %d", binfo->scrnx);
	putfonts8_asc(binfo->vram, binfo->scrnx, 16, 64, COL8_FFFFFF, s);

	for (;;) {
		io_hlt();
	}
}

 

실행결과

- binfo 구조체에 들어있는 변수값 scrnx를 문자열로 바꾸어 s에 담고 이를 putfont8s로 원하는 (16, 64) 위치에 출력

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

#include <stdio.h>

void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
void init_screen8(char *vram, int x, int y);
void putfont8(char *vram, int xsize, int x, int y, char c, char *font);
void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s);
void init_mouse_cursor8(char *mouse, char bc);
void putblock8_8(char *vram, int vxsize, int pxsize,
	int pysize, int px0, int py0, char *buf, int bxsize);

#define COL8_000000		0
#define COL8_FF0000		1
#define COL8_00FF00		2
#define COL8_FFFF00		3
#define COL8_0000FF		4
#define COL8_FF00FF		5
#define COL8_00FFFF		6
#define COL8_FFFFFF		7
#define COL8_C6C6C6		8
#define COL8_840000		9
#define COL8_008400		10
#define COL8_848400		11
#define COL8_000084		12
#define COL8_840084		13
#define COL8_008484		14
#define COL8_848484		15

struct BOOTINFO {
	char cyls, leds, vmode, reserve;
	short scrnx, scrny;
	char *vram;
};

void HariMain(void)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
	char s[40], mcursor[256];
	int mx, my;

	init_palette();
	init_screen8(binfo->vram, binfo->scrnx, binfo->scrny);
	mx = (binfo->scrnx - 16) / 2; /*마우스 커서 위치*/
	my = (binfo->scrny - 28 - 16) / 2;
	init_mouse_cursor8(mcursor, COL8_008484);
	putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16);
	sprintf(s, "(%d, %d)", mx, my); /*마우스 위치 변수를 담음 문자 출력을 위해*/
	putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s);

	for (;;) {
		io_hlt();
	}
}

void init_palette(void)
{
	static unsigned char table_rgb[16 * 3] = {
		0x00, 0x00, 0x00,	/*  0:검은색 */
		0xff, 0x00, 0x00,	/*  1:밝은 적색 */
		0x00, 0xff, 0x00,	/*  2:밝은 녹색 */
		0xff, 0xff, 0x00,	/*  3:밝은 노란색 */
		0x00, 0x00, 0xff,	/*  4:밝은 청색 */
		0xff, 0x00, 0xff,	/*  5:밝은 보라색 */
		0x00, 0xff, 0xff,	/*  6:밝은 청색*/
		0xff, 0xff, 0xff,	/*  7:흰색 */
		0xc6, 0xc6, 0xc6,	/*  8:밝은 회색 */
		0x84, 0x00, 0x00,	/*  9:어두운 적색 */
		0x00, 0x84, 0x00,	/* 10:어두운 녹색 */
		0x84, 0x84, 0x00,	/* 11:어두운 노란색 */
		0x00, 0x00, 0x84,	/* 12:군청색 */
		0x84, 0x00, 0x84,	/* 13:어두운 보라색 */
		0x00, 0x84, 0x84,	/* 14:어두운 청색 */
		0x84, 0x84, 0x84	/* 15:어두운 회색 */
	};
	set_palette(0, 15, table_rgb);
	return;

	/* static char 명령은 (주소가 아니라)데이터밖에 쓰지 못하지만, DB명령과 동일함 */
}

void set_palette(int start, int end, unsigned char *rgb)
{
	int i, eflags;
	eflags = io_load_eflags();	/* 인터럽트 허가 플래그 값을 기록 */
	io_cli(); 					/* 허가 플래그를 0으로 하여 인터럽트 금지 */
	io_out8(0x03c8, start);
	for (i = start; i <= end; i++) {
		io_out8(0x03c9, rgb[0] / 4);
		io_out8(0x03c9, rgb[1] / 4);
		io_out8(0x03c9, rgb[2] / 4);
		rgb += 3;
	}
	io_store_eflags(eflags);	/* 인터럽트 허가 플래그를 본래 값으로 되돌린다. */
	return;
}

void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
	int x, y;
	for (y = y0; y <= y1; y++) {
		for (x = x0; x <= x1; x++)
			vram[y * xsize + x] = c;
	}
	return;
}

void init_screen8(char *vram, int x, int y)
{
	boxfill8(vram, x, COL8_008484,  0,     0,      x -  1, y - 29);
	boxfill8(vram, x, COL8_C6C6C6,  0,     y - 28, x -  1, y - 28);
	boxfill8(vram, x, COL8_FFFFFF,  0,     y - 27, x -  1, y - 27);
	boxfill8(vram, x, COL8_C6C6C6,  0,     y - 26, x -  1, y -  1);

	boxfill8(vram, x, COL8_FFFFFF,  3,     y - 24, 59,     y - 24);
	boxfill8(vram, x, COL8_FFFFFF,  2,     y - 24,  2,     y -  4);
	boxfill8(vram, x, COL8_848484,  3,     y -  4, 59,     y -  4);
	boxfill8(vram, x, COL8_848484, 59,     y - 23, 59,     y -  5);
	boxfill8(vram, x, COL8_000000,  2,     y -  3, 59,     y -  3);
	boxfill8(vram, x, COL8_000000, 60,     y - 24, 60,     y -  3);

	boxfill8(vram, x, COL8_848484, x - 47, y - 24, x -  4, y - 24);
	boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y -  4);
	boxfill8(vram, x, COL8_FFFFFF, x - 47, y -  3, x -  4, y -  3);
	boxfill8(vram, x, COL8_FFFFFF, x -  3, y - 24, x -  3, y -  3);
	return;
}

void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{
	int i;
	char *p, d /* data */;
	for (i = 0; i < 16; i++) {
		p = vram + (y + i) * xsize + x;
		d = font[i];
		if ((d & 0x80) != 0) { p[0] = c; }
		if ((d & 0x40) != 0) { p[1] = c; }
		if ((d & 0x20) != 0) { p[2] = c; }
		if ((d & 0x10) != 0) { p[3] = c; }
		if ((d & 0x08) != 0) { p[4] = c; }
		if ((d & 0x04) != 0) { p[5] = c; }
		if ((d & 0x02) != 0) { p[6] = c; }
		if ((d & 0x01) != 0) { p[7] = c; }
	}
	return;
}

void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)
{
	extern char hankaku[4096];
	for (; *s != 0x00; s++) {
		putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
		x += 8;
	}
	return;
}

void init_mouse_cursor8(char *mouse, char bc)
/* 마우스 커서 준비 (16x16) */
{
	static char cursor[16][16] = {
		"**************..",
		"*OOOOOOOOOOO*...",
		"*OOOOOOOOOO*....",
		"*OOOOOOOOO*.....",
		"*OOOOOOOO*......",
		"*OOOOOOO*.......",
		"*OOOOOOO*.......",
		"*OOOOOOOO*......",
		"*OOOO**OOO*.....",
		"*OOO*..*OOO*....",
		"*OO*....*OOO*...",
		"*O*......*OOO*..",
		"**........*OOO*.",
		"*..........*OOO*",
		"............*OO*",
		".............***"
	};
	int x, y;

	for (y = 0; y < 16; y++) {
		for (x = 0; x < 16; x++) {
			if (cursor[y][x] == '*') {
				mouse[y * 16 + x] = COL8_000000;
			}
			if (cursor[y][x] == 'O') {
				mouse[y * 16 + x] = COL8_FFFFFF;
			}
			if (cursor[y][x] == '.') {
				mouse[y * 16 + x] = bc;
			}
		}
	}
	return;
}

void putblock8_8(char *vram, int vxsize, int pxsize,
	int pysize, int px0, int py0, char *buf, int bxsize)
{
	int x, y;
	for (y = 0; y < pysize; y++) {
		for (x = 0; x < pxsize; x++) {
			vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x];
		}
	}
	return;
}

현황

- 문자, 문자열, 변수 출력도 잘 됬다. 이제 마우스 커서도 그려보자

 

 

 

마우스 커서 초기화

- 마우스 커서를 16 x 16으로 하면 256바이트 공간이 필요

- 해당 공간에 마우스 커서 데이터를 담자

 *bc는 커서 배경색

void init_mouse_cursor8(char *mouse, char bc)
/* 마우스 커서 준비 (16x16) */
{
	static char cursor[16][16] = {
		"**************..",
		"*OOOOOOOOOOO*...",
		"*OOOOOOOOOO*....",
		"*OOOOOOOOO*.....",
		"*OOOOOOOO*......",
		"*OOOOOOO*.......",
		"*OOOOOOO*.......",
		"*OOOOOOOO*......",
		"*OOOO**OOO*.....",
		"*OOO*..*OOO*....",
		"*OO*....*OOO*...",
		"*O*......*OOO*..",
		"**........*OOO*.",
		"*..........*OOO*",
		"............*OO*",
		".............***"
	};
	int x, y;

	for (y = 0; y < 16; y++) {
		for (x = 0; x < 16; x++) {
			if (cursor[y][x] == '*') {
				mouse[y * 16 + x] = COL8_000000;
			}
			if (cursor[y][x] == 'O') {
				mouse[y * 16 + x] = COL8_FFFFFF;
			}
			if (cursor[y][x] == '.') {
				mouse[y * 16 + x] = bc;
			}
		}
	}
	return;
}

 

 

 

마우스를 출력하기 위한 함수

-  buf에 있는 데이터를 vram에다가 복사

- 마우스 (버퍼) 데이터들을 화면에 띄워주는데 사용

void putblock8_8(char *vram, int vxsize, int pxsize,
	int pysize, int px0, int py0, char *buf, int bxsize)
{
	int x, y;
	for (y = 0; y < pysize; y++) {
		for (x = 0; x < pxsize; x++) {
			vram[(py0 + y) * vxsize + (px0 + x)] = buf[y * bxsize + x];
		}
	}
	return;
}

 

 

메인함수

- 화면 중심을 마우스 커서 위치로 잡고 이를 putlock8_8 함수로 해당 vram 주소에다가 마우스 그리기

void HariMain(void)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
	char s[40], mcursor[256];
	int mx, my;

	init_palette();
	init_screen8(binfo->vram, binfo->scrnx, binfo->scrny);
	mx = (binfo->scrnx - 16) / 2; /*마우스 커서 위치*/
	my = (binfo->scrny - 28 - 16) / 2;
	init_mouse_cursor8(mcursor, COL8_008484);
	putblock8_8(binfo->vram, binfo->scrnx, 16, 16, mx, my, mcursor, 16);
	sprintf(s, "(%d, %d)", mx, my); /*마우스 위치 변수를 담음 문자 출력을 위해*/
	putfonts8_asc(binfo->vram, binfo->scrnx, 0, 0, COL8_FFFFFF, s);

	for (;;) {
		io_hlt();
	}
}

 

실행 결과

- 화면 중심에 마우스 커서와 해당 위치(변수) 문자 출력

 

 

 

 

 

 

 

300x250
728x90
void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
void init_screen(char *vram, int x, int y);
void putfont8(char *vram, int xsize, int x, int y, char c, char *font);

#define COL8_000000		0
#define COL8_FF0000		1
#define COL8_00FF00		2
#define COL8_FFFF00		3
#define COL8_0000FF		4
#define COL8_FF00FF		5
#define COL8_00FFFF		6
#define COL8_FFFFFF		7
#define COL8_C6C6C6		8
#define COL8_840000		9
#define COL8_008400		10
#define COL8_848400		11
#define COL8_000084		12
#define COL8_840084		13
#define COL8_008484		14
#define COL8_848484		15

struct BOOTINFO {
	char cyls, leds, vmode, reserve;
	short scrnx, scrny;
	char *vram;
};

void HariMain(void)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
	static char font_A[16] = {
		0x00, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24,
		0x24, 0x7e, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00
	};

	init_palette();
	init_screen(binfo->vram, binfo->scrnx, binfo->scrny);
	putfont8(binfo->vram, binfo->scrnx, 10, 10, COL8_FFFFFF, font_A);

	for (;;) {
		io_hlt();
	}
}

void init_palette(void)
{
	static unsigned char table_rgb[16 * 3] = {
		0x00, 0x00, 0x00,	/*  0:검은색 */
		0xff, 0x00, 0x00,	/*  1:밝은 적색 */
		0x00, 0xff, 0x00,	/*  2:밝은 녹색 */
		0xff, 0xff, 0x00,	/*  3:밝은 노란색 */
		0x00, 0x00, 0xff,	/*  4:밝은 청색 */
		0xff, 0x00, 0xff,	/*  5:밝은 보라색 */
		0x00, 0xff, 0xff,	/*  6:밝은 청색*/
		0xff, 0xff, 0xff,	/*  7:흰색 */
		0xc6, 0xc6, 0xc6,	/*  8:밝은 회색 */
		0x84, 0x00, 0x00,	/*  9:어두운 적색 */
		0x00, 0x84, 0x00,	/* 10:어두운 녹색 */
		0x84, 0x84, 0x00,	/* 11:어두운 노란색 */
		0x00, 0x00, 0x84,	/* 12:군청색 */
		0x84, 0x00, 0x84,	/* 13:어두운 보라색 */
		0x00, 0x84, 0x84,	/* 14:어두운 청색 */
		0x84, 0x84, 0x84	/* 15:어두운 회색 */
	};
	set_palette(0, 15, table_rgb);
	return;

	/* static char 명령은 (주소가 아니라)데이터밖에 쓰지 못하지만, DB명령과 동일함 */
}

void set_palette(int start, int end, unsigned char *rgb)
{
	int i, eflags;
	eflags = io_load_eflags();	/* 인터럽트 허가 플래그 값을 기록 */
	io_cli(); 					/* 허가 플래그를 0으로 하여 인터럽트 금지 */
	io_out8(0x03c8, start);
	for (i = start; i <= end; i++) {
		io_out8(0x03c9, rgb[0] / 4);
		io_out8(0x03c9, rgb[1] / 4);
		io_out8(0x03c9, rgb[2] / 4);
		rgb += 3;
	}
	io_store_eflags(eflags);	/* 인터럽트 허가 플래그를 본래 값으로 되돌린다. */
	return;
}

void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
	int x, y;
	for (y = y0; y <= y1; y++) {
		for (x = x0; x <= x1; x++)
			vram[y * xsize + x] = c;
	}
	return;
}

void init_screen(char *vram, int x, int y)
{
	boxfill8(vram, x, COL8_008484,  0,     0,      x -  1, y - 29);
	boxfill8(vram, x, COL8_C6C6C6,  0,     y - 28, x -  1, y - 28);
	boxfill8(vram, x, COL8_FFFFFF,  0,     y - 27, x -  1, y - 27);
	boxfill8(vram, x, COL8_C6C6C6,  0,     y - 26, x -  1, y -  1);

	boxfill8(vram, x, COL8_FFFFFF,  3,     y - 24, 59,     y - 24);
	boxfill8(vram, x, COL8_FFFFFF,  2,     y - 24,  2,     y -  4);
	boxfill8(vram, x, COL8_848484,  3,     y -  4, 59,     y -  4);
	boxfill8(vram, x, COL8_848484, 59,     y - 23, 59,     y -  5);
	boxfill8(vram, x, COL8_000000,  2,     y -  3, 59,     y -  3);
	boxfill8(vram, x, COL8_000000, 60,     y - 24, 60,     y -  3);

	boxfill8(vram, x, COL8_848484, x - 47, y - 24, x -  4, y - 24);
	boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y -  4);
	boxfill8(vram, x, COL8_FFFFFF, x - 47, y -  3, x -  4, y -  3);
	boxfill8(vram, x, COL8_FFFFFF, x -  3, y - 24, x -  3, y -  3);
	return;
}

void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{
	int i;
	char *p, d /* data */;
	for (i = 0; i < 16; i++) {
		p = vram + (y + i) * xsize + x;
		d = font[i];
		if ((d & 0x80) != 0) { p[0] = c; }
		if ((d & 0x40) != 0) { p[1] = c; }
		if ((d & 0x20) != 0) { p[2] = c; }
		if ((d & 0x10) != 0) { p[3] = c; }
		if ((d & 0x08) != 0) { p[4] = c; }
		if ((d & 0x04) != 0) { p[5] = c; }
		if ((d & 0x02) != 0) { p[6] = c; }
		if ((d & 0x01) != 0) { p[7] = c; }
	}
	return;
}

 

현황

- 22번 글에서는 부트 정보를 편리하게 접근할수 있도록 구조체와 화살표 연산자를 사용했다. 이제 메모리에 대한 내용들은 직접 적을 필요없이 포인터를 사용해서 접근하면 되겠지만, 이제 글자도 좀 써려고 한다.

 

 

바이오스로 문자쓰기?

- 어셈블리어로 바이오스에 입출력 요청해서 문자를 띄우면 될수도 있지만 이제 32비트 모드로 바이오스를 쓸수없음.

 

 

문자 쓰기?

- 8 x 16사각형 화소가 존재하면 문자를 어떻게 쓸가

 * 구글링해도 비슷한 사진도 없고 어떻게 보여줄까 고민 중 사진 찍으려다가 그냥 표로 그렸다. 아래의 상자는 8 x 16 화소로 문자 A를 표기한것

               
      000 000      
      000 000      
      000 000      
      000 000      
    000     000    
    000     000    
    000     000    
    000     000    
  000 000 000 000 000 000  
  000         000
 
  000         000  
  000         000  
  000         000  
000 000 000     000 000 000
               
               

- 위 표를 2진수로 나타내보고 16진수로 정리해보자

0 0 0 0 0 0 0 0   => 0x00

0 0 0 1 1 0 0 0   => 0x18

0 0 0 1 1 0 0 0   => 0x18

0 0 0 1 1 0 0 0   => 0x18

0 0 0 1 1 0 0 0   => 0x18

0 0 1 0 0 1 0 0   => 0x24

0 0 1 0 0 1 0 0   => 0x24

0 0 1 0 0 1 0 0   => 0x24

0 0 1 0 0 1 0 0   => 0x24

0 1 1 1 1 1 1 0   => 0x7e

0 1 0 0 0 0 1 0   => 0x42

0 1 0 0 0 0 1 0   => 0x42

0 1 0 0 0 0 1 0   => 0x42

1 1 1 0 0 1 1 1   => 0xe7

0 0 0 0 0 0 0 0   => 0x00

0 0 0 0 0 0 0 0   => 0x00

 

- 위 16진수 값들의 모음을 폰트 데이터가 된다.

static char font_A[16] = {
  0x00, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24,
  0x24, 0x7e, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00
};

- 8화소 폰트를 그리기 위해서 위 배열을 16번 반복하면 되며, 이를 정리한 결과가 아래의 putfont8 함수가 된다.

void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{
	int i;
	char *p, d /* data */;
	for (i = 0; i < 16; i++) {
		p = vram + (y + i) * xsize + x;
		d = font[i];
		if ((d & 0x80) != 0) { p[0] = c; }
		if ((d & 0x40) != 0) { p[1] = c; }
		if ((d & 0x20) != 0) { p[2] = c; }
		if ((d & 0x10) != 0) { p[3] = c; }
		if ((d & 0x08) != 0) { p[4] = c; }
		if ((d & 0x04) != 0) { p[5] = c; }
		if ((d & 0x02) != 0) { p[6] = c; }
		if ((d & 0x01) != 0) { p[7] = c; }
	}
	return;
}

 

 

폰트를 출력해보자

- 메인 함수를 보면 static char font_A[16] 으로 폰트 데이터를 초기화 해주고, putfont8을 보면 FFFFFFF 색상으로 (10,10)위치에 찍으라고 하는것 같다 실행해보면

void HariMain(void)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
	static char font_A[16] = {
		0x00, 0x18, 0x18, 0x18, 0x18, 0x24, 0x24, 0x24,
		0x24, 0x7e, 0x42, 0x42, 0x42, 0xe7, 0x00, 0x00
	};

	init_palette();
	init_screen(binfo->vram, binfo->scrnx, binfo->scrny);
	putfont8(binfo->vram, binfo->scrnx, 10, 10, COL8_FFFFFF, font_A);

	for (;;) {
		io_hlt();
	}
}

 

- 정상적으로 A가 출력됨

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
void init_screen(char *vram, int x, int y);
void putfont8(char *vram, int xsize, int x, int y, char c, char *font);

#define COL8_000000		0
#define COL8_FF0000		1
#define COL8_00FF00		2
#define COL8_FFFF00		3
#define COL8_0000FF		4
#define COL8_FF00FF		5
#define COL8_00FFFF		6
#define COL8_FFFFFF		7
#define COL8_C6C6C6		8
#define COL8_840000		9
#define COL8_008400		10
#define COL8_848400		11
#define COL8_000084		12
#define COL8_840084		13
#define COL8_008484		14
#define COL8_848484		15

struct BOOTINFO {
	char cyls, leds, vmode, reserve;
	short scrnx, scrny;
	char *vram;
};

void HariMain(void)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
	extern char hankaku[4096];

	init_palette();
	init_screen(binfo->vram, binfo->scrnx, binfo->scrny);
	putfont8(binfo->vram, binfo->scrnx,  8, 8, COL8_FFFFFF, hankaku + 'E' * 16);
	putfont8(binfo->vram, binfo->scrnx, 16, 8, COL8_FFFFFF, hankaku + '1' * 16);
	putfont8(binfo->vram, binfo->scrnx, 24, 8, COL8_FFFFFF, hankaku + 'D' * 16);
	putfont8(binfo->vram, binfo->scrnx, 32, 8, COL8_FFFFFF, hankaku + 'l' * 16);
	putfont8(binfo->vram, binfo->scrnx, 40, 8, COL8_FFFFFF, hankaku + 'L' * 16);
	putfont8(binfo->vram, binfo->scrnx, 48, 8, COL8_FFFFFF, hankaku + '1' * 16);
	putfont8(binfo->vram, binfo->scrnx, 56, 8, COL8_FFFFFF, hankaku + 'l' * 16);
	putfont8(binfo->vram, binfo->scrnx, 64, 8, COL8_FFFFFF, hankaku + 'E' * 16);
	putfont8(binfo->vram, binfo->scrnx, 72, 8, COL8_FFFFFF, hankaku + '1' * 16);
	putfont8(binfo->vram, binfo->scrnx, 80, 8, COL8_FFFFFF, hankaku + ' ' * 16);
	putfont8(binfo->vram, binfo->scrnx, 88, 8, COL8_FFFFFF, hankaku + 'O' * 16);
	putfont8(binfo->vram, binfo->scrnx, 96, 8, COL8_FFFFFF, hankaku + '1' * 16);
	putfont8(binfo->vram, binfo->scrnx, 104, 8, COL8_FFFFFF, hankaku + 'O' * 16);
	putfont8(binfo->vram, binfo->scrnx, 112, 8, COL8_FFFFFF, hankaku + 'F' * 16);
	putfont8(binfo->vram, binfo->scrnx, 120, 8, COL8_FFFFFF, hankaku + '7' * 16);
	putfont8(binfo->vram, binfo->scrnx, 128, 8, COL8_FFFFFF, hankaku + '1' * 16);

	for (;;) {
		io_hlt();
	}
}


void init_palette(void)
{
	static unsigned char table_rgb[16 * 3] = {
		0x00, 0x00, 0x00,	/*  0:검은색 */
		0xff, 0x00, 0x00,	/*  1:밝은 적색 */
		0x00, 0xff, 0x00,	/*  2:밝은 녹색 */
		0xff, 0xff, 0x00,	/*  3:밝은 노란색 */
		0x00, 0x00, 0xff,	/*  4:밝은 청색 */
		0xff, 0x00, 0xff,	/*  5:밝은 보라색 */
		0x00, 0xff, 0xff,	/*  6:밝은 청색*/
		0xff, 0xff, 0xff,	/*  7:흰색 */
		0xc6, 0xc6, 0xc6,	/*  8:밝은 회색 */
		0x84, 0x00, 0x00,	/*  9:어두운 적색 */
		0x00, 0x84, 0x00,	/* 10:어두운 녹색 */
		0x84, 0x84, 0x00,	/* 11:어두운 노란색 */
		0x00, 0x00, 0x84,	/* 12:군청색 */
		0x84, 0x00, 0x84,	/* 13:어두운 보라색 */
		0x00, 0x84, 0x84,	/* 14:어두운 청색 */
		0x84, 0x84, 0x84	/* 15:어두운 회색 */
	};
	set_palette(0, 15, table_rgb);
	return;

	/* static char 명령은 (주소가 아니라)데이터밖에 쓰지 못하지만, DB명령과 동일함 */
}

void set_palette(int start, int end, unsigned char *rgb)
{
	int i, eflags;
	eflags = io_load_eflags();	/* 인터럽트 허가 플래그 값을 기록 */
	io_cli(); 					/* 허가 플래그를 0으로 하여 인터럽트 금지 */
	io_out8(0x03c8, start);
	for (i = start; i <= end; i++) {
		io_out8(0x03c9, rgb[0] / 4);
		io_out8(0x03c9, rgb[1] / 4);
		io_out8(0x03c9, rgb[2] / 4);
		rgb += 3;
	}
	io_store_eflags(eflags);	/* 인터럽트 허가 플래그를 본래 값으로 되돌린다. */
	return;
}

void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
	int x, y;
	for (y = y0; y <= y1; y++) {
		for (x = x0; x <= x1; x++)
			vram[y * xsize + x] = c;
	}
	return;
}

void init_screen(char *vram, int x, int y)
{
	boxfill8(vram, x, COL8_008484,  0,     0,      x -  1, y - 29);
	boxfill8(vram, x, COL8_C6C6C6,  0,     y - 28, x -  1, y - 28);
	boxfill8(vram, x, COL8_FFFFFF,  0,     y - 27, x -  1, y - 27);
	boxfill8(vram, x, COL8_C6C6C6,  0,     y - 26, x -  1, y -  1);

	boxfill8(vram, x, COL8_FFFFFF,  3,     y - 24, 59,     y - 24);
	boxfill8(vram, x, COL8_FFFFFF,  2,     y - 24,  2,     y -  4);
	boxfill8(vram, x, COL8_848484,  3,     y -  4, 59,     y -  4);
	boxfill8(vram, x, COL8_848484, 59,     y - 23, 59,     y -  5);
	boxfill8(vram, x, COL8_000000,  2,     y -  3, 59,     y -  3);
	boxfill8(vram, x, COL8_000000, 60,     y - 24, 60,     y -  3);

	boxfill8(vram, x, COL8_848484, x - 47, y - 24, x -  4, y - 24);
	boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y -  4);
	boxfill8(vram, x, COL8_FFFFFF, x - 47, y -  3, x -  4, y -  3);
	boxfill8(vram, x, COL8_FFFFFF, x -  3, y - 24, x -  3, y -  3);
	return;
}

void putfont8(char *vram, int xsize, int x, int y, char c, char *font)
{
	int i;
	char *p, d /* data */;
	for (i = 0; i < 16; i++) {
		p = vram + (y + i) * xsize + x;
		d = font[i];
		if ((d & 0x80) != 0) { p[0] = c; }
		if ((d & 0x40) != 0) { p[1] = c; }
		if ((d & 0x20) != 0) { p[2] = c; }
		if ((d & 0x10) != 0) { p[3] = c; }
		if ((d & 0x08) != 0) { p[4] = c; }
		if ((d & 0x04) != 0) { p[5] = c; }
		if ((d & 0x02) != 0) { p[6] = c; }
		if ((d & 0x01) != 0) { p[7] = c; }
	}
	return;
}

여러 문자 출력하기

- A를 띄운건 좋지만 출력하고싶은 문자는 더 다양하다.

 알파벳은 26개의 소, 대문자, 숫자 10개, 기호 30개.. OSASK의 폰트 데이터 사용하자

 

 

OSASK 폰트 파일

- 아래는 OSASK 폰트 데이터 예시 * 어떻게 C언어에서 이걸쓸지는 Make 파일 참고

 

 

 

 

폰트파일 오브젝트 만들기

- 별도의 컴파일러(makefont.exe)로 오브젝트 파일로 만듬

 

 

메인함수

- 폰트 파일을 extern char hankaku[4096]으로 접근해서 사용

void HariMain(void)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;
	extern char hankaku[4096];

	init_palette();
	init_screen(binfo->vram, binfo->scrnx, binfo->scrny);
	putfont8(binfo->vram, binfo->scrnx,  8, 8, COL8_FFFFFF, hankaku + 'E' * 16);
	putfont8(binfo->vram, binfo->scrnx, 16, 8, COL8_FFFFFF, hankaku + '1' * 16);
	putfont8(binfo->vram, binfo->scrnx, 24, 8, COL8_FFFFFF, hankaku + 'D' * 16);
	putfont8(binfo->vram, binfo->scrnx, 32, 8, COL8_FFFFFF, hankaku + 'l' * 16);
	putfont8(binfo->vram, binfo->scrnx, 40, 8, COL8_FFFFFF, hankaku + 'L' * 16);
	putfont8(binfo->vram, binfo->scrnx, 48, 8, COL8_FFFFFF, hankaku + '1' * 16);
	putfont8(binfo->vram, binfo->scrnx, 56, 8, COL8_FFFFFF, hankaku + 'l' * 16);
	putfont8(binfo->vram, binfo->scrnx, 64, 8, COL8_FFFFFF, hankaku + 'E' * 16);
	putfont8(binfo->vram, binfo->scrnx, 72, 8, COL8_FFFFFF, hankaku + '1' * 16);
	putfont8(binfo->vram, binfo->scrnx, 80, 8, COL8_FFFFFF, hankaku + ' ' * 16);
	putfont8(binfo->vram, binfo->scrnx, 88, 8, COL8_FFFFFF, hankaku + 'O' * 16);
	putfont8(binfo->vram, binfo->scrnx, 96, 8, COL8_FFFFFF, hankaku + '1' * 16);
	putfont8(binfo->vram, binfo->scrnx, 104, 8, COL8_FFFFFF, hankaku + 'O' * 16);
	putfont8(binfo->vram, binfo->scrnx, 112, 8, COL8_FFFFFF, hankaku + 'F' * 16);
	putfont8(binfo->vram, binfo->scrnx, 120, 8, COL8_FFFFFF, hankaku + '7' * 16);
	putfont8(binfo->vram, binfo->scrnx, 128, 8, COL8_FFFFFF, hankaku + '1' * 16);

	for (;;) {
		io_hlt();
	}
}

 

 

실행 결과

- 글자는 좀 잘못썻지만 잘 나온다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

함수로 문자열 쓰기

- 방금전 예제에선 putfont8로 문자 하나하나 출력하다보니 힘들었다.

- 이를 함수로 구현해서 다뤄보자.

void putfonts8_asc(char *vram, int xsize, int x, int y, char c, unsigned char *s)
{
	extern char hankaku[4096];
	for (; *s != 0x00; s++) {
		putfont8(vram, xsize, x, y, c, hankaku + *s * 16);
		x += 8;
	}
	return;
}

 

 

메인 함수

- 위에서 정의한 putfont8_asc 함수로 지정한 위치에 차례 차례 작성해준다.

 *(31, 31)과 (30, 30)을 함으로서 폰트상 굵게 효과를 준것 같다.

void HariMain(void)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;

	init_palette();
	init_screen(binfo->vram, binfo->scrnx, binfo->scrny);
	putfonts8_asc(binfo->vram, binfo->scrnx,  8,  8, COL8_FFFFFF, "Hello BABOYA");
	putfonts8_asc(binfo->vram, binfo->scrnx, 31, 31, COL8_000000, "E1DlL1lOlE1 OlOF7l.");
	putfonts8_asc(binfo->vram, binfo->scrnx, 30, 30, COL8_000000, "E1DlL1lOlE1 OlOF7l.");
	putfonts8_asc(binfo->vram, binfo->scrnx, 30, 130, COL8_FFFFFF, "Computer");
	putfonts8_asc(binfo->vram, binfo->scrnx, 60, 150, COL8_FFFFFF, "annyohasseyo?");
	putfonts8_asc(binfo->vram, binfo->scrnx, 50,  70, COL8_FFFFFF, "Hello BABOYA");
	putfonts8_asc(binfo->vram, binfo->scrnx, 90,  75, COL8_FFFFFF, "Hello BABOYA");
	putfonts8_asc(binfo->vram, binfo->scrnx, 55,  60, COL8_FFFFFF, "Hello BABOYA");

	for (;;) {
		io_hlt();
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

300x250
728x90
void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
void init_screen(char *vram, int x, int y);

#define COL8_000000		0
#define COL8_FF0000		1
#define COL8_00FF00		2
#define COL8_FFFF00		3
#define COL8_0000FF		4
#define COL8_FF00FF		5
#define COL8_00FFFF		6
#define COL8_FFFFFF		7
#define COL8_C6C6C6		8
#define COL8_840000		9
#define COL8_008400		10
#define COL8_848400		11
#define COL8_000084		12
#define COL8_840084		13
#define COL8_008484		14
#define COL8_848484		15

void HariMain(void)
{
	char *vram;
	int xsize, ysize;
	short *binfo_scrnx, *binfo_scrny;
	int *binfo_vram;

	init_palette();
	binfo_scrnx = (short *) 0x0ff4;
	binfo_scrny = (short *) 0x0ff6;
	binfo_vram = (int *) 0x0ff8;
	xsize = *binfo_scrnx;
	ysize = *binfo_scrny;
	vram = (char *) *binfo_vram;

	init_screen(vram, xsize, ysize);

	for (;;) {
		io_hlt();
	}
}



void init_palette(void)
{
	static unsigned char table_rgb[16 * 3] = {
		0x00, 0x00, 0x00,	/*  0:검은색 */
		0xff, 0x00, 0x00,	/*  1:밝은 적색 */
		0x00, 0xff, 0x00,	/*  2:밝은 녹색 */
		0xff, 0xff, 0x00,	/*  3:밝은 노란색 */
		0x00, 0x00, 0xff,	/*  4:밝은 청색 */
		0xff, 0x00, 0xff,	/*  5:밝은 보라색 */
		0x00, 0xff, 0xff,	/*  6:밝은 청색*/
		0xff, 0xff, 0xff,	/*  7:흰색 */
		0xc6, 0xc6, 0xc6,	/*  8:밝은 회색 */
		0x84, 0x00, 0x00,	/*  9:어두운 적색 */
		0x00, 0x84, 0x00,	/* 10:어두운 녹색 */
		0x84, 0x84, 0x00,	/* 11:어두운 노란색 */
		0x00, 0x00, 0x84,	/* 12:군청색 */
		0x84, 0x00, 0x84,	/* 13:어두운 보라색 */
		0x00, 0x84, 0x84,	/* 14:어두운 청색 */
		0x84, 0x84, 0x84	/* 15:어두운 회색 */
	};
	set_palette(0, 15, table_rgb);
	return;

	/* static char 명령은 (주소가 아니라)데이터밖에 쓰지 못하지만, DB명령과 동일함 */
}

void set_palette(int start, int end, unsigned char *rgb)
{
	int i, eflags;
	eflags = io_load_eflags();	/* 인터럽트 허가 플래그 값을 기록 */
	io_cli(); 					/* 허가 플래그를 0으로 하여 인터럽트 금지 */
	io_out8(0x03c8, start);
	for (i = start; i <= end; i++) {
		io_out8(0x03c9, rgb[0] / 4);
		io_out8(0x03c9, rgb[1] / 4);
		io_out8(0x03c9, rgb[2] / 4);
		rgb += 3;
	}
	io_store_eflags(eflags);	/* 인터럽트 허가 플래그를 본래 값으로 되돌린다. */
	return;
}

void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
	int x, y;
	for (y = y0; y <= y1; y++) {
		for (x = x0; x <= x1; x++)
			vram[y * xsize + x] = c;
	}
	return;
}

void init_screen(char *vram, int x, int y)
{
	boxfill8(vram, x, COL8_008484,  0,     0,      x -  1, y - 29);
	boxfill8(vram, x, COL8_C6C6C6,  0,     y - 28, x -  1, y - 28);
	boxfill8(vram, x, COL8_FFFFFF,  0,     y - 27, x -  1, y - 27);
	boxfill8(vram, x, COL8_C6C6C6,  0,     y - 26, x -  1, y -  1);

	boxfill8(vram, x, COL8_FFFFFF,  3,     y - 24, 59,     y - 24);
	boxfill8(vram, x, COL8_FFFFFF,  2,     y - 24,  2,     y -  4);
	boxfill8(vram, x, COL8_848484,  3,     y -  4, 59,     y -  4);
	boxfill8(vram, x, COL8_848484, 59,     y - 23, 59,     y -  5);
	boxfill8(vram, x, COL8_000000,  2,     y -  3, 59,     y -  3);
	boxfill8(vram, x, COL8_000000, 60,     y - 24, 60,     y -  3);

	boxfill8(vram, x, COL8_848484, x - 47, y - 24, x -  4, y - 24);
	boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y -  4);
	boxfill8(vram, x, COL8_FFFFFF, x - 47, y -  3, x -  4, y -  3);
	boxfill8(vram, x, COL8_FFFFFF, x -  3, y - 24, x -  3, y -  3);
	return;
}

현황

- 지난시간에는 VRAM에 직접 접근해서 다양한 색상의 상자와 이로 테스크마 그리기 까지 했다. 오늘은 부팅 정보들을 가져오는 것 부터 시작하자

 

 

문제

- 지난번 예제에서 작성한 vram의 위치나, x해상도 크기, y해상도 크기는 변수로서 지정해주는게 아니라 원래 어셈블리어에서 가져와야 한다.

 

부팅정보 포인터로 접근하기

- asmhead.nas에서 지정한 주소값을 이용하여 부트 정보 binfo 와 스크린 정보 scrn를 가져오자

 * 아래의 사진은 asmhead.nas에서 x 해상도 주소, y해상도 주소, vram의 주소를 알려주고있다.

 

- 포인터를 이용해서 해당 주소들에 접근하자

void HariMain(void)
{
	char *vram;
	int xsize, ysize;
	short *binfo_scrnx, *binfo_scrny;
	int *binfo_vram;

	init_palette();
	binfo_scrnx = (short *) 0x0ff4;
	binfo_scrny = (short *) 0x0ff6;
	binfo_vram = (int *) 0x0ff8;
	xsize = *binfo_scrnx;
	ysize = *binfo_scrny;
	vram = (char *) *binfo_vram;

	init_screen(vram, xsize, ysize);

	for (;;) {
		io_hlt();
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
void init_screen(char *vram, int x, int y);

#define COL8_000000		0
#define COL8_FF0000		1
#define COL8_00FF00		2
#define COL8_FFFF00		3
#define COL8_0000FF		4
#define COL8_FF00FF		5
#define COL8_00FFFF		6
#define COL8_FFFFFF		7
#define COL8_C6C6C6		8
#define COL8_840000		9
#define COL8_008400		10
#define COL8_848400		11
#define COL8_000084		12
#define COL8_840084		13
#define COL8_008484		14
#define COL8_848484		15

struct BOOTINFO {
	char cyls, leds, vmode, reserve;
	short scrnx, scrny;
	char *vram;
};

void HariMain(void)
{
	char *vram;
	int xsize, ysize;
	struct BOOTINFO *binfo;

	init_palette();
	binfo = (struct BOOTINFO *) 0x0ff0;
	xsize = (*binfo).scrnx;
	ysize = (*binfo).scrny;
	vram = (*binfo).vram;

	init_screen(vram, xsize, ysize);

	for (;;) {
		io_hlt();
	}
}


void init_palette(void)
{
	static unsigned char table_rgb[16 * 3] = {
		0x00, 0x00, 0x00,	/*  0:검은색 */
		0xff, 0x00, 0x00,	/*  1:밝은 적색 */
		0x00, 0xff, 0x00,	/*  2:밝은 녹색 */
		0xff, 0xff, 0x00,	/*  3:밝은 노란색 */
		0x00, 0x00, 0xff,	/*  4:밝은 청색 */
		0xff, 0x00, 0xff,	/*  5:밝은 보라색 */
		0x00, 0xff, 0xff,	/*  6:밝은 청색*/
		0xff, 0xff, 0xff,	/*  7:흰색 */
		0xc6, 0xc6, 0xc6,	/*  8:밝은 회색 */
		0x84, 0x00, 0x00,	/*  9:어두운 적색 */
		0x00, 0x84, 0x00,	/* 10:어두운 녹색 */
		0x84, 0x84, 0x00,	/* 11:어두운 노란색 */
		0x00, 0x00, 0x84,	/* 12:군청색 */
		0x84, 0x00, 0x84,	/* 13:어두운 보라색 */
		0x00, 0x84, 0x84,	/* 14:어두운 청색 */
		0x84, 0x84, 0x84	/* 15:어두운 회색 */
	};
	set_palette(0, 15, table_rgb);
	return;

	/* static char 명령은 (주소가 아니라)데이터밖에 쓰지 못하지만, DB명령과 동일함 */
}

void set_palette(int start, int end, unsigned char *rgb)
{
	int i, eflags;
	eflags = io_load_eflags();	/* 인터럽트 허가 플래그 값을 기록 */
	io_cli(); 					/* 허가 플래그를 0으로 하여 인터럽트 금지 */
	io_out8(0x03c8, start);
	for (i = start; i <= end; i++) {
		io_out8(0x03c9, rgb[0] / 4);
		io_out8(0x03c9, rgb[1] / 4);
		io_out8(0x03c9, rgb[2] / 4);
		rgb += 3;
	}
	io_store_eflags(eflags);	/* 인터럽트 허가 플래그를 본래 값으로 되돌린다. */
	return;
}

void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
	int x, y;
	for (y = y0; y <= y1; y++) {
		for (x = x0; x <= x1; x++)
			vram[y * xsize + x] = c;
	}
	return;
}

void init_screen(char *vram, int x, int y)
{
	boxfill8(vram, x, COL8_008484,  0,     0,      x -  1, y - 29);
	boxfill8(vram, x, COL8_C6C6C6,  0,     y - 28, x -  1, y - 28);
	boxfill8(vram, x, COL8_FFFFFF,  0,     y - 27, x -  1, y - 27);
	boxfill8(vram, x, COL8_C6C6C6,  0,     y - 26, x -  1, y -  1);

	boxfill8(vram, x, COL8_FFFFFF,  3,     y - 24, 59,     y - 24);
	boxfill8(vram, x, COL8_FFFFFF,  2,     y - 24,  2,     y -  4);
	boxfill8(vram, x, COL8_848484,  3,     y -  4, 59,     y -  4);
	boxfill8(vram, x, COL8_848484, 59,     y - 23, 59,     y -  5);
	boxfill8(vram, x, COL8_000000,  2,     y -  3, 59,     y -  3);
	boxfill8(vram, x, COL8_000000, 60,     y - 24, 60,     y -  3);

	boxfill8(vram, x, COL8_848484, x - 47, y - 24, x -  4, y - 24);
	boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y -  4);
	boxfill8(vram, x, COL8_FFFFFF, x - 47, y -  3, x -  4, y -  3);
	boxfill8(vram, x, COL8_FFFFFF, x -  3, y - 24, x -  3, y -  3);
	return;
}

 

문제

- 기존의 값을 이제 포인터로 접근하는건 좋다. 근데 부트 인포와 관련된 값들이 많은데 개별적으로 접근하기 너무 불편하다. 구조체를 정의해서 부트 정보를 다루어보자

 * 부트 정보에 대한 개별적인 포인터로 접근해서 다루기는 불편함

 

구조체 사용하기

- 부트 정보에 대한 구조체를 다음과 같이 정의하고, 구조체의 주소를 이용해서 내부의 다른 변수들에 접근하자.

struct BOOTINFO {
	char cyls, leds, vmode, reserve;
	short scrnx, scrny;
	char *vram;
};

- 이전 방식처럼 포인터로 xsize, ysize, vram에 직접 담아줫던것보다. 부트 정보 구조체 포인터 binfo로 담아주니 편리

void HariMain(void)
{
	char *vram;
	int xsize, ysize;
	struct BOOTINFO *binfo;

	init_palette();
	binfo = (struct BOOTINFO *) 0x0ff0;
	xsize = (*binfo).scrnx;
	ysize = (*binfo).scrny;
	vram = (*binfo).vram;

	init_screen(vram, xsize, ysize);

	for (;;) {
		io_hlt();
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
void init_screen(char *vram, int x, int y);

#define COL8_000000		0
#define COL8_FF0000		1
#define COL8_00FF00		2
#define COL8_FFFF00		3
#define COL8_0000FF		4
#define COL8_FF00FF		5
#define COL8_00FFFF		6
#define COL8_FFFFFF		7
#define COL8_C6C6C6		8
#define COL8_840000		9
#define COL8_008400		10
#define COL8_848400		11
#define COL8_000084		12
#define COL8_840084		13
#define COL8_008484		14
#define COL8_848484		15

struct BOOTINFO {
	char cyls, leds, vmode, reserve;
	short scrnx, scrny;
	char *vram;
};

void HariMain(void)
{
	struct BOOTINFO *binfo = (struct BOOTINFO *) 0x0ff0;

	init_palette();
	init_screen(binfo->vram, binfo->scrnx, binfo->scrny);

	for (;;) {
		io_hlt();
	}
}

void init_palette(void)
{
	static unsigned char table_rgb[16 * 3] = {
		0x00, 0x00, 0x00,	/*  0:검은색 */
		0xff, 0x00, 0x00,	/*  1:밝은 적색 */
		0x00, 0xff, 0x00,	/*  2:밝은 녹색 */
		0xff, 0xff, 0x00,	/*  3:밝은 노란색 */
		0x00, 0x00, 0xff,	/*  4:밝은 청색 */
		0xff, 0x00, 0xff,	/*  5:밝은 보라색 */
		0x00, 0xff, 0xff,	/*  6:밝은 청색*/
		0xff, 0xff, 0xff,	/*  7:흰색 */
		0xc6, 0xc6, 0xc6,	/*  8:밝은 회색 */
		0x84, 0x00, 0x00,	/*  9:어두운 적색 */
		0x00, 0x84, 0x00,	/* 10:어두운 녹색 */
		0x84, 0x84, 0x00,	/* 11:어두운 노란색 */
		0x00, 0x00, 0x84,	/* 12:군청색 */
		0x84, 0x00, 0x84,	/* 13:어두운 보라색 */
		0x00, 0x84, 0x84,	/* 14:어두운 청색 */
		0x84, 0x84, 0x84	/* 15:어두운 회색 */
	};
	set_palette(0, 15, table_rgb);
	return;

	/* static char 명령은 (주소가 아니라)데이터밖에 쓰지 못하지만, DB명령과 동일함 */
}

void set_palette(int start, int end, unsigned char *rgb)
{
	int i, eflags;
	eflags = io_load_eflags();	/* 인터럽트 허가 플래그 값을 기록 */
	io_cli(); 					/* 허가 플래그를 0으로 하여 인터럽트 금지 */
	io_out8(0x03c8, start);
	for (i = start; i <= end; i++) {
		io_out8(0x03c9, rgb[0] / 4);
		io_out8(0x03c9, rgb[1] / 4);
		io_out8(0x03c9, rgb[2] / 4);
		rgb += 3;
	}
	io_store_eflags(eflags);	/* 인터럽트 허가 플래그를 본래 값으로 되돌린다. */
	return;
}

void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
	int x, y;
	for (y = y0; y <= y1; y++) {
		for (x = x0; x <= x1; x++)
			vram[y * xsize + x] = c;
	}
	return;
}

void init_screen(char *vram, int x, int y)
{
	boxfill8(vram, x, COL8_008484,  0,     0,      x -  1, y - 29);
	boxfill8(vram, x, COL8_C6C6C6,  0,     y - 28, x -  1, y - 28);
	boxfill8(vram, x, COL8_FFFFFF,  0,     y - 27, x -  1, y - 27);
	boxfill8(vram, x, COL8_C6C6C6,  0,     y - 26, x -  1, y -  1);

	boxfill8(vram, x, COL8_FFFFFF,  3,     y - 24, 59,     y - 24);
	boxfill8(vram, x, COL8_FFFFFF,  2,     y - 24,  2,     y -  4);
	boxfill8(vram, x, COL8_848484,  3,     y -  4, 59,     y -  4);
	boxfill8(vram, x, COL8_848484, 59,     y - 23, 59,     y -  5);
	boxfill8(vram, x, COL8_000000,  2,     y -  3, 59,     y -  3);
	boxfill8(vram, x, COL8_000000, 60,     y - 24, 60,     y -  3);

	boxfill8(vram, x, COL8_848484, x - 47, y - 24, x -  4, y - 24);
	boxfill8(vram, x, COL8_848484, x - 47, y - 23, x - 47, y -  4);
	boxfill8(vram, x, COL8_FFFFFF, x - 47, y -  3, x -  4, y -  3);
	boxfill8(vram, x, COL8_FFFFFF, x -  3, y - 24, x -  3, y -  3);
	return;
}

 

화살표 연산자 사용하기

- 구조체를 선언해서 부팅 정보 다루는것 까진 다 좋다.

 그런데 (*binfo).scrnx, (*binfo).scrny 와같이 일일히 값을 접근 하긴 불편하니 화살표 연산자 사용하자

 

haribo02b

- 화살표 연산자를 사용하면 원하는 값 편하게 가져오고, 아래와 같이 init_screen의 매개변수로 바로 전달할수 있다.

 

haribo02c

 

 

 

 

 

 

 

300x250
728x90

OS를 만들 때 잘 사용하는 BIOS 함수(AT 호환기종)

OS의 개발이 32 Bit 단계에 다다르면 사용할 수 없는 BIOS 함수들이기는 하지만, 부트 섹터나 OS 개발의 초반까지는 다음 BIOS 함수를 많이 사용하게 된다.

INT(0x10) : 비디오 관련

  • 비디오 모드 설정
    • AH = 0x00
    • AL = 모드(자주 사용되는 화면 모드만 설명)
      • 0x03:16색 텍스트, 80x25
      • 0x12:VGA 그래픽스, 640 x480x4bit 칼라
      • 0x13:VGA 그래픽스, 320 x200x8bit 칼라, Packed Pixel
      • 0x6a:확장 VGA 그래픽스, 800 x600x4bit 칼라
    • 반환값:없음

 

  • 커서 모양 설정
    • AH = 0x01
    • CH = 시작 라인
    • CL = 종료 라인
      • CH < CL라면 1개의 부분으로부터 되는 보통 커서
      • CH > CL라면 2개의 부분으로부터 되는 커서
      • CH == 0x20이면 커서는 표시되지 않는다
    • 반환값:없음

 

  • 커서 위치 지정
    • AH = 0x02
    • BH = 0(페이지 번호)
    • DL = x 좌표
    • DH = y 좌표
    • 반환값:없음

 

  • 점 출력
    • 굳이 이 함수를 이용하지 않고 바로 Video 메모리를 이용할 수도 있다.
    • AH = 0x0c
    • AL = 색상 코드(0 ~ 15)
    • CX = x좌표
    • DX = y좌표
    • 반환값:없음

 

  • 한 문자 출력
    • AH = 0x0e
    • AL = 문자 코드
    • BH = 0(페이지 번호)
    • BL = 문자의 색
    • 반환값:없음
    • 주의) beep(0x07), 백 스페이스(0x08), CR(0x0d), LF(0x0a)는 제어 코드로서 인식된다

 

  • 색상 코드를 대응되는 팔레트에 저장한다.
    • 16색 모드일 때만 사용가능하다.
    • AX = 0x1000
    • BL = 색상 코드(0 ~ 15)
    • BH = 팔레트 코드(0 ~ 63)
    • 주의) EGA 그래픽 카드와의 호환성을 유지하기 위해서 사용됩니다. 잘못 사용하면 상당히 복잡해지기 때문에 기본값 그대로 두고 사용하는 것이 좋습니다.

 

  • 팔레트 설정
    • AX = 0x1010
    • BX = 팔레트 번호(0 ~ 255)
    • DH = Red(0 ~ 63)
    • CH = Green(0 ~ 63)
    • CL = Blue(0 ~ 63)
    • 반환값:없음

 

  • 문자열 출력
    • AH = 0x13
    • AL = 옵션
      • 0x00:문자열의 속성을 BL 레지스터로 지정하고 커서는 이동시키지 않는다.
      • 0x01:문자열의 속성을 BL 레지스터로 지정하고 커서를 이동시킨다.
      • 0x02:문자열을 출력하고 커서는 이동시키지 않는다.
      • 0x03:문자열을 출력하고 커서를 이동시킨다.
      • 실제 데이터는 메모리에 [문자 코드] [칼라 코드] [문자 코드] [칼라 코드]와 같이 저장된다고 보면된다.
    • BH = 0(페이지 번호)
    • BL = 칼라 코드(AL 레지스터의 값이 0x01, 0x02일 경우에만 적용)
    • CX = 문자열의 길이
    • DL = x좌표
    • DH = y좌표
    • ES:BP = 출력할 문자열이 있는 곳의 주소
    • 반환값:없음

 

  • 제일 간단하게 사용할 수 있는 화면모드인 0x13의 사용법
    • 0x13번 화면모드는 그다지 해상도가 좋지는 않지만 Packed Pixel 모드이기 때문에 프로그래밍 하기가 편합니다. 우선 화면 모드를 변경하고 팔레트를 설정합니다.
    • 이 모드는 Video Ram의 0xa0000 ~ 0xafff의 64KB에 위치하게 됩니다. 정확히 말하면 320 x 200 = 64000이 되므로 62.5 KB라고 해야겠지만, VRAM는 0xa0000 ~ 0xaffff의 64 KB입니다.엄밀하게 말하면(자), 320 x200=64000이므로, 62.5 KB가 됩니다. 이 모드에서는 점 하나가 1바이트에 해당되기때문에 읽고 쓰기도 아주 간단합니다.

 

INT(0x11) : H/W 구성 확인

  • 컴퓨터에 설치된 H/W의 리스트를 확인한다.
    • 입력값 없음
    • 반환값:
    • AH == 장치 코드
      • 사용하는 사람이 거의 없기때문에 정확한 내용은 생략하겠습니다.

 

INT(0x12) : 시스템에 있는 메모리의 크기를 조사

  • 시스템에 있는 메모리의 크기를 조사
    • 입력값 없음
    • 반환값:
    • AX == 메모리의 크기(KB 단위)

INT(0x13) : 디스크 관련 함수

  • 디스크 시스템 리셋
    • AH = 0x00
    • DL = 드라이브 번호(0x00 ~ 0x7f:FDD, 0x80 ~ 0xff:HDD)
    • 반환값:
    • FLAGS.CF == 0 : 에러 없음
    • FLAGS.CF == 1 : 에러 발생, AH에 에러 코드가 저장된다.
      • 에러 코드 (FDD, HDD 모두 발생 가능한 에러 코드)
      • 0x01:디스크 Parameter가 잘못 전달되었다.
      • 0x02:Address Mark가 발견되지 않음
      • 0x04:섹터를 찾지 못했다
      • 0x09:DMA 오버플로우
      • 0x10:데이터 에러
      • 0x20:콘트롤러 이상
      • 0x40:탐색 실패(Seek Failure)
      • 0x80:타임 아웃
      • 에러 코드 (FDD일 경우의 에러코드)
      • 0x03:쓰기 금지된 디스크에 쓰기를 시도
      • 0x06:디스크를 찾지 못함
      • 0x08:DMA 오버플로우
      • 에러 코드 (HDD일 경우의 에러코드)
      • 0x05:리셋 실패
      • 0x07:Parameter 테이블이 정확하지 않음
      • 0x0a:섹터 Flag이 잘못되었음
      • 0x11:ECC 데이터 에러
      • 0xaa:드라이브가 아직 준비되지 않음
      • 0xbb:미정의 에러
      • 0xcc:쓰기 에러
      • 0xe0:상태(Status) 에러

Retrieved from "http://osguru.net/index.php/AT-BIOS"

[출처] [펌] OS를 만들 때 잘 사용하는 BIOS 함수(AT 호환기종)

 

 

osguru.net는 들어갈수 없어 다른 분이 펌해온걸 다시가져옴

300x250
728x90
void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);

#define COL8_000000		0
#define COL8_FF0000		1
#define COL8_00FF00		2
#define COL8_FFFF00		3
#define COL8_0000FF		4
#define COL8_FF00FF		5
#define COL8_00FFFF		6
#define COL8_FFFFFF		7
#define COL8_C6C6C6		8
#define COL8_840000		9
#define COL8_008400		10
#define COL8_848400		11
#define COL8_000084		12
#define COL8_840084		13
#define COL8_008484		14
#define COL8_848484		15

void HariMain(void)
{
	char *p;

	init_palette();

	p = (char *) 0xa0000;

	boxfill8(p, 320, COL8_FF0000,  20,  20, 120, 120);
	boxfill8(p, 320, COL8_00FF00,  70,  50, 170, 150);
	boxfill8(p, 320, COL8_0000FF, 120,  80, 220, 180);

	for (;;) {
		io_hlt();
	}
}

void init_palette(void)
{
	static unsigned char table_rgb[16 * 3] = {
		0x00, 0x00, 0x00,	/*  0:검은색 */
		0xff, 0x00, 0x00,	/*  1:밝은 적색 */
		0x00, 0xff, 0x00,	/*  2:밝은 녹색 */
		0xff, 0xff, 0x00,	/*  3:밝은 노란색 */
		0x00, 0x00, 0xff,	/*  4:밝은 청색 */
		0xff, 0x00, 0xff,	/*  5:밝은 보라색 */
		0x00, 0xff, 0xff,	/*  6:밝은 청색*/
		0xff, 0xff, 0xff,	/*  7:흰색 */
		0xc6, 0xc6, 0xc6,	/*  8:밝은 회색 */
		0x84, 0x00, 0x00,	/*  9:어두운 적색 */
		0x00, 0x84, 0x00,	/* 10:어두운 녹색 */
		0x84, 0x84, 0x00,	/* 11:어두운 노란색 */
		0x00, 0x00, 0x84,	/* 12:군청색 */
		0x84, 0x00, 0x84,	/* 13:어두운 보라색 */
		0x00, 0x84, 0x84,	/* 14:어두운 청색 */
		0x84, 0x84, 0x84	/* 15:어두운 회색 */
	};
	set_palette(0, 15, table_rgb);
	return;

	/* static char 명령은 (주소가 아니라)데이터밖에 쓰지 못하지만, DB명령과 동일함 */
}

void set_palette(int start, int end, unsigned char *rgb)
{
	int i, eflags;
	eflags = io_load_eflags();	/* 인터럽트 허가 플래그 값을 기록 */
	io_cli(); 					/* 허가 플래그를 0으로 하여 인터럽트 금지 */
	io_out8(0x03c8, start);
	for (i = start; i <= end; i++) {
		io_out8(0x03c9, rgb[0] / 4);
		io_out8(0x03c9, rgb[1] / 4);
		io_out8(0x03c9, rgb[2] / 4);
		rgb += 3;
	}
	io_store_eflags(eflags);	/* 인터럽트 허가 플래그를 본래 값으로 되돌린다. */
	return;
}

void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
	int x, y;
	for (y = y0; y <= y1; y++) {
		for (x = x0; x <= x1; x++)
			vram[y * xsize + x] = c;
	}
	return;
}

 

 

현재 그래픽 모드

- 320 x 200 ( =64,000)개 화소 존재

- (y,x) 픽셀의 VRAM 번지 : 0xa000 + x + y * 320 번지

 * 

- 해당 메모리에 올바른 색 번호를 저장하면 화면상 그위치에 지정한 색이 나오게 됨.

 

boxfill8 함수

- 위와 같은 방식으로 시작점 (x0, y0), 끝점 (x1, y1)사이에 색 번호를 채워넣는 함수

void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
	int x, y;
	for (y = y0; y <= y1; y++) {
		for (x = x0; x <= x1; x++)
			vram[y * xsize + x] = c;
	}
	return;
}

 

 

상자 3개 그리기

- HariMain에서 x의 크기가 320인 화면 모드에서 빨강색을 (20, 20) ~ (120, 120),

   파란색, 녹색을 해당 위치에 그리도록 정리

* 어느 색이 색번호에 해당하는지 구분하기 위해서 #define으로 정의

void HariMain(void)
{
	char *p;

	init_palette();

	p = (char *) 0xa0000;

	boxfill8(p, 320, COL8_FF0000,  20,  20, 120, 120);
	boxfill8(p, 320, COL8_00FF00,  70,  50, 170, 150);
	boxfill8(p, 320, COL8_0000FF, 120,  80, 220, 180);

	for (;;) {
		io_hlt();
	}
}

 

 

 

 

 

 

 

 

void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);
void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);

#define COL8_000000		0
#define COL8_FF0000		1
#define COL8_00FF00		2
#define COL8_FFFF00		3
#define COL8_0000FF		4
#define COL8_FF00FF		5
#define COL8_00FFFF		6
#define COL8_FFFFFF		7
#define COL8_C6C6C6		8
#define COL8_840000		9
#define COL8_008400		10
#define COL8_848400		11
#define COL8_000084		12
#define COL8_840084		13
#define COL8_008484		14
#define COL8_848484		15

void HariMain(void)
{
	char *vram;
	int xsize, ysize;

	init_palette();
	vram = (char *) 0xa0000;
	xsize = 320;
	ysize = 200;

	boxfill8(vram, xsize, COL8_008484,  0,         0,          xsize -  1, ysize - 29);
	boxfill8(vram, xsize, COL8_C6C6C6,  0,         ysize - 28, xsize -  1, ysize - 28);
	boxfill8(vram, xsize, COL8_FFFFFF,  0,         ysize - 27, xsize -  1, ysize - 27);
	boxfill8(vram, xsize, COL8_C6C6C6,  0,         ysize - 26, xsize -  1, ysize -  1);

	boxfill8(vram, xsize, COL8_FFFFFF,  3,         ysize - 24, 59,         ysize - 24);
	boxfill8(vram, xsize, COL8_FFFFFF,  2,         ysize - 24,  2,         ysize -  4);
	boxfill8(vram, xsize, COL8_848484,  3,         ysize -  4, 59,         ysize -  4);
	boxfill8(vram, xsize, COL8_848484, 59,         ysize - 23, 59,         ysize -  5);
	boxfill8(vram, xsize, COL8_000000,  2,         ysize -  3, 59,         ysize -  3);
	boxfill8(vram, xsize, COL8_000000, 60,         ysize - 24, 60,         ysize -  3);

	boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 24, xsize -  4, ysize - 24);
	boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 23, xsize - 47, ysize -  4);
	boxfill8(vram, xsize, COL8_FFFFFF, xsize - 47, ysize -  3, xsize -  4, ysize -  3);
	boxfill8(vram, xsize, COL8_FFFFFF, xsize -  3, ysize - 24, xsize -  3, ysize -  3);

	for (;;) {
		io_hlt();
	}
}


void init_palette(void)
{
	static unsigned char table_rgb[16 * 3] = {
		0x00, 0x00, 0x00,	/*  0:검은색 */
		0xff, 0x00, 0x00,	/*  1:밝은 적색 */
		0x00, 0xff, 0x00,	/*  2:밝은 녹색 */
		0xff, 0xff, 0x00,	/*  3:밝은 노란색 */
		0x00, 0x00, 0xff,	/*  4:밝은 청색 */
		0xff, 0x00, 0xff,	/*  5:밝은 보라색 */
		0x00, 0xff, 0xff,	/*  6:밝은 청색*/
		0xff, 0xff, 0xff,	/*  7:흰색 */
		0xc6, 0xc6, 0xc6,	/*  8:밝은 회색 */
		0x84, 0x00, 0x00,	/*  9:어두운 적색 */
		0x00, 0x84, 0x00,	/* 10:어두운 녹색 */
		0x84, 0x84, 0x00,	/* 11:어두운 노란색 */
		0x00, 0x00, 0x84,	/* 12:군청색 */
		0x84, 0x00, 0x84,	/* 13:어두운 보라색 */
		0x00, 0x84, 0x84,	/* 14:어두운 청색 */
		0x84, 0x84, 0x84	/* 15:어두운 회색 */
	};
	set_palette(0, 15, table_rgb);
	return;

	/* static char 명령은 (주소가 아니라)데이터밖에 쓰지 못하지만, DB명령과 동일함 */
}

void set_palette(int start, int end, unsigned char *rgb)
{
	int i, eflags;
	eflags = io_load_eflags();	/* 인터럽트 허가 플래그 값을 기록 */
	io_cli(); 					/* 허가 플래그를 0으로 하여 인터럽트 금지 */
	io_out8(0x03c8, start);
	for (i = start; i <= end; i++) {
		io_out8(0x03c9, rgb[0] / 4);
		io_out8(0x03c9, rgb[1] / 4);
		io_out8(0x03c9, rgb[2] / 4);
		rgb += 3;
	}
	io_store_eflags(eflags);	/* 인터럽트 허가 플래그를 본래 값으로 되돌린다. */
	return;
}

void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
{
	int x, y;
	for (y = y0; y <= y1; y++) {
		for (x = x0; x <= x1; x++)
			vram[y * xsize + x] = c;
	}
	return;
}

태스크바 만들기

- boxfill로 다음과같이 태스크바 그림 => 옛날 윈도우 화면같은 창이 만들어졌다.

- 부트섹터를 제외한 운영체제 파일 haribote.sys는 1,216 바이트 밖에 되지 않는다.

 

 

300x250
728x90

현황

- 방금전 C언어에서 직접 메모리 번지를 지정하는 방법이 없다고 하여 write_mem8 함수를 직접 어셈블리어로 구현

- 하지만 포인터를 이용하면 메모리 접근 가능

 

 

 

문제

- 어셈블리어의 문제 : 데이터가 byte인지 word인지, dword인지 알수 없음.

- c언어에서는 공간의 크기에 따라 다양한 자료형 제공

 ex. char 1바이트, short 2바이트, int 4바이트

 

 

 

 

포인터로 메모리 접근하자

- write_mem8로 i번째 주소에 접근했다면

- 지금은 포인터 변수 p에다가 주소를 담아 접근해서 사용

=> naskfunc.nas에서 wirte_mem8은 필요없으므로 지우기

 

 

 

 

색번호 설정하기

- 이제 포인터로 VRAM에 접근해서 값을 읽고 쓸수 있다. 하지만 단색은 재미없으니 색상도 바꿔보자

- 8비트 컬러 모드에서 0~255색을 표현 가능 -> 색번호 지정하는 구조를 팔레트라 부름

- 우리가 사용할 OS에서 16색만 있으면 충분할것같으니 다음과 같이 색들을 지정해주자

#000000 : 검은색 #00ffff : 밝은 청색 #000084 : 군청색
#ff0000 : 밝은 적색 #ffffff : 흰색 #840084 : 어두운 보라색
#00ff00 : 밝은 녹색 #c6c6c6 : 밝은 회색 #008484 : 어두운 청색
#ffff00 : 밝은 노란색 #840000 : 어두운 적색 #848484 : 어두운 회색
#0000ff : 밝은 청색 #008400 : 어두운 녹색  
#ff00ff : 밝은 보라색 #848400 : 어두운 노란색  

 

c언어 코드

- 맨앞의 함수들은 어셈블리어에서 정의함

void io_hlt(void);
void io_cli(void);
void io_out8(int port, int data);
int io_load_eflags(void);
void io_store_eflags(int eflags);

/* 같은 소스 내에 있어도 C언어에서 사용하기 위해선 우선 선언 필요 */

void init_palette(void);
void set_palette(int start, int end, unsigned char *rgb);

void HariMain(void)
{
	int i;
	char *p;

	init_palette(); /*팔래트 초기화 */

	p = (char *) 0xa0000; /* 번지대입 */

	for (i = 0; i <= 0xffff; i++) {
		p[i] = i & 0x0f;
	}

	for (;;) {
		io_hlt();
	}
}

void init_palette(void)
{
	static unsigned char table_rgb[16 * 3] = {
		0x00, 0x00, 0x00,	/*  0:검은색 */
		0xff, 0x00, 0x00,	/*  1:밝은 적색 */
		0x00, 0xff, 0x00,	/*  2:밝은 녹색 */
		0xff, 0xff, 0x00,	/*  3:밝은 노란색 */
		0x00, 0x00, 0xff,	/*  4:밝은 청색 */
		0xff, 0x00, 0xff,	/*  5:밝은 보라색 */
		0x00, 0xff, 0xff,	/*  6:밝은 청색*/
		0xff, 0xff, 0xff,	/*  7:흰색 */
		0xc6, 0xc6, 0xc6,	/*  8:밝은 회색 */
		0x84, 0x00, 0x00,	/*  9:어두운 적색 */
		0x00, 0x84, 0x00,	/* 10:어두운 녹색 */
		0x84, 0x84, 0x00,	/* 11:어두운 노란색 */
		0x00, 0x00, 0x84,	/* 12:군청색 */
		0x84, 0x00, 0x84,	/* 13:어두운 보라색 */
		0x00, 0x84, 0x84,	/* 14:어두운 청색 */
		0x84, 0x84, 0x84	/* 15:어두운 회색 */
	};
	set_palette(0, 15, table_rgb);
	return;

	/* static char 명령은 (주소가 아니라)데이터밖에 쓰지 못하지만, DB명령과 동일함 */
}

void set_palette(int start, int end, unsigned char *rgb)
{
	int i, eflags;
	eflags = io_load_eflags();	/* 인터럽트 허가 플래그 값을 로드함 */
	io_cli(); 					/* 허가 플래그를 0으로 하여 인터럽트 금지 */
	io_out8(0x03c8, start);
	for (i = start; i <= end; i++) {
		io_out8(0x03c9, rgb[0] / 4);
		io_out8(0x03c9, rgb[1] / 4);
		io_out8(0x03c9, rgb[2] / 4);
		rgb += 3;
	}
	io_store_eflags(eflags);	/* 인터럽트 허가 플래그를 본래 값으로 되돌린다. */
	return;
}

 

 

 

c언어와 어셈블리어 문법 잠깐 보기

- char a[3] a라는 이름의 길이가 3인 배열 공간 생성( 값들은 0)

 => 아래와 동일

     a :

           RESB 3

 

- 색상 테이블은 어셈블리어 상에서 아래와 같이 값을 대입해주는게 경제적임

 => static char로 선언한 변수에 값을 넣는게, DB 명령어로 대입하는것과 동일함

   table_rgb:

      DB 0x00, 0x00, 0x00, 0xff, 0x00, 0xff ....

 

 

 

set_palette 보기

- io_out8 함수 : 장치 번호로 지정한 장치에 데이터를 보내는 함수

- CPU와 메모리만 연결되어있으면 계산과 기억밖에 하지못함.

 => 하드디스크, 그래픽, 사운드 카드 등과 연결되어 다양한 입출력이 가능해짐

 

 

out/in 명령어

- out 명령어 : 특정 장치로 전기 신호를 보내기 위한 명령어

- in 명령어 : 특정 장치로부터 신호를 받기 위한 명령

 

 

그래픽 관련 장치 번호

- 0x03c8, 0x03c9는 그래픽 관련 장치번호

- 팔레트 액세스 순서

- 액세스 중에는 인터럽트 발생해선 안됨 ex. CLI

- 0x03c08에 사용할 팔레트 번호를 쓰고, RGB 순서대로 0x03c9에 입력

  * 다음 팔레트도 같이 설정한다면 팔레트 번호 설정 생략하고 계속 RGB순서로 쓰면됨.

- 팔레트 상태 읽을때 0x03c7에 팔레트 번호 쓰고, 0x03c9를 3번 읽음 => RGB순서대로 처리됨.

- 최초 CLI(인터럽트 금지)를 한경우 마지막에 STI(io_store_eflags, 인터럽트 허가 플래그 원위치)를 한다.

 

 

CLI와 STI

- CLI : 인터럽트 플래그 interrupt flag를 0으로 만듬( clear interrupt flag)

- STI : 인터럽트 플래그를 1로 만드는 명령 (set interrupt flag)

=> 인터럽트 플래그가 0이면 인터럽트 반응 회로가 동작 안함, 1이면 동작함

 

 

EFLAGS

- 16비트 레지스터인 FLAGS가 32비트로 레지스터로 확장된 레지스터.

- FGLAS는 캐리 플래그, 인터럽트 플래그 등으로 구성됨.

- 아래의 그림은 16비트 8086 아키택처의 FLAGS 레지스터

http://mmrcse.blogspot.com/2018/12/write-function-of-segment-register-and.html

 

 

 

set_palette에서 하는일

- 팔레트 설정하기전에 CLI실행. 

- 팔레트 설정후

- 인터럽트 플래그 허용 STI

 

 

 

naskfunc.nas

- PUSHFD : push flags double-word : vmfformfmf ejqmf dnjemfh alfdjsjgsmsek.

- POPFD : pop EFLAGS라는 뜻

=> EFLAGS를 읽거나 쓰는데 ㅏ용.

 

; naskfunc
; TAB=4

[FORMAT "WCOFF"]				; 오브젝트 파일 만드는 모드
[INSTRSET "i486p"]				; 이 프로그램이 486 아키텍처 용 프로그램임을 nask에 알림
[BITS 32]						; 32비트 모드용 기계어 만듬
[FILE "naskfunc.nas"]			; 소스 파일명 정보

		GLOBAL	_io_hlt, _io_cli, _io_sti, _io_stihlt
		GLOBAL	_io_in8,  _io_in16,  _io_in32
		GLOBAL	_io_out8, _io_out16, _io_out32
		GLOBAL	_io_load_eflags, _io_store_eflags

[SECTION .text]

_io_hlt:	; void io_hlt(void);
		HLT
		RET

_io_cli:	; void io_cli(void);
		CLI
		RET

_io_sti:	; void io_sti(void);
		STI
		RET

_io_stihlt:	; void io_stihlt(void);
		STI
		HLT
		RET

_io_in8:	; int io_in8(int port);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,0
		IN		AL,DX
		RET

_io_in16:	; int io_in16(int port);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,0
		IN		AX,DX
		RET

_io_in32:	; int io_in32(int port);
		MOV		EDX,[ESP+4]		; port
		IN		EAX,DX
		RET

_io_out8:	; void io_out8(int port, int data);
		MOV		EDX,[ESP+4]		; port
		MOV		AL,[ESP+8]		; data
		OUT		DX,AL
		RET

_io_out16:	; void io_out16(int port, int data);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,[ESP+8]		; data
		OUT		DX,AX
		RET

_io_out32:	; void io_out32(int port, int data);
		MOV		EDX,[ESP+4]		; port
		MOV		EAX,[ESP+8]		; data
		OUT		DX,EAX
		RET

_io_load_eflags:	; int io_load_eflags(void);
		PUSHFD		; PUSH EFLAGS 라는 뜻
		POP		EAX
		RET

_io_store_eflags:	; void io_store_eflags(int eflags);
		MOV		EAX,[ESP+4]
		PUSH	EAX
		POPFD		; POP EFLAGS 라는 뜻
		RET

 

 

실행 결과

- 색상있는 줄무늬들이 출력됨

 

 

300x250
728x90

현황

- 검은 화면이 뜨도록 만듬

- 뭔가 띄우려면 VRAM 비디오 램에 올바른 값을 써야함

 

문제

- c언어에서는 VRAM 등 직접 메모리 지정해서 쓰는 명령 없음 => 함수 작성

 * 사실 포인터를 이용해서 쓸수 있기하나 넘어가자

 

메모리에 쓰기 함수 추가하기

- naskfunc.nas에 write_mem8함수 추가(8비트 값을 쓰기)

- 사용법 : write_mem8(0x1234, 0x56)

 => 의미 : MOVE BYTE[0x1234], 0x56 -> 0x1234 번지에 바이트 크기(8비트)로 0x56이란 값을 쓴다.

- 사용 과정 : c언어에서 write_mem8() 함수 호출 -> naskfunc.nas의 _write_mem로 점프

- 아래의 코드에서 +4를 하는 이유 32비트 모드(4 x 8비트)이므로 한칸씩 이동하기 위함

 

 

INSTRSET

- 이 프로그램이 486용임을 nask에 알려줌.

 => nask는 EAX(32비트 레지스터)라는 단어를 만나면 레지스터로 해석함

 => 이걸 안해주면 8086 CPU 명령어로 생각해서 레이블 중 하나로 인식



 

 

 

인텔 CPU 아키텍처 흐름

- 8086 -> 80186 -> 286 -> 386 -> 486 -> Pentium -> PentiumPro -> Pentium2 -> Pentium3 -> Pentium4 ...

- 286까지 16비트 CPU, 386부터 32비트 CPU

 

 

 

bootpack.c  부트 프로그램 패키지 수정

- 변수 초기화 해주고

- VRAM에 값을 저어주는 명령을 써보자

 => 아래의 코드에선 0xa0000 ~ 0xaffff 번지에 15라는 값을 입력해줌

 

 

 

실행 결과

 

 

 

 

줄무늬 쓰기

- write_mem8(i, i & 0x0f);로 수정

- i와 0x0f를 and연산한 결과를 반환

- 정리

  0x0f = 0x0000 000f

     i     = 0x000a 0000

     i     = 0x000a  f f f f

=> i의 최하위 비트 LSB(Least Significant bit) 가 f인 경우 

    i번지에 0x0000 000f 쓰기

=> 이외의 경우

    i번지에 0x0000 0000 쓰기

- 결론 : 0x0000 0000 을 쓰다가   일정 구간이 지나서 0x0000 000f쓰기를 반복한다.

 

 

 

 

 

줄무늬 쓰기 실행결과

 

 

 

 

300x250
728x90

하리보테OS를 만드는 중에

힘들어 죽는줄 알았다.

 

친숙하지 않은 기계어 어셈블리어 가지고

부팅 가능하게 만들고 화면 띄우게 만들고

처음 하는 입장이라 상당히 시간이 오래걸렸다.

 

내일부터는 C언어 위주라 조금 수월해질듯한데,

최적화, 영상처리보다 이게 정리하는데 훨씬 오래걸렸다.

 

앞으로 조금 수월해질지는 모르겠는데 이것만 올인하기 보다는

다른 학문이랑 조금씩 병행하면서 해야되겠다.

하나만 하니 질리기도 하고

300x250
728x90
; haribote-os
; TAB=4

; BOOT_INFO 관계
CYLS	EQU		0x0ff0			; 부트섹터 설정
LEDS	EQU		0x0ff1
VMODE	EQU		0x0ff2			; 색상 갯수에 관한 정의, 몇비트 컬러인지
SCRNX	EQU		0x0ff4			; 해상도 x
SCRNY	EQU		0x0ff6			; 해상도 y
VRAM	EQU		0x0ff8			; 그래픽 버퍼 개시번지
		
		ORG		0xc200			; harybote.sys가 로딩되는 메모리 주소

		MOV		AL,0x10			; VGA 그래픽스, 320x200x8bit 컬러
		MOV		AH,0x00
		MOV		BYTE [VMODE],8	; 화면 모드를 기록함.
		MOV		WORD [SCRNX],320
		MOV		WORD [SCRNY],200
		MOV		DWORD [VRAM],0x000a0000

; 키보드 LED 상태를 BIOS가 알려줌

		MOV		AH,0x02
		INT		0x16 			; keyboard BIOS
		MOV		[LEDS],AL

fin:
		HLT
		JMP		fin

 

CPU의 모드

- 16비트모드, 32비트 모드가 존재

- 16비트 모드로 부팅시 AX, CX와 같은 16비트 레지스터 사용 가능하나 EAX같은 32비트 레지스터는 불가

- 기계어 명령 번호도 다르고, 해석 방법과 동작이 달라 호환 불가

 

 

32비트 모드 장단점

- 장점 : 메모리 1MB 이상 사용 가능. 이상한 기계어 만나도 오동작하는 보호 기능 사용 가능

- 단점 : BIOS 사용불가. BIOS는 16비트 기계어로 작성됨 => 32비트 쓰기전에 마음것 해보자

 

 

할일

- 키보드 상태를 BIOS가 알려주는것 확인

 

 

작업

- 화면 모드 설정후 관련 정보를 메모리에 저장. 이후 필요할것을 고려 => 부팅시 정보로 BOOT_INFO로 명명

- vRAM 비디오램 : 값을 저장할수도 있지만 번지와 화소가 매칭되어 그림 표현 가능

  * VRAM은 메모리 맵 상에 여러개 존재. 화면 모드가 여러가지가 존재하기 때문

 * BOOT_INFO에 어느 VRAM 사용하는지 기록(현재 0x000a 0000 ~ 0x000a fffff로 64kb)

- 기타 정보(화소수, 컬러수, 키보드 상태 등)은 0x0ff0 주변에 저장

 

 

 

 

 

 

 

 

C언어 사용하기 

- 기존의 haribote.nas -> asmhead.nas로 이름 변경

- bootpack.c c언어 파트 추가. 앞으로 OS 부팅에 필요한 처리들을 패키지로 작성 예정

 

bootpack.c를 기계어로 만들기

1. cc1.exe : bootpack.c -> bootpack.gas

 => cc1.exe는 gcc 개조한 것. gas 어셈블리어 파일 출력

2. gas2nask.exe : bootpack.gas -> bootpack.nas

 => gas를 nask로 번역

3. nask.exe : bootpack.nas -> bootpack.obj

  => nask 파일로 우선 목적 파일 작성(기계어)

4. ob2bim.exe : bootkpack.obj -> bootpack.bim

  => 서로 다른 목적파일들을 연결해야함 obj2bim : 오브젝트 파일들을 binary image file로

5. bim2hrb.exe -> bootpack.bim -> bootpack.hrb

  => 기계어를 붙여 정리한것으로 완성 x. 각 OS에 맞게 수정 필요 하리보테 os에 맞게 bim을 번역

  * 하리보테 os c언어는 harimain()에서 시작함

6. asmhead.bin과 bootpack.hrb를 붙여 haribote.sys 만듬

 

 

 

* 이미지란 단어

- 영상의 image라기 보다는 상상하는 무언가, 가짜로 된 것을 의미

 

 

 

 

 

HLT 하기

- hlt 명령어를 어셈블러로 함수 만듦

- 함수명은 io_hlt

; naskfunc
; TAB=4

[FORMAT "WCOFF"]				; 오브젝트 파일 만드는 모드
[BITS 32]						; 32비트 모드용 기계어 만듬


; 오브젝트 파일을 위한 정보

[FILE "naskfunc.nas"]			; 소스 파일명 정보

		GLOBAL	_io_hlt			; 이 프로그램에 포함된 함수명


; 아래는 실제 함수

[SECTION .text]		; 오브젝트 파일에서 다음의 함수가 있으면 어셈블리어로 작성

_io_hlt:	; void io_hlt(void);
		HLT
		RET

 

HLT 함수 파일 naskfunc.nas 설명

- bootpack.obj와 링크하기 위해 오브젝트 파일로 만들어야 함

 => 출력 포맷을 WCOFF

- 32비트용 기계어로 만들기 위해 [BITS 32] 설정

- C언어 함수와 연계할수 있도록 앞에 _를 붙여 GLOBAL 명령으로 선언

- 실제 함수 내용 작성 : 함수명과 동일한 레이블에 작성. RET는 return;

- bootpack.c에서 io_hlt는 naskfunc.nas 상에 정의되어 있으므로 선언만 해둠

void io_hlt(void);

void HariMain(void)
{

fin:
	io_hlt(); /* c언어에선 HLT 할수 없음 */
	goto fin;

}

 

실행 결과

- 실행해보면 hlt 처리되서 바로 종료되는듯 하다.

300x250

+ Recent posts