부트스트랩을 이용하여 커널 로드 하기


1장에서 사용한 boot.txt를 이용하여 커널을 로드하여 본다.

여기서는 2개의 파일이 필요하다. 첫번째는 boot.txt파일, 두번째는 kernel.txt 파일이 필요하다.

첫번째 파일 boot.txt의 소스는 아래와 같다

boot.txt

[org 0]

[bits 16]

jmp 0x07C0:start

start:

mov ax, cs

mov ds, ax

mov ax, 0xB800

mov es, ax

mov di, 0

mov ax, word [msgBack]

mov cx, 0x7FF


paint:

mov word [es:di], ax

add di, 2

dec cx

jnz paint


read:

mov ax, 0x1000

mov es, ax

mov bx, 0

mov ah, 2    : 디스크에 있는 데이터를 es:bx의 주소로

mov al, 1    : 1섹터를 읽는다.

mov ch, 0    : 0번째 Cylinder

mov cl, 2    : 2번째 섹터부터 읽기 시작

mov dh, 0    : Head = 0

mov dl, 0    : Drive = 0, A: 드라이브

int 0x13    : Read 시작


jc read    : 에러가 날 경우 다시 함    : 이 루틴에서 에러 발생 시 CPU의 CF비트가 1로 세트됨,

1로 세트되어 있다면 erad: 번지로 점프하여 디스크 읽기를 다시 실행한다.

jmp 0x1000:0000    : kernel.bin이 위치한 곳으로 점프한다.



msgBack db '.', 0x67


times 510-($-$$) db 0

dw 0xAA55

------------------------------------------------------------------

kernel.txt

.[org 0]

[bits 16]


start:

mov ax, cs    : cs에는 0x1000이 들어있다. boot.txt 파일 마지막 jmp 0x1000:0000 에서 0x1000이 cs로 들어가기 때문

mov ds, ax

xor ax, ax

mov ss, ax


lea esi, [msgKernel]    : 문자열이 있는 곳의 주소를 구한다.

mov ax, 0xB800

mov es, ax    : es에 0xB800을 넣는다.

mov edi, 0    : 화면의 제일 처음 부분부터 시작한다.

call printf

jmp $


printf:

push eax    : 먼저 있던 eax 값을 스택에 보존해 놓는다.


printf_loop:

mov al, byte [esi]    : esi가 가리키는 주소에서 문자를 하나 가져온다.

mov byte [es:edi], al    : 문자를 화면에 나타낸다.

or al, al    : al이 0인지 알아본다.

jz printf_end    : 0이라면 print_end로 점프한다.

inc edi    : 0이 아니라면 edi를 1 증가시켜

mov byte [es:edi], 0x06    : 문자색과 배경색의 값을 넣는다.

inc esi    : 다음 문자를 꺼내기 위해 esi를 하나 증가

inc edi    : 화면에 다음 문자를 나타내기 위해 edi를 증가

jmp printf_loop    : 루프를 돈다.


printf_end:

pop eax    : 스택에 보존했던 eax를 다시 꺼낸다.

ret    : 호출한 부분으로 돌아간다.


msgKernel db "We are in kernel program", 0


아래와 같이 컴파일 및 copy 명령어를 통해 합친다.


floopy disk에 넣고 vm 실행 시 아래 그림과 같이 문자열이 출력된다.


커널 로드 성공!


+ Recent posts