Just a quick update before we dive in: what we're actually doing here is running Raspberry Pi OS (64-bit) on a QEMU virtual ARM setup. This isn't full-blown hardware emulation of the Raspberry Pi 4, but more about creating a virtual environment for the OS. It doesn't mimic all the specific hardware features of the Pi 4, but it's pretty useful and great for general testing. I turned to this solution mainly to extract a modified sysroot from the Raspberry Pi OS, something not readily available in other resources. For those looking into detailed emulation of the actual Raspberry Pi 4's hardware in QEMU, check out this link for the latest updates: https://gitlab.com/qemu-project/qemu/-/issues/1208.
Hope it helps! :D
Shortcomings: No GUI yet, only console.
- Download Raspberry Pi OS (64-bit) from Raspberry Pi operating system images.
Here we downloaded Raspberry Pi OS (64-bit) with desktop, Kernel version: 6.1, Debian version: 11 (bullseye), Release date: May 3rd 2023, named2023-05-03-raspios-bullseye-arm64.img
. We put it in/home/mydir
. - Install the required packages on your host system:
$ # Cross compilers for arm64 $ sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu $ # Qemu itself $ sudo apt install qemu qemubuilder qemu-system-gui qemu-system-arm qemu-utils \ qemu-system-data qemu-system
- Build the Linux kernel for qemu arm64 (You can download the kernel from Kernel.org):
$ wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.1.34.tar.xz $ tar xvJf linux-6.1.34.tar.xz $ cd linux-6.1.34 $ # create a .config file $ ARCH=arm64 CROSS_COMPILE=/bin/aarch64-linux-gnu- make defconfig $ # Use the kvm_guest config as the base defconfig, which is suitable for qemu $ ARCH=arm64 CROSS_COMPILE=/bin/aarch64-linux-gnu- make kvm_guest.config $ # Build the kernel $ ARCH=arm64 CROSS_COMPILE=/bin/aarch64-linux-gnu- make -j8 $ cp arch/arm64/boot/Image /home/mydir
- Mount the image for enabling ssh and configuring username and password:
- Get the correct offset value with the help of
fdisk
utility:As we can see, we have two partitions inside the downloaded image. The first device (partition) is the bootable partition, and the second one is the root filesystem. The first partition is what will be mounted as$ fdisk -l 2023-05-03-raspios-bullseye-arm64.img Disk 2023-05-03-raspios-bullseye-arm64.img: 4.11 GiB, 4412407808 bytes, 8617984 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: 0x3e247b30 Device Boot Start End Sectors Size Id Type 2023-05-03-raspios-bullseye-arm64.img1 8192 532479 524288 256M c W95 FAT32 (LBA) 2023-05-03-raspios-bullseye-arm64.img2 532480 8617983 8085504 3.9G 83 Linux
/boot
in Raspberry Pi, and this is where we'll need to create some files.
Obtain the correct offset of the first device by multiplying the start of the first partition (here 8192) by the sector size (here 512). Here it will be calculated as 8192 * 512 = 4194304 - Mount the image in
/mnt/rpi
directory:$ sudo mkdir /mnt/rpi $ sudo mount -o loop,offset=4194304 2023-05-03-raspios-bullseye-arm64.img /mnt/rpi
- Create a file named
ssh
to enable ssh:$ cd /mnt/rpi $ sudo touch ssh
- Additionally, create a file named
userconf.txt
in the same directory and put your desired username and password there, like<username>:<hashed-password>
(might be better to leave the username aspi
). This will be your default credentials:$ openssl passwd -6 # Generate the <hashed-password> $ echo 'pi:<hashed-password>' | sudo tee userconf.txt # Put them inside `userconf.txt`
- Finally, unmount the image:
$ sudo umount /mnt/rpi
- Get the correct offset value with the help of
- Make a copy of the
.img
file
$ cp 2023-12-11-raspios-bookworm-arm64-lite.img{,.expanded}
- Add some space to the end of it
$ truncate -s +40G 2023-12-11-raspios-bookworm-arm64-lite.img.expanded
- Resize the partition with
virt-resize
from theguestfs-tools
package
$ virt-resize --expand /dev/sda2 2023-12-11-raspios-bookworm-arm64-lite.img 2023-12-11-raspios-bookworm-arm64-lite.img.bigger
[ 0.0] Examining 2023-12-11-raspios-bookworm-arm64-lite.img
100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
**********
Summary of changes:
virt-resize: /dev/sda1: This partition will be left alone.
virt-resize: /dev/sda2: This partition will be resized from 2.0G to 42.0G.
The filesystem ext4 on /dev/sda2 will be expanded using the ‘resize2fs’
method.
**********
[ 11.3] Setting up initial partition table on 2023-12-11-raspios-bookworm-arm64-lite.img.bigger
[ 12.5] Copying /dev/sda1
[ 13.4] Copying /dev/sda2
100% ⟦▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒⟧ 00:00
[ 20.7] Expanding /dev/sda2 using the ‘resize2fs’ method
virt-resize: Resize operation completed with no errors. Before deleting
the old disk, carefully check that the resized disk boots and works
correctly.
- Replace the original with the expanded image file
$ mv 2023-12-11-raspios-bookworm-arm64-lite.img.expanded 2023-12-11-raspios-bookworm-arm64-lite.img
- Run qemu emulator:
This machine will be able to access the internet.
$ cd /home/mydir $ qemu-system-aarch64 -machine virt -cpu cortex-a72 -smp 6 -m 4G \ -kernel Image -append "root=/dev/vda2 rootfstype=ext4 rw panic=0 console=ttyAMA0" \ -drive format=raw,file=2023-05-03-raspios-bullseye-arm64.img,if=none,id=hd0,cache=writeback \ -device virtio-blk,drive=hd0,bootindex=0 \ -netdev user,id=mynet,hostfwd=tcp::2222-:22 \ -device virtio-net-pci,netdev=mynet \ -monitor telnet:127.0.0.1:5555,server,nowait
- After the machine is completely booted up, you can login to it from your computer by using ssh and the username and password you specified:
$ ssh -l pi localhost -p 2222
- Done!