A função de leitura de disco não funciona como esperado no carregador de inicialização

Aug 16 2020

Estou tentando desenvolver um bootloader básico, mas tive um problema ao tentar criar uma função para ler setores adicionais de um disco rígido. Estou desenvolvendo em Kali Linux em NASM e usando QEMU como meu emulador. Este é meu principal arquivo de bootloader:

[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

Como você pode ver, my_stringencontra-se após 512 bytes, no segundo setor do disco rígido emulado. Mas quando eu compilo e executo o bootloader, ele não produz nada. No código que forneci acima, estou imprimindo my_string após o término da read_diskfunção. Mas, estranhamente, se eu mover as duas linhas que são impressas my_string dentro da função, ela funciona. Este é o código que funciona:

[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

Eu ficaria muito grato se alguém pudesse explicar essa estranha estranheza para mim.

Respostas

4 MichaelPetch Aug 16 2020 at 14:38

Você deve definir SS: SP e não apenas como SP antes de ler na memória. SS pode ser zero ou não. Se SS acontecer ser 0 x 000, sua pilha está em 0 x 000: 0 x 8000 e diminuirá a partir daí.

Seu código lê o segundo setor de 512 bytes no disco para a memória em 0x0000: 0x7e00 que inclui todos os bytes até e incluindo o endereço de retorno da disk_readfunção que foi colocada na pilha em 0x0000: 0x7ffe a 0x0000: 0x7fff.

Uma vez que você superou a pilha, o int 0x13provavelmente nunca retornará porque os dados internos, o endereço de retorno e os sinalizadores foram corrompidos. Corrompendo a pilha dessa forma, terá resultados imprevisíveis. Considere colocar a pilha em 0x0000: 0x7c00 abaixo do bootloader para não interferir com os dados e código que você carrega após o bootloader.

Nota: Você deve definir todos os registros de segmento de que precisa com os valores esperados. Você não deve confiar em nenhum dos registradores de segmento contendo um valor específico. O BIOS não garante seus valores, embora na maioria dos emuladores eles sejam 0x0000.