I recently built QEMU from scratch on the Raspberry Pi 5 and wanted to document my steps. My goal was to run two different Mac emulations: a 68k and PPC Mac, specifically with AppleTalk networking functioning over Ethernet.
Assumptions: Raspberry Pi 5 with Raspbian Bookworm 64-bit using Ethernet interface eth0. This part builds on the work from this blog post by Chris Crook.
I started with a stock installation of Raspbian 64-bit Bookworm with desktop.
First, update your Raspberry Pi.
sudo apt-get update
sudo apt-get upgrade
sudo reboot
Next, install QEMU dependencies.
sudo apt-get install git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build libaio-dev libbluetooth-dev libcapstone-dev libbrlapi-dev libbz2-dev libcap-ng-dev libcurl4-gnutls-dev libgtk-3-dev libibverbs-dev libjpeg62-turbo-dev libncurses5-dev libnuma-dev librbd-dev librdmacm-dev libsasl2-dev libsdl2-dev libseccomp-dev libsnappy-dev libssh-dev libvde-dev libvdeplug-dev libvte-2.91-dev libxen-dev liblzo2-dev valgrind xfslibs-dev libnfs-dev bison flex libiscsi-dev
Download the latest version of QEMU source. At the time of this writing, that is version 9.1.0-rc1. Save it to your Downloads folder in your home directory.
Unpack it, configure it, and start building it.
cd Downloads
tar -xzvf qemu-9.1.0-rc1.tar.xz
cd qemu-9.1.0-rc1
./configure
make
It took my Raspberry Pi a couple of hours to complete the build. Afterwards, you should have binaries inside the build folder. Test it with the following command.
./build/qemu-system-m68k -version
./build/qemu-system-ppc -version
You should get something like “QEMU emulator version 9.0.90” back. Finally, install everything.
sudo make install
You can check that it worked by issuing the command:
which qemu-system-ppc
Which should respond with “/usr/local/bin/qemu-system-ppc
” meaning it’s been installed.
Next, setup the bridged networking for QEMU. Part of this came from this guide. Install bridge-utils.
sudo apt-get install bridge-utils
Next, create a new folder and file called bridge.conf with a single line to allow the new bridge interface, arbitrarily called “br0”. And also set permissions on the bridge helper.
sudo mkdir /usr/local/etc/qemu
sudo echo "allow br0" > /usr/local/etc/qemu/bridge.conf
sudo chmod 0644 /usr/local/etc/qemu/bridge.conf
sudo chmod u+s /usr/lib/qemu/qemu-bridge-helper
Next, we’re going to create some startup scripts for QEMU. The first two will manage bringing up and tearing down the bridge interface. The third will actually start QEMU and start the bridge first if needed.
The first two scripts start the bridge interface and use the IP address information from eth0 and move it to br0 and vice versa. I called these br0-up.sh
and br0-down.sh
. These scripts allows you to use DHCP on your Ethernet interface and use that IP address for the bridge. When you want to tear down the bridge, the script reassigns the address back to eth0.
#!/bin/bash
# br0-up.sh
# Check sudo
if [ "$EUID" -ne 0 ]; then
echo "Please run with sudo."
exit
fi
# Get interface eth0 details
ETH=`ifconfig eth0 |grep netmask |sed 's/^ *//' |cut -d" " -f2`
MASK=`ifconfig eth0 |grep netmask |sed 's/^ *//' |cut -d" " -f5`
BROADCAST=`ifconfig eth0 |grep netmask |sed 's/^ *//' |cut -d" " -f8`
GATEWAY=`ip route |grep default |cut -d" " -f3`
if [ "x$ETH" = "x" ]; then
echo "Unable to determine current IP address of interface eth0."
echo "Interface has no IP or bridge already started?"
exit -1
else
echo "Interface eth0 ip address: $ETH"
fi
# Setup br0 if not already enabled
if [[ $(ifconfig -a |grep br0) ]]; then
echo "Interface br0 already loaded."
exit 0
fi
# Take down eth0, bring back up with no IP address
ifconfig eth0 0.0.0.0 promisc up
# Create bridge
brctl addbr br0
brctl addif br0 eth0
brctl stp br0 off
# Assign interface br0 with the IP address and add gw
ifconfig br0 $ETH netmask $MASK broadcast $BROADCAST
sleep 0.5
route add default gw $GATEWAY
echo "Bridge interface br0 up."
#!/bin/bash
# br0-down.sh
# Check sudo
if [ "$EUID" -ne 0 ]; then
echo "Please run with sudo."
exit
fi
# Get interface br0 details
ETH=`ifconfig br0 |grep netmask |sed 's/^ *//' |cut -d" " -f2`
MASK=`ifconfig br0 |grep netmask |sed 's/^ *//' |cut -d" " -f5`
BROADCAST=`ifconfig br0 |grep netmask |sed 's/^ *//' |cut -d" " -f8`
GATEWAY=`ip route |grep default |cut -d" " -f3`
ifconfig br0 down
brctl delbr br0
ifconfig eth0 -promisc
ifconfig eth0 $ETH netmask $MASK broadcast $BROADCAST
sleep 0.5
route add default gw $GATEWAY
echo "Interface br0 down and interface eth0 restored to previous settings."
Note: This will interrupt any currently existing network connections on the Raspberry Pi.
Finally, we’ll create a script to start QEMU. It will first check if the bridge interface exists, and if not, will run that script first. There are two scripts here. The first is for the m68k Mac (Quadra 800) and the second is the PPC Mac (PowerMac G4).
#!/bin/bash
# start-m68k.sh
# Check sudo
if [ "$EUID" -ne 0 ]; then
echo "Please run with sudo."
exit
fi
if [[ -z "$(ifconfig -a |grep br0)" ]]; then
echo "Bringing up bridge interface br0."
./br0-up.sh
fi
qemu-system-m68k \
-M q800 \
-m 128 \
-display gtk \
-audio none \
-bios Q800.ROM \
-g 800x600 \
-device scsi-hd,scsi-id=0,drive=hd0 \
-drive format=raw,media=disk,if=none,id=hd0,file=yourhd.hda \
-net nic,model=dp83932,macaddr=52:54:00:00:00:02 \
-net bridge,br=br0
#!/bin/bash
# start-m68k.sh
# Check sudo
if [ "$EUID" -ne 0 ]; then
echo "Please run with sudo."
exit
fi
if [[ -z "$(ifconfig -a |grep br0)" ]]; then
echo "Bringing up bridge interface br0."
./br0-up.sh
fi
qemu-system-ppc \
-accel tcg \
-L pc-bios \
-boot c \
-M mac99,via=pmu \
-m 512 \
-drive file=yourhd.hda,format=raw,media=disk \
-net nic,model=sungem,macaddr=52:54:00:00:00:01 \
-net bridge,br=br0
Replace the text yourhd.hda
with the name of your hard drive image. I found it easier to create these using MiniVMac on my desktop and then converting them to drive images using Disk Jockey. The alternative is to create a blank HD image and add lines to mount a CD-ROM. That’s not covered here but I can add it if there’s interest.
Set permissions to executable on your new scripts.
chmod 755 br0-down.sh
chmod 755 br0-up.sh
chmod 755 start-m68k.sh
chmod 755 start-ppc.sh
Launch one of your start QEMU scripts from the terminal.
./start-m68k.sh
./start-ppc.sh
A new QEMU window should open and the Mac should begin booting. Once booted, you may have to go to the Network or AppleTalk Control Panel and select Ethernet. Afterwards, go to the Chooser and you should now see your other AppleTalk devices on your Ethernet network.
If you have setup a support server with another Raspberry Pi using a TashTalk hat and TashRouter, you can see LocalTalk printers such as ImageWriter II or ImageWriter LQ.
Note: One caveat is the sound for the 68k Mac wouldn’t work so I used a switch to disable it.
You can even run both simultaneously and they’re able to see each other over AppleTalk so you can share files between them. It even plays nicely with MiniVMac using LToUDP (with an appropriate LToUDP router like TashRouter).