This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

run standalone software in user mode

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.

Parents Reply Children
  • 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!

  • 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