La fonction de lecture de disque ne fonctionne pas comme prévu dans le chargeur de démarrage

Aug 16 2020

J'essaie de développer un chargeur de démarrage de base, mais j'ai rencontré un problème lorsque j'ai essayé de créer une fonction pour lire des secteurs supplémentaires à partir d'un disque dur. Je le développe sur Kali Linux dans NASM et j'utilise QEMU comme émulateur. Ceci est mon fichier de bootloader principal:

[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

Comme vous pouvez le voir, my_stringse trouve après 512 octets, dans le deuxième secteur du disque dur émulé. Mais lorsque je compile et exécute le chargeur de démarrage, il ne produit rien. Dans le code que j'ai fourni ci-dessus, j'imprime une my_string fois la read_diskfonction terminée. Mais curieusement, si je déplace les deux lignes qui s'impriment my_string à l' intérieur de la fonction, cela fonctionne. C'est le code qui fonctionne:

[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

Je serais très reconnaissant si quelqu'un pouvait m'expliquer cette étrange bizarrerie.

Réponses

4 MichaelPetch Aug 16 2020 at 14:38

Vous devez définir SS: SP et pas seulement comme SP avant de lire en mémoire. SS peut être égal à zéro ou non. Si SS se trouve être 0x0000, votre pile est à 0x0000: 0x8000 et elle augmentera à partir de là.

Votre code lit le deuxième secteur de 512 octets sur le disque en mémoire à 0x0000: 0x7e00 qui comprend tous les octets jusqu'à et y compris l'adresse de retour de la disk_readfonction qui a été placée sur la pile à 0x0000: 0x7ffe à 0x0000: 0x7fff.

Depuis que vous avez écrasé la pile, le int 0x13ne reviendra probablement jamais car les données internes, l'adresse de retour et les indicateurs ont été corrompus. Une telle corruption de la pile aura des résultats imprévisibles. Pensez à placer la pile à 0x0000: 0x7c00 sous le chargeur de démarrage afin de ne pas interférer avec les données et le code que vous chargez après le chargeur de démarrage.

Remarque: vous devez définir tous les registres de segments dont vous avez besoin sur les valeurs attendues. Vous ne devez vous fier à aucun des registres de segments contenant une valeur spécifique. Le BIOS ne garantit pas leurs valeurs, bien que dans la plupart des émulateurs, elles soient 0x0000.