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바이트에 해당되기때문에 읽고 쓰기도 아주 간단합니다.
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),
; 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
- 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 상에 정의되어 있으므로 선언만 해둠