La función de lectura de disco no funciona como se esperaba en el cargador de arranque
Estoy tratando de desarrollar un cargador de arranque básico, pero encontré un problema cuando intenté crear una función para leer sectores adicionales desde un disco duro. Lo estoy desarrollando en Kali Linux en NASM y usando QEMU como mi emulador. Este es mi archivo principal de cargador de arranque:
[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 puede ver, se my_string
encuentra después de 512 bytes, en el segundo sector del disco duro emulado. Pero cuando compilo y ejecuto el cargador de arranque, no genera nada. En el código que proporcioné anteriormente, estoy imprimiendo my_string
después de que finaliza la read_disk
función. Pero, curiosamente, si muevo las dos líneas que se imprimen my_string
dentro de la función, funciona. Este es el 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
Estaría muy agradecido si alguien pudiera explicarme esta extraña rareza.
Respuestas
Debe configurar SS: SP y no solo como SP antes de leer en la memoria. SS puede ser cero o puede que no lo sea. Si SS resulta ser 0x0000, entonces su pila está en 0x0000: 0x8000 y crecerá hacia abajo desde allí.
Su código lee el segundo sector de 512 bytes en el disco en la memoria en 0x0000: 0x7e00 que incluye todos los bytes hasta e incluyendo la dirección de retorno de la disk_read
función que se colocó en la pila en 0x0000: 0x7ffe a 0x0000: 0x7fff.
Dado que golpeó la pila, int 0x13
es probable que nunca regrese porque los datos internos, la dirección de retorno y las banderas se han dañado. Corromper la pila de esta manera tendrá resultados impredecibles. Considere colocar la pila en 0x0000: 0x7c00 debajo del cargador de arranque para no interferir con los datos y el código que carga después del cargador de arranque.
Nota: Debe establecer todos los registros de segmento que necesita en los valores esperados. No debe confiar en ninguno de los registros de segmento que contengan un valor específico. La BIOS no garantiza sus valores, aunque en la mayoría de los emuladores serán 0x0000.