assemblyinterruptx86-16biosfasm

BIOS Int 13h 08 DBT issue Bytes per sector code returns 0xF0 instead of 0x00 - 0x04


I was using int 13h 08 to load disk parameters and got an invalid value from the disk base table (dbt).
The value in question was 0xF0.
note: dbt is returned in es:di

Reference to int 13h 08: https://stanislavs.org/helppc/int_13-8.html
Reference to dbt: https://stanislavs.org/helppc/dbt.html
repo link: https://github.com/The3Null4Player613310/RealOS

Code in question:

disk_get_params:                ; get primary disk params
    push es
    push es
    mov dl, [addr_svs_pdv]
    mov ah, 0x08
    int 13h

    push ds                 ; get dbt
    push es
    pop ds
    mov si, di

    pop ax                  ; set es
    pop es
    push ax

    shr dx, 0x08            ; set total head count
    inc dx
    mov [addr_svs_thc], dx

    call disk_get_sector    ; set sectors per track
    inc ax
    mov [addr_svs_spt], ax

    call disk_get_cylindar  ; set tracks per head
    mov [addr_svs_tph], ax

    ;add si, 0x03

    xor ah, ah              ; set bytes per sector
    lodsb
    lodsb
    lodsb
    lodsb

    mov cx, ax
    mov bx, 0x80
    shl bx, cl
    mov [addr_svs_bps], bx

    pop ds
    pop es
    jmp disk_return

Solution

  • The code snippet in the question is wrong in the way it uses the segment registers. It's not possible to draw any conclusions about the F0-issue from it. However the same code on your GitHub repository seems OK.

    The BIOS.ReturnDiskDriveParameters function 08h will only return in ES:DI a far pointer to the DisketteParameterTable if the drive number that you specified in DL on entry referred to a floppy drive (DL < 128).
    I have looked at your project on GitHub and believe that what happens here, is that this BIOS function did neither touch ES nor DI, and because both happen to contain 0 on entry (*), the code that follows will be using a NULL-pointer. An instruction like mov cl, [es:di+3] (or similar) will therefore read the 4th byte of linear memory which so happens to hold F0. The first vector of the InterruptVectorTable is the DivideException and points to somewhere in the BIOS code. A typical value being F000:EF6F (6F, EF, 00, F0).

    (*) In your boot.asm on GitHub, you setup the DS and ES segment registers via push cs push cs pop es pop ds. This is dangerous! There's absolutely no guarantee that the CS segment register will hold the 0 that you need in accordance with your ORG 7C00h directive. It would be perfectly allright for the BIOS to reach your bootloader with CS:IP = 07C0h:0000h. The only valid way to setup is:

    xor ax, ax
    mov ds, ax
    mov es, ax
    

    What to do next?