simple OS functionality


7 posts
by adriann » Wed Nov 28, 2012 9:49 am
Hello,

I have a couple of questions about writing basic OS functionality:

1. Could basic functionality (such as LED, screen, input in Baking Pi) be written in C instead of assembly? What about C++? What readings do you recommend about C or C++ OS bare metal programming (OS building) on Pi?

2. Is there any example about building a vector font, as mentioned in Baking Pi? Or are there free vector fonts that can be used in bare metal display on Pi?

Thank you,
Adrian
Posts: 3
Joined: Wed Nov 28, 2012 9:32 am
by blm768 » Wed Nov 28, 2012 7:11 pm
adriann wrote:1. Could basic functionality (such as LED, screen, input in Baking Pi) be written in C instead of assembly? What about C++? What readings do you recommend about C or C++ OS bare metal programming (OS building) on Pi?


Most of it can be done in C/C++, but you'll probably still need a bit of assembly for some things, such as your early initialization and interrupt handlers. That's the way I've done my own code.
There aren't really many good articles on bare metal programming for the Pi; Baking Pi is about the only one I've seen. One of these days, I might have to write my own. One of the challenges is that the community is still discovering many of the details of the Pi's operation; its hardware is fairly complex and not very well documented.

adriann wrote:2. Is there any example about building a vector font, as mentioned in Baking Pi? Or are there free vector fonts that can be used in bare metal display on Pi?


There are probably some resources somewhere on the Web, but I wouldn't recommend starting out with vector fonts. The implementation isn't trivial, and there's little benefit for most bare metal programs. Unless you need to scale the characters, you could just render a vector font into a bitmap and use that in your program. If you really do need vector fonts, you might be able to use the FreeType library, but you'll probably have to modify it so it can run on bare metal.
Posts: 24
Joined: Sun Nov 18, 2012 6:13 am
by jeremyp » Sat Dec 01, 2012 4:20 pm
adriann wrote:Hello,

I have a couple of questions about writing basic OS functionality:

1. Could basic functionality (such as LED, screen, input in Baking Pi) be written in C instead of assembly? What about C++? What readings do you recommend about C or C++ OS bare metal programming (OS building) on Pi?


I have redone all of the basic and screen exercises in C. The only assembler you need is

1. set up the stack pointer

2. set up the arguments to main().

It takes three mov instructions to do that.
Posts: 9
Joined: Wed Sep 26, 2012 3:58 pm
by BrianW » Sun Dec 02, 2012 11:29 am
blm768 wrote:
adriann wrote:Most of it can be done in C/C++, but you'll probably still need a bit of assembly for some things, such as your early initialization and interrupt handlers.

If you're using gcc, you can write your interrupt handler in C
Code: Select all
__attribute__ ((interrupt ("IRQ"))) void irq(void)
{
        /* Do stuff */
}
gcc will produce the necessary code to save registers onto the stack, and return from the interrupt properly when it's done.

http://gcc.gnu.org/onlinedocs/gcc/Funct ... butes.html
Posts: 77
Joined: Sun Jul 29, 2012 9:03 pm
by tufty » Sun Dec 02, 2012 2:37 pm
BrianW wrote:gcc will produce the necessary code to save registers onto the stack, and return from the interrupt properly when it's done.

I'm almost certain that doesn't produce correct code for ARM interrupt handlers.

[edit] - after testing, In fact, I'm now absolutely certain it doesn't.

"do nothing" handler
Code: Select all
__attribute__ ((interrupt ("IRQ"))) void irq (void)
{
int i = 0x0;
}

Compile :
Code: Select all
arm-none-eabi-gcc -S -mcpu=arm1176jzf-s -o irq.s irq.c

Resultant assembly (less the various bits of gcc-produced crap, and with comment added)
Code: Select all
irq:
        @ Interrupt Service Routine.
        @ args = 0, pretend = 0, frame = 8
        @ frame_needed = 1, uses_anonymous_args = 0
        @ link register save eliminated.
        stmfd   sp!, {r3, fp}
        add     fp, sp, #4
        sub     sp, sp, #8
        /* this bit sets up our "do nothing" variable, i */
        mov     r3, #0
        str     r3, [fp, #-8]
        /* done */
        sub     sp, fp, #4
        ldmfd   sp!, {r3, fp}
        subs    pc, lr, #4


Remember, when you drop into an irq, you're thrown into irq operating mode, with the address of the interrupted operation in lr and the interrupted cpsr in spsr. The code above will happily return you to a totally random context in the wrong mode.

You *could* use the code generated above for an irq-specific subhandler *dispatched* from a top level irq handler, but you don't need to add attributes in that case anyway.

Simon
Posts: 1362
Joined: Sun Sep 11, 2011 2:32 pm
by BrianW » Sun Dec 02, 2012 8:01 pm
According to the ARM Architecture Reference Manual, you can restore SPSR to CPSR by using a data processing instruction with PC as the destination and the S bit set. In fact, for an IRQ, the ARM ARM specifically says "To return after servicing the interrupt, use: SUBS PC,R14,#4"

If the interrupt routine is more complex, gcc will plant code more like this:

sub lr, lr, #4
push {r0, r1, r2, r3, ip, lr}
/* Interrupt servicing code goes here */
ldm sp!, {r0, r1, r2, r3, ip, pc}^

Again, this is one of the recommended ways of doing it, and matches an example in the ARM.

As far as I can see, gcc is doing the right thing.
Posts: 77
Joined: Sun Jul 29, 2012 9:03 pm
by tufty » Mon Dec 03, 2012 5:20 pm
That wil get you simple interrupt handling, it's true. However, it won't get you reentrant interrupts (or, at least, not without a lot of messing about, such as was required for ARMv4), and if you get re-interrupted, you'll kill your application stone dead. Yeah, I've been there :) It also makes life a bit harder if you want to do interrupt handing in some other mode (generally svc or system mode). Indeed, you'll find that most OSs (and almost certainly all RTOSs) do something slightly more complicated (although not necessarily as complicated as Linux does). It's usually done by defining the entry and exit "blocks" as inline assembler, and then using __attribute__ (naked) to remove all the usual C calling convention stuff from the handler itself. Either that, or doing the top level handler in raw assembly and then passing off to C handlers.

A better / more resilient way of irq handling (oddly enough, the approach taken by most RTOSs) is documented here : http://infocenter.arm.com/help/index.js ... eacfi.html - note the use of srs/rfe if you're on ARMv6. I'm not sure if gcc provides any way of doing this automagically, but from the implementations I've seen, I doubt it. For FIQ you can probably get away with the gcc method as described earlier, as long as your fiq handler is fast enough not to get re-interrupted while it's in progress.

Simon
Posts: 1362
Joined: Sun Sep 11, 2011 2:32 pm