I'm playing around with making a bootloader to boot into an OS. When I'm using qemu, my binary loads but when I try to boot from a USB, I always get different results.
I use the following code to emulate my AMD ryzen 64 bit cpu:
qemu-system-x86_64 hello.bin
When I run this I get the output:
Hello world!
Goodbye world!
However, when I actually load this onto a USB and boot from here when I restart my PC I get just a blinking underscore:
_
Here is my assembly code that I am using
[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
I followed some tips by other stack exchange posts and realized I should be setting up my segment registers so I added this to the top of my code:
[org 0x7c00]
mov ax, 0x00
mov es, ax
mov ss, ax
mov ds, ax
mov bp, 0x8000
mov sp, bp
cld
This seems to have helped a little bit because now when I boot using my USB I get the string Hello world!
printed to the screen, but I do not get the second string. I am wondering if there's something I am missing in setting up the stack such that pusha
and popa
are messing something up to prevent the second call of print_string
? Or maybe bx
is loading the wrong address for the Goodbye world!
portion? It doesn't make sense to my why the function would work the first time but not the second time.
It still confuses my why my code seems to work seamlessly on qemu but does not run as expected with my real CPU. Why did setting the segment registers to zero get the first call of the print_string
working?
Solved:
For using a USB to boot on a real machine, I had to add the BIOS parameter block mentioned in Michael Petch's answer: stackoverflow.com/a/47320115/3857942