INT 0x13 驱动器初始化失败并出现超时错误

INT 0x13 drive initialization fails with a timeout error

我正在尝试开发一个引导加载程序,它可以简单地扫描它自己的引导介质(带有 FAT16 的软盘)的根目录以查找文件并跳转到该文件。我终于 运行 遇到了一个我在网上找不到的问题,我觉得我做错了什么:在我的代码开始时,当我使用 INT 0x13 读取驱动器的根目录时,进位标志是正在设置,在我打印出 AH 中的错误代码后,我得到 0x80,这似乎对应于磁盘超时。我已经尝试将 DL 硬编码为 0x00(软盘 #1 - 与之前相同)、0x01(软盘 #2 - AH=0x01 非法函数)和 0x80(硬盘 #1 - 实际上有数据,但正如预期的那样,不是来自软盘映像)。我还尝试对参数的计算进行硬编码,并且只尝试读取一个扇区。下面是错误似乎发生在的代码:

    BITS 16

    jmp short bootload
    nop

    ; Drive parameters

bootload:
    ; Segment registers
    mov ax, 0x07C0+544
    cli
        mov ss, ax
        mov sp, 4096
    sti

    mov ax, 0x07C0
    mov ds, ax
    mov es, ax

    ; Boot device
    mov [bootdev], dl

    ; Calculations (I just hardcoded them in this example to make it easier to understand)
    mov byte [rootdirsize], 14
    mov byte [rootdirchssec], 1
    mov word [rootdirchstrack], 1

    ; Read sectors
    mov ah, 0x02                        ; Read sectors
    mov al, byte [rootdirsize]          ; The amount of sectors needed by the root dir entries
                                        ; (RootDirEntries / 16)
    mov dl, byte [bootdev]
    mov dh, 0                           ; Heads are ignored... yet
    mov cl, byte [rootdirchssec]        ; Sector number of the root dir in CHS
    and cx, 0b0000_0000_0011_1111       ; Sector only uses bits 0-5 of CX
    mov bx, word [rootdirchstrack]      ; Track number of the root dir in CHS
    shl bx, 6                           ; Track uses bits 6-15 of CX
    or cx, bx                           ; Transfer to CX
    mov bx, 0x0100                      ; Segment where it is loaded
    mov es, bx
    mov bx, 0                           ; Offset = 0
    int 0x13

    jc disk_error                       ; CF = error

    jmp $                               ; the rest of the bootloader

disk_error:
    mov al, ah                          ; AH is the error code
    mov ah, 0x0E                        ; print it
    int 0x10                            ; returns 'Ç' = 0x80 = timeout

    jmp $

data:
    bootdev         db 0
    rootdirsec      dw 0
    rootdirchssec   db 0
    rootdirchstrack dw 0
    rootdirsize     db 0

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

真正的代码当然要长得多,我尽量只写对问题至关重要的部分。其他可能有帮助的详细信息:

你说得对,Cylinders(Tracks)可以是10位的数字,读取的扇区号是6位的。两者都被打包到 16 位寄存器 (CX) 中,用于 int 0x13 BIOS 磁盘读取调用。 10 位柱面数仅适用于硬盘类型的介质(或任何模拟为硬盘驱动器的介质)。对于软盘媒体,柱面限制为 8 位值 (0-255),扇区号仍限制在 1-63(6 位)之间的值。

您将包含柱面的 16 位字加载到 BX 中以执行计算。您将 BX 左移 6 位。这会将柱面计数的低 2 位放入 BL 的高 2 位,将高 8 位放入 BH 寄存器。这不是 Cylinder 编号的编码方式。 INT 13h/AH=2 的文档说:

CH = low eight bits of cylinder number
CL = sector number 1-63 (bits 0-5)
high two bits of cylinder (bits 6-7, hard disk only)

这里说的是CL的高2位必须存放Cylinder号的高2位,扇区号是低6位CLCH 包含柱面编号的低 8 位。

要解决此问题,您可以更改以下行:

mov bx, word [rootdirchstrack]  ; Track number of the root dir in CHS
shl bx, 6                       ; Track uses bits 6-15 of CX
or cx, bx                       ; Transfer to CX

类似于:

mov bx, word [rootdirchstrack]  ; Track*Cylinder) number of the root dir in CHS    
xchg bl, bh                     ; Place lower 8 bits of Cylinder in BH
                                ; Upper 2 bits of Cylinder are now the lower 2 bits of BL
ror bl, 2                       ; Rotate the lower 2 bits into the upper 2 bits of BL
or cx, bx                       ; Transfer to CX already containing sec # in lower 6 bits