将扇区加载到内存中时出现磁盘读取错误 [英] Disk Read Error while loading sectors into memory
问题描述
我尝试使用此开发引导加载程序,但运行时显示:
I tried to develop a bootloader using this, but when it is run it shows:
disk read error!
如果我忽略它,则在后面的部分中,它向我显示了错误的内存映射.我也跟踪了其他一些消息,但徒劳无功.感觉就像我只是在复制他们在做什么.如果我做的有些不同,每次都会产生一种新的错误.
If I ignore it, in a later part, it shows me wrong memory mapping. I also followed some other sources too but in vain. It feels like I'm just copying what they are doing. If I do even a little different a new kind of error generates every time.
我应该使用已经构建的引导加载程序还是该怎么做?
Should I use an already built bootloader or what to do?
磁盘加载错误的代码如下:
The code of disk load error is as follow:
[org 0x7c00]
KERNEL_OFFSET equ 0x1000
mov [BOOT_DRIVE], dl
mov bp, 0x9000
mov sp, bp
mov bx, MSG_REAL_MODE
call print_string
call load_kernel
jmp $
print_string:
pusha
mov ah, 0x0e
loop:
mov al,[bx]
cmp al, 0
je return
int 0x10
inc bx
jmp loop
return:
popa
ret
disk_load:
push dx
mov ah, 0x02
mov al, dh
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
int 0x13
jc disk_error
pop dx
cmp dh, al
jne disk_error
ret
disk_error :
mov bx, DISK_ERROR_MSG
call print_string
jmp $
DISK_ERROR_MSG db "Disk read error!", 0
[bits 16]
load_kernel:
mov bx, KERNEL_OFFSET
mov dh, 15
mov dl, [BOOT_DRIVE]
call disk_load
ret
; Global variables
BOOT_DRIVE db 0
MSG_REAL_MODE db "Started in 16-bit Real Mode", 0
; Bootsector padding
times 510-($-$$) db 0
dw 0xaa55
我使用以下命令来组装并运行我的引导程序:
I use this command to assemble and run my bootloader:
nasm boot.asm -f bin -o boot.bin && qemu-system-i386 boot.bin
我现在被困住了.我的引导程序显示disk read error
.如果我此时忽略它,那么它在执行内核时会产生问题.c似乎使用了错误的内存映射.
I get stuck at this point. My bootloader display disk read error
. If I ignore it at this point in time, then it creates problems while executing my kernel.c It seems to use wrong memory mapping.
推荐答案
他正在列出清单,他正在检查两次..."
"He's making a list, he's checking it twice..."
-
您的引导加载程序以实地址模式启动,因此最好强制您的汇编器使用16位代码.您可以通过在程序顶部编写
[bits 16]
在NASM中实现此目标.Your bootloader starts in the real address mode, so it is best to force your assembler in using 16-bit code. You achieve this in NASM by writing
[bits 16]
at the top of your program.启动引导程序时,BIOS会将其放置在线性地址00007C00h中.对于段和偏移量的组合,它可以通过多种方式来实现.
当您显式编写[org 0x7C00]
时,您(有点)希望此组合的段部分等于零.但这绝不是BIOS的义务!因此,您可以手动设置段寄存器(DS,ES和SS).When your bootloader starts, BIOS will have placed it at linear address 00007C00h. It can do this in a number of ways with respect to the combination of segment and offset.
When you explicitly wrote[org 0x7C00]
you (kind of) expected this combination to have the segment part equal to zero. But this is by no means an obligation for BIOS! And so it is up to you to set the segment registers (DS, ES, and SS) manually.您在 print_string 例程中使用的BIOS电传打字功能将BL和BH用作参数.因此,您永远不要使用BX寄存器来寻址您的文本.当然,某些BIOS不再使用这些BL和BH参数,而是尝试为最大的受众开发程序.
The BIOS teletype function that you use in your print_string routine uses BL and BH as parameters. So you should never use the BX register to address your text. Sure, some BIOSes don't use these BL and BH parameters (any more) but do try to develop programs for the biggest audience.
使用0x9000初始化SP寄存器时,可以有效地建立一个堆栈,该堆栈可以很容易地在不注意的情况下覆盖其下面的程序!最好选择满足您需求的SS和SP的组合.一个4608字节的堆栈位于7C00h的引导扇区之上,并在9000h结束,则需要:SS = 07E0h SP = 1200h.为避免8086硬件出现任何问题,最好在更改SS:SP时禁用中断.
When you initialized the SP register with 0x9000 you effectively set up a stack that could easily, without you noticing it, overwrite the program beneath it! It would be best to choose a combination of SS and SP that satisfies your needs and nothing more. A 4608 bytes stack that stays above the bootsector at 7C00h and ends at 9000h would require: SS=07E0h SP=1200h. To avoid any problems on 8086 hardware it's best to disable interrupts when changing SS:SP.
您使用了
pusha
和popa
指令.这些不是8086硬件上的有效说明.在编写功能强大的软件时,我们应该测试硬件是否符合任务要求.但是,这里最简单的解决方案是仅推送/弹出单个寄存器.You used
pusha
andpopa
instructions. These are not valid instructions on 8086 hardware. When writing robust software, we should test if the hardware is up to the task. But here the simplest solution is to only push/pop single registers.您已经解释了从磁盘读取的BIOS函数的返回值,但是当传输的扇区数不正确时,您只是中止了操作.这是错误的方法.当BIOS告诉您传输不完全时(如果您的BIOS未启用多轨,可能会发生这种情况),您必须为剩余的扇区数重复该呼叫.显然,必须调整一些参数:下一个磁头,也许是下一个圆柱体,并且始终将扇区设为1. (一个完美的解决方案包括从BIOS检索磁盘几何形状或从磁盘上的BPB读取磁盘几何形状).我假设使用基本的1.44 MB软盘操作.
You have interpreted the return value from the BIOS function that reads from the disk, but you just abort when an incorrect number of sectors were transferred. This is a wrong approach. When BIOS tells you about an incomplete transfer (this can happen if your BIOS is not multitrack enabled) you have to repeat the call for the remaining number of sectors. Obviously some of the parameters will have to be adjusted: next head, maybe next cylinder, and always sector=1. (A perfect solution would involve retrieving the disk geometry from BIOS or reading it from the BPB present on the disk). I assumed basic 1.44 MB floppy operation.
如果第一次从磁盘读取失败,则应重试多次. 这样的第一次失败是完全正常的.重试五次是很有价值的.在两次尝试之间,您将调用BIOS函数来重置磁盘驱动器.
When reading from the disk doesn't succeed first time you should retry it a number of times. Such first time fails are perfectly normal. Five retries is a good value. In between tries you call the BIOS function that resets the diskdrive.
为确保QEMU实际上可以读取其他15个扇区,您应填充此文件,使其总长度为16个扇区.您链接的文本也可以做到这一点!
To make sure QEMU can actually read those additional 15 sectors you should pad this file so it has a total length of 16 sectors worth. The text you linked to did this also!
全部放在一起"
"Putting it all together"
[bits 16] [org 0x7C00] KERNEL_OFFSET equ 0x1000 xor ax, ax mov ds, ax mov es, ax mov [BOOT_DRIVE], dl mov ax, 0x07E0 cli mov ss, ax mov sp, 0x1200 sti mov si, MSG_REAL_MODE call print_string call load_kernel jmp $ print_string: push ax push bx push si mov bx, 0x0007 ;BL=WhiteOnBlack BH=Display page 0 mov ah, 0x0E ;Teletype function loop: mov al, [si] cmp al, 0 je return int 0x10 inc si jmp loop return: pop si pop bx pop ax ret disk_load: mov [SECTORS], dh mov ch, 0x00 ;C=0 mov dh, 0x00 ;H=0 mov cl, 0x02 ;S=2 next_group: mov di, 5 ;Max 5 tries again: mov ah, 0x02 ;Read sectors mov al, [SECTORS] int 0x13 jc maybe_retry sub [SECTORS], al ;Remaining sectors jz ready mov cl, 0x01 ;Always sector 1 xor dh, 1 ;Next head on diskette! jnz next_group inc ch ;Next cylinder jmp next_group maybe_retry: mov ah, 0x00 ;Reset diskdrive int 0x13 dec di jnz again jmp disk_error ready: ret disk_error: mov si, DISK_ERROR_MSG call print_string jmp $ DISK_ERROR_MSG db "Disk read error!", 0 load_kernel: mov bx, KERNEL_OFFSET mov dh, 15 mov dl, [BOOT_DRIVE] call disk_load ret ; Global variables BOOT_DRIVE db 0 SECTORS db 0 MSG_REAL_MODE db "Started in 16-bit Real Mode", 0 ; Bootsector padding times 510-($-$$) db 0 dw 0xAA55 ; 15 sector padding times 15*256 dw 0xDADA
这篇关于将扇区加载到内存中时出现磁盘读取错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!