Bochs is a free x86 emulator. It can be used to run a variety of operating systems within a variety of operating systems. For example Win95 can be run in OpenBSD and vice-versa, or as this article demonstrates OpenBSD within OpenBSD. Unlike some commercial emulators Bochs also emulates the x86 architecture on non-x86 systems, such as Sparc and PowerPC. The host system in the examples herein is a Pentium 4 ® running OpenBSD 3.2
This article discusses how to setup Bochs, install OpenBSD, send files between Bochs and the host OS, and modify the kernel to print Hello World.
If you don't have a spare machine dedicated for experimenting with OS development Bochs allows you to experiment. It saves time, because switching between two systems isn't needed. You can run Bochs in a window and do something else on the machine while it's booting.
The latest stable release of Bochs 2.0.2 is needed. You should extract it in a directory like ~/OpenBSD_Dev. Change to the ~/OpenBSD_Dev/bochs-2.0.2 directory. In our case we will configure Bochs to install into our OpenBSD_Dev directory by doing something like ./configure --prefix=/home/gps/OpenBSD_Dev/bochs_install. Run make && make install Then you will need to setup the vga font for X. As the docs/install.html details: cp font/vga.pcf to /usr/X11R6/lib/X11/fonts/misc and then run mkfontdir /usr/X11R6/lib/X11/fonts/misc, followed by xset fp rehash. Restart your font server if needed (not usually needed).
By now we should have Bochs installed. Now we need to make a disk image for our OpenBSD install. The disk image is just a file. You can create it with dd or ~/OpenBSD_Dev/bochs_install/bin/bximage. In our case we will use ./bochs_install/bin/bximage. It should ask you several questions. In our case we want a hard disk image that is 500 MB named openbsd_3_2.img In our case it reported that we should add the following line to our bochsrc:
ata0-master: type=disk, path="openbsd_3_2.img", cylinders=1015, heads=16, spt=63
By now you may be wondering what our bochsrc file should have. Here is my bochsrc openbsd_3_2.cfg:
#Bochs configuration file for OpenBSD 3.2 #floppya: 1_44="dev_floppy.fs", status=inserted #floppya: 1_44="floppy30.fs", status=inserted #ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 ata0: enabled=1 ata0-master: type=disk, path="openbsd_3_2.img", cylinders=1015, heads=16, spt=63 ata1: enabled=1 ata1-master: type=cdrom, path="/dev/rcd0c" ata3: enabled=0 romimage: file=/home/gps/OpenBSD_Dev/bochs_install/share/bochs/BIOS-bochs-latest, address=0xf0000 vgaromimage: /home/gps/OpenBSD_Dev/bochs_install/share/bochs/VGABIOS-elpin-2.40 megs: 32 parport1: enabled=1, file="parport.out" com1: enabled=1, dev="" # no sb16 boot: disk floppy_bootsig_check: disabled=0 vga_update_interval: 30000 keyboard_serial_delay: 20000 #keyboard_paste_delay: 100000 floppy_command_delay: 500000 pit: realtime=1 text_snapshot_check: 0 mouse: enabled=0 private_colormap: enabled=0 i440fxsupport: enabled=1 time0: 0 # no ne2k newharddrivesupport: enabled=1 # no loader log: bochsout.txt logprefix: %t%e%d debugger_log: - panic: action=report error: action=report info: action=report debug: action=ignore pass: action=report keyboard_mapping: enabled=1, map=/home/gps/OpenBSD_Dev/bochs_install/share/bochs/keymaps/x11-pc-us.map keyboard_type: mf user_shortcut: keys=none config_interface: textconfig display_library: x
Modify your bochsrc as needed for your specific paths. Now you will learn how to use the bochsrc we have created. We can do this like so:
$ ./bochs_install/bin/bochs -f openbsd_3_2.cfg
At this point if we try to boot, we will be unable to, because we don't have an image to boot from.
Now run the command above and select "Edit Options," followed by "Disk Options." Now select the boot device for "Boot from:" In our case we want to use the CD-ROM. Now if we try to use "Begin Simulation" after getting back to the root menu we will probably find that it doesn't boot. We can consult the bochsout.txt file to see where things went wrong.
00000531504i[BIOS ] Boot from CD-Rom failed 00000539216i[BIOS ] FATAL: Could not read the boot disk
The problem is that we aren't allowed to read from the CD-ROM device as a normal user. We can fix this by making bochs setuid root. Note that it might be possible to make it setuid operator, but I was unable to make it work this way.
How do we go about making our bochs binary setuid root you may ask? We do so by becoming root and changing the owner of the bochs binary to root, followed by setting the suid flag on the binary. For example:
$ cd bochs_install/bin/ $ su # chown root bochs # chmod +s bochs
Now start bochs using our config file as before and change the "Boot from:" to cdrom again. Begin the simulation and we should be able to boot from the CD-ROM.


At this point we are asked if we want to install, upgrade, or use a shell. Choose i for install.

Select the wd0 device as the root disk, and use the entire disk for OpenBSD. Now at the disklabel delete a: if it exists by pressing d. Add a new partition by pressing a. And give it a size of 950000, an offset of 63 and a mount point of /. Now add a b partition and give it the rest of the disk and a type of swap.

If you type p m (for print megabytes). We should now have an a: partition of 463.9M and a b: of 35.7M. At this point write the table to the disk by pressing x and choose to write the new label to the disk. Format the file system when asked and follow the rest of the procedure. Install the sets from the CD-ROM. The default set selection should be all that you need. At this point you can choose to install the sets. I suggest you take a break while the sets install.
You should now complete the rest of the install. Making the device nodes will probably take a while, so you might want to take another break.
Run halt and after OpenBSD has halted click the power button (the rightmost button in the toolbar).
Start Bochs again as we did before, but this time don't set the boot device to cdrom (the default in our config is hard disk). We should now be able to boot from the hard disk image. It will take a while to boot and generate a new DSA and RSA key for ssh. Login as root using the password you provided at installation. If you forgot the password then at the boot prompt enter boot -s bsd and change the root password and reboot. Tweak the /etc/*rc* files if needed to stop unwanted programs from starting up.
Create a src directory in ~/OpenBSD_Dev. Copy src.tar.gz from the CD-ROM or from an OpenBSD download server into the ./src directory. Extract src.tar.gz using tar -zxvf src.tar.gz
Now that we have the src tree extracted we can build a test kernel. We could compile a new kernel within bochs, but it would take quite a while, so we will compile the kernel outside of Bochs on the host system. We will transfer the kernel image to bochs later on using a Vnode disk image. For example:
$ cd ~/OpenBSD_Dev/src/sys/arch/i386/conf/ $ cp GENERIC BOCHS_GENERIC $ config BOCHS_GENERIC Don't forget to run "make depend" $ cd ../compile/BOCHS_GENERIC/ $ make depend [...] [now just in case] $ make clean [now we can build bsd] $ make [...] $ cp bsd ~/OpenBSD_Dev/ $ cd ~/OpenBSD_Dev/
Now you may wonder how will we transfer the bsd kernel to our Bochs system. Remember how we used bximage before to build a 500 MB hard disk image. We will make a small 20 MB disk image using bximage like so:
$ ./bochs_install/bin/bximage [answer that we want a hard disk image [hd] and name it transfer.img]
In our case it suggested the following bochsrc addition:
ata0-master: type=disk, path="transfer.img", cylinders=40, heads=16, spt=63We will instead use:
ata0-slave: type=disk, path="transfer.img", cylinders=40, heads=16, spt=63
Now we can boot with our modified bochsrc. In our dmesg it says that the new disk is wd1c. Use disklabel to add a partition by using:
# disklabel -E /dev/rwd1c [add partition a and use the defaults] [write the changes to the disk]
If we try to mount the transfer.img it will fail, because the disk image hasn't been formatted. To format it in the emulated system do:
# newfs /dev/rwd1a
Now let's mount the transfer.img within the emulator.
# mount_ffs /dev/wd1a /mnt # echo "I'm a little test." > /mnt/test # umount /mnt
We are almost to the point where we can mount the disk image from our host and see if our test file is viewable. Start by making a transfer directory in our OpenBSD_Dev directory. To make it easier to mount we shall write a little script called mount_transfer.sh which contains (note sudo could be used instead of su):
#!/bin/sh dir=/home/gps/OpenBSD_Dev su root -c "umount $dir/transfer; vnconfig -u svnd0; vnconfig svnd0 $dir/transfer.img ; fsck_ffs /dev/svnd0a; mount /dev/svnd0a $dir/transfer ;exit"
Create the file and run chmod +x on it. Now let's try it:
$ ./mount_transfer.sh [asks for your root password] umount: /home/gps/OpenBSD_Dev/transfer: not currently mounted ** /dev/rsvnd0a ** File system is clean; not checking $ ls transfer test $ cat transfer/test I'm a little test.
It appears to have worked. Now let's copy our test kernel that we built earlier to our Vnode disk image.
$ cp bsd ./transfer/
We will need to umount the transfer file system before we can mount it again in our emulated system. We can write a little script to make it easier.
$ cat umount_transfer.sh #!/bin/sh su root -c "umount /home/gps/OpenBSD_Dev/transfer"
Using mount_ffs in our emulated system mount our wd1a partition again like so:
# mount_ffs /dev/wd1a /mnt # ls /mnt bsd test
Now we will cp our new kernel onto our emulated system.
# cp /bsd /bsd.first # cp /mnt/bsd /bsd
Let's reboot and try it out like so:
# reboot
Now will will modify a kernel to print "Hello World" by using the Kernel's printf. The file we will modify is ~/OpenBSD_Dev/src/sys/kern/init_main.c At about line 200 in the init_main.c source for 3.2 you will see:
consinit();
printf(copyright);
printf("\n");
We can add our printf after the consinit(). If we do it before consinit it will not work. In my case I added printf("Hello World from GPS!\n"); Now we will need to recompile the kernel. This should go pretty quickly, because all we have to do is rebuild one object and link the objects together. For example:
$ cd src/sys/arch/i386/compile/BOCHS_GENERIC/ $ make [you should see it rebuild init_main.c and create a new bsd $ cp bsd ~/OpenBSD_Dev/ $ cd ~/OpenBSD_Dev/ $ umount_transfer.sh
Now we repeat the steps we ran earlier to copy a kernel to our transfer image. Reboot the emulated system and you should see something like this:

By now you should know enough to play around with your own kernel modifications. If you don't feel confident enough to do it yet, then read this again. There is a lot to remember and it takes a while to get used to.
You should read the grep manual page and be very familiar with it in order to learn how the system works. Make a backup copy of your openbsd_3_2.img if you feel unsure about some changes you make; especially if you are modifying the file system code. email George Peter Staplin