The ARM processor has several different processor modes that allow access to different resources and functionality. The current processor mode is stored in the Current Program Status Register (CPSR). By writing values to specific bits in the CPSR, the processor mode can be changed. This allows switching between modes like User mode, FIQ mode, IRQ mode, Supervisor mode, Abort mode, Undefined mode, and System mode. The specific processor mode determines what resources are available and what operations are allowed.
ARM Processor Modes Overview
Here is an overview of the main ARM processor modes:
- User Mode – Normal execution mode for most applications. Only has access to limited system resources.
- FIQ Mode – Designed for fast interrupts. Has access to some system resources.
- IRQ Mode – Used for general purpose interrupts. More limited than FIQ.
- Supervisor Mode – Protected mode for the operating system kernel. Full access to system resources.
- Abort Mode – Entered when a memory fault or instruction execution fault occurs.
- Undefined Mode – Entered when an undefined instruction is executed.
- System Mode – Privileged mode for low level system tasks. Full system access.
The processor mode controls what system resources are available to the executing code. This allows the separation of different privilege levels to protect the system. Code executing in User mode cannot access protected system resources or change modes. But code running in a privileged mode like Supervisor can access all resources and change modes.
CPSR Register and Mode Bits
The CPSR register contains the current processor mode and status flags. The processor mode field is 5 bits from 4-0 which correspond to M4-M0. Here is what each mode bit means:
- M4, M3, M2 – 010 – Supervisor Mode
- M4, M3, M2 – 011 – Undefined Mode
- M4, M3, M2 – 100 – Abort Mode
- M4, M3, M2 – 101 – System Mode
- M4, M3, M1, M0 – xxxx – User Mode
- M4 – 0, M3, M2, M1, M0 – x0001 – FIQ Mode
- M4 – 0, M3, M2, M1, M0 – x1011 – IRQ Mode
So by writing the correct bit pattern into the mode bits of the CPSR, the processor will change modes. The other status flags in the CPSR like interrupts enabled and processor state will also be changed if switching to a mode that masks or modifies them.
Writing to CPSR to Change Modes
To change the processor mode by writing directly to the CPSR register, the following steps need to be followed:
- Switch to a privileged mode that can write to the CPSR like Supervisor or System mode.
- Disable interrupts so the CPSR write is uninterrupted.
- Write the value to the CPSR to change the mode bits.
- Execute an instruction to synchronize the pipeline.
- The processor is now in the new mode.
Here is an example code snippet to change from Supervisor to System mode: MRC p15, 0, R0, c1, c0, 0 ; Read CPSR into R0 BIC R0, R0, #0x1F ; Clear mode bits ORR R0, R0, #0x1F ; Set mode bits to System MSR CPSR_c, R0 ; Write back to change mode NOP ; Synchronize pipeline
The MRC and MSR instructions read and write the CPSR. The ORR and BIC instructions set and clear the specific mode bits. And the NOP synchronizes the pipeline.
When changing back to User mode, interrupts will need to be re-enabled. This requires restoring the CPSR from a stack pointer: MRS R0, CPSR ; Read CPSR STMFD SP!, {R0} ; Store CPSR on stack BIC R0, R0, #0x1F ; Change mode bits to User MSR CPSR_c, R0 ; Set CPSR LDMFD SP!, {R0} ; Restore CPSR MSR CPSR_c, R0 ; Set CPSR
By restoring the CPSR value from the stack, the interrupt enable flags will be set correctly for User mode.
ARM Mode Switch Sequence
To properly change modes in ARM, a specific sequence needs to be followed:
- Disable interrupts if changing from User mode or enabling interrupts
- Save state to stack if restoring later (e.g. LR, SPSR)
- Change to new mode with MSR instruction
- Synchronize pipeline with NOP or instruction that switches mode
- Restore state if saved earlier
- Return to new mode with subtraction from LR or BX instruction
Following this sequence ensures a clean switch between processor modes on ARM. Failing to follow the steps properly can lead to crashes or hangs.
User Mode to System Mode Change
Here is code to switch from User mode to System mode on ARM: MRS R0, CPSR ; Read CPSR STMFD SP!, {R0} ; Save CPSR MOV R1, #0x1F ; System mode MSR CPSR_c, R1 ; Enter System mode NOP LDMFD SP!, {R0} ; Restore CPSR MSR CPSR_c, R0 ; Set CPSR
The CPSR is saved so User mode state can be restored later. The NOP synchronizes the pipeline after setting System mode. Finally the CPSR is restored to return to User mode.
Switching from User to FIQ Mode
FIQ mode has 5 dedicated banked registers that need to be saved before switching. Here is an example of changing from User to FIQ mode: STMFD SP!, {R0-R7, LR} ; Save User registers MRS R1, CPSR ; Read CPSR STMFD SP!, {R1} ; Save CPSR BIC R0, R0, #0x1F ; Clear mode bits ORR R0, R0, #0x11 ; Set FIQ bits MSR CPSR_c, R0 ; Change to FIQ NOP ; FIQ handler code LDMFD SP!, {R1} ; Restore CPSR MSR SPSR_fsxc, R1 ; Restore SPSR LDMFD SP!, {R0-R7, LR} ; Restore User registers SUBS PC, LR, #4 ; Return from handler
The User registers and LR are saved to the stack. The CPSR is also saved before changing to FIQ mode. The SPSR gets the stored CPSR value. Finally the User registers and LR are restored before returning.
Mode Changes During Interrupts
When an interrupt or exception occurs, the processor automatically changes to the handler mode:
- IRQ changes to IRQ mode
- FIQ changes to FIQ mode
- Prefetch Abort changes to Abort mode
- Data Abort changes to Abort mode
- Undefined instruction changes to Undefined mode
The handler code will execute in the appropriate mode. To return, the handler returns using SUBS PC, LR, #4 which restores the previous CPSR value from the SPSR of that mode. This automatically changes back to the pre-interrupt processor mode.
Restrictions on Mode Changes
There are some restrictions when changing modes:
- Cannot switch directly from User to System mode
- Cannot switch from IRQ to FIQ mode directly
- Undefined instructions in User cause switch to Undefined mode
- Attempting to switch to an invalid mode will cause an Undefined Instruction exception
Following the proper ARM mode change sequences avoids these issues. Trying to improperly change modes directly can lead to crashes or hangs.
CPSR Mode Bit Security
Changing the processor mode bits in the CPSR allows access to privileged system resources. This is used to separate different privilege levels. Some guidelines for using CPSR mode changes securely:
- Always sanitize user input values before writing to CPSR
- Follow proper mode switch sequences
- Use stack to save/restore state around switches
- Disable interrupts during switch
- Use NOPs to synchronize pipeline
- Restrict mode changes in application code
- Utilize privilege levels to limit access to CPSR
Properly written firmware checks inputs before writing the CPSR and restricts which routines can change modes. User input should never be allowed to directly write the CPSR. That could give attackers a way to escalate privileges.
Debugging CPSR Writes
When debugging issues with changing ARM modes via CPSR writes, here are some tips:
- Single step through code and examine CPSR register
- Check for pipeline sync issues after CPSR writes
- Verify mode switch sequence is followed
- Confirm interrupts disabled/enabled properly
- Check for exceptions/faults due to bad modes
- Examine stack during switch to check saved state
- Confirm restored CPSR has correct mode bits and flags
Stepping through the code allows checking that the CPSR gets updated correctly. The mode bits and status flags can be monitored to see their changes during the switch. Exceptions or crashes will highlight problems with the mode transition.
CPSR Mode Summary
Here are some key points on changing processor modes with CPSR writes on ARM:
- CPSR register holds current mode in 5 mode bits
- Writing certain bit patterns to CPSR changes processor mode
- Must follow mode switch sequence to transition cleanly
- Each mode allows access to different resources
- Interrupts and exceptions can automatically change mode
- Restricting CPSR writes is important for security
Understanding how the CPSR mode bits work and the rules for changing them allows properly switching between the ARM processor modes. This gives full control of the privilege levels to utilize the ARM architecture securely.