Compile SVGAlib on 32-bit Linux Guest Running in QEMU


src | v1.9.25

Choose OS

We need a 32-bit (x86) build of a Linux image to run SVGALib. The code relies on kernel headers that are found in kernel 2.6.12. Ubuntu 5.10 uses this kernel. I found this match from the table of versions on Wikipedia and downloaded the appropriate x86 release from the old Ubuntu releases archive.

OS: Ubuntu 5.10 Breezy Badger (breezy)
Kernel: 2.6.12-9-386

The kernel version string is the output of the command uname -r. This combination worked for me, but you may find another version that works too. In the rest of this document, I have substituted uname -r where the kernel version string is used. For example, if I mention a path x/uname -r/y, it actually reads, in the context of this document, x/2.6.12-9-386/y. The two back-ticks that enclose the shell command is needed for the shell to be able to run it in place and substitute it with the command's output to form a valid path.

Qemu Guest-OS Setup

Create and prepare the Linux image

Create a Qemu image from the breezy iso.

qemu-img create -f qcow2 breezy32.qcow2 10G
qemu-system-i386 -m 2G -hda breezy32.qcow2 -cdrom  ubuntu-5.10-install-i386.iso -boot d -enable-kvm

Mount the root file system that resides on the qcow2 disk image at /tmp/mnt

modprobe nbd max_part=8f
qemu-nbd --connect=/dev/nbd0 os/ubuntu32_10.04_server.qcow2
mount /dev/nbd0p1 /tmp/mnt

If booted at this point the guest OS would have no connection to the internet and the apt would point to repository URLs that are stale. So the first thing to do is edit /etc/network/interfaces and add the line auto eth0 ensuring that the following block of text exists:

auto eth0
iface eth0 inet dhcp

Then we fix the stale URLs by cleaning up the file /etc/apt/sources.list so that only contains these lines

deb breezy main restricted universe multiverse
deb breezy-updates main restricted universe multiverse
deb breezy-security main restricted universe multiverse

We copy the svgalib source from the host to the guest's file system

cp svgalib-1.9.25.tar.gz  /tmp/mnt/home/rup/

You may want to create ~/.ssh and copy your public key too, but you will find out later that the OpenSSH server running on breezy is so old that you will not be able to use your key. Using SSH, though, smoothens the workflow.

At the end, dislodge the mount, as Qemu will now need to boot the OS from breezy32.qcow2 so that you can proceed with the rest of the tasks.

umount /tmp/mnt
qemu-nbd --disconnect /dev/nbd0
rmmod nbd

Boot the guest OS, test network, install Emacs and set up an SSH server

qemu-system-i386 -m 2G -hda breezy32.qcow2 -net user,hostfwd=tcp::10021-:22 -net nic -enable-kvm

and peek into its GUI using a VNC viewer


Check that the wired network configuration is correct and the internet is reachable. We had edited /etc/network/interfaces and now that the system is up and running, the change should have had taken effect. Wireless doesn't seem to work out of the box on breezy and I haven't tried making it work.

Refresh apt repos and upgrade OS packages

apt-cdrom add
apt-get update
apt-get upgrade

Install emacs and ssh server

apt-get install emacs21 openssh-server

The emacs binary goes to /usr/bin and it may not in breezy's path so add this line to ~/.bash_profile

export PATH=/usr/bin/:$PATH

and reload the file

source ~/.bash_profile

The rest of the work, mostly around building svgalib, until we have compiled svgalib demo binaries, can be done at the command line. So quit the vnc viewer if you want and ssh into the guest

ssh rup@localhost -p 10021

There is no particular reason for the choice of SSH port which, if you remember, also appears in the Qemu incantation.

However, this will complain about key mismatch because breezy is running a very old version of the ssh server. To fix this either use this

ssh -oKexAlgorithms=+diffie-hellman-group1-sha1 rup@localhost -p 10021

or add this to ~/.ssh/config

Host localhost
     KexAlgorithms +diffie-hellman-group1-sha1

With the configuration file present, scp works in the usual way

scp -P 10021  xyz rup@localhost:~/

By the way, if on logging and using the remote shell over SSH, you see complaints about a misbehaving terminal, install ncurses-term in the guest

sudo apt install ncurses-term

Install the svgalib build dependencies

apt-get install gcc gcc-3.4 build-essential linux-headers-`uname -r`

The default gcc installation is version 4, and strangely, svgalib, at the point where it builds a kernel module, uses version 3.4. That is why we have gcc-3.4 in the list above.

Build svgalib-1.9.25

cd svgalib-1.9.25
sudo make install

sudo is important. I have not used it in the commands so far because it is fairly easy to deduce when to use it. All svgalib commands must be run as root. Even though the README says that it is not necessary, I think this very old piece of software is missing some context in the modern, virtual ecosystem.

The next steps must be done in order to compile and install a kernel module

cd svgalib-1.9.25/kernel/svgalib_helper
sudo make install

which places a kernel module here


and creates the following devices on my machine


Load the kernel module

sudo modprobe svgalib_helper

which can be done from where you are sitting in the file system; you don't need to be in the directoy where svgalib_helper.ko exists.

Ensure that the module is loaded

lsmod | grep svgalib_helper
    svgalib_helper         13348  0

cd back to svgalib-1.9.25/ and build everything

sudo make install >log 2>&1

log should have no errors and end with a note about building the demo programs, so from the same directory run

sudo make demoprogs

Several binaries are created in svgalib-1.9.25/demos/bin and svgalib-1.9.25/threeDKit/bin, out of them I have found that these two run and quit gracefully

sudo ./threeDKit/bin/plane
sudo ./threeDkit/bin/wrap

If you invoke them from your remote shell you can see the output if you VNC into the guest. The shell will tell you which virtual console the output has gone to. The demo first requests the user chose mode resolutions. I picked one from 1-4, others aren't supported in the text-mode resolution Qemu offers the guest by default on my machine. The keys q w a s z x is used to manipulate the 3D view of the model and c to exit the application. If you were in text-mode you will fall back in there. On exit, if you were in a terminal in a graphical desktop the output will get painted over your GUI and drop you back to a clean GUI.


A screenshot shows output of two different svgalib demos (wireframe sphere and aircraft) running in the guest. Both the programs present an identical text screen of options at start, so I have shown one such screen at the top left quadrant.

Changes to the source code

If you are still game for it, here are the two build errors that tripped me and how I got around them.

The first time I ran make, the build stopped at

grep: /lib/modules/2.6.12-9-386/build/include/linux/device.h: No such file or directory

so the Linux source was installed

apt-get install linux-headers-`uname -r`

Then make blurted out

/usr/src/linux-headers-2.6.12-9-386/scripts/ line 11: gcc-3.4: command not found
/usr/src/linux-headers-2.6.12-9-386/scripts/ line 12: gcc-3.4: command not found
make[2]: gcc-3.4: Command not found
make[2]: Entering directory `/usr/src/linux-headers-2.6.12-9-386'
grep: /lib/modules/2.6.12/build/include/linux/device.h: No such file or directory

So I first install gcc-3.4

apt-get install gcc-3.4

and second, as the suffix "-386" is missing in the kernel version string in the path to the linux headers, I replace the string "KERNELRELEASE" in svgalib-1.9.25/kernel/svgalibhelper/Makefile with the string "SKERNELRELEASE".


  1. My SVGAlib Github repo.
  2. SVGAlib home page.
  3. Ubuntu table of versions.
  4. Ubuntu release archive.
  5. Hardware specs of my development machine.