Explicitly accessing banked registers on ARM
According to the ARM manual, it should be possible to access the banked registers for a specific CPU mode as, for instance, "r13_svc". When I try to do this gcc yells at me with the following error:
immediate expression requires a # prefix -- `mov r2,sp_svc'
What's wrong?
Update. The following text from the ARM Architecture Reference Manual for ARMv5 and ARMv6 led me to believe that it is possible, section A2.4.2:
Registers R13 and R14 have six banked physical registers each. One is used in User and System modes, and each of the remaining five is used in one of the five exception modes. Where it is necessary to be specific about which version is being referred to, you use names of the form: R13_mode R14_mode where mode is the appropriate one of usr, svc (for Supervisor mode), abt, und, irq and fiq.
Solution 1:
The correct syntax for this is mrs r2,sp_svc
or mrs r3, sp_usr
. This is a new armv7 extension. The code can be seen in the ARM Linux KVM source file interrupt_head.S. The gas binutils patch for this instruction support by Matthew Gretton-Dann. It requires the virtualization extensions are far as I understand.
According to what I understand, the LPAE (large physical address extension) implies the virtualization extensions. So Cortex-A7, Cortex-A12, Cortex-A15, and Cortex-A17 may be able to use this extension. However, the Cortex-A5, Cortex-A8, and Cortex-A9 can not.
Documentation on the instruction can be found in the ARMv7a TRM revC, under section B9.3.9 MRS (Banked register).
For other Cortex-A (and ARMv6) CPU's you can use the cps
instruction to switch modes and transfer the banked register to an un-banked register (R0-R7) and then switch back. The obvious difficulty is with user mode. The correct way to handle this is with ldm rN, {sp,lr}^
; user mode has no simple way back to the privileged modes.
For all older CPUs, the information given by old_timer will work. Mainly, use mrs/msr
to change modes. mrs/msr
works over the full class of ARM cpus but requires multiple instructions and hence may have race issues which require interrupt and exception masking depending on context.
This is an important instruction (sequences) for context switching (which VMs do a lot of).
Solution 2:
I don't think that's possible with the mov
instruction; at least according to the ARM Architecture Reference Manual I'm reading. What document do you have? There are is a variant of ldm
that can load user mode registers from a privileged mode (using ^
). Your only other option is to switch to SVC mode, do mov r2, sp
, and then switch back to whatever other mode you were using.
The error you're getting is because it doesn't understand sp_svc
, so it thinks you're trying to do an immediate mov
, which would look like:
mov r2, #0x14
So that's why it says "requires a # prefix".
Solution 3:
You use mrs and msr to change modes by changing bits in the cpsr then use r13 normally.
From the arm arm
MRS R0,CPSR BIC R0,R0,#0x1F ORR R0,R0,#0x13 MSR CPSR_c,R0
then
mov sp,#0x10000000
or if you need more bits in the immediate
ldr sp,=0x12345600
or if you dont want the assembler placing your data, you can place it yourself.
ldr sp,svc_stack b 1f svc_stack: .word 0x12345600 1:
You will see typical arm startup code, where the application is going to support interrupts, aborts and other exceptions, to set all of your stack pointers that you are going to need, change mode, set sp, change mode, set sp, change mode ...