[org 0]
[bits 16]
start:
mov ax, cs ; CS에는 0x1000이 들어 있다.
mov ds, ax
xor ax, ax
mov ss, ax ; stack segment는 0으로 세팅
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
위의 소스코드를 입력한 후, binary를 합쳐서 이미지 만들기
123
nasm -f bin -o bootloader.bin src\bootloader.asm
nasm -f bin -o kernel.bin src\kernel.asm
copy bootloader.bin + kernel.bin /b kernel.img
바이너리 확인
만들어진 kernel.img 파일을 살펴보면, 512(=0x200)번째 offset부터 kernel.asm의 내용이 들어가 있는 것을 확인할 수 있습니다.
즉, kernel.img에서 하나의 섹터 사이즈는 512byte이기 때문에 위에서 0x13 번의 바이오스 콜을 했을 때,
두 번째 섹터를 읽으라고 하면 0x0200번째 offset에 있는 값을 읽어서 메모리로 복사합니다.
1 2 3 4 5 6 7 8 910111213141516
; ... 생략 ...
read:
mov ax, 0x1000 ; ES:BX = 1000:0000 ; 복사 목적지의 주소값
mov es, ax
mov bx, 0
mov ah, 2 ; 디스크에 있는 데이터를 es:bx의 주소로
mov al, 1 ; 1 섹터를 읽을 것이다; 플로피디스크의 한 섹터는 512byte
mov ch, 0 ; 0번째 실린더
mov cl, 2 ; 2번째 섹터부터 읽기 시작한다.
mov dh, 0 ; Head=0
mov dl, 0 ; Drive=0, A: 드라이브
int 0x13 ; Read!
; ... 생략 ...
다른 클러스터를 읽는 BIOS interrupt call(0x13)
int 0x13에 서비스 넘버(02)를 AH에 넣어서 호출하면 어느 섹터로 부터 몇 개의 섹터를 읽어라 하는 의미가 됩니다.