2015-12-11 3 views
7

Ich hat versucht, einen Bootloader mit this, zu entwickeln, aber wenn es ausgeführt wird es zeigt:Disk Read Fehler beim Laden der Sektoren in dem Speicher

disk read error! 

Wenn ich es zu ignorieren, in einem späteren Teil, es zeigt mir falschen Speicher Kartierung. Ich habe auch einige andere Quellen verfolgt, aber vergebens. Es fühlt sich an, als würde ich nur kopieren, was sie tun. Wenn ich auch nur ein bisschen anders mache, entsteht jedes Mal eine neue Art von Fehler.

Sollte ich einen bereits eingebauten Bootloader verwenden oder was tun?

Der Code der Plattenladefehler ist wie folgt:

[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 

ich diesen Befehl verwenden, meine Bootloader zu montieren und laufen:

nasm boot.asm -f bin -o boot.bin && qemu-system-i386 boot.bin 

ich an dieser Stelle stecken. Mein Bootloader-Display disk read error. Wenn ich es zu diesem Zeitpunkt ignoriere, erzeugt es Probleme bei der Ausführung von kernel.c Es scheint eine falsche Speicherzuordnung zu verwenden.

+0

Plz diesen Code überprüfen und helfen Sie mir! –

+0

Ein Problem, das Sie haben, ist, dass Sie das _DS_ (Datensegment) nicht richtig einrichten, wenn Ihr Programm startet. Sie legen auch SP fest, aber Sie legen kein gültiges _SS_ (Stack Segment) fest. Dies könnte auch Probleme verursachen. In disk_load setzen Sie nicht das _ES_ (Erweitertes Segment), das richtig gesetzt werden muss, damit der Speicherort, an dem Daten gelesen werden, vollständig spezifiziert ist (ES: BX ist der Adresspuffer). Wenn Sie eine 720-KB-Diskette mit 15 Sektoren erstellen, funktioniert dies wahrscheinlich nicht, da die maximale Sektorenanzahl auf einer Spur (Zylinder) 9 beträgt. Dies kann zu Leseproblemen führen. –

+0

Auch eine gute Idee, '[Bits 16]' an der Spitze zu setzen, so dass NASM weiß, um alle 16-Bit-Code für den Bootloader –

Antwort

5

„Er macht eine Liste, wird er es zweimal überprüft ...“

  • Ihr Bootloader startet im Realadreßmodus, so dass es am besten ist, Assembler zu zwingen, in 16- mit Bit-Code. Sie erreichen dies in NASM durch Schreiben [bits 16] an der Spitze Ihres Programms.

  • Wenn Ihr Bootloader gestartet wird, hat das BIOS ihn auf die lineare Adresse 00007C00h gesetzt. Dies kann auf verschiedene Arten in Bezug auf die Kombination von Segment und Offset erfolgen.
    Wenn Sie explizit [org 0x7C00] geschrieben haben, haben Sie (irgendwie) erwartet, dass diese Kombination den Segmentteil gleich Null hat. Aber das ist für BIOS keine Verpflichtung! Es liegt also an Ihnen, die Segmentregister (DS, ES und SS) manuell festzulegen.

  • Die BIOS Fernschreiber Funktion, die Sie in Ihrer verwenden Routine print_string verwendet BL und BH als Parameter. Daher sollten Sie niemals das BX-Register verwenden, um Ihren Text zu adressieren. Sicher, einige BIOS verwenden diese BL- und BH-Parameter nicht (mehr), sondern versuchen Programme für die größte Zielgruppe zu entwickeln.

  • Wenn Sie das SP-Register mit 0x9000 initialisiert haben, haben Sie effektiv einen Stack eingerichtet, der leicht, ohne es zu merken, das Programm darunter überschreiben könnte! Es wäre am besten, eine Kombination von SS und SP zu wählen, die Ihre Bedürfnisse erfüllt und nicht mehr. Ein 4608-Byte-Stapel, der bei 7C00h über dem Bootsektor bleibt und bei 9000h endet, würde erfordern: SS = 07E0h SP = 1200h. Um Probleme auf der 8086-Hardware zu vermeiden, ist es am besten, Interrupts zu deaktivieren, wenn SS: SP geändert wird.

  • Sie haben pusha und popa Anweisungen verwendet. Dies sind keine gültigen Anweisungen für die 8086-Hardware. Beim Schreiben robuster Software sollten wir testen, ob die Hardware der Aufgabe gewachsen ist. Aber hier ist die einfachste Lösung, nur einzelne Register zu pushen.

  • Sie haben den Rückgabewert von der BIOS-Funktion interpretiert, die von der Festplatte liest, aber Sie brechen nur ab, wenn eine falsche Anzahl von Sektoren übertragen wurde. Dies ist ein falscher Ansatz.Wenn das BIOS Sie über eine unvollständige Übertragung informiert (dies kann passieren, wenn Ihr BIOS nicht mehrspurig ist), müssen Sie den Anruf für die verbleibende Anzahl von Sektoren wiederholen. Offensichtlich müssen einige der Parameter angepasst werden: nächster Kopf, vielleicht nächster Zylinder und immer Sektor = 1. (Eine perfekte Lösung wäre das Abrufen der Festplattengeometrie aus dem BIOS oder das Lesen von der BPB, die auf der Festplatte vorhanden ist). Ich nahm Grundlegende 1,44 MB Floppy-Betrieb an.

  • Wenn das Lesen von der Festplatte zum ersten Mal nicht erfolgreich ist, sollten Sie es mehrmals versuchen. Solche ersten Mal fehlgeschlagen sind völlig normal. Fünf Wiederholungen ist ein guter Wert. Zwischendurch versuchen Sie die BIOS-Funktion aufzurufen, die das Diskettenlaufwerk zurücksetzt.

  • Um sicherzustellen, dass QEMU diese zusätzlichen 15 Sektoren tatsächlich lesen kann, sollten Sie diese Datei auffüllen, sodass sie eine Gesamtlänge von 16 Sektoren hat. Die text, mit der Sie verbunden sind, hat das auch getan!

"alle es Putting zusammen"

[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

Nur ein Kommentar über die Aktualisierung von _SS: SP_. Was Sie sagen, ist in der Tat wahr, dass es mit den unterschiedlichsten Hardware kompatibel ist, aber der Hauptgrund für das CLI/STI-Paar ist, einen Bug auf einigen fehlerhaften 8088 CPUs aus den 80er Jahren zu umgehen. Wenn Sie das Register _SS_ mit einer MOV-Anweisung aktualisieren, sollten Sie die Interrupts erst nach der Anweisung _NEXT_ deaktivieren. Normalerweise ist das die Aktualisierung auf _SP_. Leider wurden auf einigen fehlerhaften 8088-CPUs die Interrupts nicht wie erwartet abgeschaltet, daher würde man CLI/STI explizit verwenden, um den Fehler zu vermeiden. –

+1

Ich habe Ihre Antwort aktualisiert. Wird noch eine kleine Beobachtung machen. Sie verlassen sich darauf, dass _AL_ die Anzahl der gelesenen Sektoren ist.Es gibt einige alte BIOS, die nur einen Wert in _AL_ zurückgeben, wenn CF = 1 (Ja, klingt ein bisschen verrückt, ist aber wahr). Die meisten Bootloader (die auf ein breiteres Array von realer Hardware abzielen) gehen nicht davon aus, dass der Wert _AL_ zuverlässig ist. Im Allgemeinen lesen die meisten Bootloader einen Sektor nach dem anderen oder erhalten die Plattengeometrie (entweder von BPB oder BDA) und führen nur Multisektor-Lesevorgänge aus, die niemals eine Spur (Zylinder) überspannen. Aber Ihr Code wird mit der meisten Hardware (und allen mir bekannten Emulatoren) funktionieren. –

Verwandte Themen