磁盘读取功能在引导加载程序中未按预期工作

Disk Read Function not Working as Expected in Bootloader

我正在尝试开发一个基本的引导加载程序,但是当我尝试创建一个从硬盘驱动器读取额外扇区的函数时,我 运行 遇到了问题。我正在 NASM 中的 Kali Linux 上开发它,并使用 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位于模拟硬盘的第二个扇区中的 512 字节之后。但是当我编译 运行 引导加载程序时,它不会输出任何内容。在我上面提供的代码中,我在 my_string read_disk 函数结束后打印。但是 st运行gely 足够了,如果我将打印 my_string 的两行移动到 函数中,它就可以工作。 这是有效的代码:

[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

如果有人能向我解释这个 st运行ge 奇怪之处,我将不胜感激。

在读入内存之前,您应该设置 SS:SP 而不仅仅是 SPSS 可能为零,也可能不是。如果 SS 恰好是 0x0000 那么你的堆栈在 0x0000:0x8000 并且它会从那里向下增长。

您的代码将磁盘上的第二个 512 字节扇区读取到位于 0x0000:0x7e00 的内存中,其中包括所有字节直至并包括 disk_read 函数的 return 地址放在堆栈上 0x0000:0x7ffe 到 0x0000:0x7fff.

由于您破坏了堆栈,int 0x13 可能永远不会 return 因为内部数据、return 地址和标志已损坏。像这样破坏堆栈将产生不可预知的结果。考虑将堆栈 0x0000:0x7c00 放在引导加载程序下方,以免干扰您在引导加载程序之后加载的数据和代码。

注意:您应该将您需要的所有段寄存器设置为您期望的值。您不应该依赖任何包含特定值的段寄存器。 BIOS 不保证它们的值,尽管在大多数模拟器中它们将是 0x0000。