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.

14 comments:

Damon Kohler said...

Great tutorial! Worked perfectly.

andrewl said...

Good material, thanks for posting.

"A place to record obscure technical facts before I forget them." <- perfect description

Lex said...

Many thanks for this HOWTO (btw, I am not a bot!). I got a segfault with QEmu as well, and was ready to give up - but thanks to your advice, I have it working now and can start installing a toolchain to do some emulated native compilation for my many ARM-based PDAs.

Unknown said...

Hello

Thank you for the excellent HOWTO.

Can I ask, is it possible to get eth0 working? Would you have instructions for setting up QEMU eth0 emulation. This will make it easy to download packages and transfer files.

Thank you.

rabinnh said...

Excellent. I have a bunch of links that gave partial information. I downloaded ready-made images, but I needed to build an image from scratch and this saved me hours.

Many thanks.

Unknown said...

Wanted to say thanks for this mate.

Anonymous said...

Good tutorial. For whatever reason (using Debian Squeeze instead of Lenny?), mounting armdisk.img required a different offset value for me. This manifested as a mount error, "you must specify the filesystem type".

I googled around and found http://www.jefferyfernandez.id.au/2007/06/14/mounting-partitions-that-are-within-a-disk-image/ which demonstrated how to compute the correct offset for the partitions in a disk image. The gist is that you can use

fdisk -lu armdisk.img

to find the Start sector, and multiply by the sector size (probably 512) to get the correct offset value for the mount command. E.g. I had to do

# mount -o loop,offset=1048576 armdisk.img ~/arm/mnt

John Rose said...

On Ubuntu Lucid Desktop 64 bit, after downloading qemu 1.0: make gave:
/home/john/Software/RaspberryPi/qemu-1.0/linux-user/ioctls.h:187: error: ‘SNDCTL_DSP_MAPINBUF’ undeclared here (not in a function)
/home/john/Software/RaspberryPi/qemu-1.0/linux-user/ioctls.h:188: error: ‘SNDCTL_DSP_MAPOUTBUF’ undeclared here (not in a function)
/home/john/Software/RaspberryPi/qemu-1.0/linux-user/ioctls.h:243: error: ‘SOUND_MIXER_ACCESS’ undeclared here (not in a function)
make[1]: *** [syscall.o] Error 1
make: *** [subdir-i386-linux-user] Error 2

Help please!

John Rose said...

I've now installed qemu-system-arm directly on my Ubuntu 10.04 Desktop 64 bit OS instead of building it (due to Canonical nut putting package gcc-arm-linux-gnueabi on their repos for Lucid though it's there for Maverick onwards: I'm trying to record it on Launchpad but Canonical make life difficult when you try to record a missing package):

sudo add-apt-repository ppa:linaro-maintainers/tools
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install qemu-system

I've downloaded (from Debian's website Debian CD 6.0.4 Armel with lxde & xfce. Is this .iso useable with QEMU or with VirtualBox? If not, where can I download the vmlinuz &initrd.gz files for Debian 6.0.4 a required for your instructions?

Troy Test 1234 said...

Hi John,
This is a pretty old post so Lenny has rolled into legacy status for Debian. I should probably go through an update this for some new releases.

In the meanwhile you should be able to download what you need from the Debian archives:
http://archive.debian.org/debian-archive/debian/dists/lenny/main/

Hope this helps.

John Rose said...

It's not straightforward with getting, say, Debian Armel installed. I don't fully understand why but it's to do with the initial boot of the installer. I've found out how to install Debian Armel Standard & Desktop and that's explained very well (together with the necessary downloads) at
http://people.debian.org/~aurel32/qemu/armel/

Henri said...

I got problem with mount ;

mount: you must specify the filesystem type

I found an alternate way to mount disk with losetup :

sudo losetup /dev/loop0 ~/arm/armdisk.img
sudo kpartx -a /dev/loop0
sudo mount /dev/mapper/loop0p1 ~/arm/mount

Hope it will help

Unknown said...

But this only gives the console.
Is there any way to get the GUI??

Troy Test 1234 said...

Hi Sahil,
The intention here is really only to give a terminal based image for cross compilation etc. If you want a GUI I suggest you install X, and a VNC server and connect to the VNC server for your GUI.

Post a Comment