This is just a quick-start guide on how to write a bare metal program for the Raspberry Pi 3. This is heavily based on the amazing Raspberry Pi OS which details how to develop your own OS (in turn inspired heavily by the Linux kernel)
However, a shortcoming of that tutorial are the prerequisites. A Pi 3 is not that cheap and USB-to-TTL converters, though much cheaper are still an additional piece of hardware you must obtain.
There is a much cheaper alternative - QEMU. QEMU has had direct support for the Pi 3 since April 2018 through the -M
flag.
The code (Lesson 1 from the tutorial) is a simple "Hello world" program that is run completely independently of any library routines. It uses nothing but writing values on registers to achieve this goal.
This guide is quickly going to run you through how you can run the code from the tutorial on QEMU. This assumes you are using a Linux distribution (Arch Linux) for brevity's sake.
First, install the GNU CC Cross compiler for aarch64
. The Raspberry Pi 3 has an ARM64 SoC. A cross-compiler builds code meant for another platform. Your system (which almost certainly has an x86_64 processor will normally compile code for itself with gcc
)
pacman -S aarch64-linux-gnu-gcc
Now, we install QEMU, and RPI3 support for it.
pacman -S qemu qemu-arch-extra
For our source code, we clone the RPI OS repository,
git clone https://github.com/s-matyukevich/raspberry-pi-os
cd raspberry-pi-os
Our code is in src/lesson01
. Take some time to go through the line-by-line documentation at docs/lesson01 which also explains our motivation and the code structure.
Open each and every file in the src
directory to understand how they all fit together. Take a look at ./Makefile
to understand the build process.
We are now ready to build our code and run it on QEMU.
make clean && make
This generates our kernel image kernel8.img
.
Our job now is simple. Run this kernel image on our emulated system with QEMU. For this, use the following command.
#This sets uart to null and connects mini-uart to stdio, booting our kernel image
qemu-system-aarch64 -M raspi3 -serial null -serial mon:stdio -nographic -kernel kernel8.img
This should give us the output `Hello, world!' followed by echoing any input characters.
Congratulations, you just made your first bare-metal application.