translatedcode

QEMU for and on ARM cores

Installing Debian on QEMU’s 32-bit ARM “virt” board

with 52 comments

In this post I’m going to describe how to set up Debian on QEMU emulating a 32-bit ARM “virt” board. There are a lot of older tutorials out there which suggest using boards like “versatilepb” or “vexpress-a9”, but these days “virt” is a far better choice for most people, so some documentation of how to use it seems overdue. (I may do a followup post for 64-bit ARM later.)

Update 2017-07-24: I have now written that post about installing a 64-bit ARM guest.

Why the “virt” board?

QEMU has models of nearly 50 different ARM boards, which makes it difficult for new users to pick one which is right for their purposes. This wild profusion reflects a similar diversity in the real hardware world: ARM systems come in many different flavours with very different hardware components and capabilities. A kernel which is expecting to run on one system will likely not run on another. Many of QEMU’s models are annoyingly limited because the real hardware was also limited — there’s no PCI bus on most mobile devices, after all, and a fifteen year old development board wouldn’t have had a gigabyte of RAM on it.

My recommendation is that if you don’t know for certain that you want a model of a specific device, you should choose the “virt” board. This is a purely virtual platform designed for use in virtual machines, and it supports PCI, virtio, a recent ARM CPU and large amounts of RAM. The only thing it doesn’t have out of the box is graphics, but graphical programs on a fully emulated system run very slowly anyway so are best avoided.

Why Debian?

Debian has had good support for ARM for a long time, and with the Debian Jessie release it has a “multiplatform” kernel, so there’s no need to build a custom kernel. Because we’re installing a full distribution rather than a cut-down embedded environment, any development tools you need inside the VM will be easy to install later.

Prerequisites and assumptions

I’m going to assume you have a Linux host, and a recent version of QEMU (at least QEMU 2.6). I also use libguestfs to extract files from a QEMU disk image, but you could use a different tool for that step if you prefer.

Getting the installer files

I suggest creating a subdirectory for these and the other files we’re going to create.

To install on QEMU we will want the multiplatform “armmp” kernel and initrd from the Debian website:

wget -O installer-vmlinuz http://http.us.debian.org/debian/dists/jessie/main/installer-armhf/current/images/netboot/vmlinuz
wget -O installer-initrd.gz http://http.us.debian.org/debian/dists/jessie/main/installer-armhf/current/images/netboot/initrd.gz

Saving them locally as installer-vmlinuz and installer-initrd.gz means they won’t be confused with the final kernel and initrd that the installation process produces.

(If we were installing on real hardware we would also need a “device tree” file to tell the kernel the details of the exact hardware it’s running on. QEMU’s “virt” board automatically creates a device tree internally and passes it to the kernel, so we don’t need to provide one.)

Installing

First we need to create an empty disk drive to install onto. I picked a 5GB disk but you can make it larger if you like.

qemu-img create -f qcow2 hda.qcow2 5G

(Oops — an earlier version of this blogpost created a “qcow” format image, which will work but is less efficient. If you created a qcow image by mistake, you can convert it to qcow2 with mv hda.qcow2 old-hda.qcow && qemu-img convert -O qcow2 old-hda.qcow hda.qcow2. Don’t try it while the VM is running! You then need to update your QEMU command line to say “format=qcow2” rather than “format=qcow”. You can delete the old-hda.qcow once you’ve checked that the new qcow2 file works.)

Now we can run the installer:

qemu-system-arm -M virt -m 1024 \
  -kernel installer-vmlinuz \
  -initrd installer-initrd.gz \
  -drive if=none,file=hda.qcow2,format=qcow2,id=hd \
  -device virtio-blk-device,drive=hd \
  -netdev user,id=mynet \
  -device virtio-net-device,netdev=mynet \
  -nographic -no-reboot

(I would have preferred to use QEMU’s PCI virtio devices, but unfortunately the Debian kernel doesn’t support them; a future Debian release very likely will, which would allow you to use virtio-blk-pci and virtio-net-pci instead of virtio-blk-device and virtio-net-device.)

The installer will display its messages on the text console (via an emulated serial port). Follow its instructions to install Debian to the virtual disk; it’s straightforward, but if you have any difficulty the Debian release manual may help.
(Don’t worry about all the warnings the installer kernel produces about GPIOs when it first boots.)

The actual install process will take a few hours as it downloads packages over the network and writes them to disk. It will occasionally stop to ask you questions.

Late in the process, the installer will print the following warning dialog:

   +-----------------| [!] Continue without boot loader |------------------+
   |                                                                       |
   |                       No boot loader installed                        |
   | No boot loader has been installed, either because you chose not to or |
   | because your specific architecture doesn't support a boot loader yet. |
   |                                                                       |
   | You will need to boot manually with the /vmlinuz kernel on partition  |
   | /dev/vda1 and root=/dev/vda2 passed as a kernel argument.             |
   |                                                                       |
   |                              <Continue>                               |
   |                                                                       |
   +-----------------------------------------------------------------------+  

Press continue for now, and we’ll sort this out later.

Eventually the installer will finish by rebooting — this should cause QEMU to exit (since we used the -no-reboot option).

At this point you might like to make a copy of the hard disk image file, to save the tedium of repeating the install later.

Extracting the kernel

The installer warned us that it didn’t know how to arrange to automatically boot the right kernel, so we need to do it manually. For QEMU that means we need to extract the kernel the installer put into the disk image so that we can pass it to QEMU on the command line.

There are various tools you can use for this, but I’m going to recommend libguestfs, because it’s the simplest to use. To check that it works, let’s look at the partitions in our virtual disk image:

$ virt-filesystems -a hda.qcow2 
/dev/sda1
/dev/sda2

If this doesn’t work, then you should sort that out first. A couple of common reasons I’ve seen:

  • if you’re on Ubuntu then your kernels in /boot are installed not-world-readable; you can fix this with sudo chmod 644 /boot/vmlinuz*
  • if you’re running Virtualbox on the same host it will interfere with libguestfs’s attempt to run KVM; you can fix that by exiting Virtualbox

Looking at what’s in our disk we can see the kernel and initrd in /boot:

$ virt-ls -a hda.qcow2 /boot/
System.map-3.16.0-4-armmp-lpae
config-3.16.0-4-armmp-lpae
initrd.img
initrd.img-3.16.0-4-armmp-lpae
lost+found
vmlinuz
vmlinuz-3.16.0-4-armmp-lpae

and we can copy them out to the host filesystem:

$ virt-copy-out -a hda.qcow2 /boot/vmlinuz-3.16.0-4-armmp-lpae /boot/initrd.img-3.16.0-4-armmp-lpae .

(We want the longer filenames, because vmlinuz and initrd.img are just symlinks and virt-copy-out won’t copy them.)

An important warning about libguestfs, or any other tools for accessing disk images from the host system: do not try to use them while QEMU is running, or you will get disk corruption when both the guest OS inside QEMU and libguestfs try to update the same image.

Running

To run the installed system we need a different command line which boots the installed kernel and initrd, and passes the kernel the command line arguments the installer told us we’d need:

qemu-system-arm -M virt -m 1024 \
  -kernel vmlinuz-3.16.0-4-armmp-lpae \
  -initrd initrd.img-3.16.0-4-armmp-lpae \
  -append 'root=/dev/vda2' \
  -drive if=none,file=hda.qcow2,format=qcow2,id=hd \
  -device virtio-blk-device,drive=hd \
  -netdev user,id=mynet \
  -device virtio-net-device,netdev=mynet \
  -nographic

This should boot to a login prompt, where you can log in with the user and password you set up during the install.

The installation has an SSH client, so one easy way to get files in and out is to use “scp” from inside the VM to talk to an SSH server outside it. Or you can use libguestfs to write files directly into the disk image (for instance using virt-copy-in) — but make sure you only use libguestfs when the VM is not running, or you will get disk corruption.

Advertisement

Written by pm215

November 3, 2016 at 10:33 pm

Posted in linaro, qemu

52 Responses

Subscribe to comments with RSS.

  1. Hi thanks so much for this tutorial. I am really interested in the virt board’s possibilities but not finding much info (as the main qemu page just points to this article for now). For versatilepb we have the following: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0224i/index.html but would you know if there anything for virt — or is it known as another name? As I’m starting out I was really hoping to have a reference doc. Thanks!

    Ben

    November 15, 2016 at 12:15 am

    • There isn’t any specific documentation on exactly what the virt board has in it, I’m afraid. In general the idea is that the virt board will autogenerate a device tree (or ACPI tables) which tell the guest OS what components it has in it, and the guest OS will read that and do the right thing. Since (unlike versatilepb) it isn’t a model of a specific piece of real-world hardware there’s no third-party documentation the way there is for versatilepb.

      pm215

      November 27, 2016 at 5:56 pm

  2. I was trying to run qemu for raspberry PI 3 (which apprears to not be supported). I am following a youtube video and when I try to edit a file in /arm, it does not exist. Any suggestions, etc? This is the command I am trying to run from youtube.

    sudo nano /home/pi/raspidev/qemu/tcg/arm/tcg-targe­t.c

    youtube vid

    Really just trying to run WindowsXP or some other windows emulated OS.

    Steve Klise

    December 29, 2016 at 4:48 pm

    • The file has moved in the QEMU source tree and is now at tcg/arm/tcg-target.inc.c. Things do move around in the QEMU sources so if you’re following instructions on how to edit things you need to adjust for changes that have happened since the instructions were written.

      In this case the function the instructions want you to edit has been removed entirely. I would suggest just building QEMU without trying to edit any of its source files. If the compilation fails with an error message then let me know, because we can fix that bug in QEMU (but it may have been fixed already).

      PS: as those instructions note, it’s likely that the resulting setup will be too slow to run Windows usefully anyway.

      pm215

      December 30, 2016 at 11:43 am

      • AM now getting this. I was able to edit the files………..
        ————————————————————————————————————————————–

        In file included from /usr/include/string.h:640:0,
        from /home/pi/xpstuff/qemu/slirp/slirp.h:66,
        from slirp/misc.c:8:
        In function ‘memset’,
        inlined from ‘slirp_connection_info’ at slirp/misc.c:401:9:
        /usr/include/arm-linux-gnueabihf/bits/string3.h:81:7: error: call to ‘__warn_memset_zero_len’ declared with attribute warning: memset used with constant zero length parameter; this could be due to transposed parameters [-Werror]
        __warn_memset_zero_len ();
        ^
        cc1: all warnings being treated as errors
        /home/pi/xpstuff/qemu/rules.mak:18: recipe for target ‘slirp/misc.o’ failed
        make: *** [slirp/misc.o] Error 1
        pi@raspberrypi:~/xpstuff/qemu $ sudo make install
        CC slirp/misc.o
        In file included from /usr/include/string.h:640:0,
        from /home/pi/xpstuff/qemu/slirp/slirp.h:66,
        from slirp/misc.c:8:
        In function ‘memset’,
        inlined from ‘slirp_connection_info’ at slirp/misc.c:401:9:
        /usr/include/arm-linux-gnueabihf/bits/string3.h:81:7: error: call to ‘__warn_memset_zero_len’ declared with attribute warning: memset used with constant zero length parameter; this could be due to transposed parameters [-Werror]
        __warn_memset_zero_len ();
        ^
        cc1: all warnings being treated as errors
        /home/pi/xpstuff/qemu/rules.mak:18: recipe for target ‘slirp/misc.o’ failed
        make: *** [slirp/misc.o] Error 1
        pi@raspberrypi:~/xpstuff/qemu $

        Steve Klise

        December 30, 2016 at 5:05 pm

        • You seem to be trying to build a really ancient version of QEMU — that compile issue was fixed in QEMU upstream four years ago, and looking at the tarball the video instructions reference it is a five year old random development snapshot. Trying to build something that old you’re likely to run into other problems that have already been fixed. I suggest you try a newer release instead.

          pm215

          December 30, 2016 at 6:29 pm

    • is there a way to mount a share folder?
      i tried with “mount -t 9p -o trans=virtio,version=9p2000.L …” but i get “9pnet: Could not find request transport: virtio”
      i think that is because there is no support for PCI virtio devices.

      alexvdan

      August 3, 2018 at 2:24 pm

      • I’ve never tried to use the 9p stuff. Probably your guess is correct. You’ll also need to use the right QEMU command line to enable the virtio-9p device (this should be about the same as for doing it on x86.) You could try a newer kernel with virtio-pci support in it, or to adjust your command line to use virtio-mmio.

        pm215

        August 3, 2018 at 2:35 pm

  3. For my convenience I added a new VM for the ARM image to the Virtual Machine Manager. At step 1 select “Import existing disk image”, then in “Architectural Options” select “Arm”. “Machine Type will be “virt”. Click “Forward”. In step 2, enter the location of the image and its name in the first box. Add the paths and names of the initrd and kernel in the appropriate boxes and add “root=/dev/vda2” in the Kernel args box. DTB path can be left empty. Click “Forward”. In step 3 set the RAM and CPUs and click “Forward”. In step 4 check the box “Customize configuration before install” and click “Finish”. In the dialog that pops up select “SCSI Disk 1”. Open the Advanced options and click the drop down where it says “Disk bus”. Select “VirtIO”, then click “Apply”. Click “Begin Installation” at the top and the Virtual Machine Manager will create an entry for your machine and boot it. It all seems to work after that but some tweaking may be required.

    Cliff Pratt

    January 15, 2017 at 10:40 pm

  4. When I run the installer command, I get no output at all, as if the console was not properly redirected

    You need to add -append “console=ttyAMA0”

    pock

    February 14, 2017 at 9:37 am

    • Hmm, pretty sure it worked without for me, but certainly adding that append line won’t hurt.

      pm215

      February 14, 2017 at 9:58 am

  5. You mention that you would prefer to use virtio-pci devices, but that this is currently not supported by the debian kernel. Could you explain why this is the case?
    From my own experiments I also found that the debian kernel fails to recognize any PCI-devices of the qemu’s “virt” machine, however I was only able to find your blog post mentioning the problem.

    (There was also a comment in qemu’s 2.5 release notes that some kernels without CONFIG_LPAE=y will fail to detect the PCI controller if the flag “-machine highmem=off” was not used. However, neither setting the flag nor using a LPAE-kernel seems to help.)

    Best,
    Johannes

    Johannes Krupp

    February 22, 2017 at 12:12 pm

    • It’s just that the changes needed to get PCI supported went into the kernel relatively recently, and Debian’s release cycles mean that their stable kernel is just older than the necessary support/config changes. I expect that when the next Debian release happens (very shortly) PCI should just work, though I haven’t tested. (You could also try using Debian ‘testing’ for the moment.)

      pm215

      February 22, 2017 at 12:31 pm

  6. I’am very interesting for the 64 version of this tutorial. ; )
    Coming soon ?

    snak3xe

    July 20, 2017 at 12:24 pm

    • Heh, I’d forgotten I’d said I would do the 64-bit version. I’ll try to get to that this week or next…

      pm215

      July 20, 2017 at 12:56 pm

      • Thanks a lot. ; )

        snak3xe

        July 20, 2017 at 1:42 pm

        • I’ve now published the 64-bit install instructions post.

          pm215

          July 24, 2017 at 10:32 am

          • Do you have a quickly solution to bridge a network interface directly to the guest and not system dependant? I try the bridge feature of qemu but not work.

            On the host:

            # ip link add br0 type bridge

            # ip addr flush dev eth0

            # ip link set eth0 master br0

            and I add this to the qemu command line

            -netdev bridge,id=hn0
            -device virtio-net-device,netdev=hn0,id=nic1

            # ip link

            3: eth0: mtu 1500 qdisc fq_codel master br0 state UP mode DEFAULT group default qlen 1000
            link/ether 20:47:47:bb:51:ca brd ff:ff:ff:ff:ff:ff
            34: br0: mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
            link/ether 20:47:47:bb:51:ca brd ff:ff:ff:ff:ff:ff
            35: tap0: mtu 1500 qdisc fq_codel master br0 state UNKNOWN mode DEFAULT group default qlen 1000
            link/ether fe:23:18:f4:c6:31 brd ff:ff:ff:ff:ff:ff

            Next in the guest, I have an eth0 network interface, but dhcpclient fail.

            At boot time:

            [* ] A start job is running for LSB: Raise network interf…38s / no limit

            [FAILED] Failed to start LSB: IPv4 DHCP client with IPv4LL support.
            See ‘systemctl status dhcpcd.service’ for details.

            # systemctl status dhcpcd.service -l

            Jul 25 20:29:17 solid dhcpcd[276]: Not running dhcpcd because /etc/network/interfaces … failed!
            Jul 25 20:29:17 solid dhcpcd[276]: defines some interfaces that will use a DHCP client … failed!
            Jul 25 20:29:17 solid systemd[1]: dhcpcd.service: control process exited, code=exited status=6
            Jul 25 20:29:17 solid systemd[1]: Failed to start LSB: IPv4 DHCP client with IPv4LL support.
            Jul 25 20:29:17 solid systemd[1]: Unit dhcpcd.service entered failed state.

            # cat /etc/network/interfaces

            source /etc/network/interfaces.d/*

            auto lo
            iface lo inet loopback

            allow-hotplug eth0
            iface eth0 inet dhcp

            With dhcpcd:

            # dhcpcd eth0
            dhcpcd[560]: version 6.0.5 starting
            dhcpcd[560]: eth0: soliciting an IPv6 router
            dhcpcd[560]: eth0: using IPv4LL address 169.254.41.139
            dhcpcd[560]: eth0: adding host route to 169.254.41.139 via 127.0.0.1
            dhcpcd[560]: eth0: adding route to 169.254.0.0/16
            dhcpcd[560]: forked to background, child pid 583

            snak3xe

            July 25, 2017 at 7:40 pm

            • Afraid not — I’ve never used anything except ‘user’ networking. There should be no difference on ARM to getting this working with an x86 VM, though, so there should be plenty of tutorials out there.

              pm215

              July 25, 2017 at 8:32 pm

            • UPDATE

              I’am on Archlinux and I have fix the problem with the bridge interface with the following iptables rules:

              # iptables -A INPUT -i tap0 -j ACCEPT
              # iptables -A INPUT -i br0 -j ACCEPT
              # iptables -A FORWARD -i br0 -j ACCEPT

              snak3xe

              July 27, 2017 at 8:28 pm

  7. yeh ok

    snak3xe

    July 25, 2017 at 10:22 pm

  8. Hi, and thank you very much for this tutorial!
    Just as a reference for any other newbie (like me) in the Linux development, I’ve faced some issues with extracting kernel and initrd from virtual image file to host filesystem.
    Finally I solved using these 2 commands:

    $ virt-copy-out -a hda.qcow2 /boot/vmlinuz-3.16.0-4-armmp-lpae
    $ virt-copy-out -a hda.qcow2 /boot/initrd.img-3.16.0-4-armmp-lpae

    where is he folder where I’ve created the virtual image file hda.qcow2.

    mattia781

    August 31, 2017 at 10:06 am

    • Commands are:

      $ virt-copy-out -a hda.qcow2 /boot/vmlinuz-3.16.0-4-armmp-lpae local-host-folder
      $ virt-copy-out -a hda.qcow2 /boot/initrd.img-3.16.0-4-armmp-lpae local-host-folder

      where local-host-folder is the folder where I’ve created the virtual image file hda.qcow2

      mattia781

      August 31, 2017 at 10:08 am

  9. A question: is it possible to open a second terminal of the virtual machine?
    Using keys ctrl+shift+t a terminal of the host system is opened; using xdotool to emulate this same key sequence, I obtain the error “Can’t open diplay: (null) Failed creating new xdo instance”.

    mattia781

    September 1, 2017 at 1:16 pm

    • It’s a serial terminal, not a graphical window system, so you can’t just open new terminals like that. Probably the best approach is to run an ssh daemon inside the VM, configure QEMU’s networking to forward from (say) host port 2222 to VM port 22 (which is ssh), and then ssh to the host port 2222 to get another login.

      pm215

      September 1, 2017 at 1:34 pm

      • It works: thanks!

        mattia781

        September 1, 2017 at 3:05 pm

  10. hi,
    is there a chance to run Xorg ?

    sacarde

    October 18, 2017 at 9:01 pm

  11. Hi,

    For a custom OS testing using virt, should we have the hassle to have a tree parser as well?
    It defeats a bit the simplicity of the virt machine.. We just need to print datas on screen with a minimal amount of code..
    What would be another solution?

    Thanks

    Mark

    November 6, 2017 at 4:44 pm

    • “virt” is designed primarily as a VM platform for Linux and similar OSes. Yes, this means ‘virt’ isn’t such a great platform for “bare metal” toy projects, but that’s the tradeoff for making it flexible enough that we can expand/adjust it as the needs of the VM platforms change. libfdt isn’t very heavyweight, though, so I don’t think it’s a terribly onerous depenency.

      If you literally only need to print things (the classic example is small test cases), consider the semihosting ABI (pass -semihosting to QEMU, use a simple “print this string to stdout” SVC interface — https://static.docs.arm.com/100863/0200/semihosting.pdf — but beware that you’re trusting your guest code with pretty wide control over your host including writing arbitrary files).

      pm215

      November 6, 2017 at 4:51 pm

      • Thanks,

        I think it is too much privilege, yes. I will use a similar board and correct the bits for the final executable..

        Bye!

        Mark

        November 6, 2017 at 7:34 pm

  12. Hi Peter,

    interesting article – many thanks for writing this up! I tried using the “virt” target using virt-manager, but I don’t get any output on the serial console. Using vexpress-a15 it works (as described in my blog post https://blogs.fsfe.org/kuleszdl/2016/11/06/installing-a-libre-low-power-low-cost-kvm-virtualization-host/).

    The interesting thing is that it works with the “virt” target when running the kernel zimage from LEDE (available here https://downloads.lede-project.org/releases/17.01.4/targets/armvirt/generic/), so I wonder what could be causing this. Also, I did not succeed getting output from the ArchLinux “alarm” kernel, while it works fine with versatile-a15 (just like debian).

    Any ideas what could be the cause here?

    Cheers, Daniel

    Daniel Kulesz

    November 15, 2017 at 1:18 pm

    • Nope, I’ve never used virt-manager, I’m afraid.

      pm215

      November 15, 2017 at 1:23 pm

      • I see. I grepped the command-line-call that is issued by virt-manager when starting up the VM, using the virt-machine type that works with lede but does not with debian or Arch:

        /usr/bin/qemu-system-arm -name lede-test -S -machine virt,accel=kvm,usb=off -cpu host -m 1024 -realtime mlock=off -smp 1,sockets=1,cores=1,threads=1 -uuid 864f8fc6-0b61-4c5b-82d3-106d8cd596cc -nographic -no-user-config -nodefaults -chardev socket,id=charmonitor,path=/var/lib/libvirt/qemu/lede-test.monitor,server,nowait -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc -no-shutdown -boot strict=on -kernel /guest-test/vmlinuz-installer-jessie -device virtio-scsi-device,id=scsi0 -usb -drive file=/var/lib/libvirt/images/lede-test.qcow2,if=none,id=drive-scsi0-0-0-0,format=qcow2 -device scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=0,drive=drive-scsi0-0-0-0,id=scsi0-0-0-0,bootindex=1 -netdev tap,fd=23,id=hostnet0 -device virtio-net-device,netdev=hostnet0,id=net0,mac=52:54:00:71:f2:08 -serial pty -msg timestamp=on

        Any ideas? Also, regarding your way to run the qemu binary directly: Do you get any output on the console over SSH or did you try only with the host device attached locally to HDMI or similar? Myself, I am not getting any output over SSH for any of the kernels (lede, debian, arch).

        Cheers, Daniel

        Daniel Kulesz

        November 15, 2017 at 2:16 pm

        • If it works with one kernel but not with another then the chances are high that the non-working kernel is not configured with enough devices to work. Compare the two kernel configs, or ask the people who maintain the non-working kernel for advice.

          Regarding output: the command lines in this blog post put the guest’s serial port output on the stdin/stdout of wherever you run the QEMU binary. That’s separate from whether you configure the guest to run a sshd, and it doesn’t care whether your terminal is something on the host you ssh’d into or you’re running an xterm.

          pm215

          November 15, 2017 at 2:21 pm

          • After some more trial-and-error I found that the issue is related to the console= parameter as outlined in one of the previous comments. I tried the fedora image (described here https://fedoraproject.org/wiki/QA:Testcase_Virt_ARM_on_x86) which worked fine. After playing with the options, I found that

            console=ttyAMA0

            is definitely needed. I tested a number of kernels (debian jessie, debian stretch, arch, fedora) and they all seem to work fine now using virt-manager, the serial console and the “virt” machine. Yet, I was unable to get the output on the SSH terminal when running qemu directly. Did you use a x86 virtualization host or (like me) an ARMv7 machine directly?

            Daniel Kulesz

            November 15, 2017 at 4:04 pm

            • I run all these on x86. This should make no difference though: nothing cares at that level. (Only the guest will care about the ‘console=ttyAMA0’ part.) QEMU cares not at all whether its stdout is via ssh, xterm, redirected to a file or sent to /dev/null.

              pm215

              November 15, 2017 at 4:13 pm

  13. Thanks for this tutorial. It really helped me out!

    Brandon L White

    March 26, 2018 at 10:19 pm

  14. Hi i am pretty newbie to kernel . I am trying to boot old kernel with qemu-system-arm for “virt” board . It seems to work for Kernel version 3.17.1 and after . But for Kernel 3.16.7 and before it fails . it just hangs . can you please tell what files in kernel needs to changed in Kernel 3.16.7.
    i ported some changes from virt directory in 3.17.1 to 3.16.7 . But it does not work .

    config file related to Virt are enabled in both 3.17.1 and 3.16.7

    CONFIG_ARM_PATCH_PHYS_VIRT=y
    # CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
    CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
    CONFIG_ARCH_VIRT=y
    CONFIG_ARM_VIRT_EXT=y
    CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
    # CONFIG_FB_VIRTUAL is not set
    # CONFIG_SND_VIRTUOSO is not set
    CONFIG_DMA_VIRTUAL_CHANNELS=y
    # CONFIG_VIRT_DRIVERS is not set
    # CONFIG_VIRTIO_PCI is not set
    # CONFIG_VIRTIO_MMIO is not set
    CONFIG_DEBUG_UART_VIRT=0xfd000000
    # CONFIG_VIRTUALIZATION is not set

    booting log for 3.17.1
    ****************************

    $ /data2/AIngale/qeMu/qemu-2.12.0-rc3/arm-softmmu/qemu-system-arm -M virt -m 1024 -kernel arch/arm/boot/zImage -initrd ../initramfs -nographic
    [ 0.000000] Booting Linux on physical CPU 0x0
    [ 0.000000] Linux version 3.17.1 (AIngale@swpfintbld03) (gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-12ubuntu1) ) #1 SMP Wed Apr 18 18:13:39 IST 2018
    [ 0.000000] CPU: ARMv7 Processor [412fc0f1] revision 1 (ARMv7), cr=10c5387d
    [ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, PIPT instruction cache
    [ 0.000000] Machine model: linux,dummy-virt
    [ 0.000000] cma: Reserved 64 MiB at 6b800000
    [ 0.000000] Memory policy: Data cache writealloc
    [ 0.000000] psci: probing for conduit method from DT.
    [ 0.000000] psci: PSCIv0.2 detected in firmware.
    [ 0.000000] psci: Using standard PSCI v0.2 function IDs
    [ 0.000000] PERCPU: Embedded 8 pages/cpu @eafc5000 s8448 r8192 d16128 u32768
    [ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 260624
    [ 0.000000] Kernel command line:
    [ 0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes)
    [ 0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
    [ 0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
    [ 0.000000] Memory: 961892K/1048576K available (6667K kernel code, 923K rwdata, 2684K rodata, 696K init, 305K bss, 86684K reserved, 270336K highmem)
    [ 0.000000] Virtual kernel memory layout:
    [ 0.000000] vector : 0xffff0000 – 0xffff1000 ( 4 kB)
    [ 0.000000] fixmap : 0xffc00000 – 0xffe00000 (2048 kB)
    [ 0.000000] vmalloc : 0xf0000000 – 0xff000000 ( 240 MB)
    [ 0.000000] lowmem : 0xc0000000 – 0xef800000 ( 760 MB)
    [ 0.000000] pkmap : 0xbfe00000 – 0xc0000000 ( 2 MB)
    [ 0.000000] modules : 0xbf000000 – 0xbfe00000 ( 14 MB)
    [ 0.000000] .text : 0xc0208000 – 0xc0b2a1ec (9353 kB)
    [ 0.000000] .init : 0xc0b2b000 – 0xc0bd9100 ( 697 kB)
    [ 0.000000] .data : 0xc0bda000 – 0xc0cc0ca0 ( 924 kB)
    [ 0.000000] .bss : 0xc0cc0ca0 – 0xc0d0d1e0 ( 306 kB)
    [ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
    [ 0.000000] Hierarchical RCU implementation.
    [ 0.000000] RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=1.
    [ 0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1
    [ 0.000000] NR_IRQS:16 nr_irqs:16 16
    [ 0.000000] GIC CPU mask not found – kernel will fail to boot.
    [ 0.000000] GIC CPU mask not found – kernel will fail to boot.
    [ 0.000000] Architected cp15 timer(s) running at 62.50MHz (virt).
    [ 0.000293] sched_clock: 56 bits at 62MHz, resolution 16ns, wraps every 2199023255552ns
    [ 0.000445] Switching to timer-based delay loop, resolution 16ns
    [ 0.011192] Console: colour dummy device 80×30
    [ 0.013331] console [tty0] enabled
    [ 0.014373] Calibrating delay loop (skipped), value calculated using timer frequency.. 125.00 BogoMIPS (lpj=312500)
    [ 0.014695] pid_max: default: 32768 minimum: 301
    [ 0.016192] Mount-cache hash table entries: 2048 (order: 1, 8192 bytes)
    [ 0.016290] Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes)
    [ 0.027389] CPU: Testing write buffer coherency: ok
    [ 0.037004] /cpus/cpu@0 missing clock-frequency property
    [ 0.037382] CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
    [ 0.038360] Setting up static identity map for 0x4084c1a0 – 0x4084c238
    [ 0.049932] Brought up 1 CPUs
    [ 0.050027] SMP: Total of 1 processors activated.
    [ 0.050140] CPU: All CPU(s) started in SVC mode.
    [ 0.065282] devtmpfs: initialized
    [ 0.086873] VFP support v0.3: implementor 41 architecture 4 part 30 variant f rev 0
    [ 0.111482] pinctrl core: initialized pinctrl subsystem
    [ 0.125145] regulator-dummy: no parameters
    [ 0.136785] NET: Registered protocol family 16
    [ 0.150937] DMA: preallocated 256 KiB pool for atomic coherent allocations
    [ 0.155855] cpuidle: using governor ladder
    [ 0.156049] cpuidle: using governor menu
    [ 0.179810] No ATAGs?
    [ 0.180430] hw-breakpoint: found 5 (+1 reserved) breakpoint and 4 watchpoint registers.
    [ 0.180594] hw-breakpoint: maximum watchpoint size is 8 bytes.
    [ 0.181226] EXYNOS: PMU not supported
    [ 0.185203] Serial: AMBA PL011 UART driver
    [ 0.187117] 9000000.pl011: ttyAMA0 at MMIO 0x9000000 (irq = 33, base_baud = 0) is a PL011 rev1
    [ 0.197583] console [ttyAMA0] enabled
    [ 0.231350] edma-dma-engine edma-dma-engine.0: Can’t allocate PaRAM dummy slot
    [ 0.231886] edma-dma-engine: probe of edma-dma-engine.0 failed with error -22
    [ 0.236590] vgaarb: loaded
    [ 0.239164] SCSI subsystem initialized
    [ 0.241199] usbcore: registered new interface driver usbfs
    [ 0.241612] usbcore: registered new interface driver hub
    [ 0.242130] usbcore: registered new device driver usb
    [ 0.244068] Linux video capture interface: v2.00
    [ 0.244462] pps_core: LinuxPPS API ver. 1 registered
    [ 0.244641] pps_core: Software ver. 5.3.6 – Copyright 2005-2007 Rodolfo Giometti
    [ 0.245025] PTP clock support registered
    [ 0.245733] EDAC MC: Ver: 3.0.0
    [ 0.248370] Advanced Linux Sound Architecture Driver Initialized.
    [ 0.256275] Switched to clocksource arch_sys_counter
    [ 0.282801] NET: Registered protocol family 2
    [ 0.287184] TCP established hash table entries: 8192 (order: 3, 32768 bytes)
    [ 0.287575] TCP bind hash table entries: 8192 (order: 4, 65536 bytes)
    [ 0.288020] TCP: Hash tables configured (established 8192 bind 8192)
    [ 0.288668] TCP: reno registered
    [ 0.288908] UDP hash table entries: 512 (order: 2, 16384 bytes)
    [ 0.289202] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
    [ 0.291036] NET: Registered protocol family 1
    [ 0.293953] RPC: Registered named UNIX socket transport module.
    [ 0.294179] RPC: Registered udp transport module.
    [ 0.294327] RPC: Registered tcp transport module.
    [ 0.294459] RPC: Registered tcp NFSv4.1 backchannel transport module.
    [ 0.301600] Unpacking initramfs…
    [ 0.318156] Freeing initrd memory: 576K (c8000000 – c8090000)
    [ 0.322058] futex hash table entries: 256 (order: 2, 16384 bytes)
    [ 0.341986] squashfs: version 4.0 (2009/01/31) Phillip Lougher
    [ 0.346770] NFS: Registering the id_resolver key type
    [ 0.347715] Key type id_resolver registered
    [ 0.347891] Key type id_legacy registered
    [ 0.348489] msgmni has been set to 1479
    [ 0.352168] bounce: pool size: 64 pages
    [ 0.352814] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 249)
    [ 0.353280] io scheduler noop registered
    [ 0.353443] io scheduler deadline registered
    [ 0.354030] io scheduler cfq registered (default)
    [ 0.363376] pl061_gpio 9030000.pl061: PL061 GPIO chip @0x09030000 registered
    [ 0.488158] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
    [ 0.491350] of_dma_request_slave_channel: dma-names property of node ‘/pl011@9000000’ missing or empty
    [ 0.491696] uart-pl011 9000000.pl011: no DMA platform data
    [ 0.492276] Serial: IMX driver
    [ 0.493036] msm_serial: driver initialized
    [ 0.494042] STMicroelectronics ASC driver initialized
    [ 0.495572] serial: Freescale lpuart driver
    [ 0.496476] [drm] Initialized drm 1.1.0 20060810
    [ 0.507155] loop: module loaded
    [ 0.514000] CAN device driver interface
    [ 0.515386] igb: Intel(R) Gigabit Ethernet Network Driver – version 5.2.13-k
    [ 0.515597] igb: Copyright (c) 2007-2014 Intel Corporation.
    [ 0.518025] pegasus: v0.9.3 (2013/04/25), Pegasus/Pegasus II USB Ethernet driver
    [ 0.518373] usbcore: registered new interface driver pegasus
    [ 0.518712] usbcore: registered new interface driver asix
    [ 0.519000] usbcore: registered new interface driver ax88179_178a
    [ 0.519298] usbcore: registered new interface driver cdc_ether
    [ 0.519612] usbcore: registered new interface driver smsc75xx
    [ 0.519929] usbcore: registered new interface driver smsc95xx
    [ 0.520204] usbcore: registered new interface driver net1080
    [ 0.520471] usbcore: registered new interface driver cdc_subset
    [ 0.520874] usbcore: registered new interface driver zaurus
    [ 0.521289] usbcore: registered new interface driver cdc_ncm
    [ 0.521615] ehci_hcd: USB 2.0 ‘Enhanced’ Host Controller (EHCI) Driver
    [ 0.521852] ehci-pci: EHCI PCI platform driver
    [ 0.522277] ehci-platform: EHCI generic platform driver
    [ 0.522762] ehci-omap: OMAP-EHCI Host Controller driver
    [ 0.523163] ehci-orion: EHCI orion driver
    [ 0.523536] SPEAr-ehci: EHCI SPEAr driver
    [ 0.523885] tegra-ehci: Tegra EHCI driver
    [ 0.524291] ohci_hcd: USB 1.1 ‘Open’ Host Controller (OHCI) Driver
    [ 0.524565] ohci-pci: OHCI PCI platform driver
    [ 0.524958] ohci-platform: OHCI generic platform driver
    [ 0.525370] ohci-omap3: OHCI OMAP3 driver
    [ 0.525876] SPEAr-ohci: OHCI SPEAr driver
    [ 0.527501] usbcore: registered new interface driver usb-storage
    [ 0.531132] mousedev: PS/2 mouse device common for all mice
    [ 0.536390] rtc-pl031 9010000.pl031: rtc core: registered pl031 as rtc0
    [ 0.538565] i2c /dev entries driver
    [ 0.540699] usbcore: registered new interface driver uvcvideo
    [ 0.541037] USB Video Class driver (1.1.1)
    [ 0.541215] gspca_main: v2.14.0 registered
    [ 0.548635] sdhci: Secure Digital Host Controller Interface driver
    [ 0.548827] sdhci: Copyright(c) Pierre Ossman
    [ 0.550339] Synopsys Designware Multimedia Card Interface Driver
    [ 0.551639] sdhci-pltfm: SDHCI platform and OF driver helper
    [ 0.553961] usbcore: registered new interface driver usbhid
    [ 0.554138] usbhid: USB HID core driver
    [ 0.563129] TCP: cubic registered
    [ 0.563289] NET: Registered protocol family 17
    [ 0.563559] can: controller area network core (rev 20120528 abi 9)
    [ 0.564067] NET: Registered protocol family 29
    [ 0.564294] can: raw protocol (rev 20120528)
    [ 0.564498] can: broadcast manager protocol (rev 20120528 t)
    [ 0.564729] can: netlink gateway (rev 20130117) max_hops=1
    [ 0.566059] Key type dns_resolver registered
    [ 0.566332] ThumbEE CPU extension supported.
    [ 0.566543] Registering SWP/SWPB emulation handler
    [ 0.571568] gpio-keys gpio-keys: Failed to request GPIO 1019, error -517
    [ 0.571992] platform gpio-keys: Driver gpio-keys requests probe deferral
    [ 0.573071] rtc-pl031 9010000.pl031: setting system clock to 2018-04-18 12:47:27 UTC (1524055647)
    [ 0.574191] ALSA device list:
    [ 0.574338] No soundcards found.
    [ 0.597653] Freeing unused kernel memory: 696K (c0b2b000 – c0bd9000)
    Hello World!

    log for 3.16.7
    **************
    Just hangs

    AIngale@swpfintbld03:/data2/AIngale/ker/linux-3.16.7$
    AIngale@swpfintbld03:/data2/AIngale/ker/linux-3.16.7$ /data2/AIngale/qeMu/qemu-2.12.0-rc3/arm-softmmu/qemu-system-arm -M virt -m 1024 -kernel arch/arm/boot/zImage -initrd ../initramfs -nographic

    anand

    April 18, 2018 at 2:29 pm

    • Sorry, I can’t help — I’m not a kernel developer. The simplest approach is just to use the newer kernel which works — 3.16.7 is over three years old now. Trying to backport changes directory-at-a-time rather than commit-at-a-time is very unlikely to work.

      pm215

      April 18, 2018 at 2:33 pm

  15. Thanks anyway for reply

    anand

    April 18, 2018 at 3:27 pm

  16. is there a way to mount a share folder?
    i tried with “mount -t 9p -o trans=virtio,version=9p2000.L …” but i get “9pnet: Could not find request transport: virtio”
    i think that is because there is no support for PCI virtio devices.

    alexvdan

    August 3, 2018 at 2:25 pm

    • You should be able to use “-device virtio-9p-device,…” on the QEMU command line to add a 9p virtio backend that uses the virtio-mmio transport. (QEMU supports PCI virtio devices, but the kernels shipped with Debian stable don’t; they only support virtio-mmio.)

      pm215

      November 12, 2018 at 10:31 am

  17. Hi Peter!

    Can you please licence the code in this post under a FOSS licence? (See https://github.com/shlomif/Freenode-programming-channel-FAQ/blob/master/FAQ_with_ToC__generated.md#i-want-to-release-my-code—which-open-source-licence-should-i-use ) I’d like to specify a licence in this git repo based on this post: https://github.com/shlomif/ARM-Linux-on-qemu .

    Shlomi Fish

    February 16, 2020 at 11:12 am

    • There is no code in this post, really — it’s just a handful of different command lines, which I don’t think reach the bar for being something that needs a license. If you really think that that rises to the level of being something that needs a license, then for clarity you can use it under the MIT license.

      pm215

      February 16, 2020 at 1:18 pm

  18. Thanks a lot! Hopefully, now I can build and debug Raspberry Pi programs easily on my PC which is light years more powerful than that fan-less machine :)

    Mohammad

    July 21, 2020 at 8:50 pm

  19. Hi,

    Is it possible to pass through the USB to QEMU command line for ARM machines, am using virt machine.
    I added by using this command “-usb -device usb-host,hostbus=,hostaddr=” but its working for x86 QEMU machine not for ARM virt machine.

    Any help?

    Thanks,
    Srinuvasan.A

    Srinuvasan.A

    November 25, 2020 at 10:46 am

  20. Thanks Peter! I’m no longer shouting “256MB os not enough!” at `versatilepb`:)

    I have posted a Makefile for installing “buster” based on your instructions here: https://github.com/notinaboat/qemu_debian_armhf

    notinaboat

    December 1, 2020 at 11:48 pm

    • I created an issue on the script you built. I couldn’t make these instructions to work. Maybe you could take a look at there! Thanks

      PsySc0rpi0n

      March 7, 2021 at 11:16 am

  21. There is one more point about the virt machine. Mostly its the only one that supports directly the KVM and thats what I am using now.

    Here is how I am trying to install an armhf guest on an aarch64 machine (in my case jetson nano).

    ../qemu/build/qemu-system-aarch64 -M virt -m 2048 -smp 2 -cpu host,aarch64=off -enable-kvm -kernel installer-vmlinuz -initrd installer-initrd.gz -drive if=none,file=hda.qcow2,format=qcow2,id=hd -device virtio-blk-device,drive=hd -netdev user,id=mynet -device virtio-net-device,netdev=mynet -nographic -no-reboot

    Its working fine and I am able to install, though I dont know why bootloader installation fails.
    And when I continue without boot loader, and try to see the boot folder in hda.qcow2 no files are present!

    Ravishankar

    March 17, 2021 at 1:59 pm

  22. Oh. Those files are on partition 1 rather than 2!
    Now I am able to run with KVM and its really fast. Its an armhf guest now on aaarch64

    Now to figure out how to get a GUI to work with GPU acceleration..

    rreddy78@debian:~$ lscpu
    Architecture: armv7l
    Byte Order: Little Endian
    CPU(s): 2
    On-line CPU(s) list: 0,1
    Thread(s) per core: 1
    Core(s) per socket: 2
    Socket(s): 1
    Vendor ID: ARM
    Model: 1
    Model name: Cortex-A57
    Stepping: r1p1
    BogoMIPS: 38.40
    Flags: half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm aes pmull sha1 sha2 crc32
    rreddy78@debian:~$

    Ravishankar

    March 17, 2021 at 2:33 pm

  23. We can also install from a debain iso. A sample installation is as follows:

    qemu-system-aarch64 -M virt -enable-kvm -cpu host,aarch64=off -smp 2 -m 2048 \
    -device nec-usb-xhci -device usb-kbd -device usb-mouse -usb -serial stdio \
    -device usb-storage,drive=install -drive file=debian-10.8.0-armhf-xfce-CD-1.iso,if=none,id=install,media=cdrom,readonly=on \
    -drive if=none,file=hda3.qcow2,format=qcow2,id=hd -device virtio-blk-device,drive=hd \
    -device virtio-gpu-pci,virgl=on,xres=1600,yres=900 -display sdl,gl=on \
    -nic user,model=virtio -bios edk2-arm-code.fd

    Ravishankar S

    May 7, 2021 at 6:43 pm


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: