UP | HOME

Raspberry Pi VM

Table of Contents

While attempting to automate building out of Reticulum nodes for PMesh. I checked to see if I could run the pi images in an emulator. Doing so would let me more easily clean-slate when testing my scripts.

Turns out this is doable using QEMU. Though it's not exactly as easy as starting up a vm in VirtManager.

1. Steps to build a VM

Download the image from here. Likely the image name will need to be updated in the script below:

#!/bin/sh

set -e

function unmount() {
    sudo umount boot
}

mkdir -p /tmp/pi-vm/{boot,root}
cd /tmp/pi-vm

IMG_FILE=2025-05-13-raspios-bookworm-arm64-lite.img
IMG_BASE=$(basename $IMG_FILE .img)

if [ ! -f $IMG_FILE ]; then
    curl -O https://downloads.raspberrypi.com/raspios_lite_arm64/images/raspios_lite_arm64-2025-05-13/2025-05-13-raspios-bookworm-arm64-lite.img.xz
    unxz 2025-05-13-raspios-bookworm-arm64-lite.img.xz
fi

if [ ! -f  ${IMG_BASE}.qcow2 ]; then
    trap unmount EXIT

    eval $(fdisk -l $IMG_FILE | awk '$2 ~ /^[0-9]+$/ {offset=$2*512; if ($6 == "c") {print "BOOT_OFFSET=" offset;} else {print "ROOT_OFFSET=" offset;}}')

    if [ -z "$BOOT_OFFSET" ]; then
          echo "Can't determine BOOT_OFFSET"
          exit 1
    fi

    if [ -z "$ROOT_OFFSET" ]; then
          echo "Can't determine ROOT_OFFSET"
          exit 1
    fi

    sudo mount $IMG_FILE -o offset=$BOOT_OFFSET boot

    cp boot/*.dtb .
    cp boot/kernel*.img .

    PASS=$(apg -m30 -n1)
    PASS_HASH=$(echo "$PASS" | mkpasswd -m yescrypt -s)

    echo "pi:${PASS_HASH}" | sudo tee boot/userconf
    echo "pi Password set to '${PASS}'" > info.txt

    sudo touch boot/ssh

    IMG_BASE=$(basename $IMG_FILE .img)
    qemu-img convert -f raw -O qcow2 $IMG_FILE ${IMG_BASE}.qcow2
    qemu-img resize ${IMG_BASE}.qcow2 8G
fi

echo "qemu-system-aarch64 -m 1024 -M raspi3b \
                    -kernel kernel8.img \
                    -dtb bcm2710-rpi-3-b-plus.dtb \
                    -sd ${IMG_BASE}.qcow2 \
                    -snapshot \
                    -append 'root=/dev/mmcblk0p2 rw rootwait rootfstype=ext4' \
                    -device usb-net,netdev=net0 \
                    -netdev user,id=net0,hostfwd=tcp::5555-:22" > run.sh
chmod +x run.sh
echo "run.sh created"

Date: 2025-08-12 Tue 07:41

Author: Aaron Bieber

Created: 2025-08-12 Tue 14:50

Validate