Disk Read Error while loading sectors into memory

前端 未结 1 684
执念已碎
执念已碎 2021-02-08 08:59

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 me

1条回答
  •  礼貌的吻别
    2021-02-08 09:25

    "He's making a list, he's checking it twice..."

    • 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.

    • 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.

    • 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.

    • 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.

    • 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.

    • 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.

    • 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.

    • 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
    

    0 讨论(0)
提交回复
热议问题