Emulating a 32-bit Raspberry Pi ARM 7 on CentOS Linux with Qemu

Overview

Emulate an ARM processor on Intel using CentOS 7 and Qemu.

Conventions

Commands run as root will appear on a black background:

cd ~

Commands run as your regular user will appear on a grey background:

cd ~

Prerequisite Packages

Qemu

dnf -y install qemu-kvm

Cross-compilation

dnf -y install bc bison flex gcc git glibc-2.28-101.el8.i686 libstdc++-devel.i686 make openssl-devel ncurses ncurses-devel zlib.i686

Acquire Resources

Create a working directory in your unprivileged user home directory and clone the raspbian kernel source:

mkdir -p ~/git/raspberrypi
cd ~/git/raspberrypi
git clone --depth=1 https://github.com/raspberrypi/linux

Also get the Raspbian toolchain:

git clone https://github.com/raspberrypi/tools

Download a current version of Raspbian from downloads.raspberrypi.org and unpack. This example uses Raspbian Lite 2020-02-14:

wget http://downloads.raspberrypi.org/raspbian_lite/images/raspbian_lite-2020-02-14/2020-02-13-raspbian-buster-lite.zip
unzip 2020-02-13-raspbian-buster-lite.zip

Inspect the Raspbian Image

fdisk -l 2020-02-13-raspbian-buster-lite.img

The output will show two partitions. When we emulate, this img file will be handed off as hda, so these two partitions will be seen by the emulator as sda1 and sda2.

Configure and Cross-Compile Kernel

Executing $ file ${HOME}/git/raspbian/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-gcc reveals that the Linaro ARM cross-compiler in the Raspbian toolchain is dynamically linked; necessitating the i686 glibc, libstdc++, and zlib packages installed (above).

The kernel will be configured to support a minimal number of features, architectures, and filesystems:

cd linux
export KERNEL="kernel7"
export ARCH="arm"
export CROSS_COMPILE="${HOME}/git/raspbian/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin/arm-linux-gnueabihf-"
make bcm2709_defconfig
make menuconfig
make all
cd ..

ARM/Raspberry Pi Emulation

export QEMU_AUDIO_DRV=none
qemu-system-arm \
-kernel linux/vmlinux \
-cpu arm1176 \
-m 256M \
-machine versatilepb \
-no-reboot \
-serial stdio \
-append "root=/dev/sda2 panic=1 rootfstype=ext4 rw init=/bin/bash" \
-drive file=2020-02-13-raspbian-buster-lite.img,format=raw,index=0,media=disk

Command breakdown (please see man qemu-system-arm for further detail):

ParameterDescription
export QEMU_AUDIO_DRV=noneDisable audio
qemu-system-armQEMU binary that emulates ARM processors
-kernel linux/vmlinuxPath to the kernel (built above)
-cpu arm1176Specific ARM processor to emulate
-m 256MMemory in MB
-machine versatilepbMachine type to emulate. Additional types can be enumerated with qemu-system-arm -machine help
-no-reboot
-serial stdioDirects serial output to stdio (linux only)
-append "root=/dev/sda2 panic=1 rootfstype=ext4 rw init=/bin/bash"Options to pass to the kernel to describe filesystem details and initial processes
-drive file=2020-02-13-raspbian-buster-lite.img,format=raw,index=0,media=diskDisk image containing the filesystem(s)