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
关键修正细节
- 柱面号解析:通过
shr al,6提取CL的高2位作为柱面号的高8位,确保柱面号数值准确。 - 8位转16位安全处理:使用
movzx指令将8位变量扩展为16位,避免读取相邻内存的无效数据,同时保证print_number接收的AX是完整有效数值。 - 大容量兼容:当总容量超过64KB时,
mul bx会将结果存入DX:AX,修正后的代码先打印DX(非零才打印)再打印AX,避免数值截断。
内容的提问来源于stack exchange,提问作者PRoX
相关产品推荐
相关产品推荐

