Andrew Bolotov
Andrew Bolotov

Reputation: 99

BIOS. LBA mode reading doesn't read sectors

I'm working on my own bootloader and I'm using QEMU as a test lab to check/debug it. Right now I want to practice with reading of sectors using BIOS extensions. According to the docs QEMU uses SeaBIOS which should support int 13h AH=42h. I have this code

bits    16                      ; we are in 16 bit real mode

org 0                       ; we will set regisers later

start:  jmp main                    ; jump to start of bootloader


Print:
        lodsb               ; load next byte from string from SI to AL
        or  al, al          ; Does AL=0?
        jz  PrintDone       ; Yep, null terminator found-bail out
        mov ah, 0eh         ; Nope-Print the character
        int 10h
        jmp Print           ; Repeat until null terminator found
PrintDone:
        ret             ; we are done, so return


ReadSectors:

         mov ah,0x42
         mov dl,0x80
         mov si,dap
         int 0x13  
         jc .error
         jmp .exit
.error:
         mov si,msgFailure
         call Print
         cli
         hlt
.exit:  
    ret


 main:

 ;----------------------------------------------------
 ; code located at 0000:7C00, adjust segment registers
 ;----------------------------------------------------

    cli                     ; disable interrupts
    mov     ax, 0x07C0              ; setup registers to point to our segment
    mov     ds, ax
    mov     es, ax
    mov     fs, ax
    mov     gs, ax

 ;----------------------------------------------------
 ; create stack
 ;----------------------------------------------------

    mov     ax, 0x0000              ; set the stack
    mov     ss, ax
    mov     sp, 0xFFFF
    sti                     ; restore interrupts
    xor ax,ax
    mov ah,0x41
    xor dx,dx
    mov dl,0x80
    mov bx,0xAA55
    int 0x13
 ;----------------------------------------------------
 ; Display loading message
 ;----------------------------------------------------

    mov     si, msgLoading
    call    Print
    call ReadSectors
    mov si,0x200
    call Print
    cli
    hlt               
dap:
packetSize: db 0x10
reserved:   db 0x0
sectorsNumber:  dw 0x1
buf_seg:    dw 0x0000
buf_off:    dw 0x7E00
lba:        dd 0x0
            dd 0x0

msgLoading  db 0x0D, 0x0A, "Loading Boot Image ", 0x0D, 0x0A, 0x00
msgCRLF     db 0x0D, 0x0A, 0x00
msgProgress db ".", 0x00
msgFailure  db 0x0D, 0x0A, "ERROR : Press Any Key to Reboot", 0x0A, 0x00

TIMES 510-($-$$) DB 0
DW 0xAA55

It checks if the extensions are supported using AH=41h function and then reads 1 sector starting from LBA=0h to memory 0000:7E00. I'm using gdb to connect to qemu machine to check register and memory. So what I see is that

This is how I create disk image

nasm bootloader.asm -o ./bin/bootloader.bin
dd if=/dev/zero of=./floppy/floppy.img bs=1024 count=1440
dd if=./bin/bootloader.bin of=./floppy/floppy.img conv=notrunc 

And this is how I run qemu

qemu-system-x86_64 -s -S -hda ./floppy/floppy.img

Can you please help with understanding what I'm doing wrong. Thanks!

Upvotes: 1

Views: 905

Answers (1)

Michael Petch
Michael Petch

Reputation: 47623

In the Disk Access Packet (DAP) the segment:offset pair is stored with offset first followed by segment. This is because the x86 is a little endian processor and the pair is stored in reverse order. Your DAP should be changed to:

dap:
packetSize: db 0x10
reserved:   db 0x0
sectorsNumber:  dw 0x1
buf_off:    dw 0x7E00              ; Place offset before segment
buf_seg:    dw 0x0000
lba:        dd 0x0
            dd 0x0

Upvotes: 3

Related Questions