尝试使用 int 13h ah=02h 加载扇区时如何修复错误 "Media Type Not Found"?
How do I fix the error "Media Type Not Found" when attempting to load a sector with int 13h ah=02h?
我有一些代码可以在实模式下从软盘加载第二个扇区,但是 int 0x13 失败并出现错误 "media type not found"。这是为什么?
我试过把柱面、磁头和扇区从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
也是零(表示成功)。
存在许多潜在问题:
- 您将驱动器编号硬编码为 0(使用
xor dl, dl
)。这样做意味着如果您以不使用软盘驱动器 A (FDA) 的方式启动 QEMU,您的代码将无法工作。如果您作为硬盘驱动器启动,它将失败。在将控制权转移到您的引导加载程序之前,BIOS 将从 DL 中引导的驱动器编号。只需使用该值即可。通过删除 xor dl, dl
的两次出现,可以在您的代码中轻松实现这一点
- 你复制CS到其他段寄存器。在某些硬件和模拟器上 CS 可能不是 0(在某些硬件和模拟器上可能是 0x07c0)。不要依赖 CS 作为特定值。因为您使用原点 (
org 0x7c00
),所以您需要将 0 放入段寄存器中(尤其是 DS)。
- 在柱面、磁头、扇区寻址 (CHS) 中,柱面从 0 开始,磁头从 0 开始,只有扇区号从 1 开始。磁盘上的第二个扇区是 CHS=(0,0,2)。您的代码显示为 CHS=(1,0,2),这是不正确的。
HLT
指令只等待下一次中断发生。当中断(即:定时器)发生时,处理器将继续执行HLT
之后的代码。在执行 HLT
之前,您需要使用 CLI
关闭外部中断。您还应该将 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,您可以 assemble 并使用以下命令构建磁盘映像:
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
如果它正常工作,输出应该类似于:
我有一些代码可以在实模式下从软盘加载第二个扇区,但是 int 0x13 失败并出现错误 "media type not found"。这是为什么?
我试过把柱面、磁头和扇区从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
也是零(表示成功)。
存在许多潜在问题:
- 您将驱动器编号硬编码为 0(使用
xor dl, dl
)。这样做意味着如果您以不使用软盘驱动器 A (FDA) 的方式启动 QEMU,您的代码将无法工作。如果您作为硬盘驱动器启动,它将失败。在将控制权转移到您的引导加载程序之前,BIOS 将从 DL 中引导的驱动器编号。只需使用该值即可。通过删除xor dl, dl
的两次出现,可以在您的代码中轻松实现这一点
- 你复制CS到其他段寄存器。在某些硬件和模拟器上 CS 可能不是 0(在某些硬件和模拟器上可能是 0x07c0)。不要依赖 CS 作为特定值。因为您使用原点 (
org 0x7c00
),所以您需要将 0 放入段寄存器中(尤其是 DS)。 - 在柱面、磁头、扇区寻址 (CHS) 中,柱面从 0 开始,磁头从 0 开始,只有扇区号从 1 开始。磁盘上的第二个扇区是 CHS=(0,0,2)。您的代码显示为 CHS=(1,0,2),这是不正确的。
HLT
指令只等待下一次中断发生。当中断(即:定时器)发生时,处理器将继续执行HLT
之后的代码。在执行HLT
之前,您需要使用CLI
关闭外部中断。您还应该将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,您可以 assemble 并使用以下命令构建磁盘映像:
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
如果它正常工作,输出应该类似于: