Debian "buster" for Raspberry Pi 3 on QEMU

Wim Vanderbauwhede edited this page Oct 13, 2018 · 5 revisions

Debian "buster" for Raspberry Pi 3 on QEMU

Date: 2018-10-11

Debian "buster" running on QEMU, login prompt.

This tutorial explains how to run a 64-bit Linux distribution for the Raspberry Pi 3 on QEMU, a generic and open source machine emulator and virtualizer.

QEMU supports many physical hardware platforms, and has recently added support for the Raspberry Pi 3 with the raspi3 model. However, this is only for 64-bit distributions, and there is currently no emulation of the BCM2835 USB controller, so there is no USB support and also, more critically, no networking support.

Therefore, in this tutorial we will use the more generic virt model, an Arm platform which doesn't correspond to any real hardware and is designed for use in virtual machines.

QEMU version

  • Get QEMU 2.12.0 or later (I did not test a later version) from

Debian image

Changes to the original image

You'll need to modify the /etc/fstab file on the original image because the raspi3 and virt boards use different names for disk partitions.

If you are on a Linux system (or any system that can mount ext4 partitions) you can do this by mounting the ext4 partition from the image, as follows:

  • Create a mount point:

      $ sudo mkdir /mnt/debian
  • Use fdisk to get information about the image:

      $ fdisk -l 2018-01-08-raspberry-pi-3-buster-PREVIEW.img

    You should see something like this:

      Disk 2018-01-08-raspberry-pi-3-buster-PREVIEW.img: 1.1 GiB, 1153433600 bytes, 2252800 sectors
      Units: sectors of 1 * 512 = 512 bytes
      Sector size (logical/physical): 512 bytes / 512 bytes
      I/O size (minimum/optimal): 512 bytes / 512 bytes
      Disklabel type: dos
      Disk identifier: 0xac8dad98
      Device                                        Boot  Start     End Sectors  Size Id Type
      2018-01-08-raspberry-pi-3-buster-PREVIEW.img1        2048  614399  612352  299M  c W95 FAT32 (LBA)
      2018-01-08-raspberry-pi-3-buster-PREVIEW.img2      614400 2252799 1638400  800M 83 Linux

    You see that the filesystem (.img2) starts at sector 614400. Now take that value and multiply it by 512, in this case it’s 512 * 614400 = 314572800 bytes.

    Use this value as an offset in the following command:

      $ sudo mount -v -o offset=314572800 -t ext4 ./2018-01-08-raspberry-pi-3-buster-PREVIEW.img /mnt/debian
  • Edit the /etc/fstab file on the mounted partition:

      $ sudo vi /mnt/debian/etc/fstab

    In the /etc/fstab, comment out the entry for the boot partition (as it is not needed) and change the entry for the root partition to /dev/vda2, so that the final file looks as follows:

      # The root file system has fs_passno=1 as per fstab(5) for automatic fsck.
      #/dev/mmcblk0p2 / ext4 rw 0 1
      /dev/vda2 / ext4 rw 0 1
      # All other file systems have fs_passno=2 as per fstab(5) for automatic fsck.
      # /dev/mmcblk0p1 /boot/firmware vfat rw 0 2
      proc /proc proc defaults 0 0
  • Unmount the parition when you're done:

      $ sudo umount /mnt/debian/

If you can't mount the partition on your host, you can do it by booting the image on the proper Raspberry Pi 3 model, see below.

Extracting the kernel and ramdisk images from the boot partition

Although QEMU can usually boot straight from a disk image, for the raspi3 and virt boards this is not the case. To boot our virtual system via QEMU we will need to get the kernel and initrd files from the boot partition. If you are on a Linux system, you can either do that using libguestfs (I have not tried this) or using the fdisk and mount method as described above:

$ mkdir debian_bootpart
$ sudo mount -v -o offset=1048576 -t vfat ./2018-01-08-raspberry-pi-3-buster-PREVIEW.img /mnt/debian
$ cp /mnt/debian/vmlinuz-4.14.0-3-arm64 debian_bootpart
$ cp /mnt/debian/initrd.img-4.14.0-3-arm64 debian_bootpart
$ cp /mnt/debian/bcm2837-rpi-3-b.dtb debian_bootpart
$ cp /mnt/debian/cmdline.txt debian_bootpart
$ sudo umount /mnt/debian/

You don't need the device tree blob for running on the virt board, but it is needed for the raspi3 model so I suggest you copy it. You also don't really need the cmdline.txt but it is instructive.

Running QEMU

With these preparations done, we can boot the 64-bit Debian image on QEMU. The Raspberry Pi 3 has an Arm Cortex A53 and 1 GB of RAM so we provide these as CPU (-cpu) and memory (-m) options.

The kernel and initrd options take the relative paths to the extracted kernel and initrd files.

The -serial stdio option redirects the boot output messages and the console to your terminal. You can control the log level using loglevel= in the -append string, which contains all options to be passed on to the kernel at boot time. On the physical Raspberry Pi, these options can be provided in the cmdline.txt file.

In our case, the key option is root=/dev/vda2 which tells the kernel the location of the root partition to be mounted. Note also console=ttyAMA0, the Arm equivalent of console=ttyS0 on Intel machines.

The memory card is modeled using

-drive file=2018-01-08-raspberry-pi-3-buster-PREVIEW.img,format=raw,if=sd,id=hd-root \
-device virtio-blk-device,drive=hd-root \

where sd indicates that it is a solid state card as used in the Raspberry Pi.

Finally, the network is modeled using

-netdev user,id=net0,hostfwd=tcp::5022-:22 \
-device virtio-net-device,netdev=net0 \

The hostfwd is a convenience option which lets you ssh into the guest using

$ ssh -p 5022 localhost

The complete invocation is:

$ qemu-system-aarch64 \
  -kernel debian_bootpart/vmlinuz-4.14.0-3-arm64 \
  -initrd debian_bootpart/initrd.img-4.14.0-3-arm64 \
  -m 1024 -M virt \
  -cpu cortex-a53 \
  -serial stdio \
  -append "rw root=/dev/vda2 console=ttyAMA0 loglevel=8 rootwait memtest=1" \
  -drive file=2018-01-08-raspberry-pi-3-buster-PREVIEW.img,format=raw,if=sd,id=hd-root \
  -device virtio-blk-device,drive=hd-root \
  -netdev user,id=net0,hostfwd=tcp::5022-:22 \
  -device virtio-net-device,netdev=net0 \

When booting is finished, you will see a prompt

rpi3 login:

You can now login with root and password raspberry. You can create a new user (e.g. pi) with the useradd command:

$ useradd pi

Start the ssh server:

$ systemctl sshd start

You can now log in via ssh as well:

$ ssh -p 5022 pi@localhost

Access and modify the original disk image via QEMU

If you can't mount the ext4 partition on your host, you can access it via QEMU by using the actual Raspberry Pi 3 model raspi3:

  $ qemu-system-aarch64 \
    -kernel bootpart/vmlinuz-4.14.0-3-arm64 \
    -initrd bootpart/initrd.img-4.14.0-3-arm64 \
    -dtb bootpart/bcm2837-rpi-3-b.dtb \
    -M raspi3 -m 1024 \
    -serial stdio \
    -append "rw earlycon=pl011,0x3f201000 console=ttyAMA0 loglevel=8 root=/dev/mmcblk0p2 net.ifnames=0 rootwait memtest=1" \
    -drive file=2018-01-08-raspberry-pi-3-buster-PREVIEW.img,format=raw,if=sd \

Note the differences with the virt model: because the raspi3 is an actual board, we don't need to specify the processor; we do however need to provide the device tree blob. The kernel options are somewhat different, in particular the root partition.

Once it has booted, log in as root and modify /etc/fstab as above. Log out and shut down the VM.

Resizing the image

For reference

I tried many different tutorials before ending up with the solution described above.

You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.