我正在制作一个引导程序以引导进入操作系统。当我使用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!
,但没有显示第二个字符串。我想知道是否在设置堆栈时缺少某些东西,例如pusha
和popa
搞砸了一些东西以防止再次调用print_string
?还是bx
正在为Goodbye world!
部分加载错误的地址?对于我来说,为什么该功能第一次起作用而不是第二次起作用没有意义。
这仍然使我感到困惑,为什么我的代码似乎可以在qemu上无缝运行,但在我的真实CPU上无法按预期运行。为什么将段寄存器设置为零,才能使print_string
的第一个调用正常工作?
已解决:
要使用USB在真实计算机上引导,我必须添加Michael Petch的答案中提到的BIOS参数块: stackoverflow.com/a/47320115/3857942