ブートローダーでディスク読み取り機能が期待どおりに機能しない

Aug 16 2020

基本的なブートローダーを開発しようとしていますが、ハードドライブから追加のセクターを読み取るための関数を作成しようとしたときに問題が発生しました。NASMのKaliLinuxで開発しており、エミュレーターとしてQEMUを使用しています。これは私のメインのブートローダーファイルです:

[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

ご覧のとおりmy_string、エミュレートされたハードドライブの2番目のセクターの512バイトの後にあります。しかし、ブートローダーをコンパイルして実行すると、何も出力されません。上記のコードでは、関数がmy_string 終了しに印刷ていread_diskます。しかし、不思議なことmy_string 、関数内に出力される2行を移動すると、機能します。これは機能するコードです:

[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

誰かがこの奇妙な奇妙さを私に説明してくれたら、私はとても感謝しています。

回答

4 MichaelPetch Aug 16 2020 at 14:38

メモリに読み込む前に、SPとしてではなくSS:SPを設定する必要があります。SSはゼロの場合もあれば、そうでない場合もあります。場合はSSが0000であることを起こる、あなたのスタックが0x0000にある:0x8000に、それはそこからダウン成長します。

コードは、ディスク上の2番目の512バイトセクターを0x0000:0x7e00のメモリに読み取ります。これにはdisk_read、0x0000:0x7ffeから0x0000:0x7fffのスタックに配置された関数のリターンアドレスまでのすべてのバイトが含まれます。

スタックを壊したint 0x13ので、内部データ、戻りアドレス、およびフラグが破損しているため、は戻らない可能性があります。このようにスタックを破損すると、予測できない結果になります。ブートローダーの後にロードするデータとコードに干渉しないように、スタックをブートローダーの下の0x0000:0x7c00に配置することを検討してください。

注:必要なすべてのセグメントレジスタを、期待する値に設定する必要があります。特定の値を含むセグメントレジスタに依存しないでください。BIOSはそれらの値を保証しませんが、ほとんどのエミュレーターでは0x0000になります。