You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

BIOS实模式下磁盘容量计算错误求助:如何正确获取磁盘大小?

问题分析与修正代码

错误点说明

  • 柱面号解析错误:INT 13h AH=08h返回的柱面号由CH(低8位)和CL的高2位(位7-6)组成,原代码直接将CL整体存入max_cylinder+1,导致柱面号数值错误。
  • 8位数据转16位的溢出问题:处理磁头数、每磁道扇区数时,直接用16位寄存器读取8位变量,会意外读取相邻内存的无效数据;调用print_number时未确保AX为完整的16位有效数值。
  • 容量计算的寄存器误用:计算总容量过程中,对8位变量的16位转换处理不当,导致乘法结果偏差。

修正后的代码

[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     

    ; 正确解析柱面号:CH是低8位,CL高2位是高8位
    mov [max_cylinder], ch          ; 柱面号低8位
    mov al, cl
    shr al, 6                       ; 提取CL的高2位作为柱面号高8位
    mov [max_cylinder+1], al        
    mov [max_head], dh 
    and cl, 3Fh                     ; 提取每磁道扇区数(CL低6位)
    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

    ; 打印磁头数(扩展为16位避免AH干扰)
    mov si, head_msg
    call print_string
    movzx ax, byte [max_head]       ; 将8位磁头数安全扩展为16位AX
    call print_number
    call print_newline

    ; 打印每磁道扇区数(扩展为16位)
    mov si, sectors_msg
    call print_string
    movzx ax, byte [sectors_per_track]
    call print_number
    call print_newline

    ; 计算总磁盘容量:(柱面数+1)*(磁头数+1)*每磁道扇区数*512
    mov ax, [max_cylinder]
    inc ax                          ; 柱面从0开始计数,总数需+1
    movzx bx, byte [max_head]
    inc bx                          ; 磁头从0开始计数,总数需+1
    mul bx                          ; AX = (柱面数+1)*(磁头数+1)
    movzx bx, byte [sectors_per_track]
    mul bx                          ; AX = 总扇区数
    mov bx, 512        
    mul bx                          ; DX:AX = 总字节数(超过64KB时需处理DX)

    mov si, size_msg
    call print_string
    ; 先打印高16位DX(非零才打印),再打印低16位AX
    test dx, dx
    jz .print_ax_only
    mov ax, dx
    call print_number
.print_ax_only:
    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 

关键修正细节

  1. 柱面号解析:通过shr al,6提取CL的高2位作为柱面号的高8位,确保柱面号数值准确。
  2. 8位转16位安全处理:使用movzx指令将8位变量扩展为16位,避免读取相邻内存的无效数据,同时保证print_number接收的AX是完整有效数值。
  3. 大容量兼容:当总容量超过64KB时,mul bx会将结果存入DX:AX,修正后的代码先打印DX(非零才打印)再打印AX,避免数值截断。

内容的提问来源于stack exchange,提问作者PRoX

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 16:57:35