Debian "buster" for Raspberry Pi 3 on QEMU - wimvanderbauwhede/limited-systems GitHub Wiki
Debian "buster" for Raspberry Pi 3 on QEMU
Date: 2018-10-11
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 qemu.org
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 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
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 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
https://azeria-labs.com/emulate-raspberry-pi-with-qemu/
For reference
I tried many different tutorials before ending up with the solution described above.
- Running 64-bit debian on the
raspi3
board model: https://translatedcode.wordpress.com/2018/04/25/debian-on-qemus-raspberry-pi-3-model/: works but no networking. - Running Raspbian on the
versatilepb
board model: https://azeria-labs.com/emulate-raspberry-pi-with-qemu/: does no longer work if you follow the literal instructions. - Running Ubuntu on the
virt
board 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
virt
board 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.