플로피 디스크에서 OS 이미지를 로딩하자
BIOS 서비스와 소프트웨어 인터럽트
OS 이미지 로딩 기능 구현
최종 부트 로더 소스 코드 (BootLoader.asm)
[ ORG 0x00 ]
[ BITS 16 ]
SECTION .text
jmp 0x07C0:START
; MINT64 OS에 관련된 환경 설정 값
TOTALSECTORCOUNT: dw 1024
; 코드 영역
START:
mov ax, 0x07C0
mov ds, ax
mov ax, 0xB800
mov es, ax
mov ax, 0x0000
mov ss, ax
mov sp, 0xFFFE
mov bp, 0xFFFE
; 화면을 지우고, 속성값을 녹색으로 설정
mov si, 0
.SCREENCLEARLOOP:
mov byte [ es:si ], 0
mov byte [ es:si + 1 ], 0x0A
add si, 2
cmp si, 80 * 25 * 2
jl .SCREENCLEARLOOP
; 화면 상단에 메시지 출력
push MESSAGE1
push 0
push 0
call PRINTMESSAGE
add sp, 6
; OS 이미지를 로딩한다는 메시지 출력
push IMAGELOADINGMESSAGE
push 1
push 0
call PRINTMESSAGE
add sp, 6
; 디스크에서 OS 이미지를 로딩
; 디스크를 읽기 전에 먼저 리셋
RESETDISK:
; BIOS Reset Function 호출
mov ax, 0
mov dl, 0
int 0x13
jc HANDLEDISKERROR
; 디스크에서 섹터를 읽음
mov si, 0x1000
mov es, si
mov bx, 0x0000
mov di, word [ TOTALSECTORCOUNT ]
READDATA:
cmp di, 0
je READEND
sub di, 0x01
; BIOS Read Function 호출
mov ah, 0x02
mov al, 0x1
mov ch, byte [ TRACKNUMBER ]
mov cl, byte [ SECTORNUMBER ]
mov dh, byte [ HEADNUMBER ]
mov dl, 0x00
int 0x13
jc HANDLEDISKERROR
; 복사할 어드레스와 트랙, 헤더, 섹터 에드레스 계산
add si, 0x0020
mov es, si
mov al, byte [ SECTORNUMBER ]
add al, 0x01
mov byte [ SECTORNUMBER ], al
cmp al, 19
jl READDATA
xor byte [ HEADNUMBER ], 0x01
mov byte [ SECTORNUMBER ], 0x01
cmp byte [ HEADNUMBER ], 0x00
jne READDATA
add byte [ TRACKNUMBER ], 0x01
jmp READDATA
READEND:
; OS 이미지가 완료괴었다는 메시지 출력
push LOADINGCOMPLETEMESSAGE
push 1
push 20
call PRINTMESSAGE
add sp, 6
; 로딩한 가상 OS 이미지 실행
jmp 0x1000:0x0000
; 함수 코드 영역
HANDLEDISKERROR:
push DISKERRORMESSAGE
push 1
push 20
call PRINTMESSAGE
jmp $
PRINTMESSAGE:
push bp
mov bp, sp
push es
push si
push di
push ax
push cx
push dx
mov ax, 0xB800
mov es, ax
; X, Y의 좌표로 비디오 메모리의 어드레스를 계산함
mov ax, word [ bp + 6 ]
mov si, 160
mul si
mov di, ax
mov ax, word [ bp + 4 ]
mov si, 2
mul si
add di, ax
mov si, word [ bp + 8 ]
.MESSAGELOOP:
mov cl, byte [ si ]
cmp cl, 0
je .MESSAGEEND
mov byte [ es:di ], cl
add si, 1
add di, 2
jmp .MESSAGELOOP
.MESSAGEEND:
pop dx
pop cx
pop ax
pop di
pop si
pop es
pop bp
ret
; 데이터 영역
MESSAGE1: db 'MINT64 OS Boot Loader Start~!!', 0
DISKERRORMESSAGE: db 'Disk Error~!!', 0
IMAGELOADINGMESSAGE: db 'OS Image Loading...', 0
LOADINGCOMPLETEMESSAGE: db 'Complete~!!', 0
SECTORNUMBER: db 0x02
HEADNUMBER: db 0x00
TRACKNUMBER: db 0x00
times 510 - ( $ - $$ ) db 0x00
db 0x55
db 0xAA
테스트를 위한 가상 OS 이미지 생성
1024섹터 크기의 가상 OS 이미지
[ ORG 0x00 ]
[ BITS 16 ]
SECTION .text
jmp 0x1000:START
SECTORCOUNT: dw 0x0000
TOTALSECTORCOUNT equ 1024
; 코드 영역
START:
mov ax, cs
mov ds, ax
mov ax, 0xB800
mov es, ax
; 각 섹터 별로 코드를 생성
%assign i 0
%rep TOTALSECTORCOUNT
%assign i i + 1
mov ax, 2
mul word [ SECTORCOUNT ]
mov si, ax
mov byte [ es:si + ( 160 * 2 )], '0' + ( i % 10 )
add word [ SECTORCOUNT ], 1
%if i == TOTALSECTORCOUNT
jmp $
%else
jmp ( 0x1000 + i * 0x20 ):0x0000
%endif
times ( 512 - ( $ - $$ ) % 512 ) db 0x00
%endrep
macOS 환경에서 가상 OS 이미지를 로딩하여 실행한 결과는 다음과 같다. 예상된 결과와 다르게 나온다.
Linux Ubuntu 환경에서 실행한 결과이다. 원하는 결과가 나온다.
OS 이미지가 로딩되는 어드레스가 0x10000이고 0xA0000 이후 영역은 비디오 메모리로 사용하기 때문에 OS를 로딩할 수 있는 전체 크기는 0x90000B 이다. 섹터 크기는 최대 1152섹터가 된다. 그래서 1153 섹터 이상으로 설정하면 비디오 메모리를 침범하기 때문에 qemu에 오류가 발생하면서 종료된다.
Ubuntu 환경에서 1153섹터로 설정했을 때 발생한 오류
그러나 macOS에서 1153섹터를 설정해도 정상적으로 작동한다.