I am trying to make my own bootloader in GAS assembly. So far, I am able to print to the screen using BIOS interrupts. I tried to read the disk into memory, but the output in the emulator is:
Booting... (PANIC) Disk error Press any key to reboot..._
This is my code:
.code16
.text
.org 0x0
.global main
main:
jmp start # jump to beginning of code
nop
bpb:
iOEM: .ascii "Canary" # OEM String
iSectSize: .word 0x200 # bytes per sector
iClustSize: .byte 1 # sectors per cluster
iResSect: .word 1 # #of reserved sectors
iFatCnt: .byte 2 # #of FAT copies
iRootSize: .word 224 # size of root directory
iTotalSect: .word 2880 # total # of sectors if over 32 MB
iMedia: .byte 0xf0 # media Descriptor
iFatSize: .word 9 # size of each FAT
iTrackSect: .word 9 # sectors per track
iHeadCnt: .word 2 # number of read-write heads
iHiddenSect: .int 0 # number of hidden sectors
iSect32: .int 0 # # sectors for over 32 MB
iBootDrive: .byte 0 # holds drive that the boot sector came from
iReserved: .byte 0 # reserved, empty
iBootSign: .byte 0x29 # extended boot sector signature
iVolID: .ascii "seri" # disk serial
acVolumeLabel: .ascii "VOLUME A" # volume label
acFSType: .ascii "FAT16" # file system type
.func print
print:
lodsb # load byte from si into al, increment si
cmp $0, %al # test if character is 0 (end)
je print_done # jump to end if 0.
mov $0x0e, %ah # set teletype output
mov $9, %bx # set bh (page no.) to 0, and bl (attribute) to white (9)
int $0x10 # int 10h
jmp print # repeat for next character.
print_done:
ret
.endfunc
.func reboot
reboot:
mov $rebootmsg, %si # load address of reboot message into si
call print # print the string
mov $0x00, %ah
mov $0x00, %al
int $0x16 # wait for a key press
.byte 0xea # machine language to jump to ffff:0000 (reboot)
.word 0x0000
.word 0xffff
.endfunc
.func readSector
readSector:
mov $0x00, %cx # counter = 0
read:
push %ax # store logical block in stack
push %cx # store counter in stack
push %bx # store data buffer offset in stack
# Cylinder = (LBA / SectorsPerTrack) / NumHeads
# Sector = (LBA mod SectorsPerTrack) + 1
# Head = (LBA / SectorsPerTrack) mod NumHeads
mov iTrackSect, %bx # get sectors per track
mov $0x00, %dx
# Divide (dx:ax/bx to ax,dx)
# Quotient (ax) = LBA / SectorsPerTrack
# Remainder (dx) = LBA mod SectorsPerTrack
div %bx
inc %dx # increment remainder since it is a sector
mov %dl, %cl # store result in cl to use for int 13h
mov iHeadCnt, %bx # get number of heads
mov $0x00, %dx
# Divide (dx:ax/bx to ax,dx)
# Quotient (ax) = Cylinder
# Remainder (dx) = Head
div %bx
mov %al, %ch # ch = cylinder
mov %dl, %dh # dh = head
mov $0x02, %ah # subfunction 2
mov $0x01, %al # no. of sectors to read
mov iBootDrive, %dl # drive number
pop %bx # restore data buffer offset
int $0x13
jc readFailure # retry if carry flag is set (error)
pop %cx
pop %ax
ret
# On error, retry 4 times before jumping to bootFailure
readFailure:
pop %cx # get counter from stack
inc %cx
cmp $4, %cx # check if we completed 4 tries
je bootFailure # jump to bootFailure if even after 4 tries we get an error
# Reset disk system
mov $0x00, %ah
mov $0x00, %al
int $0x13
# Retry
pop %ax
jmp read
.endfunc
start:
# Setup segments:
cli
mov %dl, iBootDrive # save what drive we booted from (should be 0x0)
mov %cs, %ax # cs = 0x0, since that's where boot sector is (0x07c00)
mov %ax, %ds # cs = cs = 0x0
mov %ax, %es # cs = cs = 0x0
mov %ax, %ss # cs = cs = 0x0
mov $0x7c00, %sp # Stack grows down from offset 0x7c00 toward 0x0000.
sti
# Clear the screen
mov $0x00, %ah
mov $0x03, %al # Set video mode (80x25 text mode, 16 colors)
int $0x10
# Reset disk system
# Jump to bootFailure on error
mov iBootDrive, %dl # drive to reset
mov $0x00, %ah
mov $0x00, %al
int $0x13
jc bootFailure # display error message if carry set (error)
# Display message if successful
mov $msg, %si
call print
call readSector
# Reboot
call reboot
bootFailure:
mov $diskerror, %si
call print
call reboot
# Program Data
msg: .asciz "Booting...\r\n"
diskerror: .asciz "(PANIC) Disk error\r\n"
rebootmsg: .asciz "Press any key to reboot..."
.fill (510-(.-main)), 1, 0 # Pad with nulls up to 510 bytes (excl. boot magic)
.word 0xaa55 # magic word for BIOS
What am I doing wrong? Also, if there is a better more efficient way to write this code, please tell.