Bochs: Difference between revisions

7,798 bytes added ,  29 days ago
m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
(→‎External Links: added link to tutorial)
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(42 intermediate revisions by 27 users not shown)
Line 1:
{{Emulators}}
'''Bochs''' is a steadily improving simulator for the [[:Category:x86|IA32]] platform. Among other niceties (such as removing the need for a reboot to test your latest kernel build, just restart Bochs), it offers detailed debugging functionality that can help greatly during kernel development.
 
'''Bochs''' is a steadily improving emulator for the [[:Category:x86|x86]] platform. It greatly improves OS development because the virtual machine restarts much quicker than real hardware, plus it offers detailed debugging functionality that can help greatly during kernel development.
 
It is strongly suggested to get two installations of Bochs - in addition to the out-of-the-box version (which might well be one of the binary downloads), you should also compile a second instance with the internal debugger enabled - so when something strange occurs that your 'normal' debugging tools can't trace, you can cross-check it with the debug version. You may also wish to enable (and use) the debug IO ports.
 
It is strongly suggested to get two installations of Bochs - in addition to the out-of-the-box version (which might well be one of the binary downloads), you should also compile a second instance with the internal debugger enabled - so when something strange occurs that your 'normal' debugging tools can't trace, you can cross-check it with the debug version. You may also wish to enable (and use) the debug i/o ports.
 
==Frequent error messages==
===Running in Bogus Memory===
You sent your code pointer (eipEIP) to some uninitialized memory area. This means you either followed a nullNULL (or uninitialized) pointer, or you damaged the return address of your [[Stack#Stack example on the X86 architecture|stack frame]]. Make your code more clean, test pointers before you follow them, initialize every pointer (especially those who are on the stack) and enable *-Wall* in GCC.
 
=== 3rd exception with no resolution===
===TripleFault===
 
The CPU didn't manage to invoke an exception handler and would normally [[Triple Fault|triple fault]]. This is probably due to a bad [[Interrupt Descriptor Table|IDT]] register content, or a bad IDT descriptor. Sometimes (but less likely), it can also be due to a severe bug in your exception handler code. Check your exception works with "illegal" ASMasm instructions like <tt>idiv 0</tt>, or
 
<syntaxhighlight lang="asm">
push 0xf001
pop ds ;; 0xf001 is no valid segment,
mov ax, ~[ds:0x12345678] ;; let's see if we get the GPF
</syntaxhighlight>
 
In several cases, there are other error messages prior to this one which can provide more details in the error. Some common messages that might be displayed:
===I/O Operand Size===
Bochs performs some paranoiac checks on I/O operand size. Reading a byte from port 0x1234 is usually not the same thing as reading a dword. Go back to your chip's datasheet and double-check your sizes are correct.
 
* interrupt(): gate descriptor is not valid sys seg
===fetch_raw_descriptor: LDTR.valid=0===
: You have not loaded an IDT, or the IDT is corrupt
Many of you have said "but ... I do not have an LDT and i read it wasn't mandatory!?". You're right. And so is BOCHS. This message usually means that your program tried to load a selector with some garbage value, which happened to have the 3rd bit (Table Indicator) set. The CPU will try to look up the descriptor in the LDT, but there's no LDT registered! In most cases, the error comes from some mispairing of push and pop on the stack, which lead to a non-selector value to be loaded in a segment register.
* interrupt(): SS selector null
:* You have no TSS
:* You haven't set SS0 / ESP0 in the TSS
* CR0 = 0xe0000001 CR2 = 0xe0000001
:* Your page tables are not page-aligned
:* Your page tables do not point to the correct parts of memory
 
===I/O Operand Size===
Bochs performs some rather paranoid checks on I/O operand size. Reading a byte from port 0x1234 is usually not the same thing as reading a 32-bit value. Go back to your chip's data sheet and double-check that your sizes are correct.
 
=== fetch_raw_descriptor: LDTR.valid=0 ===
If you're still stuck, download the Bochs sources package and search for the message you received. Then, maybe you can add extra information to the message-printing code (like the faulty offset of a segfault, the segment limit, etc). But keep away from modifying Bochs' operations! Every time I suspected a bug in Bochs, I was just misunderstanding the Intel Manual...
Many of you have said "but ... I do not have an LDT and I read it wasn't mandatory!?". You're right. And so is Bochs. This message usually means that your program tried to load a selector with some garbage value, which happened to have the 3rd bit (Table Indicator) set. The CPU will try to look up the descriptor in the LDT, but there's no LDT registered! In most cases, the error comes from some mispairing of push and pop on the stack, which lead to a non-selector value to be loaded in a segment register.
 
If you're still stuck, download the Bochs source package and search for the message you received. Then, maybe you can add extra information to the message-printing code (like the faulty offset of a segfault, the segment limit, etc). But keep away from modifying Bochs' operations! Every time I suspected a bug in Bochs, I was just misunderstanding the Intel Manual...
 
==Differences between Bochs and real hardware==
;Bochs enables A20Linethe A20 line in the BIOS
:Your PC doesn't necessarily do so. Sometimes there's a BIOS option, sometimes there isn't. Check your code that enables A20Linethe A20 line and make sure it has no issues with faster hardware.
 
;Bochs wipes out its memory
:In Bochs, memory is always filled with zero until you (or the BIOS) put something else. On a normal PC, uninitialized memory tends to contain garbage (most often all-ones) or traces of previous executions. Check your pointers, initialize them, print your code on paper if necessary.
 
;Bochs does not properly emulate CPU cache/TLB
:Although Bochs does have these constructs, they do not work the same as a regular CPU cache or TLB and do not change based on which CPU is being emulated. If you're not handling caching or TLB refreshes correctly, behavior may differ in Bochs vs. hardware (i.e. it may work on Bochs but not on hardware, or vice versa).
 
;Bochs floppy has no errors
:In a normalphysical PC, it's common to issue up to 3 read commands on a sector/track before it can be read fine. If you don't have proper error check/recovery in your bootsector, you're likely to run something that is not your kernel...
 
;Bochs is flexible about returning to real mode
:UnlikeDespite what Chris Giese's Protected Mode tutorial states, you do not have to be in 16-bit protected mode to clear the PE bit of cr0CR0. If you fail to enter 16-bit protected mode on a real PC, it will hang, without giving any error indication - no triple fault or anything!
 
;Bochs' timer is not realtimereal time
:(unless you configure it closer to real time). Waiting for 2 second on bochs will let any virtual device that needs 2 seconds to be ready be ready, but that could be just 0.02 seconds for you ... or that could be 200 seconds.
 
Adding
Adding clock: sync=realtime, time0=local will cause interrupts at real intervals, but may overload the emulated OS with PIT interrupts and overflow the stack (if it's pre-emptible)
clock: sync=realtime, time0=local
will cause interrupts at real intervals, but may overload the emulated OS with PIT interrupts and overflow the stack (if it's pre-emptible) Using <tt>sync=slowdown</tt> will also set it to real-time speeds, but with a constant amount of virtual clock cycles between each virtual second. For both the slowdown and original clock, you need to set the amount of instructions executed per second to the desired value.
 
;CPU is always Intel/AMD
:Bochs emulates a Intel CPU, so CPUID will always report back Intel (if emulating a 32-bit system) or AMD (if emulating a 64-bit system) regardless of whatswhat is really in your system.
Newer versions of Bochs allow you to specify the vendor string in the CPU tag:
cpu: vendor_string="test "
# must be a twelve-character ASCII string!
 
==Bochs image files in a nutshell==
Line 58 ⟶ 81:
 
But this is awfully slow, and puts lots of stress on the floppy when you are in a tight patch - make - boot cycle. Bochs offers the use of image files, including an interactive tool to create an image file (bximage.exe). Note that Bochs will emulate the floppy's internals even when the image is a device rather than a regular file ...
 
==Bochs debugging facilities==
Bochs has several features that eases debugging. Many of them must be enabled via an configure switch:
 
===GUI debugger===
Bochs has a command-line internal debugger, and a graphical interface on top of it. You must compile Bochs with the configuration option and then edit your bochsrc file in order to enable the GUI debugger. I use this line in my bochsrc file to enable graphical debugging in X:
 
display_library: x, options="gui_debug"
 
In a Windows environment, add this line to your bochsrc.bxrc
 
display_library: win32, options="gui_debug"
 
It seems that on Windows, the "option" flag (what the above line used to read) will be accepted, but the GUI window will not appear.
 
===I/O debugger macros===
Some useful macros when Bochs is compiled with the I/O debug ports enabled (<tt>port_e9_hack: enabled=1</tt> if Bochs 2.4 or newer, <tt>configure --port-e9-hack</tt> if not):
 
<syntaxhighlight lang="c">
//outputs a character to the debug console
#define BochsConsolePrintChar(c) outportb(0xe9, c)
//stops simulation and breaks into the debug console
#define BochsBreak() outportw(0x8A00,0x8A00); outportw(0x8A00,0x08AE0);
</syntaxhighlight>
 
===Magic Breakpoint===
When you're using Bochs with the [http://bochs.sourceforge.net/doc/docbook/user/internal-debugger.html internal debugger], you can trigger the debugger via a facility called [http://bochs.sourceforge.net/doc/docbook/user/bochsrc.html#AEN2324 magic breakpoints]. To trigger a breakpoint, you can insert <tt>xchg bx, bx</tt> (in GAS syntax, <tt>xchgw %bx, %bx</tt>) anywhere in the code and Bochs will trap into the debugger as soon as it executes it. On real hardware this has no effect as it merely replaces the BX register with itself.
 
You should put the following line in your Bochs configuration file to have it listen to magic breakpoints:
magic_break: enabled=1
 
On older versions, enabling the debugger alone doesn't compile in magic breakpoint support, you will also need to specify <tt>--enable-magic-breakpoint</tt> when configuring the build on those versions.
 
===Debugging SMP===
When using the internal debugger, you may use the following command to switch CPUs:
 
set $cpu = <n>
 
I also found this was necessary on occasion in the GUI debugger, even though it has buttons for each CPU.
 
===Internal debugger commands===
 
You can pass a file containing debug commands to automatically run whenever you start bochs with the internal debugger. (bochs -rc <file>)
 
Bochs places an automatic breakpoint just before the BIOS loads, this can be automatically skipped by putting <tt>continue</tt> as the first command in the said file.
 
===Debugging Triple Faults===
 
When using the internal debugger, you may change this line in your Bochs configuration file:
 
reset_on_triple_fault 0
 
This line disables the emulator reset on a Triple fault, enabling you to debug the code after a Triple fault occured (Very useful while implementing paging).
==Compiling Bochs from Source==
Bochs has many compile-time configuration options, some of which conflict, and therefore a binary distribution of Bochs may not be suitable for your purposes. I found it was best to compile my own copy of Bochs to be sure I had the features that I needed. Also, you should consider using the CVS snapshot version of Bochs if the released version is old and not working for you. I found this was necessary up until version 2.4 was released, for example. On Ubuntu, you may have to run
 
<syntaxhighlight lang="bash">
sudo apt-get install libgtk2.0-dev
</syntaxhighlight>
 
and enter your password. On other linux distros, try the equivalent.
 
The array of Bochs configuration options can be confusing, and you cannot assume the defaults are going to be sensible. These are the options I use, this can get you started:
 
<syntaxhighlight lang="bash">
./configure --enable-smp \
--enable-cpu-level=6 \
--enable-all-optimizations \
--enable-x86-64 \
--enable-pci \
--enable-vmx \
--enable-debugger \
--enable-disasm \
--enable-debugger-gui \
--enable-logging \
--enable-fpu \
--enable-3dnow \
--enable-sb16=dummy \
--enable-cdrom \
--enable-x86-debugger \
--enable-iodebug \
--disable-plugins \
--disable-docbook \
--with-x --with-x11 --with-term --with-sdl2
</syntaxhighlight>
 
A few notes:
* If you are on Windows, that last line should probably read "--with-win32".
* On Linux, using SDL as the display library over X11 is preferable as the performance appears to increase greatly on some setups
* Bochs has GDB stub support, and its own internal debugger. These cannot be compiled into the same Bochs binary. The internal debugger is very useful, its flag is --enable-debugger
* The GDB stub in Bochs does not support SMP, last time I checked.
* If you do not enable PCI, then the Intel Multiprocessing tables will not appear in memory.
* I was unable to successfully load the GUI debugger without specifying <tt>--disable-plugins</tt>. Otherwise, I get dynamic loading symbol errors.
* Post-2.4.2 several of the CPU specific options were folded into the CPU-level specification and are therefore deprecated. They have been removed from the example above.
* The default compile does not support x86-64, --enable-x86-64 will turn it on
* On many Linux distributions it is possible to install Bochs via a package manager. For example, on distributions that use apt-get we can do
<syntaxhighlight lang="bash">
sudo apt-get install bochs
sudo apt-get install bochs-x
</syntaxhighlight>
to install Bochs and the X11 plugin (which may crash on ubuntu/linux mint: install the sdl plugin and use sdl instead of x as the display library in this case). Note that there is a big chance that the graphical debugger is not enabled in the binaries from the package manager.
 
==See Also==
===Articles===
*[[Bochs Graphics Adaptor]]
*[[Emulator Comparison]]
*[[GDB]]
*[[:Category:Disk Image Utilities|Category:Disk Image Utilities]]
 
===External Links===
*[http://bochs.sourceforge.net Bochs Homepage]
*[http://bochs.sourceforge.net/doc/docbook/user/internal-debugger.html Bochs internal debugger commands documentation]
*[http://www.codeproject.com/system/MakingOS_2.asp]
*[http://www.codeproject.com/system/MakingOS_2.asp CodeProject article on using Bochs]
 
[[Category:Emulators]]
[[de:Bochs]]