Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save eduard-sukharev/4f7449af2b108f28585d942784489f83 to your computer and use it in GitHub Desktop.
Save eduard-sukharev/4f7449af2b108f28585d942784489f83 to your computer and use it in GitHub Desktop.
Emulating ARM with QEMU on Debian/Ubuntu

Running ARM Debian/Ubuntu on QEMU

If the below is too much, you can try Ubuntu-ARMv7-Qemu but note it contains non-free blobs.

Architectures cheatsheet:

  • armel - emulated floating point (ARMv6 and older)
  • armhf - hardware floating point (ARMv7 and newer)
  • arm64 (aarch64, aarm64) - ARM with 64bit support (mainly ARMv8 and newer)

Cortex-A8, A9, A15 are all ARMv7 CPUs.

Good read

Install QEMU

sudo apt-get install qemu

Create a hard disk

Create a hard disk for your virtual machine with required capacity.

qemu-img create -f raw armdisk.img 8G

Chose CPU

You can get a list of all supported CPUs (to be passed with -cpu option, see later below):

qemu-system-arm -cpu help

You can get a list of all supported machines (to be passed with -M option, see later below):

qemu-system-arm -machine help

In this example we use cortex-a9 CPU and vexpress-a9 machine. This is an ARMv7 CPU which Debian calls as armhf (ARM hard float).

Note that you need armel for ARMv5, v6. Raspberry Pi uses ARMv6. In this case, the cpu is arm1176 and machine is versatilepb.

You can then install Debian using an ISO CD or Netboot over network

Netboot from vmlinuz

Select a directory for preferred distro from Debian repo and descend into ./main/installer-armhf/current/images/netboot. You must download vmlinuz and initrd files.

Create a virtual machine with 1024 MB RAM and a Cortex-A9 CPU.

qemu-system-arm -m 1024M -M vexpress-a9 \
                -kernel vmlinuz -initrd initrd.gz \
                -append "root=/dev/ram" -sd armdisk.img -no-reboot
  • Note that some kernels may not support PCI SCSI hard disks, hence -sd instead of -sda or -hda.

For ARMv6, use versatilepb for -M argument:

qemu-system-arm -m 1024M -M versatilepb \
                -kernel vmlinuz -initrd initrd.gz \
                -append "root=/dev/ram" -hda armdisk.img -no-reboot

This will start a new QEMU window and the Debian installer will kick-in. Just proceed with the installation (takes maybe 3 hours or so). Make sure you install "ssh-server" in tasksel screen.

First boot from newly installed system

You need to copy vmlinuz from the installed disk image and pass it again to qemu-system-img [Qemu wiki] (http://en.wikibooks.org/wiki/QEMU/Images#Mounting_an_image_on_the_host").

sudo modprobe nbd max_part=16
sudo qemu-nbd -c /dev/nbd0 armdisk.img
mkdir ~/qemu-mounted
sudo mount /dev/nbd0p1 ~/qemu-mounted
mkdir after-copy

cp ~/qemu-mounted/boot/* after-copy/

sudo umount ~/qemu-mounted
sudo qemu-nbd -d /dev/nbd0
sudo killall qemu-nbd

Then pass the copied kernel and initrd to qemu-system-img. Also note that we are now booting from /dev/sda1 because that is where Linux was installed

qemu-system-arm -M vexpress-a9 -m 1024M  \
                -kernel after-copy/vmlinuz \
                -initrd after-copy/initrd.img \
                -hda armdisk.img -append "root=/dev/mmcblk0p1"

For armel set -append "root=/dev/sda1" and modify -M as specified during installation.

Once again, note the device (mmcblk0p1) and partition (armhf.img) reflect SD-card usage.

Connecting to the SSH server

Login to the guest OS and create a private/public key pair: ssh-keygen -t rsa.

On the host, just redirect some random port from the host to guest's port 22 (or whichever port the SSH server is running on, see /etc/ssh/sshd_config)

qemu-system-arm ....  -redir tcp:5555::22 &

Then you can connect to SSH just like ssh -p 5555 localhost.

Chroot Voodoo your ARM VM (architectural chroot with QEMU)

After the install of your ARM, you will probably see that it is really slow. To speed up your arm, you can chroot it natively and let qemu-user-static interpret the ARM instruction. [5]

sudo apt-get install qemu-user-static kpartx

We mount the image using loopback

sudo kpartx -a -v armdisk.img
sudo mkdir /mnt/arm-vm
sudo mount /dev/mapper/loop0p2 /mnt/arm-vm

Copy the static binary

sudo cp /usr/bin/qemu-arm-static /mnt/arm-vm/usr/bin
sudo mount -o bind /proc /mnt/arm-vm/proc
sudo mount -o bind /dev /mnt/temp/dev
sudo mount -o bind /sys /mnt/temp/sys

We register qemu-arm-static as ARM interpreter to the kernel linux. [6]

#This can only be run as root (sudo don't work)
sudo su
echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:' > /proc/sys/fs/binfmt_misc/register
exit

Now we chroot to our VM.

sudo chroot /mnt/arm-vm

Let see if it work:

$ uname -a
Linux cis-linux-arm 2.6.32 #19-Ubuntu SMP Wed Oct 9 16:20:46 UTC 2013 armv7l GNU/Linux

N.B: After test, qemu 1.1 (Debian wheezy) had some strange behaviour but the 1.5 (Ubuntu saucy) was working perfectly !

When you finished your work you should unmount everything to avert bad behaviour. Do not forget to not start your VM with Qemu before unmount everything !

sudo umount /mnt/arm-vm/proc
sudo umount /mnt/arm-vm/dev
sudo umount /mnt/arm-vm/sys
sudo umount /mnt/arm-vm
sudo kpartx -d -v armdisk.img
References

[1] http://www.linuxforu.com/2011/05/quick-quide-to-qemu-setup/ [2] http://blog.troyastle.com/2010/07/building-arm-powered-debian-vm-with.html [3] Differences between ARM926, ARM1136, A8 and A9 [4] http://www.makestuff.eu/wordpress/running-debian-for-arm-powerpc-on-qemu/ [5] http://www.darrinhodges.com/chroot-voodoo/ [6] https://en.wikipedia.org/wiki/Binfmt_misc

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment