We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
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.
Actually it is, but are you sure nothing else interferes?
But to be honest, I am not sure, you can switch directly to USR mode. I do it always via "movs pc,lr".
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