Hello,
I am using a standalone software which is current run in SYSTEM mode. But I would like to run it in USER mode instead, in order to be in non-privileged mode and be able to test my MMU fault handler (in particular permission faults).
In the linker script I have declared the USER stack within the stack section, and defined its size as 1024B.
_STACK_SIZE = DEFINED(_STACK_SIZE) ? _STACK_SIZE : 0x2000; _ABORT_STACK_SIZE = DEFINED(_ABORT_STACK_SIZE) ? _ABORT_STACK_SIZE : 1024; _SUPERVISOR_STACK_SIZE = DEFINED(_SUPERVISOR_STACK_SIZE) ? _SUPERVISOR_STACK_SIZE : 2048; _IRQ_STACK_SIZE = DEFINED(_IRQ_STACK_SIZE) ? _IRQ_STACK_SIZE : 1024; _FIQ_STACK_SIZE = DEFINED(_FIQ_STACK_SIZE) ? _FIQ_STACK_SIZE : 1024; _UNDEF_STACK_SIZE = DEFINED(_UNDEF_STACK_SIZE) ? _UNDEF_STACK_SIZE : 1024; _USR_STACK_SIZE = DEFINED(_USR_STACK_SIZE) ? _USR_STACK_SIZE : 1024;
.stack (NOLOAD) : { . = ALIGN(16); _stack_end = .; . += _STACK_SIZE; . = ALIGN(16); _stack = .; __stack = _stack; . = ALIGN(16); _irq_stack_end = .; . += _IRQ_STACK_SIZE; . = ALIGN(16); __irq_stack = .; _supervisor_stack_end = .; . += _SUPERVISOR_STACK_SIZE; . = ALIGN(16); __supervisor_stack = .; _abort_stack_end = .; . += _ABORT_STACK_SIZE; . = ALIGN(16); __abort_stack = .; _fiq_stack_end = .; . += _FIQ_STACK_SIZE; . = ALIGN(16); __fiq_stack = .; _undef_stack_end = .; . += _UNDEF_STACK_SIZE; . = ALIGN(16); __undef_stack = .; _usr_stack_end = .; . += _USR_STACK_SIZE; . = ALIGN(16); __usr_stack = .; } > ps7_ddr_0
Then in the __boot assembly code I added the code to initialize the USER stack and switch to USER mode (after SYS mode init):
mrs r0, cpsr /* get the current PSR */ mvn r1, #0x1f /* set up the system stack pointer */ and r2, r1, r0 orr r2, r2, #0x1F /* SYS mode */ msr cpsr, r2 ldr r13,=SYS_stack /* SYS stack pointer */ bic r2, r2, #(0x1 << 9) /* Set EE bit to little-endian */ msr spsr_fsxc,r2 mrs r0, cpsr /* get the current PSR */ mvn r1, #0x1f /* set up the user stack pointer */ and r2, r1, r0 orr r2, r2, #0x10 /* USER mode */ msr cpsr, r2 ldr r13,=USR_stack /* USER stack pointer */
But when I try to read the current CPSR mode when the standalone software is executing, I find out it is still in SYSTEM mode (0x1f)...
Could anyone tell me if the stack is setup properly?
Thank you a lot.
The only thing which is done afterwards to CPSR is unmask asynchronous abort (bit A of CPSR). Since it requires PL1 privilege, I guess it does not work in USER mode.
I doubt I can use movs pc, lr as the lr has never been written before: I execute inline assembly code from the entry point.
Actually it would be best to change CPU mode before branching to main, as I need to initialize a bunch of system registers in between stack initialization and main handoff.
For this purpose I have used the CPS instruction right before branching to main as follows: cps #10
#10 is the code for USER mode
I still face an undefined exception inside my main function. I guess this is because my standalone code still modifies TTB Control Register and SCTRL.AFE bit which all need PL1... I will therefore try to use the assembly instruction inline with my C code....
I guess this is more or less solved. Thanks!
XNoOp said:I doubt I can use movs pc, lr as the lr has never been written before: I execute inline assembly code from the entry point.
You can use it to call main.
ldr r14,=main movs pc,lr