piOS
is the still ongoing result of me going through various online tutorials
about baremetal coding on the Pi, which you can check out in the list below (see here).
I'm stepping into the world of embedded software development with almost zero prior experience, and unfortunately,
my university days didn't touch on this domain. This project is purely a hobby, sparked by a desire to dip my toes
into the world of embedded systems.
What is the end goal? To be honest, I don't know yet. The things that I would like to get working but are not yet:
- Filesystem: I don't want to continue to compile everything I need into the kernel. There is a SD card so let's use it.
- Bluethooth: Would be nice to connect an external keyboard or something like this? I have no idea how hard this is.
- TCP/IP stack: Would be fun to try to get it connected to the internet.
Honestly, if you are interested in baremetal programming, you can probably use any of the below projects as a starting point. Since I don't believe there is one perfect source for the relevant topics, here is a short summary of what I have been following, reading, and using as template along the way. I'd like to make clear that a good chunk of the code in this repository is almost 1-to-1 from the below projects. The goal here was not to create something new (at least not yet), but rather use the code from these projects to explore how things work, what you can do with it, and of course also what potential pitfalls are. I changed some things were I found it appropriate (building the project, structure of the code, documentation, etc.).
- armOS (Thanos Koutroubas): This was the first source I followed and you will see a large overlap between this project and mine. But this project goes much more into the direction of creating an OS that I plan. Nevertheless, it was a good source to start and gave me some nice idea of how to structure my project.
- Bare metal Raspberry Pi 3 tutorials (Zoltan Baldaszti): Really nice tutorial that introduces the basic ways of how HW and SW should interact with each other. The individual lessons are not really connected, so it's quite easy to just pick out what you need.
- Building an Operating System for the RaspberryPi (Jake Sandler) Has a nice introduction to setting up dynamic memory allocation for 32-bit systems, but seems a little bit light on some details.
- Raspberry Pi bare metal experiments (Brian Widdas)
- Learning operating system development using Linux kernel and Raspberry Pi (Sergey Matyukevich) Lots of explanations about concepts related to OS development using the Linux kernel and Pi OS as an example. Helps to understand some of the code out there doing things/solving things and seeing the bigger picture!
One thing that I haven't mentioned so far, but was basically open the whole time, is the documentation of the SoC, Broadcom 2835/2837.
The tricky part for this project is the compiler. Since we are writing code that is supposed to run on an ARM
processor, you will need the corresponding compiler. All compilers to build for ARM CPU's can be found on
ARM's website.
You will most probably have to cross-compile (x86
->arm
) and you will need to be careful if you are compiling the
kernel for a 32-bit
or a 64-bit
CPU (arm-none-eabi
vs aarch64-none-elf
).
The CMakeLists.txt
file has all the logic needed to handle which compiler to pick depending on the Raspberry Pi
Model you want to compile this code for (just make sure they are installed and in the $PATH
).
You will find in the top-level CMakeLists.txt
file a variable that's called MODEL_X
, where X
can be [0,1,2,3,4]
.
MODEL_3
and MODEL_4
have a 64bit
CPU and thus need the aarch64
compiler.
Note: This project was started with a 32bit
board (Pi 0) and thus most of the code was initially written with the
ARMv6 architecture in mind. For example, the entire memory management code was written with ATAGS (ARM Tags) in mind,
which where replaced by DTB's (device tree blob's) in ARMv8-a and would thus need a refresh.
I will do this at some point, but for now I will focus more on exploring some of the capabilities of the 32bit
version of the board.
In short, the 64bit
boards have a lot less functionality compared to the 32bit
boards with this kernel as of now.
Once you have all of this setup, you should be able to simply cd
into the root of this repo and run
(assuming you have cmake
and ninja-build
installed on your system)
cmake -G Ninja -B ./build -S .
cmake --build ./build
or you can use Docker
DOCKER_BUILDKIT=1 docker build --progress=plain -f Dockerfile --rm -t pi_os:latest . --output ${PATH_TO_WHERE_YOU_WANT_THE_ELF_AND_IMG}
While the ultimate goal of course is to run the kernel on a Pi, for development it is useful to also run it in qemu
.
For the 32-bit
version you can use
# ARMv6 / 32 bit
qemu-system-arm -M raspi0 -serial null -serial stdio -kernel $PATH_TO_ELF/kernel.elf
# ARMv8-a / 64 bit
qemu-system-aarch64 -M raspi3b -serial null -serial stdio -kernel $PATH_TO_ELF/kernel7.elf
Note: To run the code with qemu
you use the .elf
, i.e. the full executable. If you want to test the kernel out
on a real Raspberry Pi, then you need to move the .img
file onto the SD card.
To generate the documentation you can run
doxygen .doxyfile
Please make sure to install doxygen
and graphviz
.