Festplattenlesefunktion funktioniert im Bootloader nicht wie erwartet

Aug 16 2020

Ich versuche, einen einfachen Bootloader zu entwickeln, aber ich bin auf ein Problem gestoßen, als ich versucht habe, eine Funktion zum Lesen zusätzlicher Sektoren von einer Festplatte zu erstellen. Ich entwickle es unter Kali Linux in NASM und verwende QEMU als Emulator. Dies ist meine Haupt-Bootloader-Datei:

[org 0x7c00]

mov bp, 0x8000
mov sp, bp

call read_disk

mov si, my_string
call print          ;prints a string, si points to the string to be printed

jmp $ read_disk mov ah, 0x02 ;read from disk mov al, 0x01 ;read one sector mov ch, 0x00 ;read from cylinder 0 mov dh, 0x00 ;read from head 0 mov cl, 0x02 ;read the second sector mov bx, 0 mov es, bx mov bx, 0x7c00+512 int 0x13 jc disk_error ;BIOS sets the carry flag if disk read was unsuccessful ret disk_error: mov si, error_msg call print jmp $
;
;Functions
;
%include "functions/print.asm"
%include "functions/print_hex.asm"
%include "functions/print_nl.asm"
%include "functions/calc_len.asm"
%include "functions/find_string.asm"

;
;Data
;
error_msg:
    db 'Error reading disk', 0

times 510-($-$$) db 0    ;pad out the rest of the bootloader with zeros to increase the size to 512 bytes
dw 0xaa55                ;Magic bytes so BIOS recognizes the hard drive as bootable

;
;SECOND SECTOR
;

my_string:
    db 'Disk read successful', 0

times 512 db 0   ;need to pad out the rest of the sector with zeros since  QEMU requires it

Wie Sie sehen können, my_stringliegt nach 512 Bytes im zweiten Sektor der emulierten Festplatte. Aber wenn ich den Bootloader kompiliere und ausführe, gibt er nichts aus. In dem oben angegebenen Code drucke ich, my_string nachdem die read_diskFunktion beendet ist. Aber seltsamerweise funktioniert es , wenn ich die beiden Zeilen, die my_string innerhalb der Funktion gedruckt werden, verschiebe. Dies ist der Code, der funktioniert:

[org 0x7c00]

mov bp, 0x8000
mov sp, bp

call read_disk

jmp $ read_disk mov ah, 0x02 ;read from disk mov al, 0x01 ;read one sector mov ch, 0x00 ;read from cylinder 0 mov dh, 0x00 ;read from head 0 mov cl, 0x02 ;read the second sector mov bx, 0 mov es, bx mov bx, 0x7c00+512 int 0x13 jc disk_error ;BIOS sets the carry flag if disk read was unsuccessful mov si, my_string call print ;prints a string, si points to the string to be printed ret disk_error: mov si, error_msg call print jmp $
;
;Functions
;
%include "functions/print.asm"
%include "functions/print_hex.asm"
%include "functions/print_nl.asm"
%include "functions/calc_len.asm"
%include "functions/find_string.asm"

;
;Data
;
error_msg:
    db 'Error reading disk', 0

times 510-($-$$) db 0    ;pad out the rest of the bootloader with zeros to increase the size to 512 bytes
dw 0xaa55                ;Magic bytes so BIOS recognizes the hard drive as bootable

;
;SECOND SECTOR
;

my_string:
    db 'Disk read successful', 0

times 512 db 0   ;need to pad out the rest of the sector with zeros since  QEMU requires it

Ich wäre sehr dankbar, wenn mir jemand diese seltsame Kuriosität erklären könnte.

Antworten

4 MichaelPetch Aug 16 2020 at 14:38

Sie sollten SS: SP und nicht nur als SP einstellen, bevor Sie in den Speicher lesen. SS kann Null sein oder nicht. Wenn SS zufällig 0x0000 ist, befindet sich Ihr Stack bei 0x0000: 0x8000 und wächst von dort aus nach unten.

Ihr Code liest den zweiten 512-Byte-Sektor auf der Festplatte bei 0x0000: 0x7e00 in den Speicher, der alle Bytes bis einschließlich der Rücksprungadresse der disk_readFunktion enthält, die bei 0x0000: 0x7ffe bis 0x0000: 0x7fff auf dem Stapel abgelegt wurde.

Da Sie den Stapel überlastet haben, int 0x13wird der wahrscheinlich nie zurückkehren, da die internen Daten, die Rücksprungadresse und die Flags beschädigt wurden. Eine solche Beschädigung des Stapels führt zu unvorhersehbaren Ergebnissen. Stellen Sie den Stack auf 0x0000: 0x7c00 unter dem Bootloader, um die Daten und den Code, die Sie nach dem Bootloader laden, nicht zu beeinträchtigen.

Hinweis: Sie sollten alle Segmentregister, die Sie benötigen, auf die erwarteten Werte einstellen. Sie sollten sich nicht auf eines der Segmentregister verlassen, die einen bestimmten Wert enthalten. Das BIOS garantiert ihre Werte nicht, obwohl sie in den meisten Emulatoren 0x0000 sind.