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

问题描述 投票:1回答:1

我想开发一个引导加载器,简单地扫描自己的引导介质(FAT16的软盘)的根目录,然后跳转到它。最后我遇到了一个问题,我在网上找不到任何地方,我觉得我做错了什么。在我的代码开始的时候,当我用INT 0x13读取驱动器的根目录时,carry标志被设置了,在我让它打印出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上用虚拟软盘测试。
  • 其他代码工作正常(例如,打印东西或与键盘交互)。
  • 我做了多个快照,用十六进制编辑器检查虚拟内存,磁盘数据(除了启动码)从来没有加载到内存中。
assembly x86 bootloader disk bios
1个回答
1
投票

你说的没错,Cylinders(Tracks)可以是一个10位的数字,而要读取的扇区号是6位。两者都装在一个16位的寄存器中(CX) int 0x13 BIOS磁盘读取调用。10位的圆筒号只适用于硬盘类型的介质(或任何模拟为硬盘驱动器的东西)。对于软盘介质,圆柱体被限制为8位值(0-255),扇区号仍然被限制在1-63(6位)之间。

你将一个包含圆柱体的16位字载入到 BX 来进行计算。你移 BX 左6位。这就把圆柱体计数的下2位放到了圆柱体计数的上2位。BL 和上8位进入 BH 寄存器。这不是圆柱体编号的编码方式。寄存器的文件 INT 13hAH=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)

这说明必须将圆柱体编号的前2位存储在... CL,扇区号是低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
© www.soinside.com 2019 - 2024. All rights reserved.