In our last article, we've gone through a brief overview of ARM Cortex M series microcontrollers and using the STM32 development board wrote the Hello World example program. This article will try to understand various operational modes available in Cortex M microcontrollers with the help of a simple example.
Operation Modes in Cortex M
ARM Cortex M microcontrollers have two modes.
Thread Mode
Handler Mode
Thread mode is equivalent to the user mode of the Unix operating system. The user program runs in thread mode. The processor enters Thread mode out of reset and returns to Thread mode on completion of an exception handler.
Handler mode is akin to the kernel mode of the Unix Operating system. All exceptions cause entry into Handler mode. Exception and fault handling codes run in handler mode. We achieve unix-style operation mode with the help of the Cortex M processor's band stack. Cortex M processors have two stack pointers 1. Main Stack Pointer (MSP) and Process Stack Pointer (PSP).
Access levels in Cortex M
There are two levels of privilege in ARM Cortex M processors.
Unprivileged Level
Privileged Level
In the unprivileged access level, the software has limited access to system resources. In the privileged access level, the software has full access to system resources, subject to security restrictions. When the device is in Thread mode, the CONTROL register controls whether software execution is privileged or unprivileged. Whereas in Handler mode, software execution is always privileged.
Only privileged software can write to the CONTROL register to change the privilege level for software execution in Thread mode. Unprivileged software can use the SVC instruction to make a Supervisor Call to transfer control to privileged software.
CONTROL Register and Access Level
Let's try to understand these concepts with the help of the below control flow diagram.
Once program execution starts i.e. after reset, the processor starts execution in thread mode with privileged access level
Modifying CONTROL register's 0th bit to 1 forces the processor into unprivileged mode.
Once the processor is in unprivileged mode, it's not possible to access the CONTROL register and hence mode can not be changed.
The only way to revert to privileged mode from unprivileged mode is with the help of an exception.
Once an exception is generated, the appropriate exception handler will get executed in Handler mode. Since the Handler mode has a privileged access level, the user can update CONTOL register's 0th bit to 1, making the access level again privileged, after the exception handler exit.
Referring to the Cortex M4 general purpose user guides (PM0214), section 2.1.3 Core Register section, and table 11 we can identify 0th bit controls the privilege level. Since the CONTROL register can not be accessed directly, we need to use the assembly function to modify the CONTROL register
Below is a sample program to change the access level to unprivileged mode.
/* AccessLevel.c */
void changeAccessLevelUnprivilege(void) {
// read CONTROL register value in R0
__asm volatile("MRS R0, CONTROL");
// modify/OR value of R0 with value 0x01
__asm volatile("ORR R0,R0, #0x01");
__asm volatile("MSR CONTROL, R0");
}
/* Note:
- After entering in unprivilege access level, user task can not access MSR,MRS and hence can not go back to privilege mode.
- Only way is to change thread mode to handler mode via exception where CONTROL reg can be changed and after exit of exception handler
mode will be thread mode.
- MSR: Move the contents of general purpose register into specfied special register
- MRS: Move the contents of a special register to a general purpose register
*/
/*main.c*/
void changeAccessLevelUnprivilege(void);
int main(void) {
printf("Before Interrupt : Thread Mode\n");
changeAccessLevelUnprivilege();
// after entering unprivileged access level, program has limited access.
printf("After Interrupt : Thread Mode\n");
for(;;);
}
Executing the above program may not give much indication of what is going on inside the processor but post execution of function changeAccessLevelUnprivilege() processor can not access privileged command. Let's try to understand this by updating main.c with the below changes.
/*main.c*/
void changeAccessLevelUnprivilege(void);
/** This function executes in Thread Mode of the processor
to generate IRQ3 which is for RTC wakeup interrupt
*/
void generateInterrupt(void) {
// Software Trigger Interrupt Register
volatile uint32_t *pSTIR = (uint32_t*) 0xE000EF00;
// Interrupt Set Enable Register
volatile uint32_t *pISER0 = (uint32_t*) 0xE000E100;
*pISER0 |= (1 << 3);// enable IRQ3 interrupt
*pSTIR = (3 & 0x1FF);// enable IRQ3 interrupt (0:8) bit used for IRQ#
}
int main(void) {
printf("Before Interrupt : Thread Mode\n");
changeAccessLevelUnprivilege();
/* after entering unprivileged access level, program has limited access. Hence trying to generate exception using generateInterrupt() will result in hard fault*/
generateInterrupt(); // HardFault exception
printf("After Interrupt : Thread Mode\n");
for(;;);
}
/* The STM32F411VETx interrupt vector table updated with below handler*/
void HardFault_Handler(void) {
printf("Inside Hardfault Interrupt Handler: Handler Mode\n");
}
/*
* This function(ISR) executes in HANDLER MODE of the processor
*/
void RTC_WKUP_IRQHandler(void) {
// IRQ3: RTC Wakeup interrupt through the EXTI line
/* Monitor Interrupt Program Status Register (IPSR) part of xPSR Special register once ISR execute.
- IPSR will contain ISR_NUMBER in [8:0] bits. 0 Thread mode and non zero handler mode(refer doc)
- In debug mode monitor xPSR register: last 8 bits would be 19 which is 3rd IQR
*/
printf("Inside RTC Wakeup Interrupt Handler: Handler Mode\n");
}
Running the above program will cause a hard fault as after changeAccessLevelUnprivilege() access level is unprivileged and running IRQ3 will cause a hard fault exception as the processor is not allowed to access privileged resources. For detailed information refer to this GitHub repository.
Conclusion
ARM Cortex M series controllers have two modes. Thread mode is the default mode where the user program executes, and Handler mode is for exception and fault handling code. Using ARM Cortex M's band stack i.e. Process Stack Pointer and Main Stack Pointer and processor mode can be used to implement OS like environment where user processes program run in thread mode with limited privileges in unprivileged access level and handler mode to manage hardware resources using privileged access level.
Comments