I already found the Baking Pi tutorials, but they only use assembly language. I followed the first lessons, but I am already wondering how to use C instead. I mean, there is a reason they invented higher-level languages. I tried just compiling the C code to an object (.o) file, compiling

.section .init
.globl _start

bl main

b loop$

to another object file and linking them together and so obtaining kernel.img. I then replaced the already present kernel with my own, but it doesn't execute the C code. The C code I wrote should just turn on the OK LED and then return (then comes loop$: b loop$). But the OK LED flashes randomly a few times and then just stays off. Here's my C code:

int main(int argc, char ** argv) {
    volatile unsigned *gpioAddr = (volatile unsigned *)0x20200000;
    *(gpioAddr + 4) = 1 << 18;
    *(gpioAddr + 40) = 1 << 16;
    return 0;

How do I use C for operating system development on a Raspberry Pi?

I doubt it is an error in the code (although I'm just a hobbyist). I'm aware setting up C may be complicated, but I'm not the first one doing this. AFAIK, all the currently dominant OSes are mainly written in C, so there has to be an article explaining the process. I would be very happy with a list of steps too, so I can google for those steps and perhaps ask a question a little less broad.

Note: the ARM assembly equivalent of the above C code works just fine. It turns on the LED (after a bit of blinking). I think (hope) that indicates my Raspberry Pi is fine.

  • 1
    C was designed to be portable assembly language for Unix. Linux is written in C, you can save quite a bit of time by looking at how it is done. Jul 27, 2013 at 22:27
  • 1
    @ThorbjørnRavnAndersen I think I'm not up to reading the source of Linux. Linux is far more complex than what I want know, thus obscuring the for me interesting pieces.
    – 11684
    Aug 25, 2013 at 15:48
  • 1
    Um, 'wire up' a few LEDs.
    – 11684
    Aug 26, 2013 at 6:49
  • 1
    Thank you, but I want to do most things myself. It's a learning project.
    – 11684
    Aug 26, 2013 at 6:51
  • 1
    I Must admit I never saw a question any where before on how to write an OS. And there are some interesting answers. It is just crazy...
    – Piotr Kula
    Sep 13, 2013 at 13:24

5 Answers 5


I wrote a very simple kernel years ago, and ran it on a 386. I haven't done bare metal programming in years, but in broad terms you need to write some assembler code that will:

  • disable interrupts during the boot process
  • if the Pi has a memory controller, you'll need to set that up
  • set up a timer tick
  • configure the interrupt controller
  • set up a stack so that you can execute C code

Setting up the stack is easy - find some memory that's not being used, and load that address into which ever register is used as the stack pointer.

In your C code you need to init OS data structures like a memory pools and thread tables. You won't be able to use C library functions - you'll need to write that stuff yourself.

If you want to write a simple multitasking os, you'll need to write some assembler routines to save CPU registers on the stack, and load a different set of register values from another thread's stack. And you'll need to write an API to create different threads.

  • 1
    Hard to choose between this answer and Georges Dupéron's. I accepted this one and gave the other an upvote.
    – 11684
    Sep 17, 2013 at 17:39

I haven't looked at your code in depth, but it seems to me you're on the right track. Make sure that:

  • The _start symbol is indeed the one used when compiling & linking your assembly file and your C file (and that main() isn't used instead)
  • When calling main(), you need to use the C calling convention:
    • push on the stack the address of the instruction following your call (the return address, which will be used by the return statement in C)
    • push the arguments for the function. In your case you can push two 32-bit values (8 bytes in total), but to make things simpler you could also remove the arguments and just have int main() { ... }
    • maybe reserve some space on the stack for the return value
    • I can't remember in what order these things should be pushed
    • To know what the C function expects exactly, disassemble it (objdump -S main.o) and look at how it manipulates the stack.
  • If you don't respect the calling convention, then the assembly code generated by the C compiler might tamper with the return address on the stack, and in your case you didn't even push a return address, so the return instruction will jump somewhere random, instead of going to loop$.

The OSDev wiki will be a very useful ressource -- it's mainly concerned with x86 development but most information is still applicable to the raspberry pi.

Some more raspberry-pi osdev specific resources:

  • Hard to choose between this answer and Steve's. I gave you an upvote and accepted the other one. I regret the 5 rep difference.
    – 11684
    Sep 17, 2013 at 17:39
  • OSDev wiki is good - and even has some specific RasPi stuff
    – wally
    Dec 30, 2014 at 15:24

The main problem you might encounter is the C libraries and prologue code. It's started before your own code starts executing and sets up the stack, the heap and does plenty of other helpful things. However, when you're trying to program for bare metal you don't have any OS running below you and you'd better to avoid calling these functions. In order to do that you need modified versions of C libraries and/or some global symbols defined or replaced with your own. This process is a bit involving, that's why 'Baking Pi' people chose to use assembly for their tutorials.

  • Thank you for answering my question (and sorry for responding so late). But (surprise!) I bought my pi to learn about just that, the bit involving low level processes (I'd rather not do that on an expensive desktop with the risk of destroying personal files/mails/photos). Could you please add how I set up the stack, or an article/tutorial/some resource explaining that? (And what else I might need to run C).
    – 11684
    Aug 5, 2013 at 7:24

Try this instead:


Also, the x86 experience is a bit different. It may be applicable to general ARM bare metal OS programming. But for Pi, sorry it is the gpu start first and set up quite a bit before your OS (?) code.

  • 1
    A little more detail would be great, what happens if the link in your answer breaks?
    – Darth Vader
    May 22, 2016 at 7:34
  • It still there but I think for those who come to here, may google "valves bare metal" and better try OSDEV series (to get past the cross dev one as I struggled, read the forum; I post one you can try google "OSDEV forum six month cross")
    – Dennis Ng
    Jun 13, 2016 at 10:15
  • I know this is an old answer to an even older question, but the page is on web.archive.org in case it goes down.
    – anonymoose
    Jun 12, 2018 at 20:28



This awesome repo does both the C bootstraping, and goes into pretty complex topics.

Furthermore, it looks into how the Linux kernel does things, and annotates Linux kernel code.

Have a look at the first tutorial for a minimalistic setup: https://github.com/s-matyukevich/raspberry-pi-os/tree/43f682d406c8fc08736ca3edd08a1c8e477c72b0/src/lesson01/src

I highly recommend it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.