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
真正的代码当然要长得多,我尽量只写对问题至关重要的部分。其他可能有帮助的详细信息:
- 我正在使用 NASM
- 我正在使用虚拟软盘在 VMWare Workstation 上进行测试
- 其他代码工作正常(例如,打印内容或与键盘交互)
- 我用十六进制编辑器做了多个快照来检查虚拟内存,磁盘数据(除了引导代码)从未加载到内存中
你说得对,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位CL。 CH 包含柱面编号的低 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
我正在尝试开发一个引导加载程序,它可以简单地扫描它自己的引导介质(带有 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
真正的代码当然要长得多,我尽量只写对问题至关重要的部分。其他可能有帮助的详细信息:
- 我正在使用 NASM
- 我正在使用虚拟软盘在 VMWare Workstation 上进行测试
- 其他代码工作正常(例如,打印内容或与键盘交互)
- 我用十六进制编辑器做了多个快照来检查虚拟内存,磁盘数据(除了引导代码)从未加载到内存中
你说得对,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位CL。 CH 包含柱面编号的低 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