为什么qemu对于引导加载程序有效,但实际计算机却不起作用?

时间:2018-12-17 07:41:46

标签: assembly x86 boot bootloader osdev

我正在制作一个引导程序以引导进入操作系统。当我使用qemu时,二进制文件会加载,但是当我尝试从USB启动时,总​​是会得到不同的结果。

我使用以下代码来模拟我的AMD ryzen 64位cpu:

qemu-system-x86_64 hello.bin

运行此命令时,我得到输出:

Hello world!
Goodbye world!

但是,当我将其实际加载到USB上并在重新启动PC时从此处启动时,我得到的是闪烁的下划线:

_

这是我正在使用的汇编代码

[org 0x7c00]
mov bx, HELLO_MSG
call print_string    
mov bx, NEWLINE
call print_string  
mov bx, GOODBYE_MSG
call print_string   
mov bx, NEWLINE
call print_string

jmp $

print_string:
    pusha
    mov ah, 0x0e        ; set ah to 0x0e so that int 0x10 will call BIOS teletype
    loop:
        mov al, [bx]    ;set al to character pointed by bx to print
        add bx, 1       ;increment to next char
        cmp al, 0       ;check if the char is NULL (null term string)
        je finish       
        int 0x10        ;call BIOS interrupt to print char to screen
        jmp loop
    finish:
        popa
        ret

HELLO_MSG:
db 'Hello world!', 0
GOODBYE_MSG:
db 'Goodbye world!', 0
NEWLINE:
db 0x0A,0x0D, 0

times 510-($-$$) db 0
dw 0xaa55

我遵循了一些其他堆栈交换文章的技巧,并意识到我应该设置我的段寄存器,因此我将其添加到了代码的顶部:

[org 0x7c00]
mov ax, 0x00
mov es, ax
mov ss, ax
mov ds, ax
mov bp, 0x8000
mov sp, bp
cld

这似乎有所帮助,因为现在当我使用USB启动时,在屏幕上显示了字符串Hello world!,但没有显示第二个字符串。我想知道是否在设置堆栈时缺少某些东西,例如pushapopa搞砸了一些东西以防止再次调用print_string?还是bx正在为Goodbye world!部分加载错误的地址?对于我来说,为什么该功能第一次起作用而不是第二次起作用没有意义。

这仍然使我感到困惑,为什么我的代码似乎可以在qemu上无缝运行,但在我的真实CPU上无法按预期运行。为什么将段寄存器设置为零,才能使print_string的第一个调用正常工作?

已解决:

要使用USB在真实计算机上引导,我必须添加Michael Petch的答案中提到的BIOS参数块: stackoverflow.com/a/47320115/3857942

0 个答案:

没有答案