We are currently developing firmware for an embedded system which operates a Cortex-A9 processor in bare-metal (no OS). We are using armclang and ARM Development studio, which provides the C library initialisation etc.
There are two parts to the firmware, an custom bootloader used to either load the main application, or perform firmware update. Then the main application image that does everything else.
The recovery firmware for the most part works fine. During startup we initialise the various IRQ stacks, and set the processor into SYS mode. We also then have to configure the SCTLR flags, which boils essentially down to:
MRC p15,0,r0,c1,c0,0
BIC r0,r0,#2
MCR p15,0,r0,c1,c0,0
This works correctly in the recovery firmware. After doing everything else, we come to loading the main image, which essentially boils down to
... r0 set to entry point ...
BLX r0
This is where things start to go weird. The branch succeeds and we end up at the entry point which runs the startup code. The main application uses the exact same startup code as the recovery firmware, initialising the stacks etc. However we then hit the SCTLR access, and bam, undefined instruction. The read access (MRC) appears to work fine, but the write back (MCR) fails.
Just to be awkward, if the debugger is connected (even if things like semihosting are disabled), everything works absolutely fine. I've narrowed it down the the MCR instruction by slowly moving a while(1) through the startup code until the undefined instruction occurs.
Furthermore, for the sake of interest, I made the undefined instruction handler in the application image jump back to the entry point of the recovery image. The same MCR instruction in the recovery firmware startup (which remember, worked fine during the initial launch) triggers the same undefined instruction exception.
To a certain extent, I can strip some of this code away for the application image, but it still has to configure p15 co-proccessor registers (for the VFP unit, etc), so I need to figure out what is blocking the MCR commands when the processor is running on its own (without the debugger connected).
Now I'm aware that MCR is a priviledged instruction and will cause the undefined instruction when in a non-priviledge mode, i.e. CPSR.M = USR, however as this is a bare-metal application, everything is executed with the processor in CPSR.M = SYS, which is a priviledged mode, so access should be possible.
I've checked the value of the SCR register in CP15, and that has the NS bit clear, so based on this in fact all modes should be operating in secure state. Unless of course the debugger is clearing this flag itself. But then I've checked the full disassembly of the recovery firmware, and nothing is writing to the NS flag, so it surely must always have been zero otherwise it would have crashed when first launched.
I'm looking for some advice on whether there are any other registers I need to check that might be preventing access to the co-processor registers in SYS mode with NS clear.