4

I am trying to step through the simple bootloader shown in this tutorial: http://mikeos.berlios.de/write-your-own-os.html - so I can use the Qemu monitor to inspect the general registers for educational purposes.

Eventhough I am able to connect Qemu and gdb and the breakpoint is set at the beginning of the bootloader (0x7c0), after hitting "c" on gdb the code just runs all the way till the end.

I have read kvm may "confuse" gbd with virtual memory addresses, so I disabled it. This didn't work.

I also read (Debugging bootloader with gdb in qemu) things worked when debugging Freedos boot after compiling gdb from HEAD. Instead of recompiling gdb, I tried debugging the Freedos boot - It worked!

So, I do believe my problem is actually getting the tutorial's bootloader to go through a step-by-step execution.

Other things I tried (none of them worked):

Use dozens of "si" before inserting the breakpoint Try different breakpoint addresses Use the -singlestep key on qemu

Here is my qemu command line:

qemu-system-i386 -fda disquete.img -boot a -s -S -monitor stdio

Here is my command sequence inside gdb:

(gdb) target remote localhost:1234 (gdb) set architecture i8086 (gdb) br *0x7c0

Then I hit "c" and it just passes the breakpoint all the way.

Versions:

$ uname -a

Linux Brod 3.8.0-30-generic #44-Ubuntu SMP Thu Aug 22 20:52:24 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

$ gdb --version

GNU gdb (GDB) 7.5.91.20130417-cvs-ubuntu

$ qemu --version

QEMU emulator version 1.4.0 (Debian 1.4.0+dfsg-1expubuntu4), Copyright (c) 2003-2008 Fabrice Bellard

As I am able to step through the Freedos boot, I do believe my setup is fine and I must be failing within some conceptual misunderstanding of the boot process for the bootloader tutorial I mentioned in the beginning of this post.

All help is welcome!

Community
  • 1
  • 1
Cesar Brod
  • 320
  • 3
  • 13
  • Note that the bootloader is at `0x7c00` (one more zero). Does that work better? – Jester Oct 11 '13 at 13:20
  • I actually tried rewrite the code on http://mikeos.berlios.de/write-your-own-os.html (which actually works quite well on 0x7c0) so it would load on 0x7c00, same address as Freedos. Then Qemu just keeps waiting for a diskette and nothing happens. An alternative (I believe) would be just to forget the bootloader I am working on right now and try the one in this wikibooks page (http://en.wikibooks.org/wiki/X86_Assembly/Bootloaders). Yet, I am quite curious why I just cannot get Qemu to stop on the 0x7c0 address... I will do this and report my results sometime in the next couple weeks. Thanks! – Cesar Brod Oct 13 '13 at 21:18
  • 1
    Also remember that in real mode `0x7c00` can be addressed using segment `0x7c0` offset `0`, but the debugger has no idea about that and needs the physical address. – Jester Oct 13 '13 at 21:30
  • Here I describe a working setup: https://github.com/cirosantilli/linux-kernel-module-cheat/tree/8815312cad053d0284c4d91bfbf36a1e9ea207af#baremetal-gdb-step-debug – Ciro Santilli OurBigBook.com Oct 07 '18 at 17:51
  • `hbreak` is much more potent, does not need to replace any code with a breakpoint opcode, and cannot be overwritten like software breakpoints. If you use TCG (i.e. run qemu without `-enable-kvm`) then all breakpoints are as if hardware breakpoints. KVM software breakpoints (0xcc opcode) tend to be placed too early, they get overwritten when the firmware loads the boot sector. – doug65536 Aug 08 '20 at 23:50

2 Answers2

3

Because of hardware virtualization, it may be necessary to use a hardware breakpoint:

(gdb) hbreak *0x7c00

Also watch out for the correct architecture in gdb, even when using a 64-bit CPU (or kvm): The bootloader needs (gdb) set architecture i8086 as the CPU is still in real mode.

TheJJ
  • 931
  • 12
  • 21
0

I was actually able to debug the sample bootloader I took from mikeos.berlios.de/write-your-own-os.html after rewriting it to specifically load at 0x7c00. My sources of information (other than the contributions here) were:

http://en.wikibooks.org/wiki/X86_Assembly/Bootloaders http://viralpatel.net/taj/tutorial/hello_world_bootloader.php

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

Now I can step through the program and see the registers changing.

Cesar Brod
  • 320
  • 3
  • 13