<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>qemu &amp;mdash; Jerry of the Week</title>
    <link>https://write.in0rdr.ch/tag:qemu</link>
    <description>ˈdʒɛri - Individual who sends life against the grain no matter the consequences</description>
    <pubDate>Tue, 28 Apr 2026 13:01:24 +0000</pubDate>
    <item>
      <title>Emulate Raspberry Pi4 on QEMU</title>
      <link>https://write.in0rdr.ch/emulate-raspberry-pi4-on-qemu</link>
      <description>&lt;![CDATA[I was looking into emulating the Raspberry Pi OS on QEMU. This short post summarizes my findings.&#xA;&#xA;#raspberry #homelab #debian #qemu&#xA;!--more--&#xA;&#xA;I needed a virtual host to test Ansible scripts for my Raspberry Pi in the home lab. I found my way around this task by reading through the many great posts and examples online.&#xA;&#xA;Extract kernel and device tree&#xA;&#xA;First, you have to get the image (in my case, I used a modified build of the bookworm image) and extract the &#34;kernel&#34; and the &#34;device tree&#34; (to be honest, this was new for me when I read about this today).&#xA;&#xA;We do this by mounting the boot partition and extracting the relevant files.&#xA;&#xA;Check image partitions&#xA;$ fdisk -l ./HashiPi-pi0.img&#xA;&#xA;Setup loop device with image, scan partitions. This is easier than fiddling with fdisk and partition offsets for mounting.&#xA;&#xA;$ sudo losetup -P /dev/loop0 HashiPi-pi0.img&#xA;$ sudo mount /dev/loop0p1 /mnt&#xA;&#xA;copy kernel and device tree binary (dtb)&#xA;$ cp /mnt/kernel8.img .&#xA;$ cp /mnt/bcm2711-rpi-4-b.dtb .&#xA;&#xA;unmount&#xA;$ sudo umount /mnt&#xA;$ sudo losetup --detach /dev/loop0&#xA;&#xA;Patch device tree to enable USB controller&#xA;&#xA;The &#34;device tree binary&#34; (.dtb) needs to be translated into a readable &#34;device tree source&#34; (.dts) file.&#xA;&#xA;$ dtc -I dtb -O dts -o bcm2711-rpi-4-b.dts bcm2711-rpi-4-b.dtb&#xA;&#xA;The .dts file can be patched to enable the usb controller. This is required, if we want to boot later using the usbnet device and port-forward (hostfwd) the ssh port.&#xA;&#xA;--- bcm2711-rpi-4-b.dts.orig    2025-09-21 15:05:59.304575294 +0200&#xA;+++ bcm2711-rpi-4-b.dts 2025-09-21 15:04:56.709581742 +0200&#xA;@@ -1450,7 +1450,7 @@&#xA;                        phy-names = &#34;usb2-phy&#34;;&#xA;                        interrupt-names = &#34;usb&#34;, &#34;soft&#34;;&#xA;                        power-domains = 0x10 0x06;&#xA;status = &#34;disabled&#34;;&#xA;status = &#34;okay&#34;;&#xA;                        phandle = 0xbf;&#xA;                };&#xA;&#xA;Unfortunately, we need to use this usb device, because all other emulated network devices are pci based which is not supported by QEMU for the Raspberry Pi&#xA;&#xA;$ qemu-system-aarch64 -device help&#xA;...&#xA;Network devices:&#xA;name &#34;e1000&#34;, bus PCI, alias &#34;e1000-82540em&#34;, desc &#34;Intel Gigabit Ethernet&#34;&#xA;name &#34;e1000-82544gc&#34;, bus PCI, desc &#34;Intel Gigabit Ethernet&#34;&#xA;name &#34;e1000-82545em&#34;, bus PCI, desc &#34;Intel Gigabit Ethernet&#34;&#xA;name &#34;e1000e&#34;, bus PCI, desc &#34;Intel 82574L GbE Controller&#34;&#xA;name &#34;i82550&#34;, bus PCI, desc &#34;Intel i82550 Ethernet&#34;&#xA;name &#34;i82551&#34;, bus PCI, desc &#34;Intel i82551 Ethernet&#34;&#xA;name &#34;i82557a&#34;, bus PCI, desc &#34;Intel i82557A Ethernet&#34;&#xA;name &#34;i82557b&#34;, bus PCI, desc &#34;Intel i82557B Ethernet&#34;&#xA;name &#34;i82557c&#34;, bus PCI, desc &#34;Intel i82557C Ethernet&#34;&#xA;name &#34;i82558a&#34;, bus PCI, desc &#34;Intel i82558A Ethernet&#34;&#xA;name &#34;i82558b&#34;, bus PCI, desc &#34;Intel i82558B Ethernet&#34;&#xA;name &#34;i82559a&#34;, bus PCI, desc &#34;Intel i82559A Ethernet&#34;&#xA;name &#34;i82559b&#34;, bus PCI, desc &#34;Intel i82559B Ethernet&#34;&#xA;name &#34;i82559c&#34;, bus PCI, desc &#34;Intel i82559C Ethernet&#34;&#xA;name &#34;i82559er&#34;, bus PCI, desc &#34;Intel i82559ER Ethernet&#34;&#xA;name &#34;i82562&#34;, bus PCI, desc &#34;Intel i82562 Ethernet&#34;&#xA;name &#34;i82801&#34;, bus PCI, desc &#34;Intel i82801 Ethernet&#34;&#xA;name &#34;igb&#34;, bus PCI, desc &#34;Intel 82576 Gigabit Ethernet Controller&#34;&#xA;name &#34;ne2kpci&#34;, bus PCI&#xA;name &#34;pcnet&#34;, bus PCI&#xA;name &#34;rocker&#34;, bus PCI, desc &#34;Rocker Switch&#34;&#xA;name &#34;rtl8139&#34;, bus PCI&#xA;name &#34;tulip&#34;, bus PCI&#xA;-  name &#34;usb-net&#34;, bus usb-bus&#xA;name &#34;virtio-net-device&#34;, bus virtio-bus # No &#39;virtio-bus&#39; bus found for device &#39;virtio-net-device&#39;&#xA;name &#34;virtio-net-pci&#34;, bus PCI, alias &#34;virtio-net&#34;&#xA;name &#34;virtio-net-pci-non-transitional&#34;, bus PCI&#xA;name &#34;virtio-net-pci-transitional&#34;, bus PCI&#xA;name &#34;vmxnet3&#34;, bus PCI, desc &#34;VMWare Paravirtualized Ethernet v3&#34;&#xA;&#xA;We really need the usb device (virtio-net-device does not work either I tried), that&#39;s the reason for the patch.&#xA;&#xA;A comment of the &#34;interrupt.memfault blog&#34; describes it nicely (very helpful community):&#xA;&#xA;  Note that for raspi4, the bcm2711-rpi-4-b.dtb devicetree file has disabled the USB controller.&#xA;So, to enable USB keyboard &amp; mouse, the .dtb file must be decompiled to .dts,&#xA;patched, and recompiled back to .dtb.&#xA;&#xA;Unfortunately, it&#39;s not only needed for keyboard and mouse, but also to make our network adapter work (for ssh port-forwarding).&#xA;&#xA;Thaa patching.. Then recompiling into binary form with dtc:&#xA;$ dtc -I dtb -O dts -o bcm2711-rpi-4-b.dts bcm2711-rpi-4-b.dtb&#xA;&#xA;Would be really nice to have this usb controller enabled by default in the next Trixie Pi OS 🤞&#xA;&#xA;Boot the image&#xA;&#xA;For booting the image, I had to ensure two things for the kernel arguments for the Raspberry 4:&#xA;&#xA;Use the ttyAMA1 console&#xA;Use the root partition mmcblk1p2&#xA;&#xA;Note that I&#39;m not enabling the keyboard &amp; mouse devices (as suggested in the references online), because I&#39;m mainly interested to connect to the machine remotely via the ssh port fowarding:&#xA;&#xA;$ sudo qemu-system-aarch64 \&#xA;  -machine raspi4b -cpu cortex-a72 \&#xA;  -dtb bcm2711-rpi-4-b-mod.dtb \ # use mod device tree&#xA;  -m 2G -smp 4 \&#xA;  -kernel kernel8.img -sd HashiPi-pi0.img \&#xA;  -append &#34;rw earlyprintk loglevel=8 console=ttyAMA1,115200 dwcotg.lpm_enable=0 root=/dev/mmcblk1p2 rootdelay=1&#34; \&#xA;  -device usb-net,netdev=net0 \&#xA;  -netdev user,id=net0,hostfwd=tcp::2222-:22&#xA;&#xA;That&#39;s it. Is still a bit slow, but good enough to throw some Ansible against the wall and see if it sticks.&#xA;&#xA;My idea here is to do less with the HashiCorp packer scripts and go back to more Ansible, because that might be more sustainable in the long run.. Let&#39;s see. Next I&#39;m probably also going to give the Trixie (nightly image) a try.&#xA;&#xA;References&#xA;&#xA;https://interrupt.memfault.com/blog/emulating-raspberry-pi-in-qemu&#xA;https://www.qemu.org/docs/master/system/qemu-manpage.html&#xA;https://www.qemu.org/docs/master/system/arm/raspi.html&#xA;https://github.com/trinitronx/qemu-raspbian/blob/main/run-raspi4.sh&#xA;https://github.com/trinitronx/qemu-raspbian/blob/main/bcm2711-rpi-4-b.dts.patch&#xA;https://downloads.raspberrypi.org&#xA;https://www.man7.org/linux/man-pages/man8/losetup.8.html&#xA;&#xA;div style=&#34;text-align:center; font-size: 0.8em&#34;&#xD;&#xA;a href=&#34;https://write.in0rdr.ch/feed&#34;&amp;#128732; RSS/a | a href=&#34;https://m.in0rdr.ch/in0rdr&#34;&amp;#128024; Fediverse/a | a href=&#34;https://chat.in0rdr.ch/#/guest?join=p0c@conference.in0rdr.ch&#34;&amp;#128172; XMPP/a&#xD;&#xA;/div]]&gt;</description>
      <content:encoded><![CDATA[<p>I was looking into emulating the Raspberry Pi OS on QEMU. This short post summarizes my findings.</p>

<p><a href="https://write.in0rdr.ch/tag:raspberry" class="hashtag"><span>#</span><span class="p-category">raspberry</span></a> <a href="https://write.in0rdr.ch/tag:homelab" class="hashtag"><span>#</span><span class="p-category">homelab</span></a> <a href="https://write.in0rdr.ch/tag:debian" class="hashtag"><span>#</span><span class="p-category">debian</span></a> <a href="https://write.in0rdr.ch/tag:qemu" class="hashtag"><span>#</span><span class="p-category">qemu</span></a>
</p>

<p>I needed a virtual host to test Ansible scripts for my Raspberry Pi in the home lab. I found my way around this task by reading through the many great posts and examples online.</p>

<h2 id="extract-kernel-and-device-tree">Extract kernel and device tree</h2>

<p>First, you have to get the <a href="https://downloads.raspberrypi.org">image</a> (in my case, I used a modified build of the bookworm image) and extract the “kernel” and the <a href="https://www.kernel.org/doc/html/latest/devicetree/usage-model.html">“device tree”</a> (to be honest, this was new for me when I read about this today).</p>

<p>We do this by mounting the boot partition and extracting the relevant files.</p>

<pre><code class="language-bash"># Check image partitions
$ fdisk -l ./HashiPi-pi0.img
</code></pre>

<p>Setup loop device with image, scan partitions. This is easier than fiddling with fdisk and partition offsets for mounting.</p>

<pre><code class="language-bash">$ sudo losetup -P /dev/loop0 HashiPi-pi0.img
$ sudo mount /dev/loop0p1 /mnt

# copy kernel and device tree binary (dtb)
$ cp /mnt/kernel8.img .
$ cp /mnt/bcm2711-rpi-4-b.dtb .

# unmount
$ sudo umount /mnt
$ sudo losetup --detach /dev/loop0
</code></pre>

<h2 id="patch-device-tree-to-enable-usb-controller">Patch device tree to enable USB controller</h2>

<p>The “device tree binary” (.dtb) needs to be translated into a readable <a href="https://www.kernel.org/doc/html/latest/devicetree/bindings/dts-coding-style.html">“device tree source” (.dts)</a> file.</p>

<pre><code class="language-bash">$ dtc -I dtb -O dts -o bcm2711-rpi-4-b.dts bcm2711-rpi-4-b.dtb
</code></pre>

<p>The .dts file can be <a href="https://github.com/trinitronx/qemu-raspbian">patched</a> to enable the usb controller. This is required, if we want to boot later using the <a href="https://en.wikipedia.org/wiki/Ethernet_over_USB">usbnet</a> device and port-forward (<a href="https://www.qemu.org/docs/master/system/qemu-manpage.html"><code>hostfwd</code></a>) the ssh port.</p>

<pre><code class="language-diff">--- bcm2711-rpi-4-b.dts.orig    2025-09-21 15:05:59.304575294 +0200
+++ bcm2711-rpi-4-b.dts 2025-09-21 15:04:56.709581742 +0200
@@ -1450,7 +1450,7 @@
                        phy-names = &#34;usb2-phy&#34;;
                        interrupt-names = &#34;usb&#34;, &#34;soft&#34;;
                        power-domains = &lt;0x10 0x06&gt;;
-                       status = &#34;disabled&#34;;
+                       status = &#34;okay&#34;;
                        phandle = &lt;0xbf&gt;;
                };
</code></pre>

<p>Unfortunately, we need to use this usb device, because all other emulated network devices are pci based which is <a href="https://www.qemu.org/docs/master/system/arm/raspi.html">not supported by QEMU for the Raspberry Pi</a></p>

<pre><code class="language-bash">$ qemu-system-aarch64 -device help
...
Network devices:
name &#34;e1000&#34;, bus PCI, alias &#34;e1000-82540em&#34;, desc &#34;Intel Gigabit Ethernet&#34;
name &#34;e1000-82544gc&#34;, bus PCI, desc &#34;Intel Gigabit Ethernet&#34;
name &#34;e1000-82545em&#34;, bus PCI, desc &#34;Intel Gigabit Ethernet&#34;
name &#34;e1000e&#34;, bus PCI, desc &#34;Intel 82574L GbE Controller&#34;
name &#34;i82550&#34;, bus PCI, desc &#34;Intel i82550 Ethernet&#34;
name &#34;i82551&#34;, bus PCI, desc &#34;Intel i82551 Ethernet&#34;
name &#34;i82557a&#34;, bus PCI, desc &#34;Intel i82557A Ethernet&#34;
name &#34;i82557b&#34;, bus PCI, desc &#34;Intel i82557B Ethernet&#34;
name &#34;i82557c&#34;, bus PCI, desc &#34;Intel i82557C Ethernet&#34;
name &#34;i82558a&#34;, bus PCI, desc &#34;Intel i82558A Ethernet&#34;
name &#34;i82558b&#34;, bus PCI, desc &#34;Intel i82558B Ethernet&#34;
name &#34;i82559a&#34;, bus PCI, desc &#34;Intel i82559A Ethernet&#34;
name &#34;i82559b&#34;, bus PCI, desc &#34;Intel i82559B Ethernet&#34;
name &#34;i82559c&#34;, bus PCI, desc &#34;Intel i82559C Ethernet&#34;
name &#34;i82559er&#34;, bus PCI, desc &#34;Intel i82559ER Ethernet&#34;
name &#34;i82562&#34;, bus PCI, desc &#34;Intel i82562 Ethernet&#34;
name &#34;i82801&#34;, bus PCI, desc &#34;Intel i82801 Ethernet&#34;
name &#34;igb&#34;, bus PCI, desc &#34;Intel 82576 Gigabit Ethernet Controller&#34;
name &#34;ne2k_pci&#34;, bus PCI
name &#34;pcnet&#34;, bus PCI
name &#34;rocker&#34;, bus PCI, desc &#34;Rocker Switch&#34;
name &#34;rtl8139&#34;, bus PCI
name &#34;tulip&#34;, bus PCI
-&gt; name &#34;usb-net&#34;, bus usb-bus
name &#34;virtio-net-device&#34;, bus virtio-bus # No &#39;virtio-bus&#39; bus found for device &#39;virtio-net-device&#39;
name &#34;virtio-net-pci&#34;, bus PCI, alias &#34;virtio-net&#34;
name &#34;virtio-net-pci-non-transitional&#34;, bus PCI
name &#34;virtio-net-pci-transitional&#34;, bus PCI
name &#34;vmxnet3&#34;, bus PCI, desc &#34;VMWare Paravirtualized Ethernet v3&#34;
</code></pre>

<p>We really need the usb device (virtio-net-device does not work either I tried), that&#39;s the reason for the patch.</p>

<p>A <a href="https://community.memfault.com/t/emulating-a-raspberry-pi-in-qemu-interrupt/684/10">comment</a> of the “interrupt.memfault blog” describes it nicely (very helpful community):</p>

<blockquote><p>Note that for raspi4, the bcm2711-rpi-4-b.dtb devicetree file has disabled the USB controller.
So, to enable USB keyboard &amp; mouse, the .dtb file must be decompiled to .dts,
patched, and recompiled back to .dtb.</p></blockquote>

<p>Unfortunately, it&#39;s not only needed for keyboard and mouse, but also to make our network adapter work (for ssh port-forwarding).</p>

<p>Thaa patching.. Then recompiling into binary form with <code>dtc</code>:</p>

<pre><code class="language-bash">$ dtc -I dtb -O dts -o bcm2711-rpi-4-b.dts bcm2711-rpi-4-b.dtb
</code></pre>

<p>Would be really nice to have this usb controller enabled by default in the next Trixie Pi OS 🤞</p>

<h2 id="boot-the-image">Boot the image</h2>

<p>For booting the image, I had to ensure two things for the kernel arguments for the Raspberry 4:</p>
<ul><li>Use the <code>ttyAMA1</code> console</li>
<li>Use the root partition <code>mmcblk1p2</code></li></ul>

<p>Note that I&#39;m not enabling the keyboard &amp; mouse devices (as suggested in the references online), because I&#39;m mainly interested to connect to the machine remotely via the ssh port fowarding:</p>

<pre><code class="language-bash">$ sudo qemu-system-aarch64 \
  -machine raspi4b -cpu cortex-a72 \
  -dtb bcm2711-rpi-4-b-mod.dtb \ # use mod device tree
  -m 2G -smp 4 \
  -kernel kernel8.img -sd HashiPi-pi0.img \
  -append &#34;rw earlyprintk loglevel=8 console=ttyAMA1,115200 dwc_otg.lpm_enable=0 root=/dev/mmcblk1p2 rootdelay=1&#34; \
  -device usb-net,netdev=net0 \
  -netdev user,id=net0,hostfwd=tcp::2222-:22
</code></pre>

<p>That&#39;s it. Is still a bit slow, but good enough to throw some Ansible against the wall and see if it sticks.</p>

<p>My idea here is to do less with the HashiCorp packer scripts and go back to more Ansible, because that might be more sustainable in the long run.. Let&#39;s see. Next I&#39;m probably also going to give the Trixie (<a href="https://downloads.raspberrypi.org/nightlies/">nightly</a> image) a try.</p>

<h2 id="references">References</h2>
<ul><li><a href="https://interrupt.memfault.com/blog/emulating-raspberry-pi-in-qemu">https://interrupt.memfault.com/blog/emulating-raspberry-pi-in-qemu</a></li>
<li><a href="https://www.qemu.org/docs/master/system/qemu-manpage.html">https://www.qemu.org/docs/master/system/qemu-manpage.html</a></li>
<li><a href="https://www.qemu.org/docs/master/system/arm/raspi.html">https://www.qemu.org/docs/master/system/arm/raspi.html</a></li>
<li><a href="https://github.com/trinitronx/qemu-raspbian/blob/main/run-raspi4.sh">https://github.com/trinitronx/qemu-raspbian/blob/main/run-raspi4.sh</a></li>
<li><a href="https://github.com/trinitronx/qemu-raspbian/blob/main/bcm2711-rpi-4-b.dts.patch">https://github.com/trinitronx/qemu-raspbian/blob/main/bcm2711-rpi-4-b.dts.patch</a></li>
<li><a href="https://downloads.raspberrypi.org">https://downloads.raspberrypi.org</a></li>
<li><a href="https://www.man7.org/linux/man-pages/man8/losetup.8.html">https://www.man7.org/linux/man-pages/man8/losetup.8.html</a></li></ul>

<div style="text-align:center; font-size: 0.8em">
<a href="https://write.in0rdr.ch/feed">🛜 RSS</a> | <a href="https://m.in0rdr.ch/in0rdr">🐘 Fediverse</a> | <a href="https://chat.in0rdr.ch/#/guest?join=p0c@conference.in0rdr.ch">💬 XMPP</a>
</div>
]]></content:encoded>
      <guid>https://write.in0rdr.ch/emulate-raspberry-pi4-on-qemu</guid>
      <pubDate>Sun, 21 Sep 2025 13:20:54 +0000</pubDate>
    </item>
  </channel>
</rss>