I wanted to write a small kernel but I failed at the bootloader. I created a img file formatted as FAT12 which contains my bootloader and the stage 2 called KRNLDR.SYS
I used the following commands:
Code: Select all
nasm -fbin -o boot.bin boot.asm
dd if=/dev/zero of=test.img bs=512 count=2880
sudo losetup /dev/loop0 test.img
sudo mkdosfs -F 12 /dev/loop0
Then I executed:
Code: Select all
sudo dd if=boot.bin of=/dev/loop0 bs=512 count=1 conv=notrunc
sudo umount /dev/loop0
sudo losetup -d /dev/loop0
Now I execute it in QEMU:
Code: Select all
qemu-system-i386 -device format=raw,file=test.img
Code: Select all
Operating System not found
Press any key to reboot
My Code:
Code: Select all
org 0x0
bits 16
jmp word loader
bsOEMName: db "TestOS "
bpbBytesPerSector: dw 512
bpbSectorsPerCluster: db 1
bpbReservedSectors: dw 1
bpbNumberOfFATs: db 2
bpbNumberOfRootEntries: dw 224
bpbTotalSectors: dw 2880
bpbMedia: db 0xf0
bpbSectorsPerFAT: dw 9
bpbSectorsPerTrack: dw 18
bpbNumberOfHeads: dw 2
bpbHiddenSectors: dd 0
bpbTotalSectorsBig: dd 0
bsDriveNumber: db 0
bsReserved: db 0
bsExtendedBootSignature: db 0x29
bsVolumeID: dd 0x12345678
bsVolumeLabel: db "TestOS "
bsFileSystem: db "FAT12 "
;-------------------------------------------------------------------------------
; SI = Zero terminated string to print
;-------------------------------------------------------------------------------
printMsg:
push ax
.printStart:
lodsb
or al, al
jz .printEnd
mov ah, 0x0e
int 0x10
jmp .printStart
.printEnd:
pop ax
ret
;-------------------------------------------------------------------------------
; AX = Starting sector
; CX = Number of sectors to read
; ES:BX = Buffer
;-------------------------------------------------------------------------------
readSectors:
mov di, 0x0005
.readLoop:
push ax
push bx
push cx
call lbaToChs
mov ah, 0x02
mov al, 0x01
mov ch, byte [track]
mov cl, byte [sector]
mov dh, byte [head]
mov dl, byte [bsDriveNumber]
int 0x13
jnc .success
dec di
pop cx
pop bx
pop ax
jnz .readLoop
.success:
pop cx
pop bx
pop ax
inc ax
add bx, word [bpbBytesPerSector]
loop readSectors
ret
track: db 0
head: db 0
sector: db 0
;-------------------------------------------------------------------------------
; AX = Logical sector
;-------------------------------------------------------------------------------
lbaToChs:
xor dx, dx
div word [bpbSectorsPerTrack]
inc dl
mov byte [sector], dl
xor dx, dx
div word [bpbNumberOfHeads]
mov byte [head], dl
mov byte [track], al
ret
;-------------------------------------------------------------------------------
; AX = Cluster number
;-------------------------------------------------------------------------------
clusterToLba:
sub ax, 0x0002
xor cx, cx
mov cl, byte [bpbSectorsPerCluster]
mul cx
ret
;-------------------------------------------------------------------------------
loader:
cli
mov ax, 0x07c0
mov es, ax
mov gs, ax
mov fs, ax
mov ds, ax
mov ax, 0x0000
mov ss, ax
mov sp, 0xffff
sti
mov byte [bsDriveNumber], dl
xor dx, dx
xor cx, cx
mov ax, 0x0020
mul word [bpbNumberOfRootEntries]
div word [bpbBytesPerSector]
xchg cx, ax ; Number of sectors of the root directory
mov al, byte [bpbNumberOfFATs]
mul word [bpbSectorsPerFAT]
add ax, word [bpbReservedSectors] ; Starting sector of the root directory
mov bx, 0x0200
call readSectors
mov cx, word [bpbNumberOfRootEntries]
mov di, 0x0200
searchRoot:
push cx
mov cx, 0x000b
mov si, stage2
push di
rep cmpsb
pop di
je loadFat
pop cx
add di, 0x0020
loop searchRoot
jmp failure
loadFat:
mov dx, [di + 26] ; Starting address of entry
xor ax, ax
mov al, byte [bpbNumberOfFATs]
mul word [bpbSectorsPerFAT] ; Number of sectors used by the FATs
mov word [cluster], dx
mov cx, ax
mov ax, word [bpbReservedSectors]
mov bx, 0x0200
call readSectors
mov ax, 0x0050
mov es, ax
mov bx, 0x0000
push bx
loadFile:
mov ax, word [cluster]
pop bx
call clusterToLba
xor cx, cx
mov cl, byte [bpbSectorsPerCluster]
call readSectors
push bx
mov ax, word [cluster]
mov cx, ax
mov dx, ax
shr dx, 1
add cx, dx
mov bx, 0x0200
add bx, cx
mov dx, [bx]
test ax, 1
jnz oddCluster
evenCluster:
and dx, 0b0000111111111111
jmp next
oddCluster:
shr dx, 4
next:
mov word [cluster], dx
cmp dx, 0x0ff0
jb loadFile
jmp 0x0050:0 ; Far jmp to KRNLDR.SYS
failure:
mov si, fail
call printMsg
mov si, anykey
call printMsg
mov ah, 0x00
int 0x16 ; Await key press
jmp 0xffff:0 ; Reboot with far jmp to BIOS
stage2: db "KRNLDR SYS"
fail: db "Operating system not found", 0xd, 0xa, 0x0
anykey: db "Press any key to reboot", 0xd, 0xa, 0x0
cluster: dw 0
times 510 - ($ - $$) db 0
dw 0xaa55