尝试以int 13h ah = 02h加载扇区时,如何解决错误“找不到媒体类型”?

时间:2019-05-02 07:39:32

标签: assembly x86 bootloader osdev real-mode

我有一些代码可以在实模式下从软盘加载第二个扇区,但是int 0x13失败,错误为“找不到媒体类型”。为什么会这样?

我试图将柱面,磁头和扇区分别从0、0和2更改为1、1和1,但无济于事(我不知道CHS寻址是使用0还是1开始)。我也多次重做此代码,以更好地将其组织为功能,但无济于事。它失败,但不显示我的错误字符串,这使我感到困惑。它似乎总是会因相同的错误而失败。

代码如下:

bits 16
org 0x7c00

start:
    mov ax, cs
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x7c00
    mov si, msg

    mov ah, 0x00
    mov al, 0x03
    int 0x10

    call reset_disk
    mov si, suc_reset
    call puts

    call load_stage2
    mov si, suc_load
    call puts

    hlt

; routine to reset disk state
reset_disk:
    xor ah, ah          ; int 0x13 ah = 0x00
    xor dl, dl          ; drive 0
    int 0x13
    jc .error           ; error if carry flag is set
    ret
.error:
    mov si, err_reset
    call puts
    hlt

; routine to load stage 2
load_stage2:
    mov ah, 0x02        ; int 0x13 ah = 0x02 (read sectors)
    mov al, 0x01        ; number of sectors to read
    mov ch, 0x01        ; cylinder 0
    mov cl, 0x02        ; sector 2
    xor dh, dh          ; head 0
    xor dl, dl          ; drive 0
    mov bx, 0x9c00      ; address 9c00
    mov es, bx
    xor bx, bx          ; 0x9c00:0x0000

    int 0x13
    or ah, ah
    jnz .error
    ret
.error:
    mov si, err_load
    call puts
    hlt

; routine to print a string
puts:
    mov ah, 0x0e        ; int 0x10 ah = 0x0e (putchar)
.loop:
    lodsb               ; load string byte from si
    or al, al           ; check if al is zero
    jz .end             ; if zero jump to end (null terminator)
    int 0x10            ; print character
    jmp .loop           ; loop
.end:
    ret

err_reset: db "Failed to reset disk", 0x0a, 0x0d, 0
err_load: db "Failed to load stage 2", 0x0a, 0x0d, 0
suc_reset: db "Successfully reset disk 0...", 0x0a, 0x0d, 0
suc_load: db "Successfully loaded stage 2...", 0x0a, 0x0d, 0
msg: db "Test", 0
times 510-($-$$) db 0
dw 0xaa55

我希望输出是成功消息,但EAX也会是零(表示成功)。

1 个答案:

答案 0 :(得分:2)

存在许多潜在问题:

  • 您将驱动器号硬编码为0(使用xor dl, dl)。这样做意味着,如果您以不使用软盘驱动器A(FDA)的方式启动QEMU,则您的代码将无法工作。如果以硬盘驱动器启动,它将失败。 BIOS在将控制权转移到引导加载程序之前,将在 DL 中引导的驱动器号放入。只需使用该值即可。通过删除两次出现的xor dl, dl
  • ,可以轻松地在代码中实现这一点
  • 您将 CS 复制到其他段寄存器。在某些硬件和仿真器上, CS 可能不为0(在某些情况下,可能为0x07c0)。不要依赖 CS 作为特定值。由于您使用的是原点(org 0x7c00),因此需要在段寄存器(尤其是 DS )中放入0。
  • 在“柱面,头,扇区寻址(CHS)”中,柱面基于0,头基于0,仅扇区号基于1。磁盘上的第二个扇区是CHS =(0,0,2)。您显示的代码显示为CHS =(1,0,2),这是不正确的。
  • HLT指令仅等待下一个中断发生。当发生中断(即计时器)时,处理器将在HLT之后继续执行代码。在执行CLI之前,您将需要使用HLT关闭外部中断。您还应该将HLT放入循环中,因为在实际硬件上可能会发生不可屏蔽中断(NMI)。要正确使用HLT,您可以执行以下操作:

        cli
    .hltloop:
        hlt
        jmp .hltloop
    

    或者,对于引导加载程序,一个简单的无限循环就足够了:jmp $


通过对代码进行的此类更改以及用于测试目的的简单第二阶段,我们可以创建代码,将第二阶段读取到内存0x9c00:0x0000,然后将FAR JMP读取并执行代码。在此示例中,MDP将以洋红色属性的白色直接显示在显示屏上。

boot.asm

bits 16
org 0x7c00

start:
    mov ax, cs
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x7c00

    mov ah, 0x00
    mov al, 0x03
    int 0x10

    call reset_disk
    mov si, suc_reset
    call puts

    call load_stage2
    mov si, suc_load
    call puts

    ; As a test if stage2 is loaded jump to code contained in stage2
    jmp 0x9c00:0x0000
;    jmp halt


; routine to reset disk state
reset_disk:
    xor ah, ah          ; int 0x13 ah = 0x00
    int 0x13
    jc .error           ; error if carry flag is set
    ret
.error:
    mov si, err_reset
    call puts
    jmp halt

; routine to load stage 2
load_stage2:
    mov ah, 0x02        ; int 0x13 ah = 0x02 (read sectors)
    mov al, 0x01        ; number of sectors to read
    mov ch, 0x00        ; cylinder 0
    mov cl, 0x02        ; sector 2
    xor dh, dh          ; head 0
    mov bx, 0x9c00      ; address 9c00
    mov es, bx
    xor bx, bx          ; 0x9c00:0x0000

    int 0x13
    or ah, ah
    jnz .error
    ret
.error:
    mov si, err_load
    call puts

halt:
    cli
.hltloop:
    hlt
    jmp .hltloop

; routine to print a string
puts:
    mov ah, 0x0e        ; int 0x10 ah = 0x0e (putchar)
.loop:
    lodsb               ; load string byte from si
    or al, al           ; check if al is zero
    jz .end             ; if zero jump to end (null terminator)
    int 0x10            ; print character
    jmp .loop           ; loop
.end:
    ret

err_reset: db "Failed to reset disk", 0x0a, 0x0d, 0
err_load: db "Failed to load stage 2", 0x0a, 0x0d, 0
suc_reset: db "Successfully reset disk 0...", 0x0a, 0x0d, 0
suc_load: db "Successfully loaded stage 2...", 0x0a, 0x0d, 0

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

stage2.asm

org 0x0000
bits 16

stage2:
    ; Display MDP with white on magenta on 4th line of text display
    mov ax, 0xb800
    mov es, ax
    mov word [es:480], 0x57<<8 | 'M'
    mov word [es:482], 0x57<<8 | 'D'
    mov word [es:484], 0x57<<8 | 'P'

    jmp $

我通常使用DD创建磁盘映像,但是由于您使用的是CAT,因此您可以使用以下命令组装和构建磁盘映像:

nasm -f bin boot.asm -o boot.bin
nasm -f bin stage2.asm -o stage2.bin
cat boot.bin stage2.bin >disk.img

您可以运行QEMU并从软盘(FDA)或硬盘(HDA)引导。可以使用以下任一方法进行工作:

qemu-system-i386 -fda disk.img

或:

qemu-system-i386 -hda disk.img

如果工作正常,输出应类似于:

enter image description here