Skip to content

01. Environment Setup for Raspberry Pi OS Development

Target Hardware

This tutorial series targets the Raspberry Pi 4 Model B (BCM2711, Cortex-A72, ARMv8-A 64-bit).

What is "Bare Metal"?

Usually, when you write a program (like in Python or C++), it runs on top of an Operating System (OS) like Windows, macOS, or Linux. The OS handles hard work like reading files, sending network packets, and drawing to the screen.

Bare Metal programming means writing code that runs directly on the hardware, without any OS. You are the boss. You have total control, but you also have to do everything yourself (even drawing a single pixel to the screen!).

graph TD
    subgraph "Normal Programming"
        App["Application"] --> OS["Operating System"]
        OS --> HW["Hardware (CPU, RAM, IO)"]
    end

    subgraph "Bare Metal"
        MyOS["Your Code / Kernel"] --> HW2["Hardware (CPU, RAM, IO)"]
    end

Setting Up the Toolchain

To build our OS, we need a special set of tools.

Why do we need a "Cross-Compiler"?

Your computer (PC or Mac) likely uses an x86_64 processor (Intel or AMD). The Raspberry Pi 4 uses an ARM64 processor. They speak different languages (instruction sets)!

  • x86_64 CPU: Understands only x86 instructions.
  • ARM64 CPU: Understands only ARM instructions.

If you compile code normally on your PC, it creates x86 machine code. The Raspberry Pi won't understand it. We need a Cross-Compiler: a translator that runs on your PC (x86) but translates code into ARM64 language for the Pi.

sequenceDiagram
    participant PC as "PC (x86_64)"
    participant CC as "Cross-Compiler"
    participant Pi as "Raspberry Pi (ARM64)"

    PC->>CC: Feed Source Code (C/C++)
    CC->>CC: Translate to ARM64 Machine Code
    CC->>PC: Output kernel8.img
    PC->>Pi: Transfer kernel8.img (via SD Card)
    Pi->>Pi: Execute ARM64 Code

Installing the Cross-Compiler

Since we're developing on a PC/Mac for the Raspberry Pi's ARM64 architecture, we need a cross-compiler.

sudo apt update
sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu cmake git
brew install aarch64-elf-gcc cmake git
sudo pacman -S aarch64-linux-gnu-gcc cmake git

Verify the installation:

aarch64-linux-gnu-gcc --version

Installing Build Tools

We'll use CMake as our build system:

cmake --version  # Should be 3.10 or higher

Setting Up the Project

Clone the simpian-os repository:

1
2
3
cd ~/projects
git clone https://github.com/ohyaan/simpian-os
cd simpian-os

Project Structure

1
2
3
4
5
6
7
8
9
simpian-os/
├── CMakeLists.txt          # Main build configuration
├── cmake/
│   └── aarch64-none-elf.cmake  # Toolchain file
├── kernel/
│   ├── boot.S              # Assembly entry point
│   ├── kernel.c            # C kernel code
│   └── linker.ld           # Linker script
└── build/                  # Build output (generated)

Building the Kernel

1
2
3
mkdir build && cd build
cmake ..
make

If successful, you'll see:

[100%] Built target kernel8.elf
Generating raw binary image kernel8.img

The output file kernel8.img is what we'll deploy to the Raspberry Pi.

Understanding the Toolchain

CMake Toolchain File

Located at cmake/aarch64-none-elf.cmake, this file tells CMake how to cross-compile:

  • Compiler: aarch64-linux-gnu-gcc
  • Target: ARMv8-A (64-bit) Cortex-A72
  • Flags: -ffreestanding (no standard library), -nostdlib (no startup files)

Key Compiler Flags

  • -mcpu=cortex-a72+nosimd: Target the Raspberry Pi 4's CPU
  • -ffreestanding: We're not using a hosted environment
  • -nostdlib: Don't link against the standard C library

Next Steps

Now that your environment is ready, we'll dive into the boot process and write our first assembly code!