4

When booting up a toy kernel, I use this code to switch to user mode:

  mrs r1, CPSR                  @ Switch to System mode
  orr r1, r1, #0xc
  msr CPSR, r1
  ldr sp, =gUsrStackBase        @ Setup USR stack (shared with System mode)
  mov  r1, #0x10                @ Get user-mode CPSR into SPSR
  msr  SPSR, r1
  movs pc, r0                   @ Switch to USR mode and branch

But following the movs instruction, instead of the user-mode CPSR value I set, (0x10), there's random garbage in the CPSR. Why could this be?

Brendan
  • 1,995
  • 1
  • 20
  • 35

1 Answers1

2

I banged my head against this issue for a very very, very [1] long time! Finally I found the cause of the problem. In the ARM Architecture Reference Manual (only the up-to-date, ARMv7A -R version!) [2], is this:

An MSR (register) executed in System mode is UNPREDICTABLE if it attempts to update the SPSR.

(This is also true for MSR with immediate).

The solution is to switch back to supervisor (or other privileged) mode before setting the SPSR.

[1] very

[2] You can get the ARMv7-ARM here (you'll need to sign up): http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0406c/index.html

Brendan
  • 1,995
  • 1
  • 20
  • 35
  • 1
    FWIW, the older ARM ARMs also have this information, just in a different place. In v6 and v5, the "Progammers' Model" chapter, section 2.5 "Program Status Registers", has this note: "User mode and System mode do not have an SPSR, because they are not exception modes. All instructions which read or write the SPSR are unpredictable when executed in User mode or System mode." v4 has a similar statement at the end of the equivalent section. Guess it got lost in early editions of v7. – Notlikethat Nov 03 '14 at 13:48
  • You should also specify the full *feilds*. Like `msr CPSF_fsxc,r1` as at least some assemblers will default to a single field (control); it is better to be explicit. – artless noise Nov 03 '14 at 16:13