Thursday, July 22, 2010

Building a ARM powered Debian VM with QEMU on Ubuntu Lucid

I have recently spent some time trying to get an emulated ARM machine up and running on an x86 Ubuntu Lucid host. Initially I wanted Ubuntu for the client OS but I found that the only ARM installers available were for the Ubuntu Netbook Edition, which does not suit my needs at this point. So I went with Debian Lenny (the current Debian stable release) which has a myriad of ARM installers available.

When tracking down info about the Debian ARM port you'll quickly discover that there are two ports available ARM and ARMEL. ARM is the original port (now deprecated) and ARMEL is name of the newer code stream which supports ARM EABI.

The emulation software I am using is QEMU. An open-source project started by Fabrice Bellard (who also founded the ffmpeg project!). QEMU is fairly versatile and will emulate a myriad of CPU architectures including ARM, Sparc, PPC and even s390 (under KVM).

The Ubuntu Lucid repositories do contain packages for QEMU. However after installing via apt-get I found the binary failed out with a segmentation fault almost immediately. Not to worry the QEMU build system is easy to master.

Part 1: Building and installing QEMU:
  1. Download the QEMU source (0.12.4, the current release, is available here):
    trastle$ wget http://download.savannah.gnu.org/releases/qemu/qemu-0.12.4.tar.gz
  2. Unpack the tar ball:
    trastle$ tar -xvvf qemu-0.12.4.tar.gz
  3. Install the required packages to build QEMU:
    trastle$ sudo apt-get build-dep qemu
  4. Build and install QEMU:
    trastle$ cd qemu-0.12.4
    trastle$ ./configure
    trastle$ make
    trastle$ sudo make install

Part 2: Install Debian Lenny in QEMU:
  1. Change to the directory you want to build your VM in:
    trastle$ mkdir ~/arm
    trastle$ cd ~/arm
  2. Download the current build of the Debian Lenny ARMEL kernel (vmlinuz) and installer (initrd) images from a local Debian mirror:
    trastle$ wget ftp://ftp.au.debian.org/debian/dists/lenny/main/installer-armel
             /current/images/versatile/netboot/vmlinuz-2.6.26-2-versatile
    trastle$ wget ftp://ftp.au.debian.org/debian/dists/lenny/main/installer-armel
             /current/images/versatile/netboot/initrd.gz
  3. Create a disk image for QEMU (more details on qemu-img).
    Importantly, the raw format will allow you to mount the image from Ubuntu once its populated:
    trastle$ qemu-img create -f raw armdisk.img 8G
  4. Start the Debian install with QEMU:
    trastle$ qemu-system-arm -m 256 -M versatilepb \
             -kernel ~/arm/vmlinuz-2.6.26-2-versatile \
             -initrd ~/arm/initrd.gz \
             -hda ~/arm/armdisk.img -append "root=/dev/ram"
    QEMU will open a terminal window and within that window the Lenny installer will kick into action. Follow the installer's directions and allow the install to begin. Installation will be slower than normal. Allow 4 or 5 hours for it to complete.

  5. As the install completes you'll be informed no boot loader is present, don't worry QEMU takes the place of the boot loader. Once the install completes the VM will reboot kicking off the installer again, don't proceed, just kill QEMU.

Part 3: Running your ARM Lenny install in QEMU:
  1. Once the installation is complete you will need to copy the initrd from the installed system. To do this you must mount the QEMU disk image.
    trastle$ mkdir ~/arm/mount/
    trastle$ sudo mount -o loop,offset=32256 ~/arm/armdisk.img ~/arm/mount
    trastle$ cp ~/arm/mount/boot/initrd.img-2.6.26-2-versatile ~/arm/.
    trastle$ sudo umount ~/arm/mount
    
    32256 is not just a random number, it's the sector where the first disk partition begins.

  2. Boot your Debian Lenny VM:
    trastle$ qemu-system-arm -m 256 -M versatilepb \
             -kernel ~/arm/vmlinuz-2.6.26-2-versatile \
             -initrd ~/arm/initrd.img-2.6.26-2-versatile \
             -hda ~/arm/armdisk.img -append "root=/dev/sda1"
Now you have a running ARM VM to do with as you please.