I am trying to load sector number from [head = 0, cylinder(track) = 1, sector = 1] from floppy using BIOS interrupt 13h, from my FAT12 bootloader.
I use the subroutine read_sectors
to read the sector and load it at es:bx
.
This code works well with any sector from the first track, but it reads just 0s from any sector from the other tracks, while those sectors are actually populated. With sector 18, for example, cx
is 0x0041
, which is right. The problem is, the interrupt sets CF, saying that there is an error. It also sets ah (return code) to 1, and al(sectors read) to 1.
This is the complete bootloader .asm file
bits 16
org 0
start: jmp load
nop
OEM: DB "ptiaOS "
bytesPerSector: DW 512
sectorsPerCluster: DB 1
reservedSectors: DW 1
numberOfFATs: DB 2
rootEntries: DW 224
totalSectors: DW 2880
media: DB 0xf8
sectorsPerFAT: DW 9
sectorsPerTrack: DW 18
headsPerCylinder: DW 2
hiddenSectors: DD 0
totalSectorsBig: DD 0
driveNumber: DB 0
unused: DB 0
extBootSignature: DB 0x29
serialNumber: DD 0xa0a1a2a3
volumeLabel: DB "PTIAOS FLP "
fileSystem: DB "FAT12 "
load:
;The bootloader is loaded at the address 0x7C00 and is 0x200 (512) bytes long
cli
mov ax, 0x07C0 ; setup registers to point to our segment
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
sti
mov si, hello_string
call prints
mov si, try_string
call prints
mov ax, 18
call lba_to_chs
mov al, 2
mov bx, 0x200
call read_sectors
mov si, success_string
call prints
mov si, 0x200
call prints
cli
hlt ;halt
;--------DATA--------
hello_string db `Hi, bootloader of ptiaOS here\n\r`, 0
success_string db `Successfully loaded from floppy\n\r`, 0
try_string db `Loading more data from floppy...\n\r`, 0
;CHS position of the sector to read
sector_number db 0 ;1 is the first (they're 18 per track)
cilinder_number db 0 ;track number: 0 is the first (they're 80 per side)
head_number db 0 ;0 is the first (the're 2)
;---SOTTOPROGRAMMI---
;print a 0-terminated string pointed by ds:si
prints:
mov ah, 0x0E ;dico all'interrupt del BIOS video di eseguire la funzione di stampa [al: carattere, bh: pagina]
.prints_printchar:
lodsb ;al = *(si++)
cmp al, 0
je .prints_end ;if(al == 0) goto print_string_end
int 0x10 ;chiamo l'interrupt di i/o dello schermo, con ah = 0x0E per stampare il carattere in al
jmp .prints_printchar
.prints_end:
ret
;Read sectors from floppy at the address specified by CHS variables, and load them in es:bx
read_sectors:
mov ah, 0x02 ;function 0x02, interrupt 0x13: read sectors
;al (the number of sectors to read), es:bx (destination) are set as arguments
xor cx, cx
mov cl, [cylinder_number]
shl cl, 6
or cl, [sector_number]
mov dh, [head_number]
mov dl, 0
int 0x13
jnc .sectors_read_successfully ;CF = 0 if no errors, 1 otherwise
;if errors occured, try to reset floppy
.flp_reset:
mov ah, 0 ;function 0, interrupt 0x13: reset disk
mov dl, 0 ;disk to reset: 0=floppy
int 0x13
jc .flp_reset ;CF = 0 if no errors, 1 otherwise
jmp read_sectors
.sectors_read_successfully:
ret
lba_to_chs:
mov cx, ax
mov bl, [sectorsPerTrack]
div bl
inc ah ;ah = lba % 18 + 1
mov byte [sector_number], ah
mov ax, cx
mov bl, [sectorsPerTrack]
div bl ;al = lba / 18
cbw ;ax = lba / 18
mov bl, [headsPerCylinder]
div bl ;al = lba / 18 / 2; ah = lba / 18 % 2
mov byte [cilinder_number], ah
mov byte [head_number], al
ret
times 510-($-$$) db 0
dw 0xAA55
I am running this code on qemu, from Ubuntu, and compiling it with
nasm -f bin -o ptiaos.bin ptiaboot.asm
nasm -f bin -o BSTAGE2.SYS blstage2.asm
mkdir floppy
dd status=noxfer conv=notrunc if=ptiaos.bin of=ptiaos.flp
sudo mount -o loop ptiaos.flp floppy
sudo cp BSTAGE2.SYS floppy
sleep 0.1
sudo umount floppy
rm BSTAGE2.SYS
rm ptiaos.bin
rmdir floppy