I have been playing around with azure-rtos (THREADX) and trying to port the OS for the cortex R5 based system. After looking at the port files, it seems that OS runs the threads in Supervisor (SVC) mode.
For example, in the function _tx_thread_stack_build
, while building the stack for threads, initialization value for the CPSR
is such that mode bits correspond to SVC mode. This initialization value is later used to initialize the CPSR before jumping to the thread entry function.
Following is the snippet of the function _tx_thread_stack_build
storing initialization value of CPSR on the stack of a thread. For your reference see file tx_thread_stack_build.S.
.global _tx_thread_stack_build
.type _tx_thread_stack_build,function
_tx_thread_stack_build:
@ Stack Bottom: (higher memory address) */
@
...
MRS r1, CPSR @ Pickup CPSR
BIC r1, r1, #CPSR_MASK @ Mask mode bits of CPSR
ORR r3, r1, #SVC_MODE @ Build CPSR, SVC mode, interrupts enabled
STR r3, [r2, #4] @ Store initial CPSR
...
To give another example, the function tx_thread_context_restore.S
switches to SVC mode from IRQ mode to save the context of thread being switched out, which indicates that OS assumes here that thread is running in an SVC mode. For your reference see the file tx_thread_context_restore.s
Following is a snippet of the function saving context of a thread being switched out.
LDMIA sp!, {r3, r10, r12, lr} ; Recover temporarily saved registers
MOV r1, lr ; Save lr (point of interrupt)
MOV r2, #SVC_MODE ; Build SVC mode CPSR
MSR CPSR_c, r2 ; Enter SVC mode
STR r1, [sp, #-4]! ; Save point of interrupt
STMDB sp!, {r4-r12, lr} ; Save upper half of registers
MOV r4, r3 ; Save SPSR in r4
MOV r2, #IRQ_MODE ; Build IRQ mode CPSR
MSR CPSR_c, r2 ; Enter IRQ mode
LDMIA sp!, {r0-r3} ; Recover r0-r3
MOV r5, #SVC_MODE ; Build SVC mode CPSR
MSR CPSR_c, r5 ; Enter SVC mode
STMDB sp!, {r0-r3} ; Save r0-r3 on thread's stack
This leads me to a question, is there a way to run threads in USER mode? It is typically a case in OS that threads run in USER mode while kernel and services provided by it run in an SVC mode, which does not seem to be the case with Azure RTOS.
This is by design, ThreadX is a small monolithic kernel, where application code is tightly integrated with the kernel and lives in the same address space and mode. This allows for greater performance and lower footprint. You can also use ThreadX Modules, where the available MPU or MMU is used to separate kernel and user code into different modes and provide additional protection, but this incurs a small performance and footprint penalty.