将扇区加载到内存中时出现磁盘读取错误 [英] Disk Read Error while loading sectors into memory

查看:105
本文介绍了将扇区加载到内存中时出现磁盘读取错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用此开发引导加载程序,但运行时显示:

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.

      您使用了pushapopa指令.这些不是8086硬件上的有效说明.在编写功能强大的软件时,我们应该测试硬件是否符合任务要求.但是,这里最简单的解决方案是仅推送/弹出单个寄存器.

      You used pusha and popa 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆