For educational purposes, I have adapted this bootloader from mikeos.berlios.de/write-your-own-os.html rewriting it to specifically load at address 0x7c00.
The final code is this:
[BITS 16] ; Tells nasm to build 16 bits code
[ORG 0x7C00] ; The address the code will start
start:
mov ax, 0 ; Reserves 4Kbytes after the bootloader
add ax, 288 ; (4096 + 512)/ 16 bytes per paragraph
mov ss, ax
mov sp, 4096
mov ax, 0 ; Sets the data segment
mov ds, ax
mov si, texto ; Sets the text position
call imprime ; Calls the printing routine
jmp $ ; Infinite loop
texto db 'It works! :-D', 0
imprime: ; Prints the text on screen
mov ah, 0Eh ; int 10h - printing function
.repeat:
lodsb ; Grabs one char
cmp al, 0
je .done ; If char is zero, ends
int 10h ; Else prints char
jmp .repeat
.done:
ret
times 510-($-$$) db 0 ; Fills the remaining boot sector with 0s
dw 0xAA55 ; Standard boot signature
I can step through the program and see the registers changing, along with the instruction being executed, stepping with gdb (si) and inspecting with QEMU monitor (info registers, x /i $eip, etc).
After I get into int 10h (the BIOS printing routine), things get a little strange. If I step 500 instructions at once, I can see the character "I" (the first of char of my text string) printed on the screen. So I restarted again and stepped 400 steps (si 400) and then I did one step at a time to see in which exact step "I" got printed. It never happened. I actually stepped 200 steps one by one and nothing happened. As soon as I stepped 100 steps at once (si 100) I got "I" printed on the screen again.
So, I wonder if there is a timing issue (some system interrupt gets in the way as I do a step by step debug). What else could this be?
Anyway, is there a way of skipping the whole BIOS interrupt and other functions and just go back and keep stepping the bootloader code? As suggested by Peter Quiring in the comments, I tried using next. This did not work.
(gdb) next
Cannot find bounds of current function
So I tried nexti and it just behaves as si.
Thanks!