This little guide will help you use Bochs to debug and simulate your kernel. Bochs is a software simulator (a hardware emulator) that can give you detailed information about the interaction between your system software and the underlying hardware.
After you grab it, untar it, and traverse to the main directory. Within this directory, run the following command to configure with some nice default options.
./configure --enable-pci --enable-debugger --enable-apic --enable-x86-64 --enable-smp --enable-vbe --enable-acpi --enable-ne2000 --enable-sse=3
for bochs 2.46 and later several config options have been deprecated, and are now configured at runtime.
./configure --enable-pci --enable-debugger --enable-x86-64 --enable-smp --enable-ne2000
If you get this error while compiling:
gui/libgui.a(gtk_enh_dbg_osdep.o): In function `MakeGTKthreads()': ./build/bochs-2.4.2/gui/gtk_enh_dbg_osdep.cc:2120: undefined reference to `pthread_create'
You need to add -lpthread to the Makefile under LIBS (approximately line 98)
After this step, you may build.
If you'd like to install, you can run this command as a privileged user.
And then follow the rest of this guide to use the software.
Bochs uses a
bochsrc file as a means of configuration. Here is an example:
romimage: /usr/local/share/bochs/BIOS-bochs-latest megs: 128 ata1-slave: type=cdrom, path="./xomb.iso", status=inserted boot: cdrom cpu: count=2, reset_on_triple_fault=0
This configuration shows the minimum one would need to boot a small OS from strictly a compact disc image. There are more sophisticated settings, but these are good to get started. For more in depth information, look at the Bochs manual at their website. A link is provided in the External Links section.
Each option either describes a configuration of the system or a behavior of the BIOS:
- romimage is the path to the BIOS image that bochs will use, and the path given in the sample is the typical path used my bochs when installed.
- megs depicts the physical memory capacity of the system.
- ata1-slave describes what IO device is connected to the first ATA line. It also gives a path to the iso image you wish to mount.
- boot tells the BIOS which IO device to use as the first boot option.
- cpu describes the number of processors in count and whether or not it should cause a reset on a triple fault. By not resetting, it is easier to notice and investigate a triple fault within your system software.
For the sample configuration above, the system will load an iso file (xomb.iso) as a cdrom and boot from this disc. If this
bochsrc is in the same directory as the iso, this configuration will work. To start bochs, you just need a simple command:
This will start bochs and automatically use the configuration file in the current directory. If bochs was built with the debugger (
--debugger), then it may present a command prompt. To continue, just type a
c and press enter.
This tells it to execute. If your system software runs without fault, bravo! If not, the rest of this article will help you use bochs to investigate why.
The rest of this guide assumes that you have built Bochs with the
--debugger configuration option.
With a breakpoint, you can stop execution at a specific address. This is useful for debugging a specific set of instructions as you can set the breakpoint as the first address and then step through each instruction in turn. At each instruction, you can view information such as the values of registers and memory.
To set a breakpoint, use the
vb option. If you have experience with other command line based debuggers, you will notice many options are similar. This command, which stands for 'virtual break', will take a virtual address to an instruction given in segment:address form. That is, if you want to stop at
0xffff800000100000 when CS is
0x10, which is a typical pairing for a kernel, and the configuration XOmB uses, you would use this command:
> vb 0x10:0xffff800000100000
When bochs gets to this address when it attempts to decode an instruction, it will halt all execution and give you a command prompt. With this you can control further execution. For instance, you can step through instructions one at a time using the
s command. Like so:
This will execute one instruction and then return control back with yet another command prompt.
When you get to a call instruction, sometimes you don't want to take the code path into the function and just want to continue within the current or check the validity of the return of the function to be called. You can use the next instruction to execute the call statement and not halt execution until after a ret returns to the instruction immediately after the call. Then it will give you yet another command prompt.
When you want to continue execution and give back control to bochs (at least until another breakpoint), you can use the
c command to do this. When bochs starts, you will see a command line, and you will probably want to just run the code as is. You can use this command in that case.
If you are writing a kernel and are writing the modules to support paging and virtual memory, it can be a tough thing to debug. Bochs uses the data structures used for virtual memory just as an actual piece of hardware would. It also gives methods of reading and interpreting this data (or at least what bochs is seeing) so that you can compare with the expected values.
The first command is the
page command. This takes a virtual address. Bochs will report, if successfully mapped and marked present, the linear address of the physical page.
You may press 's' and step through code when using multiple cores only to frustratingly realize that it only steps CPU 0. Also, 'regs' and 'creg' will only work for CPU 0 at first as well. This occurs because Bochs internally relies on a CPU variable for the debugger, which can be set using the 'set' command as such:
set $cpu = 1
This will set the current cpu (in terms of which the debugger refers) to CPU 1. If you have 4 cores, this value can range from 0 to 3, and so on. Each command will then refer to this cpu, and this cpu alone.