1# Process Isolation {#CMSIS_RTOS_ProcessIsolation} 2 3CMSIS-RTOS2 API supports a concept of **process isolation** that allows developers to protect execution of critical software tasks against potential flaws in other parts of a program. 4 5Process Isolation in CMSIS-RTOS2 is enabled by following features: 6 7 - \subpage rtos_process_isolation_mpu for memory access protection in the system using Memory Protection Unit (MPU).<br/> 8 RTOS threads are executed with permission to access only memory regions and peripherals required for their operation. Hence thread code cannot accidentally modify critical RTOS kernel data or memory dedicated to other tasks. 9 . 10 - \subpage rtos_process_isolation_safety_class for access protection to RTOS objects via RTOS APIs.<br/> 11 The RTOS objects with a higher safety class assigned to them cannot be modified via RTOS API functions from threads that have lower safety class assigned. 12 . 13 - \subpage rtos_process_isolation_thread_wdt to verify execution times of threads.<br/> 14 Each thread can maintain own thread watchdog and in case of timing violations, corresponding thread watchdog alarm will be triggered. 15 . 16 - \subpage rtos_process_isolation_faults in case of a detected failure (for example thread watchdog alarm or MPU Fault).<br/> 17 The RTOS provides functions to block execution of malfunctioning components and with that dedicate system resources for operation of the safety critical threads. 18 19\if FuSaRTS 20Section \ref fusa_process_isolation lists safety requirements for Process Isolation functions. 21\endif 22 23<!-- =============================================================== !--> 24\page rtos_process_isolation_mpu MPU Protected Zones 25 26Memory Protection Unit (MPU) is available on many Cortex-M devices and allows to execute code with restricted access to memory regions and peripherals. Detailed information about the MPU can be found in [Cortex-M Reference Manuals](../Core/index.html#ref_man_sec). 27 28CMSIS-RTOS2 provides a concept of **MPU Protected Zones** as a simple and flexible mechanism for using MPUs with RTOS threads. MPU Protected Zones are defined by a user as a set of memory regions and peripherals with specified access rights, and each RTOS threads gets assigned to a specific MPU Protected Zone that it is allowed to use. 29 30The figure below illustrates the concept for MPU Protected Zones for isolating threads. 31 32 33 34Sections below explain in details how to define and use MPU Protected Zones: 35 36 - \ref rtos_process_isolation_mpu_def 37 - \ref rtos_process_isolation_mpu_load 38 - \ref rtos_process_isolation_mpu_objects 39 - \ref rtos_process_isolation_mpu_fault 40 41**Function references** 42 43Following functions implement and use MPU Protected Zone functionality: 44 45 - \ref osThreadNew : \copybrief osThreadNew 46 - \ref osThreadZone : \copybrief osThreadZone 47 - \ref osThreadGetZone : \copybrief osThreadGetZone 48 - \ref osThreadTerminateZone : \copybrief osThreadTerminateZone 49 - \ref osZoneSetup_Callback : \copybrief osZoneSetup_Callback 50 51## Define MPU Protected Zones {#rtos_process_isolation_mpu_def} 52 53In the architectural design phase an application is logically split into functionalities with the same integrity level (same safety requirements). They can safely operate within the same MPU Protected Zone and hence access same memory areas and peripherals. 54 55MPU protected zones are defined in an MPU table where each row describes an individual MPU zone and each cell in the row specifies an MPU region within that zone. For details see section [MPU Functions](../Core/group__mpu__functions.html) in CMSIS-Core(M) documentation. 56 57> **Note** 58> - Interrupt handlers bypass the MPU protection. For this reason, it is required that potential impact of all interrupt handlers is strictly analyzed to exclude unintended memory accesses. 59 60**Zone Identifier** (Zone ID) is used to refer to a specific MPU protected zone. Zone ID value equals to the row index (starting from 0) in the MPU table that describes corresponding MPU Protected Zone. 61 62An MPU Protected Zone is assigned to one or more RTOS threads. This is done by providing the Zone ID value in thread attributes \ref osThreadAttr_t when creating the thread with the \ref osThreadNew function. 63 64**Example:** 65 66```c 67/* ThreadA thread attributes */ 68const osThreadAttr_t thread_A_attr = { 69 .name = "ThreadA", // human readable thread name 70 .attr_bits = osThreadZone(3U) // assign thread to MPU protected zone with Zone Id 3 71}; 72osThreadNew(ThreadA, NULL, &thread_A_attr); 73``` 74 75[CMSIS-Zone](../Zone/index.html) provides a utility that allows graphic configuration of MPU protected zones and generates MPU table in the CMSIS format. 76 77## Load MPU Protected Zone {#rtos_process_isolation_mpu_load} 78 79When switching threads the RTOS kernel compares Zone IDs of the currently running thread and the next thread to be executed. If the Zone Ids are different then a callback function \ref osZoneSetup_Callback is called. This callback function shall be implemented in the user application code to actually switch to the new MPU Protected Zone. In the function the user should load the MPU Protected Zone according to the Zone Id provided in the argument. 80 81**Example:** 82 83```c 84/* Update MPU settings for newly activating Zone */ 85void osZoneSetup_Callback (uint32_t zone) { 86 87 if (zone >= ZONES_NUM) { 88 // Here issue an error for incorrect zone value 89 } 90 91 ARM_MPU_Load(mpu_table[zone], MPU_REGIONS); 92} 93``` 94 95## RTOS Objects and MPU Protection {#rtos_process_isolation_mpu_objects} 96 97To access RTOS objects from the application RTOS APIs rely on a numeric `xxx_id` parameter associated with the object as explained in \ref rtos_objects. For example as `evt_flags` in this code: 98 99```c 100osEventFlagsId_t evt_flags; 101evt_flags = osEventFlagsNew(NULL); 102osEventFlagsSet(evt_flags, 1); 103``` 104 105The allocation of an RTOS object to the memory in a specific MPU Protected Zone does not provide access restriction. The access restriction can be bypassed if another thread calls the CMSIS-RTOS2 API with the object ID of the RTOS object as argument. The CMSIS-RTOS2 function is executed in handler mode and therefore can access and modify the RTOS object without raising a Memory Fault. 106 107To enable access control for RTOS objects the \ref rtos_process_isolation_safety_class concept is introduced in CMSIS-RTOS2. 108 109## Handle Memory Access Faults {#rtos_process_isolation_mpu_fault} 110 111A memory access fault is triggered when a thread tries to access memory or peripherals outside of the MPU Protected Zone loaded while the thread is running. In such case Memory Management Interrupt [MemoryManagement_IRQn](../Core/group__NVIC__gr.html) is triggered by the processor and its handling function is executed according to the exception vector table specified in the device startup file (by default \token{MemManage_Handler(void)} ). 112 113The \e MemManage_Handler() interrupt handler is application specific and needs to be implemented by the user. In the handler it is possible to identify the thread that caused the memory access fault, the corresponding zone id and the safety class. This information can be used to define actions for entering a safe state. \ref rtos_process_isolation_faults provides more details on the available system recovery possibilities. 114 115<!-- =============================================================== !--> 116\page rtos_process_isolation_safety_class Safety Classes 117 118\ref rtos_process_isolation_mpu_objects explains that MPU Protected Zones do not provide full access protection to RTOS objects accessed via CMSIS-RTOS2 API. The concept of a safety class fills this gap. 119 120Every RTOS object, including thread is assigned with a numeric safety class value. A thread cannot modify an RTOS object if its safety class value is higher than the safety class value of the thread. 121For example, it is not possible to change the priority or suspend a thread that has a higher safety class value than the thread that is currently executed. 122 123**Function references** 124 125 - Following functions and macros are used explicitly for managing safety classes: 126 - \ref osSafetyClass : \copybrief osSafetyClass 127 - \ref osThreadGetClass : \copybrief osThreadGetClass 128 - \ref osSafetyWithSameClass : \copybrief osSafetyWithSameClass 129 - \ref osSafetyWithLowerClass : \copybrief osSafetyWithLowerClass 130 - \ref osKernelProtect : \copybrief osKernelProtect 131 - \ref osThreadSuspendClass : \copybrief osThreadSuspendClass 132 - \ref osThreadResumeClass : \copybrief osThreadResumeClass 133 - \ref osKernelDestroyClass : \copybrief osKernelDestroyClass 134 - CMSIS-RTOS2 API functions that support safety class assignment when creating RTOS objects are listed in \ref rtos_process_isolation_safety_class_assign. 135 - CMSIS-RTOS2 API functions that verify safety class assignment before execution are listed in \ref rtos_process_isolation_safety_class_error lists. 136 137## Assign Safety Class to an RTOS Object {#rtos_process_isolation_safety_class_assign} 138 139It is possible to create any objects regardless of the safety class after the kernel initialize with \ref osKernelInitialize, but before the kernel is started with \ref osKernelStart. This allows to setup a system before actually starting the RTOS kernel. 140 141Threads of a higher safety class can create RTOS objects that belong to a lower or same safety class. For the object types listed below, the \e attr_bits can have an optional safety class value that is assigned when the RTOS object is created with the \e <i>os<Object>New</i> function. The macro \ref osSafetyClass encodes the value for the \e attr_bits field in the attr struct. For example: 142 143```c 144const osEventFlagsAttr_t evt_flags_attr = { 145 .attr_bits = osSafetyClass(SAFETY_CLASS_SAFE_MODE_OPERATION) 146}; 147osEventFlagsId_t evt_flags; 148evt_flags = osEventFlagsNew(&evt_flags_attr); 149``` 150 151The following object types support safety class assignment when creating an object with corresponding \e os<Object>New function: 152 153 - \ref osThreadAttr_t \copybrief osThreadAttr_t Used in the \ref osThreadNew function. 154 - \ref osEventFlagsAttr_t \copybrief osEventFlagsAttr_t Used in the \ref osThreadNew function. 155 - \ref osTimerAttr_t \copybrief osTimerAttr_t Used in the \ref osTimerNew function. 156 - \ref osMutexAttr_t \copybrief osMutexAttr_t Used in the \ref osMutexNew function. 157 - \ref osSemaphoreAttr_t \copybrief osSemaphoreAttr_t Used in the \ref osSemaphoreNew function. 158 - \ref osMemoryPoolAttr_t \copybrief osMemoryPoolAttr_t Used in the \ref osMemoryPoolNew function. 159 - \ref osMessageQueueAttr_t \copybrief osMessageQueueAttr_t Used in the \ref osMessageQueueNew function. 160 161If safety class is not provided when creating the RTOS object then it inherits the safety class of the current running thread that creates the object. If the object is created before kernel is started and no safety class is provided, then it receives default safety class 0. This simplifies integration of third-party code that can be classified as non-safety critical. 162 163## Handle Object Access Violation {#rtos_process_isolation_safety_class_error} 164 165RTOS API call returns error code \ref osErrorSafetyClass if the requested object manipulation cannot be performed because the target object has higher safety class than the safety class of the running thread. For example: 166 167```c 168status = osEventFlagsSet(evt_flags, 1); 169if (status == osErrorSafetyClass) 170{ 171 //handle the safety class error 172} 173``` 174 175Following functions compare the safety class of the running thread with the safety class of the target object. 176 177In \ref CMSIS_RTOS_KernelCtrl functions: 178 179Comparison is done with safety class configured with \ref osKernelProtect 180 181 - \ref osKernelLock 182 - \ref osKernelRestoreLock 183 - \ref osKernelSuspend 184 - \ref osKernelProtect 185 - \ref osKernelDestroyClass 186 187In \ref CMSIS_RTOS_ThreadMgmt functions: 188 189 - \ref osThreadNew 190 - \ref osThreadSetPriority 191 - \ref osThreadSuspend 192 - \ref osThreadResume 193 - \ref osThreadDetach 194 - \ref osThreadJoin 195 - \ref osThreadTerminate 196 - \ref osThreadSuspendClass 197 - \ref osThreadResumeClass 198 199In \ref CMSIS_RTOS_ThreadFlagsMgmt functions: 200 201 - \ref osThreadFlagsSet 202 203In \ref CMSIS_RTOS_EventFlags functions: 204 205 - \ref osEventFlagsNew 206 - \ref osEventFlagsSet 207 - \ref osEventFlagsClear 208 - \ref osEventFlagsWait 209 - \ref osEventFlagsDelete 210 211In \ref CMSIS_RTOS_TimerMgmt functions: 212 213 - \ref osTimerNew 214 - \ref osTimerStart 215 - \ref osTimerStop 216 - \ref osTimerDelete 217 218In \ref CMSIS_RTOS_MutexMgmt functions: 219 220 - \ref osMutexNew 221 - \ref osMutexAcquire 222 - \ref osMutexDelete 223 224In \ref CMSIS_RTOS_SemaphoreMgmt functions: 225 226 - \ref osSemaphoreNew 227 - \ref osSemaphoreAcquire 228 - \ref osSemaphoreRelease 229 - \ref osSemaphoreDelete 230 231In \ref CMSIS_RTOS_PoolMgmt functions: 232 233 - \ref osMemoryPoolNew 234 - \ref osMemoryPoolAlloc 235 - \ref osMemoryPoolFree 236 - \ref osMemoryPoolDelete 237 238In \ref CMSIS_RTOS_Message functions: 239 240 - \ref osMessageQueueNew 241 - \ref osMessageQueuePut 242 - \ref osMessageQueueGet 243 - \ref osMessageQueueReset 244 - \ref osMessageQueueDelete 245 246<!-- =============================================================== !--> 247\page rtos_process_isolation_thread_wdt Thread Watchdogs 248 249CMSIS-RTOS defines **Thread Watchdogs** that allow to control timing constraints for thread execution [temporal isolation](https://en.wikipedia.org/wiki/Temporal_isolation). 250 251Each thread has an independent watchdog timer that is started with the function \ref osThreadFeedWatchdog(uint32_t ticks). The \token{ticks} value specifies the timeout before it expires. Within this time interval the function \ref osThreadFeedWatchdog must be called again within the thread to restart the watchdog timer. 252 253If the thread watchdog is not restarted during the specified amount of ticks the Watchdog Alarm callback \ref osWatchdogAlarm_Handler(osThreadId_t thread_id) is triggered and can be used to recover the system or proceed to the system shutdown. 254 255Figure below explains the concept with an example: 256 257 258 259\ref rtos_process_isolation_faults provides more details on the available possibilities for system recovery. 260 261> **Note** 262> - If the application suspends a thread from scheduling by calling \ref osThreadSuspend or \ref osThreadSuspendClass, the thread watchdog still continues to run, and it is expected to expire and trigger \ref osWatchdogAlarm_Handler because the thread will not be serviced as expected. 263> - Hence it may be necessary to differentiate handling of thread watchdogs that expired unexpectedly from the thread watchdog alarms of intentionally suspended threads. 264 265**Function references** 266 267Summary of functions that implement thread watchdog functionality: 268 269 - \ref osThreadFeedWatchdog : \copybrief osThreadFeedWatchdog 270 - \ref osWatchdogAlarm_Handler : \copybrief osWatchdogAlarm_Handler 271 272<!-- =============================================================== !--> 273\page rtos_process_isolation_faults Fault Handling 274 275When a failure, or an error is detected in a system (for example \ref rtos_process_isolation_mpu_fault "memory access fault", \ref rtos_process_isolation_thread_wdt "thread watchdog alarm", or others) CMSIS-RTOS2 API allows to stop further execution of selected RTOS threads. This can be used to block malfunctioning components or free computing resources and so enable execution of the safety critical threads. 276 277Following approaches are available: 278 279 - function \ref osThreadTerminateZone can be called in case of a fault exception. It will terminate all threads from the specified MPU Protected Zone (for example, can be the zone that has caused the fault). The function cannot be called in thread context or interrupts other than faults. Note that \ref osFaultResume can be called at the end of the handling code to return program execution into a known context and let kernel schedule the next thread ready for execution. 280 - function \ref osThreadSuspendClass can be called in case of a thread watchdog alarm or other errors handled in thread context. It allows to suspend operation of threads based on the safety class assignment. Function \ref osThreadResumeClass can be used to resume operation of threads based on their safety class. \ref rtos_process_isolation_thread_wdt contains an example that demonstrates fault handling concept for thread watchdogs. 281 282Function \ref osKernelDestroyClass fully removes RTOS objects of specific safety classes from the system. This can be useful to do before restarting operation of terminated or suspended threads. 283 284**Function references** 285 286Following CMSIS-RTOS2 functions and macros support fault handling: 287 288 - \ref osThreadGetZone : \copybrief osThreadGetZone 289 - \ref osThreadTerminateZone : \copybrief osThreadTerminateZone 290 - \ref osThreadGetClass : \copybrief osThreadGetClass 291 - \ref osSafetyWithSameClass : \copybrief osSafetyWithSameClass 292 - \ref osSafetyWithLowerClass : \copybrief osSafetyWithLowerClass 293 - \ref osThreadSuspendClass : \copybrief osThreadSuspendClass 294 - \ref osThreadResumeClass : \copybrief osThreadResumeClass 295 - \ref osKernelDestroyClass : \copybrief osKernelDestroyClass 296 - \ref osFaultResume : \copybrief osFaultResume 297 - \ref osWatchdogAlarm_Handler : \copybrief osFaultResume 298