Howto Create Your Own Image - macromorgan/raspbian-qemu GitHub Wiki
The purpose of this wiki is to document how I created a Raspbian Desktop image that boots in QEMU/Libvirt without the limitations of the versatilepb board (256MB of RAM, for starters). I am personally running this in a VM with KVM enabled on a Raspberry Pi 4. This tutorial assumes you are running the image creation process on a Raspberry Pi; this can also probably be done on any computer with qemu-user-static, but I haven't tested it.
Step 1: Download the Raspbian Image from the Raspberrypi Foundation
For this tutorial, I will be using the "Raspbian with Desktop".
wget https://downloads.raspberrypi.org/raspbian_latest -O raspbian_latest.zip
unzip raspbian_latest.zip
Step 2: Mount the Raspbian Disk Image and start to prepare it for use by the QEMU virtual machine.
This step creates loop devices out of the image that you can mount as block devices to manipulate just as you would any other disk:
sudo kpartx -a 2019-09-26-raspbian-buster.img
Since kpartx created my devices as loop0, I will mount the Raspbian image in /mnt as follows:
sudo mount /dev/mapper/loop0p2 /mnt
sudo mount /dev/mapper/loop0p1 /mnt/boot
Next, we need to mount some essential filesystems so we can chroot into it successfully.
sudo mount -t proc proc /mnt/proc/
sudo mount --rbind /sys /mnt/sys/
sudo mount --rbind /dev /mnt/dev/
Step 3: Enter the Chroot
Now we enter the chroot by doing the following:
sudo chroot /mnt /bin/bash
Step 4: Make the image suitable for QEMU.
First we delete the foundation kernel. We'll use a different one instead anyway. Note the lack of sudo. We're already root here so no need.
apt purge raspberrypi-kernel
Sadly we can't purge the bootloader (even though we don't need it anymore) without making additional substantial changes to the OS. So we'll leave it for now.
Add the main Debian source so that we can use Debian's kernel for this image.
nano /etc/apt/sources.list.d/debiankernel.list
Inside this file add the following line:
deb http://deb.debian.org/debian buster main
Now add the key for Debian Buster to the apt keychain:
apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 04EE7237B7D453EC
Now let's deprioritize the hell out of the Debian repository, since aside from the kernel there is nothing there we want.
nano /etc/apt/preferences.d/Debian
Put the following into the file:
Package: *
Pin: origin deb.debian.org
Pin-Priority: 1
Now update the list of packages so we can pull in our kernel:
apt get update
apt get install linux-image-armmp-lpae
Step 4: Now let's exit the chroot and build another image; this one will be GPT with an ESP partition. That way, we can use TianoCore to boot instead of the Raspberry Pi firmware.
exit
Now that we're out of the chroot let's create a 16GB disk image.
sudo dd if=/dev/zero of=raspbian.img bs=1M count=16384
Let's partition the image file:
sudo fdisk raspbian.img
First, set the partition table to "GUID" by typing the command g
. When creating your partitions, make sure you create a 256MB EFI System Partition (create the partition then change the type to 1 which is EFI System Partition) and the rest can be a Linux filesystem type. When done, write your changes and exit.
Create loop devices with kpartx:
sudo kpartx -a raspbian.img
Now create your filesystems. For the ESP partition:
sudo mkfs.vfat /dev/mapper/loop1p1
And for the root partition:
sudo mkfs.ext4 /dev/mapper/loop1p2
Lastly, let's create some mountpoints and mount our new filesystem.
mkdir /tmp/rasp
sudo mount /dev/mapper/loop1p2 /tmp/rasp
sudo mkdir -p /tmp/rasp/boot/efi
Step 5: Now that we have our GPT image ready to go, let's populate it with data so we can then chroot into it.
This is the part where I fucked up...
I had to restart my Raspberry Pi and remount all the directories before I could copy things. Assume it has something to do with the pseudo-filesystems (proc/sys/dev). When I remounted post-reboot I didn't mount those systems yet and instead just did the copy.
sudo cp -av /mnt/* /tmp/rasp/.
Now, mount your proc/dev/sys filesystems again, this time to the new image.
sudo mount -t proc /proc /tmp/rasp/proc/
sudo mount --rbind /sys /tmp/rasp/sys/
sudo mount --rbind /dev /tmp/rasp/dev/
And chroot into the new image again.
sudo chroot /tmp/rasp /bin/bash
Step 6:
Set up Grub as the bootloader in the chroot.
apt install grub-efi-arm
Disable the OS Prober for Grub:
nano /etc/default/grub
And add the following line:
GRUB_DISABLE_OS_PROBER=true
Now install grub so that it can boot properly:
grub-install --target=arm-efi --efi-directory=/boot/efi --bootloader-id=GRUB --no-nvram
update-grub
Step 7:
Final tweaks before time to boot the new image. First we need to get the partition UUIDs and update fstab with them. Make sure you also update the /boot folder to /boot/efi (since /boot is part of the root partition now).
blkid
nano /etc/fstab
Lastly, disable the fbturbo since it causes problems:
mv /usr/share/X11/xorg.conf.d/99-fbturbo.conf /usr/share/X11/xorg.conf.d/99-fbturbo.conf.old
Unmount your image and load it up in QEMU now. For reference I have included my XML for libvirt.