assemblynasmbootloaderbios

How to get disk size?


I need the total disk size in bytes to be displayed at startup, as well as some additional information.

I tried doing it this way, but the data displayed on the screen was completely wrong:

[BITS 16]
[ORG 7C00h]

start:
    xor ax, ax
    mov es, ax
    mov ds, ax

    mov ah, 08h      
    mov dl, 80h
    int 13h 
    jc disk_error     

    mov [max_cylinder], ch  
    mov [max_cylinder+1], cl 
    mov [max_head], dh 
    and cl, 3Fh            
    mov [sectors_per_track], cl

    call print_disk_info

    jmp $

print_disk_info:
    mov si, cylinder_msg
    call print_string
    mov ax, [max_cylinder]
    call print_number
    call print_newline

    mov si, head_msg
    call print_string
    mov al, [max_head]
    call print_number
    call print_newline

    mov si, sectors_msg
    call print_string
    mov al, [sectors_per_track]
    call print_number
    call print_newline

    mov ax, [max_cylinder]
    inc ax               
    mov bx, [max_head]
    inc bx              
    mul bx              
    mov bx, [sectors_per_track]
    mul bx              
    mov bx, 512        
    mul bx          

    mov si, size_msg
    call print_string
    call print_number
    mov si, bytes_msg
    call print_string
    call print_newline

    ret

print_number:
    pusha
    mov bx, 10        
    xor cx, cx     
.convert_loop:
    xor dx, dx
    div bx           
    add dl, '0'      
    push dx           
    inc cx         
    test ax, ax    
    jnz .convert_loop 
.print_loop:
    pop ax         
    mov ah, 0x0E    
    int 0x10
    loop .print_loop  
    popa
    ret

print_string:
    mov ah, 0x0E
    mov bh, 0x00
    mov bl, 0x0F
.print_char:
    lodsb
    cmp al, 0
    je .done
    int 0x10
    jmp .print_char
.done:
    ret

print_newline:
    mov ah, 0x0E
    mov al, 0x0D 
    int 0x10
    mov al, 0x0A
    int 0x10
    ret

disk_error:
    mov si, disk_error_msg
    call print_string
    jmp $

max_cylinder dw 0 
max_head db 0 
sectors_per_track db 0

cylinder_msg db 'Cylinders: ', 0
head_msg db 'Heads: ', 0
sectors_msg db 'Sectors per track: ', 0
size_msg db 'Total disk size: ', 0
bytes_msg db ' bytes', 0
disk_error_msg db 'Disk error!', 0

times 510-($-$$) db 0
dw 0xAA55 

the program writes that the size of my disk is 3584 bytes, although the disk size is actually 8kb

I would be very grateful if you could provide a code example.


Solution

  • mov [max_cylinder], ch  
    mov [max_cylinder+1], cl 
    

    This is not consistent with the description of the BIOS call, which says:

    CH = low eight bits of maximum cylinder number

    CL = maximum sector number (bits 5-0); high two bits of maximum cylinder number (bits 7-6)

    So you need to shift cl before storing in max_cylinder+1.

    I might write (not optimized):

    mov [max_cylinder], ch
    mov al, cl
    shr cl, 6
    mov [max_cylinder+1], cl
    and al, 3fh
    mov [sectors_per_track], al
    

    If you don't have at least a 186, you'll need instead something like

    mov bl, cl
    mov cl, 6
    shr bl, cl
    mov [max_cylinder+1], bl
    

    It was also noted in comments that you have things like

    mov bx, [max_head]
    

    where max_head is a byte, not a word. You need to zero-extend it, which on 8086 is perhaps most simply done by

    mov bl, [max_head]
    xor bh, bh
    

    There's the same issue with mov bx, [sectors_per_track] just below.