[Fwd: Modes, stack setup for "no-OS" ARM app]

Toralf Lund toralf@procaptura.com
Tue Apr 20 13:54:00 GMT 2004

Nick Clifton wrote:

> Hi Toralf,
>> I've been wondering about how I should handle processor modes and set up
>> stack pointers etc. for my newlib-based ARM application running on a
>> "bare" system (no OS, no debug monitor.) Unlike the default crt0, mine
>> will definitely have to set up stack pointers for more than one mode,
>> since I use interrupts actively. 
> (Starting from a privileged mode) use the MSR instruction to write to 
> the CPSR to select the privileged mode you want.  Then initialise that 
> modes stack pointer.  Then move on to the next mode.

Yep. I've done that already, but only for FIQ and IRQ in addition to the 
initial mode, presumably SVC.

Another question is how choose the stack size for each mode. For maximum 
flexibility, I guess I should allow the user to control each of the 
stacks via symbols defined in the linker script or similar, but that way 
the start code perhaps get a bit too dependent on external symbols.

>> Also, I'm not quite sure what mode the
>> application itself ought to run under. I need to access "privileged"
>> registers etc. during the init phase at least, so some bits have to run
>> in Supervisor or System, but do I want to do *everything* in one of
>> those modes?
> No - if at all possible run in User mode.  This will give you the most 
> protection from bugs in your overwriting important registers and 
> memory locations.

So, you'd run the bulk of the code in User mode even when there is only 
one program that "owns" the hardware?

Yeah, I guess that's the safest way. Whether I can easily organise my 
code (which is a port of an old M68K app that used to run in Supervisory 
mode, by the way) to make it possible remains to be seen, though...

>> Some issues related to this (in no particular order):
>>   1. Once User mode is entered, there is no easy way back, as far as I
>>      know, so I can't simply switch to that mode e.g. to set up the
>>      stack, if I want SVC or System later.
> Correct.  The only way back is via an interrupt, (hard or soft) which 
> is supposed to be vectored into OS code which decides if the process 
> can have its privileges escalated.  In your case you should be able to 
> install a vector into 0x00000008 and then use the SWI instruction to 
> start that code executing in Supervisor mode.

Yep. I don't think I can rely on such a method within the actual startup 
code, though (if I want it to be general), as the actual vector setup 
(i.e. how to load data at address 0, and where the vectors may point) is 
highly hardware dependent.

>>   2. System is ARM version 4 and above, so perhaps I shouldn't use that
>>      in my crt0, which I intend to be very general.
> There are very few ARMv3 and earlier systems left these days, so you 
> probably can safely ignore them.  Using ARMv4 as the basis of your 
> crt0 should be quite safe.

Fair enough...

>>      stack pointer e.g. from supervisor mode, at least when using gas.
>   3. As far as I can tell, there is no way to access the user mode
> Check out the LDM(2) and STM(2) instructions.  (You do have a copy of 
> the ARM Architecture Reference Manual right ?).  They will allow user 
> mode general purpose registers to be accessed when running in a 
> privileged mode.

I didn't notice those variants at first, but then someone pointed them 
out. I'm not sure I want to use them in any case, though, unless I 
manage to organise the code in such a way that a static value can be used.

I'm actually trying to write a crt0.S that is sufficiently general to be 
included in the newlib sources, so I don't want to make assumptions 
about the memory layout, or even require the code to be loaded in 
writeable memory. (And if I can assume at least ARMv4, I proably won't 
have to.)

- Toralf

More information about the Newlib mailing list