我有一些代码可以在实模式下从软盘加载第二个扇区,但是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
也会是零(表示成功)。
答案 0 :(得分:2)
存在许多潜在问题:
xor dl, dl
)。这样做意味着,如果您以不使用软盘驱动器A(FDA)的方式启动QEMU,则您的代码将无法工作。如果以硬盘驱动器启动,它将失败。 BIOS在将控制权转移到引导加载程序之前,将在 DL 中引导的驱动器号放入。只需使用该值即可。通过删除两次出现的xor dl, dl
org 0x7c00
),因此需要在段寄存器(尤其是 DS )中放入0。 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
如果工作正常,输出应类似于: