How to Use QEMUs “debugcon”-Feature (and Write Debug Infomation to the Terminal or a File)

Published by Philipp Schuster on

QEMU is a VMM often used for low-level OS/kernel development and testing. Especially when you write your own OS/kernel, things can get really hard and difficult to debug. Furthermore, there are not many debug capabilities, as you can’t write to files or print to the screen in early boot phases, thus, without loaded drivers. For these cases, QEMU has a featured called debugcon. It is not as good/prominent documented as it should be, but it is really handy to debug things. It can be used in the earliest phases of the boot already.

About “debugcon”

The debug connection allows you to write to the x86 I/O-port 0xe9. Practically this means that you can transfer for example ASCII, UTF-8, UTF-16, or UTF-32 via this interface. On the QEMU side, one can connect the I/O port to either a file or a device, like /dev/stdout. When QEMU runs and the binary writes data to the file, you can open it afterwards with an editor or text viewer of your choice.


Due to my research, this feature comes originally from Bochs, a x86 emulator, but QEMU has it for some time now. In my opinion, QEMU is not documented very well and especially this feature is hard to use from the official documentation. After some research on GitHub, I found out, how others solved it.

How to Activate it

To connect -debugcon with stdout (the terminal that started your QEMU process), pass -debugcon /dev/stdout to QEMU. To redirect the data to a file, pass -debugcon file:qemu/debugcon.txt to QEMU. You can use any absolute or relative path behind the :. The file will be created or truncated automatically, if QEMU has permission to do that in the given directory.

How to Use in Code

You need the outb instruction of x86. If you are not writing a program in pure assembly, I recommend inline assembly in C or Rust. For Rust, there is a nice abstraction, which can be found in the x86-crate.

Your code might look like this:

// Only do this if the app runs in QEMU (or Bochs), otherwise bad things might happen).
// Or to be more specific, only do this, if I/O port 0xe9 is valid.
if runs_inside_qemu() {
    unsafe {
        x86::io::outb(0xe9, b'H');
        x86::io::outb(0xe9, b'e');
        x86::io::outb(0xe9, b'l');
        x86::io::outb(0xe9, b'l');
        x86::io::outb(0xe9, b'o');
        x86::io::outb(0xe9, b'\n');
    }
}

Example QEMU config

The following snippet shows a .sh-file, that starts QEMU with the debugcon feature. It’s taken from one of my projects.

QEMU_ARGS=(
          ...

          # Enable serial (can co-exist with debugcon)
          "-serial"
          "stdio"

          # https://qemu-project.gitlab.io/qemu/system/invocation.html
          # using this, the program can write to X86 I/O port 0xe9 and talk
          # to qemu => debug output
          "-debugcon"
          # or "stdio" => it appears in terminal window
          # or "/dev/stdout" => or any other device
          # Write to a file (will automatically be created or truncated)
          "file:qemu/debugcon.txt"

          ...
  )

  echo "Executing: qemu-system-x86_64 " "${QEMU_ARGS[@]}"
  qemu-system-x86_64 "${QEMU_ARGS[@]}

Philipp Schuster

Hi, I'm Philipp and interested in Computer Science. I especially like low level development, making ugly things nice, and de-mystify "low level magic".

0 Comments

Leave a Reply

Your email address will not be published.