3e8.org

In EBCDIC we trust.

November 28, 2012

QEMU linux test image with serial console

As provided, QEMU's test linux image expects to be on either a graphical or curses-based terminal. Let's say you'd like to patch the image to use the serial console instead. To make this more interesting, let's not resort to booting in graphical or curses mode to set up the serial console in the first place.

First, grab the test image.

$ mkdir linux-test && cd linux-test
$ curl http://wiki.qemu.org/download/linux-0.2.img.bz2 | bunzip2 > linux-0.2.img

The image uses LILO; to get LILO to interact with the serial port, we have to add serial=0,9600n8 to lilo.conf. We also need to get the kernel to use the serial line by appending console=ttyS0 to the kernel arguments in lilo.conf.

One problem: the image doesn't come with an editor (not even ed, man!). Also, we have no interactive console yet either way. So, in order to manipulate the disk image directly, we use the amazing guestfish.

$ guestfish -i -a linux-0.2.img
><fs> edit /etc/lilo.conf

Now we can edit lilo.conf to add the serial and console arguments. Updated, it looks something like:

boot = /dev/hda
serial = 0,9600n8
root = /dev/hda
# [... 5 lines omitted ...]
append = "console=ttyS0 sb=0x220,5,1,5 ide2=noprobe ide3=noprobe ide4=noprobe ide5=noprobe"
image = /boot/vmlinuz-2.6.20
  label = linux

It might have been nice to automate this editing with guestfish's support for augeas, but unfortunately augeas lacks a lens for lilo.conf.

Anyway, we still have to execute lilo to update the boot sector. We can try to do this via guestfish as well; the guestfish instance is running a mini-VM attached to your disk, and you can actually run code located on your disk within the mini-VM.

><fs> command lilo
libguestfs: error: command: Fatal: open /dev/hda: No such file or directory

Ugh. Our disk in the guestfish VM is located at /dev/vda, not hda. Well, we can fake it with a symlink:

><fs> command "ln -s /dev/vda /dev/hda"
><fs> command lilo
libguestfs: error: command: Fatal: Sorry, don't know how to handle device 0xfd00

By device 0xfd00 it means /dev/vda (major 253, minor 0); apparently it doesn't like virtblk devices. It might work by explicitly specifying the geometry, or upgrading LILO, but let's try another method.

What we'll do is use QEMU's support for directly loading the kernel and bypassing the boot loader. We can copy the kernel out of the image, and launch our VM using that external kernel, pointing it to the serial console. We can then run LILO to update the boot sector.

(Naturally, using this method, we could skip messing around with LILO at all, and just start up the VM this way all the time. But we've come this far, so let's make the change permanent.)

><fs> copy-out /boot/vmlinuz-2.6.20 .
><fs> quit

$ ls -l vmlinuz-2.6.20
-rw-r----- 1 jim jim 2040204 Nov 27 22:16 vmlinuz-2.6.20

$ kvm -nographic -hda linux-0.2.img -kernel vmlinuz-2.6.20 \
      -append "console=ttyS0 root=/dev/hda"

The machine should boot up and print its output to the serial console (your terminal). Run lilo when you get the login shell:

sh-2.05b# lilo
Added linux *
sh-2.05b# exit

Now this image has been permanently converted to communicate with the serial console. Boot it like so and you'll see both the LILO and kernel output on your terminal:

$ kvm -nographic -hda linux-0.2.img