Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.Sign up
Debian "buster" for Raspberry Pi 3 on QEMU
Debian "buster" for Raspberry Pi 3 on QEMU
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.
- Get QEMU 2.12.0 or later (I did not test a later version) from qemu.org
Changes to the original image
You'll need to modify the
/etc/fstab file on the original image because the
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
fdiskto 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
/etc/fstabfile on the mounted partition:
$ sudo vi /mnt/debian/etc/fstab
/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
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
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.
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 (
initrd options take the relative paths to the extracted kernel and initrd files.
-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
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 \
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 \
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 fsck.repair=yes 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 \ -no-reboot
When booting is finished, you will see a prompt
You can now login with
root and password
raspberry. You can create a new user (e.g. pi) with the
$ useradd pi
$ 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
$ 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 fsck.repair=yes net.ifnames=0 rootwait memtest=1" \ -drive file=2018-01-08-raspberry-pi-3-buster-PREVIEW.img,format=raw,if=sd \ -no-reboot
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
I tried many different tutorials before ending up with the solution described above.
- Running 64-bit debian on the
raspi3board model: https://translatedcode.wordpress.com/2018/04/25/debian-on-qemus-raspberry-pi-3-model/: works but no networking.
- Running Raspbian on the
versatilepbboard model: https://azeria-labs.com/emulate-raspberry-pi-with-qemu/: does no longer work if you follow the literal instructions.
- Running Ubuntu on the
virtboard model: https://wiki.ubuntu.com/ARM64/QEMU: works but requires root and can't login on console or with ssh. However, this can maybe be fixed (I did not try this): https://trickycloud.wordpress.com/2013/11/09/default-user-and-password-in-ubuntu-cloud-images/
- Installing and running Debian on the
virtboard model with netboot: https://translatedcode.wordpress.com/2016/11/03/installing-debian-on-qemus-32-bit-arm-virt-board/, https://translatedcode.wordpress.com/2017/07/24/installing-debian-on-qemus-64-bit-arm-virt-board/ : works but takes a long time.