RTX5: Add support for Process Isolation (Functional Safety)
Based on CMSIS-RTOS2 API 2.2.0:
- MPU Protected Zones
- Safety Classes
- Thread Watchdogs
Additional safety features:
- Object Pointer checking
- SVC Function Pointer checking
diff --git a/CMSIS/DoxyGen/RTOS2/src/cmsis_os2.txt b/CMSIS/DoxyGen/RTOS2/src/cmsis_os2.txt
index 7790bde..5f602c9 100644
--- a/CMSIS/DoxyGen/RTOS2/src/cmsis_os2.txt
+++ b/CMSIS/DoxyGen/RTOS2/src/cmsis_os2.txt
@@ -742,7 +742,7 @@
The file "RTX_Config.h" defines the configuration parameters of CMSIS-RTOS RTX and must be part of every project that is
using the CMSIS-RTOS RTX kernel. The configuration options are explained in detail in the following sections:
-- \ref systemConfig covers system-wide settings for the global memory pool, tick frequency, ISR event buffer and round-robin thread switching.
+- \ref systemConfig covers system-wide settings for the global memory pool, tick frequency, ISR event buffer and round-robin thread switching as well as process isolation-related features.
- \ref threadConfig provides several parameters to configure the \ref CMSIS_RTOS_ThreadMgmt functions.
- \ref timerConfig provides several parameters to configure the \ref CMSIS_RTOS_TimerMgmt functions.
- \ref eventFlagsConfig provides several parameters to configure the \ref CMSIS_RTOS_EventFlags functions.
@@ -776,14 +776,20 @@
<b>System Configuration Options</b>
\image html config_wizard_system.png "RTX_Config.h: System Configuration"
-Name | \#define | Description
----------------------------------------|--------------------------|----------------------------------------------------------------
-Global Dynamic Memory size [bytes] | \c OS_DYNAMIC_MEM_SIZE | Defines the combined global dynamic memory size for the \ref GlobalMemoryPool. Default value is \token{32768}. Value range is \token{[0-1073741824]} bytes, in multiples of \token{8} bytes.
-Kernel Tick Frequency (Hz) | \c OS_TICK_FREQ | Defines base time unit for delays and timeouts in Hz. Default: 1000Hz = 1ms period.
-Round-Robin Thread switching | \c OS_ROBIN_ENABLE | Enables Round-Robin Thread switching.
-Round-Robin Timeout | \c OS_ROBIN_TIMEOUT | Defines how long a thread will execute before a thread switch. Default value is \token{5}. Value range is \token{[1-1000]}.
-ISR FIFO Queue | \c OS_ISR_FIFO_QUEUE | RTOS Functions called from ISR store requests to this buffer. Default value is \token{16 entries}. Value range is \token{[4-256]} entries in multiples of \token{4}.
-Object Memory usage counters | \c OS_OBJ_MEM_USAGE | Enables object memory usage counters to evaluate the maximum memory pool requirements individually for each RTOS object type.
+Name | \#define | Description
+--------------------------------------------|--------------------------|----------------------------------------------------------------
+\ref systemConfig_glob_mem | \c OS_DYNAMIC_MEM_SIZE | Defines the combined global dynamic memory size for the \ref GlobalMemoryPool. Default value is \token{32768}. Value range is \token{[0-1073741824]} bytes, in multiples of \token{8} bytes.
+Kernel Tick Frequency (Hz) | \c OS_TICK_FREQ | Defines base time unit for delays and timeouts in Hz. Default value is \token{1000} (1000 Hz = 1 ms period).
+\ref systemConfig_rr | \c OS_ROBIN_ENABLE | Enables Round-Robin Thread switching. Default value is \token{1} (enabled).
+ Round-Robin Timeout | \c OS_ROBIN_TIMEOUT | Defines how long a thread will execute before a thread switch. Default value is \token{5}. Value range is \token{[1-1000]}.
+\ref safetyConfig_safety | \c OS_SAFETY_FEATURES | Enables safety-related features as configured in this group. Default value is \token{1} (enabled).
+ Safety class | \c OS_SAFETY_CLASS | Enables \ref rtos_process_isolation_safety_class functionality. Default value is \token{1} (enabled).
+ MPU Protected Zone | \c OS_EXECUTION_ZONE | Enables \ref rtos_process_isolation_mpu. Default value is \token{1} (enabled).
+ Thread Watchdog | \c OS_THREAD_WATCHDOG | Enables \ref rtos_process_isolation_thread_wdt functionality. Default value is \token{1} (enabled).
+ Object Pointer checking | \c OS_OBJ_PTR_CHECK | Enables verification of object pointer alignment and memory region. Default value is \token{0} (disabled).
+ SVC Function Pointer checking | \c OS_SVC_PTR_CHECK | Enables verification of SVC function pointer alignment and memory region. Default value is \token{0} (disabled).
+\ref systemConfig_isr_fifo | \c OS_ISR_FIFO_QUEUE | RTOS Functions called from ISR store requests to this buffer. Default value is \token{16 entries}. Value range is \token{[4-256]} entries in multiples of \token{4}.
+\ref systemConfig_usage_counters | \c OS_OBJ_MEM_USAGE | Enables object memory usage counters to evaluate the maximum memory pool requirements individually for each RTOS object type. Default value is \token{0} (disabled).
\subsection systemConfig_glob_mem Global Dynamic Memory size [bytes]
Refer to \ref GlobalMemoryPool.
@@ -809,6 +815,52 @@
Round-Robin multitasking is controlled with the <b>\#define OS_ROBIN_ENABLE</b>. The time slice period is configured (in RTX
timer ticks) with the <b>\#define OS_ROBIN_TIMEOUT</b>.
+\subsection safetyConfig_safety Safety features (Source variant only)
+
+Safety features group in \ref systemConfig enables individual selection of safety-related functionalities.
+It requires that RTX is used in the source variant.
+
+It also includes:
+- Thread functions: \ref osThreadProtectPrivileged
+
+<b>MPU Protected Zone</b><br>
+Enables \ref rtos_process_isolation_mpu functionality in the system. This includes:
+- Thread attributes: \ref osThreadZone
+- Thread functions: \ref osThreadGetZone, \ref osThreadTerminateZone
+- Zone Management: \ref osZoneSetup_Callback
+
+When enabled, the MPU Protected Zone values also need to be specified for the threads created by the kernel:
+- For Idle thread in \ref threadConfig
+- For Timer thread in \ref timerConfig
+
+<b>Safety class</b><br>
+Enables \ref rtos_process_isolation_safety_class functionality in the system RTOS. This includes:
+- Object attributes: \ref osSafetyClass
+- Kernel functions: \ref osKernelProtect, \ref osKernelDestroyClass
+- Thread functions: \ref osThreadGetClass, \ref osThreadSuspendClass, \ref osThreadResumeClass
+
+When enabled, the safety class values need to be specified for threads created by the kernel:
+- For Idle thread in \ref threadConfig
+- For Timer thread in \ref timerConfig
+
+<b>Thread Watchdog</b><br>
+Enables \ref rtos_process_isolation_thread_wdt functionality in the system RTOS. This includes:
+- Thread functions: \ref osThreadFeedWatchdog
+- Handler functions: \ref osWatchdogAlarm_Handler
+
+<b>Object Pointer checking</b><br>
+Enables verification of object pointer alignment and memory region.
+
+Before accessing RTX objects the RTX kernel verifies that obtained object pointer is valid (at least not \token{NULL}). When <i>Object Pointer checking</i> is enabled the kernel will additionally verify that
+the control block of the object is located in the memory section allocated for such object type, and that it is correctly aligned within that memory section.
+
+If static memory allocation is used, the user shall place the control blocks of the objects into the correct named memory sections as described in \ref StaticObjectMemory.
+For object-specific and dynamic memory allocations the kernel will place the objects correctly.
+
+<b>SVC Function Pointer checking</b><br>
+Enables verification of SVC function pointer alignment and memory region.
+
+Many kernel functions are executed in SVC context. Corresponding function pointers are placed by the kernel into a special named memory section. If <i>SVC Function Pointer checking</i> is enabled the kernel before calling an SVC function will additionally verify that its pointer is located in the expected memory section and is correctly aligned within that memory region.
\subsection systemConfig_isr_fifo ISR FIFO Queue
The RTX functions (\ref CMSIS_RTOS_ISR_Calls), when called from and interrupt handler, store the request type and optional
@@ -845,9 +897,11 @@
Default Thread Stack size [bytes] | \c OS_STACK_SIZE | Defines stack size for threads with zero stack size specified. Default value is \token{3072}. Value range is \token{[96-1073741824]} Bytes, in multiples of \token{8}.
Idle Thread Stack size [bytes] | \c OS_IDLE_THREAD_STACK_SIZE | Defines stack size for Idle thread. Default value is \token{512}. Value range is \token{[72-1073741824]} bytes, in multiples of \token{8}.
Idle Thread TrustZone Module ID | \c OS_IDLE_THREAD_TZ_MOD_ID | Defines the \ref osThreadAttr_t::tz_module "TrustZone Module ID" the Idle Thread shall use. This needs to be set to a non-zero value if the Idle Thread need to call secure functions. Default value is \token{0}.
+Idle Thread Safety Class | \c OS_IDLE_THREAD_CLASS | Defines the the \ref rtos_process_isolation_safety_class "Safety Class" for the Idle thread. Applied only if Safety Class functionality is enabled in \ref systemConfig. Default value is \token{0}.
+Idle Thread Zone | \c OS_IDLE_THREAD_ZONE | Defines the \ref rtos_process_isolation_mpu "MPU Protected Zone" for the Idle thread. Applied only if MPU protected Zone functionality is enabled in \ref systemConfig. Default value is \token{0}.
Stack overrun checking | \c OS_STACK_CHECK | Enable stack overrun checks at thread switch.
Stack usage watermark | \c OS_STACK_WATERMARK | Initialize thread stack with watermark pattern for analyzing stack usage. Enabling this option increases significantly the execution time of thread creation.
-Processor mode for Thread execution | \c OS_PRIVILEGE_MODE | Controls the processor mode. Default value is \token{Privileged} mode. Value range is \token{[0=Unprivileged; 1=Privileged]} mode.
+Processor mode for Thread execution | \c OS_PRIVILEGE_MODE | Controls the default processor mode when not specified through thread attributes \ref osThreadUnprivileged or \ref osThreadPrivileged. Default value is \token{Unprivileged} mode. Value range is \token{[0=Unprivileged; 1=Privileged]} mode.
\subsection threadConfig_countstack Configuration of Thread Count and Stack Space
@@ -889,8 +943,10 @@
Enabling this option significantly increases the execution time of \ref osThreadNew (depends on thread stack size).
\subsection threadConfig_procmode Processor Mode for Thread Execution
-RTX5 allows to execute threads in unprivileged or privileged processor mode. The processor mode is controlled with the
+RTX5 allows to execute threads in unprivileged or privileged processor mode. The processor mode is configured for all threads with the
define \c OS_PRIVILEGE_MODE.
+
+It is also possible to specify the privilege level for individual threads. For that use \ref osThreadUnprivileged and \ref osThreadPrivileged defines in the \e attr_bits of \ref osThreadAttr_t argument when creating a thread with \ref osThreadNew.
In \b unprivileged processor mode, the application software:
- has limited access to the MSR and MRS instructions, and cannot use the CPS instruction.
@@ -914,6 +970,8 @@
Timer Thread Priority | \c OS_TIMER_THREAD_PRIO | Defines priority for timer thread. Default value is \token{40}. Value range is \token{[8-48]}, in multiples of \token{8}. The numbers have the following priority correlation: \token{8=Low}; \token{16=Below Normal}; \token{24=Normal}; \token{32=Above Normal}; \token{40=High}; \token{48=Realtime}
Timer Thread Stack size [bytes] | \c OS_TIMER_THREAD_STACK_SIZE | Defines stack size for Timer thread. May be set to 0 when timers are not used. Default value is \token{512}. Value range is \token{[0-1073741824]}, in multiples of \token{8}.
Timer Thread TrustZone Module ID | \c OS_TIMER_THREAD_TZ_MOD_ID | Defines the \ref osThreadAttr_t::tz_module "TrustZone Module ID" the Timer Thread shall use. This needs to be set to a non-zero value if any Timer Callbacks need to call secure functions. Default value is \token{0}.
+Timer Thread Safety Class | \c OS_TIMER_THREAD_CLASS | Defines the the \ref rtos_process_isolation_safety_class "Safety Class" for the Timer thread. Applied only if Safety class functionality is enabled in \ref systemConfig. Default value is \token{0}.
+Timer Thread Zone | \c OS_TIMER_THREAD_ZONE | Defines the \ref rtos_process_isolation_mpu "MPU Protected Zone" for the Timer thread. Applied only if MPU protected Zone functionality is enabled in \ref systemConfig. Default value is \token{0}.
Timer Callback Queue entries | \c OS_TIMER_CB_QUEUE | Number of concurrent active timer callback functions. May be set to 0 when timers are not used. Default value is \token{4}. Value range is \token{[0-256]}.
\subsection timerConfig_obj Object-specific memory allocation
@@ -1127,12 +1185,15 @@
\c EVR_RTX_KERNEL_LOCKED_DISABLE, \c EVR_RTX_KERNEL_UNLOCK_DISABLE, \c EVR_RTX_KERNEL_UNLOCKED_DISABLE,
\c EVR_RTX_KERNEL_RESTORE_LOCK_DISABLE, \c EVR_RTX_KERNEL_LOCK_RESTORED_DISABLE, \c EVR_RTX_KERNEL_SUSPEND_DISABLE,
\c EVR_RTX_KERNEL_SUSPENDED_DISABLE, \c EVR_RTX_KERNEL_RESUME_DISABLE, \c EVR_RTX_KERNEL_RESUMED_DISABLE,
+\c EVR_RTX_KERNEL_PROTECT_DISABLE, \c EVR_RTX_KERNEL_PROTECTED_DISABLE,
\c EVR_RTX_KERNEL_GET_TICK_COUNT_DISABLE, \c EVR_RTX_KERNEL_GET_TICK_FREQ_DISABLE,
-\c EVR_RTX_KERNEL_GET_SYS_TIMER_COUNT_DISABLE, \c EVR_RTX_KERNEL_GET_SYS_TIMER_FREQ_DISABLE
+\c EVR_RTX_KERNEL_GET_SYS_TIMER_COUNT_DISABLE, \c EVR_RTX_KERNEL_GET_SYS_TIMER_FREQ_DISABLE,
+\c EVR_RTX_KERNEL_DESTROY_CLASS_DISABLE, \c EVR_RTX_KERNEL_ERROR_NOTIFY_DISABLE
\b Thread \b events \n
\c EVR_RTX_THREAD_ERROR_DISABLE, \c EVR_RTX_THREAD_NEW_DISABLE, \c EVR_RTX_THREAD_CREATED_DISABLE,
\c EVR_RTX_THREAD_GET_NAME_DISABLE, \c EVR_RTX_THREAD_GET_ID_DISABLE, \c EVR_RTX_THREAD_GET_STATE_DISABLE,
+\c EVR_RTX_THREAD_GET_CLASS_DISABLE, \c EVR_RTX_THREAD_GET_ZONE_DISABLE,
\c EVR_RTX_THREAD_GET_STACK_SIZE_DISABLE, \c EVR_RTX_THREAD_GET_STACK_SPACE_DISABLE, \c EVR_RTX_THREAD_SET_PRIORITY_DISABLE,
\c EVR_RTX_THREAD_PRIORITY_UPDATED_DISABLE, \c EVR_RTX_THREAD_GET_PRIORITY_DISABLE, \c EVR_RTX_THREAD_YIELD_DISABLE,
\c EVR_RTX_THREAD_SUSPEND_DISABLE, \c EVR_RTX_THREAD_SUSPENDED_DISABLE, \c EVR_RTX_THREAD_RESUME_DISABLE,
@@ -1140,7 +1201,10 @@
\c EVR_RTX_THREAD_JOIN_DISABLE, \c EVR_RTX_THREAD_JOIN_PENDING_DISABLE, \c EVR_RTX_THREAD_JOINED_DISABLE,
\c EVR_RTX_THREAD_BLOCKED_DISABLE, \c EVR_RTX_THREAD_UNBLOCKED_DISABLE, \c EVR_RTX_THREAD_PREEMPTED_DISABLE,
\c EVR_RTX_THREAD_SWITCHED_DISABLE, \c EVR_RTX_THREAD_EXIT_DISABLE, \c EVR_RTX_THREAD_TERMINATE_DISABLE,
-\c EVR_RTX_THREAD_DESTROYED_DISABLE, \c EVR_RTX_THREAD_GET_COUNT_DISABLE, \c EVR_RTX_THREAD_ENUMERATE_DISABLE
+\c EVR_RTX_THREAD_DESTROYED_DISABLE, \c EVR_RTX_THREAD_GET_COUNT_DISABLE, \c EVR_RTX_THREAD_ENUMERATE_DISABLE,
+\c EVR_RTX_THREAD_FEED_WATCHDOG_DISABLE, \c EVR_RTX_THREAD_FEED_WATCHDOG_DONE_DISABLE, \c EVR_RTX_THREAD_WATCHDOG_EXPIRED_DISABLE,
+\c EVR_RTX_THREAD_PROTECT_PRIVILEGED_DISABLE, \c EVR_RTX_THREAD_PRIVILEGED_PROTECTED_DISABLE,
+\c EVR_RTX_THREAD_SUSPEND_CLASS_DISABLE, \c EVR_RTX_THREAD_RESUME_CLASS_DISABLE, \c EVR_RTX_THREAD_TERMINATE_ZONE_DISABLE
\b Generic \b wait \b events \n
\c EVR_RTX_DELAY_ERROR_DISABLE, \c EVR_RTX_DELAY_DISABLE, \c EVR_RTX_DELAY_UNTIL_DISABLE,
@@ -1266,9 +1330,9 @@
Interrupt Control | The CMSIS-Core functions __disable_irq and __enable_irq to control the interrupt system via the CPSR core register.
The RTX implements interfaces to the processor hardware in following files:
- - <b>%irq_armv6m.s</b> defines exception handlers for Cortex-M0/M0+
+ - <b>%irq_armv6m.S</b> defines exception handlers for Cortex-M0/M0+
\if ARMv8M
- - <b>%irq_armv8mbl.s</b> defines exception handlers for Cortex-M23
+ - <b>%irq_armv8mbl.S</b> defines exception handlers for Cortex-M23
\endif
- <b>%rtx_core_cm.h</b> defines processor specific helper functions and the interfaces to Core Registers and Core Peripherals.
- <b>%os_tick.h</b> is the \ref CMSIS_RTOS_TickAPI that defines the interface functions to the SysTick timer.
@@ -1294,9 +1358,9 @@
LDREX, STREX instructions | Exclusive access instructions \b LDREX and \b STREX are used to implement atomic execution without disabling interrupts.
The interface files to the processor hardware are:
- - <b>%irq_armv7m.s</b> defines exception handlers for Cortex-M3 and Cortex-M4/M7.
+ - <b>%irq_armv7m.S</b> defines exception handlers for Cortex-M3 and Cortex-M4/M7.
\if ARMv8M
- - <b>%irq_armv8mml.s</b> defines exception handlers for Cortex-M33/M35P
+ - <b>%irq_armv8mml.S</b> defines exception handlers for Cortex-M33/M35P
\endif
- <b>%rtx_core_cm.h</b> defines processor specific helper functions and the interfaces to Core Registers and Core Peripherals.
- <b>%os_tick.h</b> is the \ref CMSIS_RTOS_TickAPI that defines the interface functions to the SysTick timer.
@@ -1316,7 +1380,7 @@
Interrupt Controller | An interrupt controller interface is required to setup and control Timer Peripheral interrupt. The interface for Arm GIC (Generic Interrupt Controller) is implemented in %irq_ctrl_gic.c using the <a class="el" href="../../Core_A/html/group__irq__ctrl__gr.html">IRQ Controller API</a>.
The interface files to the processor hardware are:
- - <b>%irq_armv7a.s</b> defines SVC, IRQ, Data Abort, Prefetch Abort and Undefined Instruction exception handlers.
+ - <b>%irq_armv7a.S</b> defines SVC, IRQ, Data Abort, Prefetch Abort and Undefined Instruction exception handlers.
- <b>%rtx_core_ca.h</b> defines processor specific helper functions and the interfaces to Core Registers and Core Peripherals.
- <b>%os_tick.h</b> is the \ref CMSIS_RTOS_TickAPI that defines the interface functions to the timer peripheral.
- <b>%irq_ctrl.h</b> is the <a class="el" href="../../Core_A/html/group__irq__ctrl__gr.html">IRQ Controller API</a> that defines the interface functions to the interrupt controller.
@@ -1379,7 +1443,7 @@
Category | Control Block Size Attribute | Size | \#define symbol
:-----------------------------|:----------------------------------|:-----------|:--------------------
-\ref CMSIS_RTOS_ThreadMgmt | \ref osThreadAttr_t::cb_mem | 68 bytes | \ref osRtxThreadCbSize
+\ref CMSIS_RTOS_ThreadMgmt | \ref osThreadAttr_t::cb_mem | 80 bytes | \ref osRtxThreadCbSize
\ref CMSIS_RTOS_TimerMgmt | \ref osTimerAttr_t::cb_mem | 32 bytes | \ref osRtxTimerCbSize
\ref CMSIS_RTOS_EventFlags | \ref osEventFlagsAttr_t::cb_mem | 16 bytes | \ref osRtxEventFlagsCbSize
\ref CMSIS_RTOS_MutexMgmt | \ref osMutexAttr_t::cb_mem | 28 bytes | \ref osRtxMutexCbSize
@@ -1568,8 +1632,8 @@
<ul>
<li>Arm Compiler 5.06 Update 7</li>
<li>Arm Compiler 6.6.4 (Long Term Maintenance)</li>
- <li>Arm Compiler 6.16</li>
- <li>RTOS-aware debugging with uVision 5.34</li>
+ <li>Arm Compiler 6.19</li>
+ <li>RTOS-aware debugging with uVision 5.38</li>
</ul>
@@ -1622,7 +1686,7 @@
\page misraCompliance5 MISRA C:2012 Compliance
The RTX5 C source files use <b><a class=el href="http://www.misra.org.uk/" target="_blank">MISRA C:2012</a></b> guidelines as underlying coding standard.
-For MISRA validation, <b><a class=el href="http://www.gimpel.com/" target="_blank">PC-lint</a></b> V9.00L is used with configuration for Arm Compiler V6.16.
+For MISRA validation, <b><a class=el href="http://www.gimpel.com/" target="_blank">PC-lint</a></b> V9.00L is used with configuration for Arm Compiler V6.19.
The PC-Lint validation setup is part of the project file <b>.\\CMSIS\\RTOS2\\RTX\\Library\\ARM\\MDK\\RTX_CM.uvprojx</b> as shown below.
Refer to <b><a class=el href="https://www.keil.com/support/man/docs/uv4/uv4_ut_pclint_validation.htm" target="_blank">Setup for PC-Lint</a></b> for more information.
diff --git a/CMSIS/DoxyGen/RTOS2/src/history.txt b/CMSIS/DoxyGen/RTOS2/src/history.txt
index 5a903d4..1ee375e 100644
--- a/CMSIS/DoxyGen/RTOS2/src/history.txt
+++ b/CMSIS/DoxyGen/RTOS2/src/history.txt
@@ -117,6 +117,13 @@
<th>Description</th>
</tr>
<tr>
+ <td>V5.7.0</td>
+ <td>
+ - Based on CMSIS-RTOS API V2.2.0.
+ - Added support for Process Isolation: MPU Protected Zones, Safety Classes, Thread Watchdogs.
+ </td>
+ </tr>
+ <tr>
<td>V5.5.5</td>
<td>
- Added de-allocation of Arm C library thread data (libspace) when thread is terminated.
diff --git a/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_evtrecRTOSEvtFilterSetup.png b/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_evtrecRTOSEvtFilterSetup.png
index 007ad4c..611119a 100644
--- a/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_evtrecRTOSEvtFilterSetup.png
+++ b/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_evtrecRTOSEvtFilterSetup.png
Binary files differ
diff --git a/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_system.png b/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_system.png
index 6502d6e..c1544bf 100644
--- a/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_system.png
+++ b/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_system.png
Binary files differ
diff --git a/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_threads.png b/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_threads.png
index f7870fd..68cc44d 100644
--- a/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_threads.png
+++ b/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_threads.png
Binary files differ
diff --git a/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_timer.png b/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_timer.png
index 1722acb..3aa1790 100644
--- a/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_timer.png
+++ b/CMSIS/DoxyGen/RTOS2/src/images/config_wizard_timer.png
Binary files differ
diff --git a/CMSIS/DoxyGen/RTOS2/src/rtx_evr.txt b/CMSIS/DoxyGen/RTOS2/src/rtx_evr.txt
index 262fb1e..b184a2e 100644
--- a/CMSIS/DoxyGen/RTOS2/src/rtx_evr.txt
+++ b/CMSIS/DoxyGen/RTOS2/src/rtx_evr.txt
@@ -105,24 +105,25 @@
The status parameter indicates the execution status and can be one of the \ref osStatus_t "osStatus_t codes" or one
of the extended execution status codes which are summarized in the table below.
-| Extended Status Code | Description |
-|:------------------------------|:------------|
-| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
-| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
-| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
-| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
-| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
-| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
-| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
-| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
-| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
-| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
-| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
-| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
-| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
-| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
+| Extended Status Code | Description |
+|:--------------------------------|:------------|
+| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
+| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
+| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
+| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
+| osRtxErrorInvalidPrivilegedMode | Privileged thread cannot be created - kernel protect privileged is active. |
+| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
+| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
+| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
+| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
+| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
+| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
+| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
+| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
+| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
+| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
\b Value in the Event Recorder shows:
- \b status : execution status code.
@@ -262,6 +263,21 @@
*/
/**
+\fn void EvrRtxKernelProtect (uint32_t safety_class)
+\details
+The event \b KernelProtect is generated when the function \ref osKernelProtect is called.
+
+\b Value in the Event Recorder shows:
+ - \b safety_class : safety class value.
+*/
+
+/**
+\fn void EvrRtxKernelProtected (void)
+\details
+The event \b KernelProtected is generated when the function \ref osKernelProtect successfully applies kernel safety class protection.
+*/
+
+/**
\fn void EvrRtxKernelGetTickCount (uint32_t count)
\details
The event \b KernelGetTickCount is generated when the function \ref osKernelGetTickCount is called.
@@ -306,6 +322,16 @@
- \b code : error code.
- \b object_id : object that caused the error.
*/
+
+/**
+\fn void EvrRtxKernelDestroyClass (uint32_t safety_class, uint32_t mode)
+\details
+The event \b KernelDestroyClass is generated when the function \ref osKernelDestroyClass is called.
+
+\b Value in the Event Recorder shows:
+ - \b safety_class : safety class value.
+ - \b mode : operation mode.
+*/
*/
/**
@@ -327,24 +353,25 @@
The status parameter indicates the execution status and can be one of the \ref osStatus_t "osStatus_t codes" or one
of the extended execution status codes which are summarized in the table below.
-| Extended Status Code | Description |
-|:------------------------------|:------------|
-| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
-| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
-| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
-| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
-| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
-| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
-| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
-| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
-| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
-| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
-| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
-| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
-| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
-| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
+| Extended Status Code | Description |
+|:--------------------------------|:------------|
+| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
+| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
+| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
+| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
+| osRtxErrorInvalidPrivilegedMode | Privileged thread cannot be created - kernel protect privileged is active. |
+| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
+| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
+| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
+| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
+| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
+| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
+| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
+| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
+| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
+| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
\b Value in the Event Recorder shows:
- \b thread_id : thread ID.
@@ -382,6 +409,26 @@
*/
/**
+\fn void EvrRtxThreadGetClass (osThreadId_t thread_id, uint32_t safety_class)
+\details
+The event \b ThreadGetClass is generated when the function \ref osThreadGetClass is called and its execution result is known.
+
+\b Value in the Event Recorder shows:
+ - \b thread_id : thread ID.
+ - \b safety_class : retrieved safety class value (osErrorId in case of a failure).
+*/
+
+/**
+\fn void EvrRtxThreadGetZone (osThreadId_t thread_id, uint32_t zone)
+\details
+The event \b ThreadGetZone is generated when the function \ref osThreadGetZone is called and its execution result is known.
+
+\b Value in the Event Recorder shows:
+ - \b thread_id : thread ID.
+ - \b zone : retrieved MPU Protected Zone value (osErrorId in case of a failure).
+*/
+
+/**
\fn void EvrRtxThreadGetId (osThreadId_t thread_id)
\details
The event \b ThreadGetId is generated when the function \ref osThreadGetId is called and its execution result is known.
@@ -600,6 +647,34 @@
*/
/**
+\fn void EvrRtxThreadFeedWatchdog (uint32_t ticks)
+\details
+
+The event \b ThreadFeedWatchdog is generated when the function \ref osThreadFeedWatchdog is called.
+
+\b Value in the Event Recorder shows:
+ - \b ticks : watchdog timeout in number of kernel ticks.
+*/
+
+/**
+\fn void EvrRtxThreadFeedWatchdogDone (void)
+\details
+The event \b ThreadFeedWatchdogDone is generated when the function \ref osThreadFeedWatchdog successfully feeds the watchdog timer.
+*/
+
+/**
+\fn void EvrRtxThreadProtectPrivileged (void)
+\details
+The event \b ThreadProtectPrivileged is generated when the function \ref osThreadProtectPrivileged is called.
+*/
+
+/**
+\fn void EvrRtxThreadPrivilegedProtected (void)
+\details
+The event \b ThreadPrivilegedProtected is generated when the function \ref osThreadProtectPrivileged successfully applies the new privileged thread creation protection.
+*/
+
+/**
\fn void EvrRtxThreadGetCount (uint32_t count)
\details
The event \b ThreadGetCount is generated when the function \ref osThreadGetCount is called and its execution result is known.
@@ -620,6 +695,44 @@
*/
/**
+\fn void EvrRtxThreadSuspendClass (uint32_t safety_class, uint32_t mode)
+\details
+The event \b ThreadSuspendClass is generated when the function \ref osThreadSuspendClass is called.
+
+\b Value in the Event Recorder shows:
+ - \b safety_class : safety class value.
+ - \b mode : operation mode.
+*/
+
+/**
+\fn void EvrRtxThreadResumeClass (uint32_t safety_class, uint32_t mode)
+\details
+The event \b ThreadResumeClass is generated when the function \ref osThreadResumeClass is called.
+
+\b Value in the Event Recorder shows:
+ - \b safety_class : safety class value.
+ - \b mode : operation mode.
+*/
+
+/**
+\fn void EvrRtxThreadTerminateZone (uint32_t zone)
+\details
+The event \b ThreadTerminateZone is generated when the function \ref osThreadTerminateZone is called.
+
+\b Value in the Event Recorder shows:
+ - \b zone : MPU Protected Zone value.
+*/
+
+/**
+\fn void EvrRtxThreadWatchdogExpired (osThreadId_t thread_id)
+\details
+The event \b ThreadWatchdogExpired is generated when the thread watchdog timer expires.
+
+\b Value in the Event Recorder shows:
+ - \b thread_id : thread ID.
+*/
+
+/**
@}
*/
@@ -638,24 +751,25 @@
The status parameter indicates the execution status and can be one of the \ref osStatus_t "osStatus_t codes" or one
of the extended execution status codes which are summarized in the table below.
-| Extended Status Code | Description |
-|:------------------------------|:------------|
-| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
-| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
-| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
-| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
-| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
-| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
-| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
-| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
-| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
-| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
-| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
-| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
-| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
-| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
+| Extended Status Code | Description |
+|:--------------------------------|:------------|
+| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
+| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
+| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
+| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
+| osRtxErrorInvalidPrivilegedMode | Privileged thread cannot be created - kernel protect privileged is active. |
+| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
+| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
+| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
+| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
+| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
+| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
+| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
+| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
+| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
+| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
\b Value in the Event Recorder shows:
- \b status : execution status code.
@@ -725,24 +839,25 @@
The status parameter indicates the execution status and can be one of the \ref osStatus_t "osStatus_t codes" or one
of the extended execution status codes which are summarized in the table below.
-| Extended Status Code | Description |
-|:------------------------------|:------------|
-| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
-| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
-| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
-| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
-| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
-| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
-| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
-| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
-| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
-| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
-| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
-| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
-| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
-| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
+| Extended Status Code | Description |
+|:--------------------------------|:------------|
+| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
+| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
+| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
+| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
+| osRtxErrorInvalidPrivilegedMode | Privileged thread cannot be created - kernel protect privileged is active. |
+| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
+| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
+| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
+| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
+| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
+| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
+| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
+| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
+| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
+| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
\b Value in the Event Recorder shows:
- \b thread_id : thread ID.
@@ -868,24 +983,25 @@
The status parameter indicates the execution status and can be one of the \ref osStatus_t "osStatus_t codes" or one
of the extended execution status codes which are summarized in the table below.
-| Extended Status Code | Description |
-|:------------------------------|:------------|
-| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
-| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
-| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
-| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
-| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
-| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
-| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
-| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
-| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
-| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
-| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
-| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
-| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
-| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
+| Extended Status Code | Description |
+|:--------------------------------|:------------|
+| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
+| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
+| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
+| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
+| osRtxErrorInvalidPrivilegedMode | Privileged thread cannot be created - kernel protect privileged is active. |
+| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
+| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
+| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
+| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
+| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
+| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
+| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
+| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
+| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
+| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
\b Value in the Event Recorder shows:
- \b ef_id : event flags ID.
@@ -1063,24 +1179,25 @@
The status parameter indicates the execution status and can be one of the \ref osStatus_t "osStatus_t codes" or one
of the extended execution status codes which are summarized in the table below.
-| Extended Status Code | Description |
-|:------------------------------|:------------|
-| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
-| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
-| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
-| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
-| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
-| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
-| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
-| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
-| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
-| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
-| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
-| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
-| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
-| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
+| Extended Status Code | Description |
+|:--------------------------------|:------------|
+| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
+| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
+| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
+| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
+| osRtxErrorInvalidPrivilegedMode | Privileged thread cannot be created - kernel protect privileged is active. |
+| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
+| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
+| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
+| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
+| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
+| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
+| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
+| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
+| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
+| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
\b Value in the Event Recorder shows:
- \b timer_id : timer ID.
@@ -1212,24 +1329,25 @@
The status parameter indicates the execution status and can be one of the \ref osStatus_t "osStatus_t codes" or one
of the extended execution status codes which are summarized in the table below.
-| Extended Status Code | Description |
-|:------------------------------|:------------|
-| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
-| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
-| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
-| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
-| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
-| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
-| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
-| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
-| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
-| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
-| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
-| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
-| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
-| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
+| Extended Status Code | Description |
+|:--------------------------------|:------------|
+| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
+| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
+| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
+| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
+| osRtxErrorInvalidPrivilegedMode | Privileged thread cannot be created - kernel protect privileged is active. |
+| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
+| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
+| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
+| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
+| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
+| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
+| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
+| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
+| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
+| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
\b Value in the Event Recorder shows:
- \b mutex_id : mutex ID.
@@ -1378,24 +1496,25 @@
The status parameter indicates the execution status and can be one of the \ref osStatus_t "osStatus_t codes" or one
of the extended execution status codes which are summarized in the table below.
-| Extended Status Code | Description |
-|:------------------------------|:------------|
-| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
-| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
-| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
-| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
-| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
-| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
-| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
-| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
-| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
-| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
-| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
-| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
-| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
-| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
+| Extended Status Code | Description |
+|:--------------------------------|:------------|
+| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
+| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
+| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
+| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
+| osRtxErrorInvalidPrivilegedMode | Privileged thread cannot be created - kernel protect privileged is active. |
+| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
+| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
+| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
+| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
+| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
+| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
+| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
+| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
+| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
+| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
\b Value in the Event Recorder shows:
- \b semaphore_id : semaphore ID.
@@ -1546,24 +1665,25 @@
The status parameter indicates the execution status and can be one of the \ref osStatus_t "osStatus_t codes" or one
of the extended execution status codes which are summarized in the table below.
-| Extended Status Code | Description |
-|:------------------------------|:------------|
-| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
-| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
-| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
-| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
-| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
-| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
-| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
-| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
-| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
-| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
-| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
-| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
-| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
-| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
+| Extended Status Code | Description |
+|:--------------------------------|:------------|
+| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
+| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
+| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
+| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
+| osRtxErrorInvalidPrivilegedMode | Privileged thread cannot be created - kernel protect privileged is active. |
+| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
+| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
+| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
+| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
+| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
+| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
+| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
+| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
+| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
+| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
\b Value in the Event Recorder shows:
- \b mp_id : memory pool ID.
@@ -1755,24 +1875,25 @@
The status parameter indicates the execution status and can be one of the \ref osStatus_t "osStatus_t codes" or one
of the extended execution status codes which are summarized in the table below.
-| Extended Status Code | Description |
-|:------------------------------|:------------|
-| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
-| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
-| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
-| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
-| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
-| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
-| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
-| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
-| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
-| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
-| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
-| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
-| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
-| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
-| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
+| Extended Status Code | Description |
+|:--------------------------------|:------------|
+| osRtxErrorKernelNotReady | Kernel scheduler is not in Ready state. |
+| osRtxErrorKernelNotRunning | Kernel scheduler is not executing - there is no running thread. |
+| osRtxErrorInvalidControlBlock | Object control block with invalid alignment or size was specified. |
+| osRtxErrorInvalidDataMemory | Object data memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidThreadStack | Thread stack memory with invalid alignment or size was specified. |
+| osRtxErrorInvalidPriority | Invalid thread priority was specified. |
+| osRtxErrorInvalidPrivilegedMode | Privileged thread cannot be created - kernel protect privileged is active. |
+| osRtxErrorThreadNotJoinable | Specified thread is not joinable. |
+| osRtxErrorMutexNotOwned | Specified mutex is not owned by the current running thread. |
+| osRtxErrorMutexNotLocked | Specified mutex is not locked. |
+| osRtxErrorMutexLockLimit | Maximum number of recursive mutex locks reached. |
+| osRtxErrorSemaphoreCountLimit | Semaphore count limit reached. |
+| osRtxErrorTZ_InitContext_S | Secure context memory system initialization failed. |
+| osRtxErrorTZ_AllocContext_S | Secure context memory allocation failed. |
+| osRtxErrorTZ_FreeContext_S | Secure context memory deallocation failed. |
+| osRtxErrorTZ_LoadContext_S | Secure context load failed. |
+| osRtxErrorTZ_SaveContext_S | Secure context save failed. |
\b Value in the Event Recorder shows:
- \b mq_id : message queue ID.
@@ -2007,4 +2128,4 @@
/**
@}
*/
-// end group Event Recorder
\ No newline at end of file
+// end group Event Recorder
diff --git a/CMSIS/DoxyGen/RTOS2/src/rtx_os.txt b/CMSIS/DoxyGen/RTOS2/src/rtx_os.txt
index cde714d..c2dc3c6 100644
--- a/CMSIS/DoxyGen/RTOS2/src/rtx_os.txt
+++ b/CMSIS/DoxyGen/RTOS2/src/rtx_os.txt
@@ -239,6 +239,15 @@
to lock global C/C++ library resources.
*/
+/*=======0=========1=========2=========3=========4=========5=========6=========7=========8=========9=========0=========1====*/
+/**
+\def osRtxErrorSVC
+\brief Invalid SVC function called.
+\details
+This error identifier is used with \ref osRtxErrorNotify when RTX5 detects SVC function pointer that is not properly aligned
+or is located outside of the RTX5 SVC function table.
+*/
+
/**
@}
*/
@@ -267,6 +276,7 @@
| \ref osRtxErrorTimerQueueOverflow | User Timer Callback Queue overflow detected for timer (timer_id=object_id) |
| \ref osRtxErrorClibSpace | Standard C/C++ library libspace not available: increase \c OS_THREAD_LIBSPACE_NUM |
| \ref osRtxErrorClibMutex | Standard C/C++ library mutex initialization failed |
+| \ref osRtxErrorSVC | Invalid SVC function called (function=object_id) |
The function \b osRtxErrorNotify must contain an infinite loop to prevent further program execution. You can use an emulator
to step over the infinite loop and trace into the code introducing a runtime error. For the overflow errors this means you
@@ -295,6 +305,9 @@
case osRtxErrorClibMutex:
// Standard C/C++ library mutex initialization failed
break;
+ case osRtxErrorSVC:
+ // Invalid SVC function called (function=object_id)
+ break;
default:
break;
}
diff --git a/CMSIS/RTOS2/RTX/Config/RTX_Config.c b/CMSIS/RTOS2/RTX/Config/RTX_Config.c
index 737078a..d21fa0a 100644
--- a/CMSIS/RTOS2/RTX/Config/RTX_Config.c
+++ b/CMSIS/RTOS2/RTX/Config/RTX_Config.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -17,7 +17,7 @@
*
* -----------------------------------------------------------------------------
*
- * $Revision: V5.1.1
+ * $Revision: V5.2.0
*
* Project: CMSIS-RTOS RTX
* Title: RTX Configuration
@@ -55,6 +55,9 @@
case osRtxErrorClibMutex:
// Standard C/C++ library mutex initialization failed
break;
+ case osRtxErrorSVC:
+ // Invalid SVC function called (function=object_id)
+ break;
default:
// Reserved
break;
diff --git a/CMSIS/RTOS2/RTX/Config/RTX_Config.h b/CMSIS/RTOS2/RTX/Config/RTX_Config.h
index 4d2f501..fe0c57b 100644
--- a/CMSIS/RTOS2/RTX/Config/RTX_Config.h
+++ b/CMSIS/RTOS2/RTX/Config/RTX_Config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -17,7 +17,7 @@
*
* -----------------------------------------------------------------------------
*
- * $Revision: V5.5.2
+ * $Revision: V5.6.0
*
* Project: CMSIS-RTOS RTX
* Title: RTX Configuration definitions
@@ -69,6 +69,61 @@
// </e>
+// <e>Safety features (Source variant only)
+// <i> Enables FuSa related features.
+// <i> Requires RTX Source variant.
+// <i> Enables:
+// <i> - selected features from this group
+// <i> - Thread functions: osThreadProtectPrivileged
+#ifndef OS_SAFETY_FEATURES
+#define OS_SAFETY_FEATURES 0
+#endif
+
+// <q>Safety Class
+// <i> Threads assigned to lower classes cannot modify higher class threads.
+// <i> Enables:
+// <i> - Object attributes: osSafetyClass
+// <i> - Kernel functions: osKernelProtect, osKernelDestroyClass
+// <i> - Thread functions: osThreadGetClass, osThreadSuspendClass, osThreadResumeClass
+#ifndef OS_SAFETY_CLASS
+#define OS_SAFETY_CLASS 1
+#endif
+
+// <q>MPU Protected Zone
+// <i> Access protection via MPU (Spatial isolation).
+// <i> Enables:
+// <i> - Thread attributes: osThreadZone
+// <i> - Thread functions: osThreadGetZone, osThreadTerminateZone
+// <i> - Zone Management: osZoneSetup_Callback
+#ifndef OS_EXECUTION_ZONE
+#define OS_EXECUTION_ZONE 1
+#endif
+
+// <q>Thread Watchdog
+// <i> Watchdog alerts ensure timing for critical threads (Temporal isolation).
+// <i> Enables:
+// <i> - Thread functions: osThreadFeedWatchdog
+// <i> - Handler functions: osWatchdogAlarm_Handler
+#ifndef OS_THREAD_WATCHDOG
+#define OS_THREAD_WATCHDOG 1
+#endif
+
+// <q>Object Pointer checking
+// <i> Check object pointer alignment and memory region.
+#ifndef OS_OBJ_PTR_CHECK
+#define OS_OBJ_PTR_CHECK 0
+#endif
+
+// <q>SVC Function Pointer checking
+// <i> Check SVC function pointer alignment and memory region.
+// <i> User needs to define a linker execution region RTX_SVC_VENEERS
+// <i> containing input sections: rtx_*.o (.text.os.svc.veneer.*)
+#ifndef OS_SVC_PTR_CHECK
+#define OS_SVC_PTR_CHECK 0
+#endif
+
+// </e>
+
// <o>ISR FIFO Queue
// <4=> 4 entries <8=> 8 entries <12=> 12 entries <16=> 16 entries
// <24=> 24 entries <32=> 32 entries <48=> 48 entries <64=> 64 entries
@@ -142,11 +197,25 @@
#define OS_IDLE_THREAD_TZ_MOD_ID 0
#endif
+// <o>Idle Thread Safety Class <0-15>
+// <i> Defines the Safety Class number.
+// <i> Default: 0
+#ifndef OS_IDLE_THREAD_CLASS
+#define OS_IDLE_THREAD_CLASS 0
+#endif
+
+// <o>Idle Thread Zone <0-127>
+// <i> Defines Thread Zone.
+// <i> Default: 0
+#ifndef OS_IDLE_THREAD_ZONE
+#define OS_IDLE_THREAD_ZONE 0
+#endif
+
// <q>Stack overrun checking
// <i> Enables stack overrun check at thread switch (requires RTX source variant).
// <i> Enabling this option increases slightly the execution time of a thread switch.
#ifndef OS_STACK_CHECK
-#define OS_STACK_CHECK 0
+#define OS_STACK_CHECK 1
#endif
// <q>Stack usage watermark
@@ -156,12 +225,12 @@
#define OS_STACK_WATERMARK 0
#endif
-// <o>Processor mode for Thread execution
+// <o>Default Processor mode for Thread execution
// <0=> Unprivileged mode
// <1=> Privileged mode
-// <i> Default: Privileged mode
+// <i> Default: Unprivileged mode
#ifndef OS_PRIVILEGE_MODE
-#define OS_PRIVILEGE_MODE 1
+#define OS_PRIVILEGE_MODE 0
#endif
// </h>
@@ -211,6 +280,20 @@
#define OS_TIMER_THREAD_TZ_MOD_ID 0
#endif
+// <o>Timer Thread Safety Class <0-15>
+// <i> Defines the Safety Class number.
+// <i> Default: 0
+#ifndef OS_TIMER_THREAD_CLASS
+#define OS_TIMER_THREAD_CLASS 0
+#endif
+
+// <o>Timer Thread Zone <0-127>
+// <i> Defines Thread Zone.
+// <i> Default: 0
+#ifndef OS_TIMER_THREAD_ZONE
+#define OS_TIMER_THREAD_ZONE 0
+#endif
+
// <o>Timer Callback Queue entries <0-256>
// <i> Number of concurrent active timer callback functions.
// <i> May be set to 0 when timers are not used.
diff --git a/CMSIS/RTOS2/RTX/Include/rtx_def.h b/CMSIS/RTOS2/RTX/Include/rtx_def.h
index 26230e7..370af6c 100644
--- a/CMSIS/RTOS2/RTX/Include/rtx_def.h
+++ b/CMSIS/RTOS2/RTX/Include/rtx_def.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2021-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -31,12 +31,31 @@
#endif
#include "RTX_Config.h"
+#if (defined(OS_SAFETY_FEATURES) && (OS_SAFETY_FEATURES != 0))
+ #define RTX_SAFETY_FEATURES
+ #if (defined(OS_SAFETY_CLASS) && (OS_SAFETY_CLASS != 0))
+ #define RTX_SAFETY_CLASS
+ #endif
+ #if (defined(OS_EXECUTION_ZONE) && (OS_EXECUTION_ZONE != 0))
+ #define RTX_EXECUTION_ZONE
+ #endif
+ #if (defined(OS_THREAD_WATCHDOG) && (OS_THREAD_WATCHDOG != 0))
+ #define RTX_THREAD_WATCHDOG
+ #endif
+ #if (defined(OS_OBJ_PTR_CHECK) && (OS_OBJ_PTR_CHECK != 0))
+ #define RTX_OBJ_PTR_CHECK
+ #endif
+ #if (defined(OS_SVC_PTR_CHECK) && (OS_SVC_PTR_CHECK != 0))
+ #define RTX_SVC_PTR_CHECK
+ #endif
+#endif
+
#if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))
- #define RTX_OBJ_MEM_USAGE
+ #define RTX_OBJ_MEM_USAGE
#endif
#if (defined(OS_STACK_CHECK) && (OS_STACK_CHECK != 0))
- #define RTX_STACK_CHECK
+ #define RTX_STACK_CHECK
#endif
#ifdef RTE_CMSIS_RTOS2_RTX5_ARMV8M_NS
diff --git a/CMSIS/RTOS2/RTX/Include/rtx_evr.h b/CMSIS/RTOS2/RTX/Include/rtx_evr.h
index 2a6899e..67e9ae0 100644
--- a/CMSIS/RTOS2/RTX/Include/rtx_evr.h
+++ b/CMSIS/RTOS2/RTX/Include/rtx_evr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -79,22 +79,23 @@
/// Extended Status codes
-#define osRtxErrorKernelNotReady (-7)
-#define osRtxErrorKernelNotRunning (-8)
-#define osRtxErrorInvalidControlBlock (-9)
-#define osRtxErrorInvalidDataMemory (-10)
-#define osRtxErrorInvalidThreadStack (-11)
-#define osRtxErrorInvalidPriority (-12)
-#define osRtxErrorThreadNotJoinable (-13)
-#define osRtxErrorMutexNotOwned (-14)
-#define osRtxErrorMutexNotLocked (-15)
-#define osRtxErrorMutexLockLimit (-16)
-#define osRtxErrorSemaphoreCountLimit (-17)
-#define osRtxErrorTZ_InitContext_S (-18)
-#define osRtxErrorTZ_AllocContext_S (-19)
-#define osRtxErrorTZ_FreeContext_S (-20)
-#define osRtxErrorTZ_LoadContext_S (-21)
-#define osRtxErrorTZ_SaveContext_S (-22)
+#define osRtxErrorKernelNotReady (-8)
+#define osRtxErrorKernelNotRunning (-9)
+#define osRtxErrorInvalidControlBlock (-10)
+#define osRtxErrorInvalidDataMemory (-11)
+#define osRtxErrorInvalidThreadStack (-12)
+#define osRtxErrorInvalidPriority (-13)
+#define osRtxErrorInvalidPrivilegedMode (-14)
+#define osRtxErrorThreadNotJoinable (-15)
+#define osRtxErrorMutexNotOwned (-16)
+#define osRtxErrorMutexNotLocked (-17)
+#define osRtxErrorMutexLockLimit (-18)
+#define osRtxErrorSemaphoreCountLimit (-19)
+#define osRtxErrorTZ_InitContext_S (-20)
+#define osRtxErrorTZ_AllocContext_S (-21)
+#define osRtxErrorTZ_FreeContext_S (-22)
+#define osRtxErrorTZ_LoadContext_S (-23)
+#define osRtxErrorTZ_SaveContext_S (-24)
// ==== Memory Events ====
@@ -352,6 +353,25 @@
#endif
/**
+ \brief Event on protect the RTOS Kernel scheduler access (API)
+ \param[in] safety_class safety class.
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_KERNEL != 0) && !defined(EVR_RTX_KERNEL_PROTECT_DISABLE))
+extern void EvrRtxKernelProtect (uint32_t safety_class);
+#else
+#define EvrRtxKernelProtect(safety_class)
+#endif
+
+/**
+ \brief Event on successful RTOS Kernel scheduler protect (API)
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_KERNEL != 0) && !defined(EVR_RTX_KERNEL_PROTECTED_DISABLE))
+extern void EvrRtxKernelProtected (void);
+#else
+#define EvrRtxKernelProtected()
+#endif
+
+/**
\brief Event on RTOS kernel tick count retrieve (API)
\param[in] count RTOS kernel current tick count.
*/
@@ -402,6 +422,17 @@
#define EvrRtxKernelErrorNotify(code, object_id)
#endif
+/**
+ \brief Event on destroy safety class objects (API)
+ \param[in] safety_class safety class.
+ \param[in] mode safety mode.
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_KERNEL != 0) && !defined(EVR_RTX_KERNEL_DESTROY_CLASS_DISABLE))
+extern void EvrRtxKernelDestroyClass (uint32_t safety_class, uint32_t mode);
+#else
+#define EvrRtxKernelDestroyClass(safety_class, mode)
+#endif
+
// ==== Thread Events ====
@@ -452,6 +483,28 @@
#endif
/**
+ \brief Event on thread safety class retrieve (API)
+ \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+ \param[in] safety_class thread safety class.
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_GET_CLASS_DISABLE))
+extern void EvrRtxThreadGetClass (osThreadId_t thread_id, uint32_t safety_class);
+#else
+#define EvrRtxThreadGetClass(thread_id, safety_class)
+#endif
+
+/**
+ \brief Event on thread zone retrieve (API)
+ \param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
+ \param[in] zone thread zone.
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_GET_ZONE_DISABLE))
+extern void EvrRtxThreadGetZone (osThreadId_t thread_id, uint32_t zone);
+#else
+#define EvrRtxThreadGetZone(thread_id, zone)
+#endif
+
+/**
\brief Event on current running thread ID retrieve (API)
\param[in] thread_id thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
*/
@@ -698,6 +751,43 @@
#endif
/**
+ \brief Event on thread feed watchdog (API)
+ \param[in] ticks timeout in number of ticks.
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_FEED_WATCHDOG_DISABLE))
+extern void EvrRtxThreadFeedWatchdog (uint32_t ticks);
+#else
+#define EvrRtxThreadFeedWatchdog(ticks)
+#endif
+
+/**
+ \brief Event on thread feed watchdog done (Op)
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_FEED_WATCHDOG_DONE_DISABLE))
+extern void EvrRtxThreadFeedWatchdogDone (void);
+#else
+#define EvrRtxThreadFeedWatchdogDone()
+#endif
+
+/**
+ \brief Event on protect the creation of privileged threads (API)
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_PROTECT_PRIVILEGED_DISABLE))
+extern void EvrRtxThreadProtectPrivileged (void);
+#else
+#define EvrRtxThreadProtectPrivileged()
+#endif
+
+/**
+ \brief Event on successful protect the creation of privileged threads (Op)
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_PRIVILEGED_PROTECTED_DISABLE))
+extern void EvrRtxThreadPrivilegedProtected (void);
+#else
+#define EvrRtxThreadPrivilegedProtected()
+#endif
+
+/**
\brief Event on active thread count retrieve (API)
\param[in] count number of active threads.
*/
@@ -719,6 +809,48 @@
#define EvrRtxThreadEnumerate(thread_array, array_items, count)
#endif
+/**
+ \brief Event on thread safety class suspend (API)
+ \param[in] safety_class safety class.
+ \param[in] mode safety mode.
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_SUSPEND_CLASS_DISABLE))
+extern void EvrRtxThreadSuspendClass (uint32_t safety_class, uint32_t mode);
+#else
+#define EvrRtxThreadSuspendClass(safety_class, mode)
+#endif
+
+/**
+ \brief Event on thread safety class resume (API)
+ \param[in] safety_class safety class.
+ \param[in] mode safety mode.
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_RESUME_CLASS_DISABLE))
+extern void EvrRtxThreadResumeClass (uint32_t safety_class, uint32_t mode);
+#else
+#define EvrRtxThreadResumeClass(safety_class, mode)
+#endif
+
+/**
+ \brief Event on thread zone terminate (API)
+ \param[in] zone thread zone.
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_TERMINATE_ZONE_DISABLE))
+extern void EvrRtxThreadTerminateZone (uint32_t zone);
+#else
+#define EvrRtxThreadTerminateZone(zone)
+#endif
+
+/**
+ \brief Event on thread watchdog expired (Error)
+ \param[in] thread_id thread ID obtained by \ref osThreadNew.
+*/
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_WATCHDOG_EXPIRED_DISABLE))
+extern void EvrRtxThreadWatchdogExpired (osThreadId_t thread_id);
+#else
+#define EvrRtxThreadWatchdogExpired(thread_id)
+#endif
+
// ==== Thread Flags Events ====
diff --git a/CMSIS/RTOS2/RTX/Include/rtx_os.h b/CMSIS/RTOS2/RTX/Include/rtx_os.h
index 66e4843..80f14a9 100644
--- a/CMSIS/RTOS2/RTX/Include/rtx_os.h
+++ b/CMSIS/RTOS2/RTX/Include/rtx_os.h
@@ -38,9 +38,9 @@
/// Kernel Information
-#define osRtxVersionAPI 20010003 ///< API version (2.1.3)
-#define osRtxVersionKernel 50050005 ///< Kernel version (5.5.5)
-#define osRtxKernelId "RTX V5.5.5" ///< Kernel identification string
+#define osRtxVersionAPI 20020000 ///< API version (2.2.0)
+#define osRtxVersionKernel 50070000 ///< Kernel version (5.7.0)
+#define osRtxKernelId "RTX V5.7.0" ///< Kernel identification string
// ==== Common definitions ====
@@ -60,6 +60,10 @@
#define osRtxFlagSystemObject 0x01U
#define osRtxFlagSystemMemory 0x02U
+/// Object Attribute Class definitions
+#define osRtxAttrClass_Pos 4U
+#define osRtxAttrClass_Msk 0xF0U
+
// ==== Kernel definitions ====
@@ -70,6 +74,11 @@
#define osRtxKernelLocked ((uint8_t)osKernelLocked)
#define osRtxKernelSuspended ((uint8_t)osKernelSuspended)
+/// Kernel Protect definitions
+#define osRtxKernelProtectPrivileged 0x01U
+#define osRtxKernelProtectClass_Pos 4U
+#define osRtxKernelProtectClass_Msk 0xF0U
+
// ==== Thread definitions ====
@@ -124,9 +133,10 @@
uint32_t sp; ///< Current Stack Pointer
uint32_t thread_addr; ///< Thread entry address
uint32_t tz_memory; ///< TrustZone Memory Identifier
-#ifdef RTX_TF_M_EXTENSION
- uint32_t tz_module; ///< TrustZone Module Identifier
-#endif
+ uint8_t zone; ///< Thread Zone
+ uint8_t reserved[3];
+ struct osRtxThread_s *wdog_next; ///< Link pointer to next Thread in Watchdog list
+ uint32_t wdog_tick; ///< Watchdog tick counter
} osRtxThread_t;
@@ -137,8 +147,8 @@
#define osRtxTimerStopped 0x01U ///< Timer Stopped
#define osRtxTimerRunning 0x02U ///< Timer Running
-/// Timer Type definitions
-#define osRtxTimerPeriodic ((uint8_t)osTimerPeriodic)
+/// Timer attribute definitions
+#define osRtxTimerPeriodic 0x01U ///< Timer Periodic mode
/// Timer Function Information
typedef struct {
@@ -151,7 +161,7 @@
uint8_t id; ///< Object Identifier
uint8_t state; ///< Object State
uint8_t flags; ///< Object Flags
- uint8_t type; ///< Timer Type (Periodic/One-shot)
+ uint8_t attr; ///< Object Attributes
const char *name; ///< Object Name
struct osRtxTimer_s *prev; ///< Pointer to previous active Timer
struct osRtxTimer_s *next; ///< Pointer to next active Timer
@@ -168,7 +178,7 @@
uint8_t id; ///< Object Identifier
uint8_t reserved_state; ///< Object State (not used)
uint8_t flags; ///< Object Flags
- uint8_t reserved;
+ uint8_t attr; ///< Object Attributes
const char *name; ///< Object Name
osRtxThread_t *thread_list; ///< Waiting Threads List
uint32_t event_flags; ///< Event Flags
@@ -200,7 +210,7 @@
uint8_t id; ///< Object Identifier
uint8_t reserved_state; ///< Object State (not used)
uint8_t flags; ///< Object Flags
- uint8_t reserved;
+ uint8_t attr; ///< Object Attributes
const char *name; ///< Object Name
osRtxThread_t *thread_list; ///< Waiting Threads List
uint16_t tokens; ///< Current number of tokens
@@ -225,7 +235,7 @@
uint8_t id; ///< Object Identifier
uint8_t reserved_state; ///< Object State (not used)
uint8_t flags; ///< Object Flags
- uint8_t reserved;
+ uint8_t attr; ///< Object Attributes
const char *name; ///< Object Name
osRtxThread_t *thread_list; ///< Waiting Threads List
osRtxMpInfo_t mp_info; ///< Memory Pool Info
@@ -249,7 +259,7 @@
uint8_t id; ///< Object Identifier
uint8_t reserved_state; ///< Object State (not used)
uint8_t flags; ///< Object Flags
- uint8_t reserved;
+ uint8_t attr; ///< Object Attributes
const char *name; ///< Object Name
osRtxThread_t *thread_list; ///< Waiting Threads List
osRtxMpInfo_t mp_info; ///< Memory Pool Info
@@ -267,7 +277,7 @@
uint8_t id; ///< Object Identifier
uint8_t state; ///< Object State
uint8_t flags; ///< Object Flags
- uint8_t reserved;
+ uint8_t attr; ///< Object Attributes
const char *name; ///< Object Name
osRtxThread_t *thread_list; ///< Threads List
} osRtxObject_t;
@@ -283,7 +293,7 @@
uint8_t state; ///< State
volatile uint8_t blocked; ///< Blocked
uint8_t pendSV; ///< Pending SV
- uint8_t reserved;
+ uint8_t protect; ///< Protect options
uint32_t tick; ///< Tick counter
} kernel;
int32_t tick_irqn; ///< Tick Timer IRQ Number
@@ -297,7 +307,7 @@
osRtxThread_t *delay_list; ///< Delay List
osRtxThread_t *wait_list; ///< Wait List (no Timeout)
osRtxThread_t *terminate_list; ///< Terminate Thread List
- uint32_t reserved;
+ osRtxThread_t *wdog_list; ///< Watchdog List
struct { ///< Thread Round Robin Info
osRtxThread_t *thread; ///< Round Robin Thread
uint32_t timeout; ///< Round Robin Timeout
@@ -399,6 +409,7 @@
#define osRtxErrorTimerQueueOverflow 3U ///< User Timer Callback Queue overflow detected for timer.
#define osRtxErrorClibSpace 4U ///< Standard C/C++ library libspace not available: increase \c OS_THREAD_LIBSPACE_NUM.
#define osRtxErrorClibMutex 5U ///< Standard C/C++ library mutex initialization failed.
+#define osRtxErrorSVC 6U ///< Invalid SVC function called.
/// OS Error Callback function
extern uint32_t osRtxErrorNotify (uint32_t code, void *object_id);
@@ -412,11 +423,6 @@
extern void PendSV_Handler (void);
extern void SysTick_Handler (void);
-/// OS Trusted Firmware M Extension
-#ifdef RTX_TF_M_EXTENSION
-extern uint32_t osRtxTzGetModuleId (void);
-#endif
-
// ==== OS External Configuration ====
@@ -424,6 +430,12 @@
#define osRtxConfigPrivilegedMode (1UL<<0) ///< Threads in Privileged mode
#define osRtxConfigStackCheck (1UL<<1) ///< Stack overrun checking
#define osRtxConfigStackWatermark (1UL<<2) ///< Stack usage Watermark
+#define osRtxConfigSafetyFeatures (1UL<<3) ///< Safety features enabled
+#define osRtxConfigSafetyClass (1UL<<4) ///< Safety Class feature enabled
+#define osRtxConfigExecutionZone (1UL<<5) ///< Execution Zone enabled
+#define osRtxConfigThreadWatchdog (1UL<<6) ///< Thread Watchdog enabled
+#define osRtxConfigObjPtrCheck (1UL<<7) ///< Object Pointer Checking enabled
+#define osRtxConfigSVCPtrCheck (1UL<<8) ///< SVC Pointer Checking enabled
/// OS Configuration structure
typedef struct {
diff --git a/CMSIS/RTOS2/RTX/Library/ARM/MDK/RTX_CM.uvprojx b/CMSIS/RTOS2/RTX/Library/ARM/MDK/RTX_CM.uvprojx
index 9a5fcd3..1d92738 100644
--- a/CMSIS/RTOS2/RTX/Library/ARM/MDK/RTX_CM.uvprojx
+++ b/CMSIS/RTOS2/RTX/Library/ARM/MDK/RTX_CM.uvprojx
@@ -10,7 +10,7 @@
<TargetName>CM0_LE</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<ToolsetName>ARM-ADS</ToolsetName>
- <pCCUsed>6160000::V6.16::ARMCLANG</pCCUsed>
+ <pCCUsed>6190000::V6.19::ARMCLANG</pCCUsed>
<uAC6>1</uAC6>
<TargetOption>
<TargetCommonOption>
@@ -186,6 +186,7 @@
<RvdsVP>0</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<StupSel>8</StupSel>
@@ -608,7 +609,7 @@
<TargetName>CM3_LE</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<ToolsetName>ARM-ADS</ToolsetName>
- <pCCUsed>6160000::V6.16::ARMCLANG</pCCUsed>
+ <pCCUsed>6190000::V6.19::ARMCLANG</pCCUsed>
<uAC6>1</uAC6>
<TargetOption>
<TargetCommonOption>
@@ -784,6 +785,7 @@
<RvdsVP>0</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<StupSel>8</StupSel>
@@ -1206,7 +1208,7 @@
<TargetName>CM4F_LE</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<ToolsetName>ARM-ADS</ToolsetName>
- <pCCUsed>6160000::V6.16::ARMCLANG</pCCUsed>
+ <pCCUsed>6190000::V6.19::ARMCLANG</pCCUsed>
<uAC6>1</uAC6>
<TargetOption>
<TargetCommonOption>
@@ -1382,6 +1384,7 @@
<RvdsVP>2</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<StupSel>8</StupSel>
@@ -1804,7 +1807,7 @@
<TargetName>ARMv8MBL_LE</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<ToolsetName>ARM-ADS</ToolsetName>
- <pCCUsed>6160000::V6.16::ARMCLANG</pCCUsed>
+ <pCCUsed>6190000::V6.19::ARMCLANG</pCCUsed>
<uAC6>1</uAC6>
<TargetOption>
<TargetCommonOption>
@@ -1980,6 +1983,7 @@
<RvdsVP>0</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<StupSel>8</StupSel>
@@ -2402,7 +2406,7 @@
<TargetName>ARMv8MBL_NS_LE</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<ToolsetName>ARM-ADS</ToolsetName>
- <pCCUsed>6160000::V6.16::ARMCLANG</pCCUsed>
+ <pCCUsed>6190000::V6.19::ARMCLANG</pCCUsed>
<uAC6>1</uAC6>
<TargetOption>
<TargetCommonOption>
@@ -2578,6 +2582,7 @@
<RvdsVP>0</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<StupSel>8</StupSel>
@@ -3000,7 +3005,7 @@
<TargetName>ARMv8MML_LE</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<ToolsetName>ARM-ADS</ToolsetName>
- <pCCUsed>6160000::V6.16::ARMCLANG</pCCUsed>
+ <pCCUsed>6190000::V6.19::ARMCLANG</pCCUsed>
<uAC6>1</uAC6>
<TargetOption>
<TargetCommonOption>
@@ -3176,6 +3181,7 @@
<RvdsVP>0</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<StupSel>8</StupSel>
@@ -3598,7 +3604,7 @@
<TargetName>ARMv8MML_NS_LE</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<ToolsetName>ARM-ADS</ToolsetName>
- <pCCUsed>6160000::V6.16::ARMCLANG</pCCUsed>
+ <pCCUsed>6190000::V6.19::ARMCLANG</pCCUsed>
<uAC6>1</uAC6>
<TargetOption>
<TargetCommonOption>
@@ -3774,6 +3780,7 @@
<RvdsVP>0</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<StupSel>8</StupSel>
@@ -4196,7 +4203,7 @@
<TargetName>ARMv8MML_SP_LE</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<ToolsetName>ARM-ADS</ToolsetName>
- <pCCUsed>6160000::V6.16::ARMCLANG</pCCUsed>
+ <pCCUsed>6190000::V6.19::ARMCLANG</pCCUsed>
<uAC6>1</uAC6>
<TargetOption>
<TargetCommonOption>
@@ -4372,6 +4379,7 @@
<RvdsVP>2</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<StupSel>8</StupSel>
@@ -4794,7 +4802,7 @@
<TargetName>ARMv8MML_SP_NS_LE</TargetName>
<ToolsetNumber>0x4</ToolsetNumber>
<ToolsetName>ARM-ADS</ToolsetName>
- <pCCUsed>6160000::V6.16::ARMCLANG</pCCUsed>
+ <pCCUsed>6190000::V6.19::ARMCLANG</pCCUsed>
<uAC6>1</uAC6>
<TargetOption>
<TargetCommonOption>
@@ -4970,6 +4978,7 @@
<RvdsVP>2</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<StupSel>8</StupSel>
diff --git a/CMSIS/RTOS2/RTX/Library/GCC/MDK/RTX_CM.uvprojx b/CMSIS/RTOS2/RTX/Library/GCC/MDK/RTX_CM.uvprojx
index 2b32337..0cd60c4 100644
--- a/CMSIS/RTOS2/RTX/Library/GCC/MDK/RTX_CM.uvprojx
+++ b/CMSIS/RTOS2/RTX/Library/GCC/MDK/RTX_CM.uvprojx
@@ -171,6 +171,7 @@
<RvdsVP>0</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<OnChipMemories>
@@ -661,6 +662,7 @@
<RvdsVP>0</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<OnChipMemories>
@@ -1198,6 +1200,7 @@
<RvdsVP>2</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<OnChipMemories>
@@ -1688,6 +1691,7 @@
<RvdsVP>0</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<OnChipMemories>
@@ -2225,6 +2229,7 @@
<RvdsVP>0</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<OnChipMemories>
@@ -2762,6 +2767,7 @@
<RvdsVP>0</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<OnChipMemories>
@@ -3299,6 +3305,7 @@
<RvdsVP>0</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<OnChipMemories>
@@ -3836,6 +3843,7 @@
<RvdsVP>2</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<OnChipMemories>
@@ -4373,6 +4381,7 @@
<RvdsVP>2</RvdsVP>
<RvdsMve>0</RvdsMve>
<RvdsCdeCp>0</RvdsCdeCp>
+ <nBranchProt>0</nBranchProt>
<hadIRAM2>0</hadIRAM2>
<hadIROM2>0</hadIROM2>
<OnChipMemories>
diff --git a/CMSIS/RTOS2/RTX/RTX5.scvd b/CMSIS/RTOS2/RTX/RTX5.scvd
index 5b5d126..2585bae 100644
--- a/CMSIS/RTOS2/RTX/RTX5.scvd
+++ b/CMSIS/RTOS2/RTX/RTX5.scvd
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<component_viewer schemaVersion="1.2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="Component_Viewer.xsd">
- <component name="CMSIS:RTOS2:Keil RTX5" shortname="RTX5" version="5.5.3"/> <!-- name and version of the component -->
+ <component name="CMSIS:RTOS2:Keil RTX5" shortname="RTX5" version="5.7.0"/> <!-- name and version of the component -->
<typedefs>
<!-- Attributes structure for thread -->
@@ -69,7 +69,7 @@
</typedef>
<!-- Thread Control Block -->
- <typedef name="osRtxThread_t" info="" size="68">
+ <typedef name="osRtxThread_t" info="" size="80">
<member name="id" type="uint8_t" offset="0" info="Object Identifier"/>
<member name="state" type="uint8_t" offset="1" info="Object State">
<enum name="osThreadInactive" value="0" info=""/>
@@ -91,8 +91,10 @@
</member>
<member name="flags" type="uint8_t" offset="2" info="Object Flags"/>
<member name="attr" type="uint8_t" offset="3" info="Object Attributes">
- <enum name="osThreadDetached" value="0x00" info="Thread created in detached mode"/>
- <enum name="osThreadJoinable" value="0x01" info="Thread created in joinable mode"/>
+ <enum name="osThreadDetached" value="0x00" info="Thread created in detached mode"/>
+ <enum name="osThreadJoinable" value="0x01" info="Thread created in joinable mode"/>
+ <enum name="osThreadUnprivileged" value="0x02" info="Thread created in unprivileged mode"/>
+ <enum name="osThreadPrivileged" value="0x04" info="Thread created in privileged mode"/>
</member>
<member name="name" type="uint32_t" offset="4" info="Object name (type is *uint8_t)"/>
<member name="thread_next" type="*osRtxThread_t" offset="8" info="Link pointer to next Thread in Object list"/>
@@ -170,12 +172,18 @@
<member name="sp" type="uint32_t" offset="56" info="Current stack pointer"/>
<member name="thread_addr" type="uint32_t" offset="60" info="Thread entry address"/>
<member name="tz_memory" type="uint32_t" offset="64" info="TrustZone Memory Identifier"/>
+ <member name="zone" type="uint8_t" offset="68" info="Thread Zone"/>
+ <member name="reserved" type="uint8_t" offset="69" info="Reserved bytes"/>
+ <member name="wdog_next" type="*osRtxThread_t" offset="72" info="Link pointer to next Thread in Watchdog list"/>
+ <member name="wdog_tick" type="uint32_t" offset="76" info="Watchdog tick counter"/>
<var name="cb_valid" type="uint32_t" info="Control block validation status (valid=1, invalid=0)"/>
<var name="sp_valid" type="uint32_t" info="Stack pointer validation status (valid=1, invalid=0)"/>
<var name="out_type" type="uint8_t" info="Output display type ID"/>
<var name="ex_delay" type="uint32_t" info="Calculated execution delay"/>
+ <var name="wd_tick" type="uint32_t" info="Calculated absolute watchdog tick time"/>
+ <var name="wd_state" type="uint32_t" info="Watchdog state (0=not running, 1=running)"/>
<var name="stack_val" type="uint32_t" info="Stack usage: analysis result"/>
<var name="stack_cur" type="uint32_t" info="Stack usage: current (address)"/>
@@ -195,7 +203,7 @@
<enum name="Running" value="2" info="Timer is running"/>
</member>
<member name="flags" type="uint8_t" offset="2" info="Object Flags"/>
- <member name="type" type="uint8_t" offset="3" info="Timer Type">
+ <member name="attr" type="uint8_t" offset="3" info="Object Attributes">
<enum name="osTimerOnce" value="0" info="One-shot timer"/>
<enum name="osTimerPeriodic" value="1" info="Periodic timer"/>
</member>
@@ -217,7 +225,7 @@
<member name="id" type="uint8_t" offset="0" info="Object Identifier"/>
<member name="state" type="uint8_t" offset="1" info="Object State"/>
<member name="flags" type="uint8_t" offset="2" info="Object Flags"/>
- <member name="reserved" type="uint8_t" offset="3" info=""/>
+ <member name="attr" type="uint8_t" offset="3" info="Object Attributes"/>
<member name="name" type="uint32_t" offset="4" info="Object name (type is *uint8_t)"/>
<member name="thread_list" type="*osRtxThread_t" offset="8" info="Waiting threads list"/>
<member name="event_flags" type="int32_t" offset="12" info="Event flags"/>
@@ -254,7 +262,7 @@
<member name="id" type="uint8_t" offset="0" info="Object Identifier"/>
<member name="state" type="uint8_t" offset="1" info="Object State"/>
<member name="flags" type="uint8_t" offset="2" info="Object Flags"/>
- <member name="reserved" type="uint8_t" offset="3" info=""/>
+ <member name="attr" type="uint8_t" offset="3" info="Object Attributes"/>
<member name="name" type="uint32_t" offset="4" info="Object name (type is *uint8_t)"/>
<member name="thread_list" type="*osRtxThread_t" offset="8" info="Waiting threads list"/>
<member name="tokens" type="uint16_t" offset="12" info="Current number of tokens"/>
@@ -280,7 +288,7 @@
<member name="id" type="uint8_t" offset="0" info="Object Identifier"/>
<member name="state" type="uint8_t" offset="1" info="Object State"/>
<member name="flags" type="uint8_t" offset="2" info="Object Flags"/>
- <member name="reserved" type="uint8_t" offset="3" info=""/>
+ <member name="attr" type="uint8_t" offset="3" info="Object Attributes"/>
<member name="name" type="uint32_t" offset="4" info="Object name (type is *uint8_t)"/>
<member name="thread_list" type="*osRtxThread_t" offset="8" info="Waiting threads list"/>
@@ -314,7 +322,7 @@
<member name="id" type="uint8_t" offset="0" info="Object Identifier"/>
<member name="state" type="uint8_t" offset="1" info="Object State"/>
<member name="flags" type="uint8_t" offset="2" info="Object Flags"/>
- <member name="reserved" type="uint8_t" offset="3" info=""/>
+ <member name="attr" type="uint8_t" offset="3" info="Object Attributes"/>
<member name="name" type="uint32_t" offset="4" info="Object name (type is *uint8_t)"/>
<member name="thread_list" type="*osRtxThread_t" offset="8" info="Waiting threads list"/>
@@ -352,6 +360,7 @@
</member>
<member name="kernel_blocked" type="uint8_t" offset="9" info="Kernel blocked"/>
<member name="kernel_pendSV" type="uint8_t" offset="10" info="Kernel pending SV"/>
+ <member name="kernel_protect" type="uint8_t" offset="11" info="Protect options"/>
<member name="kernel_tick" type="uint32_t" offset="12" info="Kernel tick counter"/>
<member name="tick_irqn" type="int32_t" offset="16" info="Tick timer IRQ number"/>
<member name="thread_run_curr" type="*osRtxThread_t" offset="20" info="Current running thread"/>
@@ -361,7 +370,7 @@
<member name="thread_ready_id" type="uint8_t" offset="28+0" info="Object Identifier" />
<member name="thread_ready_state" type="uint8_t" offset="28+1" info="Object State" />
<member name="thread_ready_flags" type="uint8_t" offset="28+2" info="Object Flags" />
- <member name="thread_ready_rsvd" type="uint8_t" offset="28+3" info="Reserved" />
+ <member name="thread_ready_attr" type="uint8_t" offset="28+3" info="Object Attributes"/>
<member name="thread_ready_name" type="uint32_t" offset="28+4" info="Object Name (type is *uint8_t)" />
<member name="thread_ready_thread_list" type="*osRtxThread_t" offset="28+8" info="Threads List" />
@@ -369,6 +378,7 @@
<member name="thread_delay_list" type="*osRtxThread_t" offset="44" info="Delay list"/>
<member name="thread_wait_list" type="*osRtxThread_t" offset="48" info="Wait list (no timeout)"/>
<member name="thread_terminate_list" type="*osRtxThread_t" offset="52" info="Terminate list"/>
+ <member name="thread_wdog_list" type="*osRtxThread_t" offset="56" info="Watchdog list"/>
<member name="thread_robin_thread" type="*osRtxThread_t" offset="60" info="Round Robin thread"/>
<member name="thread_timeout" type="uint32_t" offset="64" info="Round Robin timeout"/>
@@ -452,6 +462,12 @@
<var name="stack_check" type="uint8_t" info="Stack checking (0:disabled, 1:enabled)"/>
<var name="stack_wmark" type="uint8_t" info="Stack watermark (0:disabled, 1:enabled)"/>
+ <var name="safety_feat" type="uint8_t" info="Safety features (0:disabled, 1:enabled)"/>
+ <var name="safety_class" type="uint8_t" info="Thread safety class (0:disabled, 1:enabled)"/>
+ <var name="exec_zone" type="uint8_t" info="Execution zone (0:disabled, 1:enabled)"/>
+ <var name="watchdog" type="uint8_t" info="Thread watchdog (0:disabled, 1:enabled)"/>
+ <var name="obj_check" type="uint8_t" info="Object pointer checking (0:disabled, 1:enabled)"/>
+ <var name="svc_check" type="uint8_t" info="SVC function pointer checking (0:disabled, 1:enabled)"/>
</typedef>
<!-- Memory Pool Header -->
@@ -489,29 +505,31 @@
<typedef name="rtx_t" info="Various RTX Definitions" size="8">
<member name="status" type="int32_t" offset="0" info="RTX5 operations status">
- <enum name="osOK" value="0" info="Operation completed successfully"/>
- <enum name="osError" value="-1" info="Unspecified RTOS error: run-time error but no other error message fits."/>
- <enum name="osErrorTimeout" value="-2" info="Operation not completed within the timeout period."/>
- <enum name="osErrorResource" value="-3" info="Resource not available"/>
- <enum name="osErrorParameter" value="-4" info="Parameter error"/>
- <enum name="osErrorNoMemory" value="-5" info="System is out of memory: it was impossible to allocate or reserve memory for the operation"/>
- <enum name="osErrorISR" value="-6" info="Not allowed in ISR context: the function cannot be called from interrupt service routines"/>
- <enum name="osRtxErrorKernelNotReady" value="-7" info="RTOS Kernel scheduler is not ready"/>
- <enum name="osRtxErrorKernelNotRunning" value="-8" info="RTOS Kernel scheduler is not running"/>
- <enum name="osRtxErrorInvalidControlBlock" value="-9" info="Object control block is not properly aligned or has an invalid size"/>
- <enum name="osRtxErrorInvalidDataMemory" value="-10" info="Data memory is not is not properly aligned or has an invalid size"/>
- <enum name="osRtxErrorInvalidThreadStack" value="-11" info="Thread stack is invalid"/>
- <enum name="osRtxErrorInvalidPriority" value="-12" info="Thread priority is invalid"/>
- <enum name="osRtxErrorThreadNotJoinable" value="-13" info="Thread is not joinable"/>
- <enum name="osRtxErrorMutexNotOwned" value="-14" info="Mutex is not owned by the current running thread"/>
- <enum name="osRtxErrorMutexNotLocked" value="-15" info="Mutex is not locked"/>
- <enum name="osRtxErrorMutexLockLimit" value="-16" info="Maximum number of recursive mutex locks reached"/>
- <enum name="osRtxErrorSemaphoreCountLimit" value="-17" info="Semaphore count limit reached"/>
- <enum name="osRtxErrorTZ_InitContext_S" value="-18" info=""/>
- <enum name="osRtxErrorTZ_AllocContext_S" value="-19" info=""/>
- <enum name="osRtxErrorTZ_FreeContext_S" value="-20" info=""/>
- <enum name="osRtxErrorTZ_LoadContext_S" value="-21" info=""/>
- <enum name="osRtxErrorTZ_SaveContext_S" value="-22" info=""/>
+ <enum name="osOK" value="0" info="Operation completed successfully"/>
+ <enum name="osError" value="-1" info="Unspecified RTOS error: run-time error but no other error message fits."/>
+ <enum name="osErrorTimeout" value="-2" info="Operation not completed within the timeout period."/>
+ <enum name="osErrorResource" value="-3" info="Resource not available"/>
+ <enum name="osErrorParameter" value="-4" info="Parameter error"/>
+ <enum name="osErrorNoMemory" value="-5" info="System is out of memory: it was impossible to allocate or reserve memory for the operation"/>
+ <enum name="osErrorISR" value="-6" info="Not allowed in ISR context: the function cannot be called from interrupt service routines"/>
+ <enum name="osErrorSafetyClass" value="-7" info="Operation denied because of safety class violation"/>
+ <enum name="osRtxErrorKernelNotReady" value="-8" info="RTOS Kernel scheduler is not ready"/>
+ <enum name="osRtxErrorKernelNotRunning" value="-9" info="RTOS Kernel scheduler is not running"/>
+ <enum name="osRtxErrorInvalidControlBlock" value="-10" info="Object control block is not properly aligned or has an invalid size"/>
+ <enum name="osRtxErrorInvalidDataMemory" value="-11" info="Data memory is not is not properly aligned or has an invalid size"/>
+ <enum name="osRtxErrorInvalidThreadStack" value="-12" info="Thread stack is invalid"/>
+ <enum name="osRtxErrorInvalidPriority" value="-13" info="Thread priority is invalid"/>
+ <enum name="osRtxErrorInvalidPrivilegedMode" value="-14" info="Privileged thread cannot be created, kernel protect is active"/>
+ <enum name="osRtxErrorThreadNotJoinable" value="-15" info="Thread is not joinable"/>
+ <enum name="osRtxErrorMutexNotOwned" value="-16" info="Mutex is not owned by the current running thread"/>
+ <enum name="osRtxErrorMutexNotLocked" value="-17" info="Mutex is not locked"/>
+ <enum name="osRtxErrorMutexLockLimit" value="-18" info="Maximum number of recursive mutex locks reached"/>
+ <enum name="osRtxErrorSemaphoreCountLimit" value="-19" info="Semaphore count limit reached"/>
+ <enum name="osRtxErrorTZ_InitContext_S" value="-20" info=""/>
+ <enum name="osRtxErrorTZ_AllocContext_S" value="-21" info=""/>
+ <enum name="osRtxErrorTZ_FreeContext_S" value="-22" info=""/>
+ <enum name="osRtxErrorTZ_LoadContext_S" value="-23" info=""/>
+ <enum name="osRtxErrorTZ_SaveContext_S" value="-24" info=""/>
</member>
</typedef>
@@ -616,6 +634,7 @@
<enum name="osRtxErrorTimerQueueOverflow" value="3" info="User Timer Callback Queue overflow"/>
<enum name="osRtxErrorClibSpace" value="4" info="Standard C/C++ library libspace not available"/>
<enum name="osRtxErrorClibMutex" value="5" info="Standard C/C++ library mutex initialization failed"/>
+ <enum name="osRtxErrorSVC" value="6" info="Invalid SVC function called"/>
</member>
</typedef>
@@ -677,6 +696,12 @@
<calc>
os_Config.stack_check = (os_Config.flags >> 1) & 1;
os_Config.stack_wmark = (os_Config.flags >> 2) & 1;
+ os_Config.safety_feat = (os_Config.flags >> 3) & 1;
+ os_Config.safety_class = (os_Config.flags >> 4) & 1;
+ os_Config.exec_zone = (os_Config.flags >> 5) & 1;
+ os_Config.watchdog = (os_Config.flags >> 6) & 1;
+ os_Config.obj_check = (os_Config.flags >> 7) & 1;
+ os_Config.svc_check = (os_Config.flags >> 8) & 1;
</calc>
<calc cond="((os_Info.version / 10000000) == 5) && (os_Info.kernel_state > 0) && (os_Info.kernel_state < 5)">
@@ -711,7 +736,7 @@
</calc>
<!-- Determine number of control blocks to read -->
- <calc cond="TCB_Rd"> TCB_Rd /= 68; </calc>
+ <calc cond="TCB_Rd"> TCB_Rd /= 80; </calc>
<calc cond="CCB_Rd"> CCB_Rd /= 32; </calc>
<calc cond="ECB_Rd"> ECB_Rd /= 16; </calc>
<calc cond="MCB_Rd"> MCB_Rd /= 28; </calc>
@@ -823,6 +848,9 @@
<readlist cond="(mem_list_com[i].len & 1) && (mem_list_com[i].id == 0xFA)" name="QCB" type="osRtxMessageQueue_t" offset="addr" count="1" />
</list>
+ <!-- Read thread watchdog list -->
+ <readlist name="WDL" cond="RTX_En && os_Config.watchdog && os_Info.thread_wdog_list" type="osRtxThread_t" offset="os_Info.thread_wdog_list" next="wdog_next" init="1"/>
+
<!-- Validate and process Thread control blocks -->
<list name="i" start="0" limit="TCB._count">
<calc>
@@ -908,6 +936,26 @@
TCB[i].ex_delay += TDL[j].delay;
</calc>
</list>
+
+ <!-- Determine thread absolute watchdog tick value -->
+ <calc cond="os_Config.watchdog">
+ k = 0;
+ </calc>
+
+ <list cond="os_Config.watchdog" name="j" start="0" limit="WDL._count">
+ <calc cond="k == 0">
+ TCB[i].wd_tick += WDL[j].wdog_tick;
+ </calc>
+
+ <calc cond="TCB[i]._addr == WDL[j]._addr">
+ k = 1;
+ </calc>
+ </list>
+
+ <!-- Watchdog is running for a thread that was found in the watchdog list -->
+ <calc cond="os_Config.safety_feat">
+ TCB[i].wd_state = k;
+ </calc>
</list>
<!-- Validate and process Timer control blocks -->
@@ -1100,6 +1148,10 @@
<item property="Kernel ID" value="RTX V%d[V_Major].%d[V_Minor].%d[V_Patch]" cond="RTX_En != 0"/>
<item property="Kernel State" value="osKernelInactive" cond="RTX_En == 0"/>
<item property="Kernel State" value="%E[os_Info.kernel_state]" cond="RTX_En != 0"/>
+ <item>
+ <print property="Kernel Protect" value="osThreadPrivileged: %t[(os_Info.kernel_protect & 1) ? "Disabled" : "Enabled"]" cond="(os_Config.safety_feat == 1) && (os_Config.safety_class == 0) && (RTX_En != 0)" />
+ <print property="Kernel Protect" value="osThreadPrivileged: %t[(os_Info.kernel_protect & 1) ? "Disabled" : "Enabled"], osSafetyClass(%d[os_Info.kernel_protect/16])" cond="(os_Config.safety_feat == 1) && (os_Config.safety_class == 1) && (RTX_En != 0)" />
+ </item>
<item property="Kernel Tick Count" value="%d[os_Info.kernel_tick]" cond="RTX_En != 0"/>
<item property="Kernel Tick Frequency" value="%d[os_Config.tick_freq]" cond="RTX_En != 0" />
<item property="Round Robin" value="Disabled" cond="(os_Config.robin_timeout == 0) && (RTX_En != 0)" />
@@ -1172,7 +1224,12 @@
<item property="State" value="%E[TCB[i].state & 0x07]"/>
<item property="Priority" value="%E[TCB[i].priority]"/>
- <item property="Attributes" value="%E[TCB[i].attr & 0x01]"/>
+ <item>
+ <print cond="(os_Config.exec_zone == 0) && (os_Config.safety_class == 0)" property="Attributes" value="%E[TCB[i].attr & 0x01], %E[TCB[i].attr & 0x06]"/>
+ <print cond="(os_Config.exec_zone == 0) && (os_Config.safety_class == 1)" property="Attributes" value="%E[TCB[i].attr & 0x01], %E[TCB[i].attr & 0x06], osSafetyClass(%d[TCB[i].attr/16])"/>
+ <print cond="(os_Config.exec_zone == 1) && (os_Config.safety_class == 0)" property="Attributes" value="%E[TCB[i].attr & 0x01], %E[TCB[i].attr & 0x06], osThreadZone(%d[TCB[i].zone])"/>
+ <print cond="(os_Config.exec_zone == 1) && (os_Config.safety_class == 1)" property="Attributes" value="%E[TCB[i].attr & 0x01], %E[TCB[i].attr & 0x06], osSafetyClass(%d[TCB[i].attr/16]), osThreadZone(%d[TCB[i].zone])"/>
+ </item>
<item>
<print property="Waiting" value="%E[TCB[i].state], Timeout: %d[TCB[i].ex_delay]" cond="((TCB[i].state & 0x07) == 3) && (TCB[i].ex_delay != -1)"/>
@@ -1231,6 +1288,10 @@
<item property="Stack Overrun" value="Overrun detected" cond="TCB[i].stack_over != 0"/>
<item property="Flags" value="%x[TCB[i].thread_flags]"/>
+ <item>
+ <print cond="(os_Config.watchdog != 0) && (TCB[i].wd_state == 0)" property="Watchdog" value="Inactive"/>
+ <print cond="(os_Config.watchdog != 0) && (TCB[i].wd_state == 1)" property="Watchdog" value="Running, Timeout: %d[TCB[i].wd_tick]"/>
+ </item>
<item property="Wait Flags" value="%x[TCB[i].wait_flags], %E[TCB[i].flags_options & 1]" cond="(TCB[i].wait_flags != 0) && ((TCB[i].flags_options & 2) == 0)"/>
<item property="Wait Flags" value="%x[TCB[i].wait_flags], %E[TCB[i].flags_options & 1], osFlagsNoClear" cond="(TCB[i].wait_flags != 0) && ((TCB[i].flags_options & 2) != 0)"/>
<item property="TrustZone ID" value="%d[TCB[i].tz_memory]" cond="TCB[i].tz_memory"/>
@@ -1242,11 +1303,12 @@
<item cond="CCB_En" property="Timers" value="">
<list name="i" start="0" limit="CCB._count">
<item cond="CCB[i].cb_valid" property="id: %x[CCB[i]._addr] %N[CCB[i].name]" value="%E[CCB[i].state], Tick: %d[CCB[i].ex_tick]">
- <item property="State" value="%E[CCB[i].state]" />
- <item property="Type" value="%E[CCB[i].type]" />
- <item property="Tick" value="%d[CCB[i].ex_tick]" />
- <item property="Load" value="%d[CCB[i].load]" />
- <item property="Callback" value="Func: %S[CCB[i].finfo_fp], Arg: %x[CCB[i].finfo_arg]" />
+ <item property="State" value="%E[CCB[i].state]" />
+ <item property="Type" value="%E[CCB[i].attr & 0x01]" />
+ <item property="Attributes" value="osSafetyClass(%d[CCB[i].attr/16])" cond="os_Config.safety_class == 1"/>
+ <item property="Tick" value="%d[CCB[i].ex_tick]" />
+ <item property="Load" value="%d[CCB[i].load]" />
+ <item property="Callback" value="Func: %S[CCB[i].finfo_fp], Arg: %x[CCB[i].finfo_arg]" />
</item>
</list>
</item>
@@ -1255,6 +1317,7 @@
<item cond="SCB_En" property="Semaphores" value="">
<list name="i" start="0" limit="SCB._count">
<item cond="SCB[i].cb_valid" property="id: %x[SCB[i]._addr] %N[SCB[i].name]" value="Tokens: %d[SCB[i].tokens], Max: %d[SCB[i].max_tokens]">
+ <item property="Attributes" value="osSafetyClass(%d[SCB[i].attr/16])" cond="os_Config.safety_class == 1"/>
<item property="Tokens" value="%d[SCB[i].tokens]" />
<item property="Max Tokens" value="%d[SCB[i].max_tokens]" />
@@ -1278,7 +1341,7 @@
<list name="i" start="0" limit="MCB._count">
<item cond="MCB[i].cb_valid" property="id: %x[MCB[i]._addr] %N[MCB[i].name]" value="Lock counter: %d[MCB[i].lock]">
<item property="Lock counter" value="%x[MCB[i].lock]"/>
- <item property="Attributes" value="%x[MCB[i].attr]">
+ <item property="Attributes" value="osSafetyClass(%d[MCB[i].attr/16])" cond="os_Config.safety_class == 1">
<item property="osMutexRecursive" value="%t[(MCB[i].attr & 0x01) ? "True" : "False"]" />
<item property="osMutexPrioInherit" value="%t[(MCB[i].attr & 0x02) ? "True" : "False"]" />
<item property="osMutexRobust" value="%t[(MCB[i].attr & 0x08) ? "True" : "False"]" />
@@ -1307,6 +1370,7 @@
<item cond="ECB_En" property="Event Flags" value="">
<list name="i" start="0" limit="ECB._count">
<item cond="ECB[i].cb_valid" property="id: %x[ECB[i]._addr] %N[ECB[i].name]" value="Flags: %x[ECB[i].event_flags]">
+ <item property="Attributes" value="osSafetyClass(%d[ECB[i].attr/16])" cond="os_Config.safety_class == 1"/>
<!-- Waiting thread list -->
<item cond="ECB[i].wl_cnt" property="Threads waiting (%d[ECB[i].wl_cnt])" value="">
@@ -1328,6 +1392,7 @@
<list name="i" start="0" limit="PCB._count">
<item cond="PCB[i].cb_valid" property="id: %x[PCB[i]._addr] %N[PCB[i].name]" value="Used: %d[PCB[i].used_blocks], Max: %d[PCB[i].max_blocks]">
+ <item property="Attributes" value="osSafetyClass(%d[PCB[i].attr/16])" cond="os_Config.safety_class == 1"/>
<item property="Used blocks" value="%d[PCB[i].used_blocks]"/>
<item property="Max blocks" value="%d[PCB[i].max_blocks]"/>
<item property="Block size" value="%d[PCB[i].block_size]"/>
@@ -1354,6 +1419,7 @@
<list name="i" start="0" limit="QCB._count">
<item cond="QCB[i].cb_valid" property="id: %x[QCB[i]._addr] %N[QCB[i].name]" value="Messages: %d[QCB[i].msg_count], Max: %d[QCB[i].max_blocks]">
+ <item property="Attributes" value="osSafetyClass(%d[QCB[i].attr/16])" cond="os_Config.safety_class == 1"/>
<item property="Messages" value="%d[QCB[i].ml_cnt]"/>
<item property="Max Messages" value="%d[QCB[i].max_blocks]"/>
<item property="Message size" value="%d[QCB[i].msg_size]"/>
@@ -1439,17 +1505,22 @@
<event id="0xF100 + 0x10" level="Op" property="KernelSuspended" value="sleep_ticks=%d[val1]" info="Kernel execution was suspended."/>
<event id="0xF100 + 0x11" level="API" property="KernelResume" value="sleep_ticks=%d[val1]" info="osKernelResume function was called."/>
<event id="0xF100 + 0x12" level="Op" property="KernelResumed" value="" info="Kernel execution was resumed."/>
+ <event id="0xF100 + 0x17" level="API" property="KernelProtect" value="safety_class=%d[val1]" info="osKernelProtect function was called."/>
+ <event id="0xF100 + 0x18" level="Op" property="KernelProtected" value="" info="Kernel safety class protection was activated."/>
<event id="0xF100 + 0x13" level="API" property="KernelGetTickCount" value="count=%d[val1]" info="osKernelGetTickCount function was called."/>
<event id="0xF100 + 0x14" level="API" property="KernelGetTickFreq" value="freq=%d[val1]" info="osKernelGetTickFreq function was called."/>
<event id="0xF100 + 0x15" level="API" property="KernelGetSysTimerCount" value="count=%d[val1]" info="osKernelGetSysTimerCount function was called."/>
<event id="0xF100 + 0x16" level="API" property="KernelGetSysTimerFreq" value="freq=%d[val1]" info="osKernelGetSysTimerFreq function was called."/>
<event id="0xF100 + 0x19" level="Error" property="KernelErrorNotify" value="code=%E[val1, rtx_error:id], object_id=%x[val2]" info="osKernelErrorNotify function was called."/>
+ <event id="0xF100 + 0x1A" level="API" property="KernelDestroyClass" value="safety_class=%d[val1], mode=%x[val2]" info="osKernelDestroyClass function was called."/>
<event id="0xF200 + 0x00" level="Error" property="ThreadError" value="thread_id=%x[val1], status=%E[val2, rtx_t:status]" info="Thread error occurred."/>
<event id="0xF200 + 0x01" level="API" property="ThreadNew" value="func=%S[val1], argument=%x[val2], attr=%x[val3]" info="osThreadNew function was called."/>
<event id="0xF200 + 0x03" level="Op" property="ThreadCreated" tracking="Start" state="Ready" handle="val1" hname="%S[val2]" value="thread_id=%x[val1]" info="Thread object was created."/>
<event id="0xF200 + 0x2C" level="Op" property="ThreadCreated" tracking="Start" state="Ready" handle="val1" hname="%N[val2]" value="thread_id=%x[val1]" info="Thread object was created."/>
<event id="0xF200 + 0x04" level="API" property="ThreadGetName" value="thread_id=%x[val1], name=%N[val2]" info="osThreadGetName function was called and object name was retrieved."/>
+ <event id="0xF200 + 0x30" level="API" property="ThreadGetClass" value="thread_id=%x[val1], safety_class=%d[val2]" info="osThreadGetClass function was called and thread safety class was retrieved."/>
+ <event id="0xF200 + 0x31" level="API" property="ThreadGetZone" value="thread_id=%x[val1], zone=%d[val2]" info="osThreadGetZone function was called and thread execution zone was retrieved."/>
<event id="0xF200 + 0x06" level="API" property="ThreadGetId" value="thread_id=%x[val1]" info="osThreadGetId function was called and current running thread id was retrieved."/>
<event id="0xF200 + 0x07" level="API" property="ThreadGetState" value="thread_id=%x[val1], state=%E[val2, rtx_th_state:id]" info="osThreadGetState function was called and thread state was retrieved."/>
<event id="0xF200 + 0x08" level="API" property="ThreadGetStackSize" value="thread_id=%x[val1], stack_size=%d[val2]" info="osThreadGetStackSize function was called and thread stack size was retrieved."/>
@@ -1474,8 +1545,16 @@
<event id="0xF200 + 0x1A" level="API" property="ThreadExit" value="" info="osThreadExit function was called."/>
<event id="0xF200 + 0x1B" level="API" property="ThreadTerminate" value="thread_id=%x[val1]" info="osThreadTerminate function was called."/>
<event id="0xF200 + 0x1C" level="Op" property="ThreadDestroyed" tracking="Stop" state="Inactive" handle="val1" value="thread_id=%x[val1]" info="Thread execution was terminated."/>
+ <event id="0xF200 + 0x2E" level="API" property="ThreadFeedWatchdog" value="ticks=%d[val1]" info="osThreadFeedWatchdog function was called."/>
+ <event id="0xF200 + 0x2F" level="Op" property="ThreadFeedWatchdogDone" value="" info="Thread watchdog timer was feed."/>
+ <event id="0xF200 + 0x32" level="API" property="ThreadProtectPrivileged" value="" info="osThreadProtectPrivileged function was called."/>
+ <event id="0xF200 + 0x33" level="Op" property="ThreadPrivilegedProtected" value="" info="Creation of privileged threads was protected."/>
<event id="0xF200 + 0x1D" level="API" property="ThreadGetCount" value="count=%d[val1]" info="osThreadGetCount function was called and number of active threads was retrieved."/>
<event id="0xF200 + 0x1E" level="API" property="ThreadEnumerate" value="thread_array=%x[val1], array_items=%d[val2], count=%d[val3]" info="osThreadEnumerate function was called and active threads were enumerated."/>
+ <event id="0xF200 + 0x34" level="API" property="ThreadSuspendClass" value="safety_class=%d[val1], mode=%x[val2]" info="osThreadSuspendClass function was called."/>
+ <event id="0xF200 + 0x35" level="API" property="ThreadResumeClass" value="safety_class=%d[val1], mode=%x[val2]" info="osThreadResumeClass function was called."/>
+ <event id="0xF200 + 0x36" level="API" property="ThreadTerminateZone" value="zone=%d[val1]" info="osThreadTerminateZone function was called."/>
+ <event id="0xF200 + 0x37" level="Error" property="ThreadWatchdogExpired" value="thread_id=%x[val1]" info="Thread watchdog timer has expired."/>
<event id="0xF400 + 0x00" level="Error" property="ThreadFlagsError" value="thread_id=%x[val1], status=%E[val2, rtx_t:status]" info="Thread flags error occurred."/>
<event id="0xF400 + 0x01" level="API" property="ThreadFlagsSet" value="thread_id=%x[val1], flags=%x[val2]" info="osThreadFlagsSet function was called."/>
diff --git a/CMSIS/RTOS2/RTX/Source/ARM/irq_armv6m.s b/CMSIS/RTOS2/RTX/Source/ARM/irq_armv6m.s
index 7900d8d..6ad99aa 100644
--- a/CMSIS/RTOS2/RTX/Source/ARM/irq_armv6m.s
+++ b/CMSIS/RTOS2/RTX/Source/ARM/irq_armv6m.s
@@ -1,5 +1,5 @@
;/*
-; * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+; * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
@@ -24,15 +24,13 @@
; */
- IF :LNOT::DEF:RTX_STACK_CHECK
-RTX_STACK_CHECK EQU 0
- ENDIF
-
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
TCB_SP_OFS EQU 56 ; TCB.SP offset
+TCB_ZONE_OFS EQU 68 ; TCB.zone offset
osRtxErrorStackOverflow\
EQU 1 ; Stack overflow
+osRtxErrorSVC EQU 6 ; Invalid SVC function called
PRESERVE8
@@ -51,10 +49,18 @@
EXPORT SVC_Handler
IMPORT osRtxUserSVC
IMPORT osRtxInfo
- IF RTX_STACK_CHECK != 0
+ IF :DEF:RTX_STACK_CHECK
IMPORT osRtxThreadStackCheck
IMPORT osRtxKernelErrorNotify
ENDIF
+ IF :DEF:RTX_SVC_PTR_CHECK
+ IMPORT |Image$$RTX_SVC_VENEERS$$Base|
+ IMPORT |Image$$RTX_SVC_VENEERS$$Length|
+ IMPORT osRtxKernelErrorNotify
+ ENDIF
+ IF :DEF:RTX_EXECUTION_ZONE
+ IMPORT osZoneSetup_Callback
+ ENDIF
MOV R0,LR
LSRS R0,R0,#3 ; Determine return stack from EXC_RETURN bit 2
@@ -68,6 +74,30 @@
CMP R1,#0 ; Check SVC number
BNE SVC_User ; Branch if not SVC 0
+ IF :DEF:RTX_SVC_PTR_CHECK
+
+ SUBS R1,R7,#0x01 ; Clear T-bit of function address
+ LSLS R2,R1,#29 ; Check if 8-byte aligned
+ BEQ SVC_PtrBoundsCheck ; Branch if address is aligned
+
+SVC_PtrInvalid
+ PUSH {R0,LR} ; Save SP and EXC_RETURN
+ MOVS R0,#osRtxErrorSVC ; Parameter: code
+ MOV R1,R7 ; Parameter: object_id
+ BL osRtxKernelErrorNotify ; Call osRtxKernelErrorNotify
+ POP {R2,R3} ; Restore SP and EXC_RETURN
+ MOV LR,R3 ; Set EXC_RETURN
+ B SVC_Context ; Branch to context handling
+
+SVC_PtrBoundsCheck
+ LDR R2,=|Image$$RTX_SVC_VENEERS$$Base|
+ LDR R3,=|Image$$RTX_SVC_VENEERS$$Length|
+ SUBS R2,R1,R2 ; Subtract SVC table base address
+ CMP R2,R3 ; Compare with SVC table boundaries
+ BHS SVC_PtrInvalid ; Branch if address is out of bounds
+
+ ENDIF
+
PUSH {R0,LR} ; Save SP and EXC_RETURN
LDMIA R0,{R0-R3} ; Load function parameters from stack
BLX R7 ; Call service function
@@ -91,7 +121,7 @@
SUBS R0,R0,#32 ; Calculate SP: space for R4..R11
STR R0,[R1,#TCB_SP_OFS] ; Store SP
- IF RTX_STACK_CHECK != 0
+ IF :DEF:RTX_STACK_CHECK
PUSH {R1,R2} ; Save osRtxInfo.thread.run: curr & next
MOV R0,R1 ; Parameter: osRtxInfo.thread.run.curr
@@ -105,6 +135,7 @@
LDR R3,=osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.thread.run
LDR R2,[R3,#4] ; Load osRtxInfo.thread.run: next
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
+ MOVS R1,#0 ; Simulate deleted running thread
B SVC_ContextRestore ; Branch to context restore handling
SVC_ContextSaveRegs
@@ -120,7 +151,22 @@
STMIA R0!,{R4-R7} ; Save R8..R11
SVC_ContextRestore
- LDR R0,[R2,#TCB_SP_OFS] ; Load SP
+ MOVS R4,R2 ; Assign osRtxInfo.thread.run.next to R4
+ IF :DEF:RTX_EXECUTION_ZONE
+ MOVS R3,#TCB_ZONE_OFS ; Get TCB.zone offset
+ LDRB R0,[R2,R3] ; Load osRtxInfo.thread.run.next: zone
+ CMP R1,#0
+ BEQ SVC_ZoneSetup ; Branch if running thread is deleted
+ LDRB R1,[R1,R3] ; Load osRtxInfo.thread.run.curr: zone
+ CMP R0,R1 ; Check if next:zone == curr:zone
+ BEQ SVC_ContextRestore_N ; Branch if zone has not changed
+
+SVC_ZoneSetup
+ BL osZoneSetup_Callback ; Setup zone for next thread
+ ENDIF
+
+SVC_ContextRestore_N
+ LDR R0,[R4,#TCB_SP_OFS] ; Load SP
ADDS R0,R0,#16 ; Adjust address
LDMIA R0!,{R4-R7} ; Restore R8..R11
MOV R8,R4
@@ -192,4 +238,17 @@
ENDP
+ IF :DEF:RTX_SAFETY_FEATURES
+
+osFaultResume PROC
+ EXPORT osFaultResume
+
+ B SVC_Context ; Branch to context handling
+
+ ALIGN
+ ENDP
+
+ ENDIF
+
+
END
diff --git a/CMSIS/RTOS2/RTX/Source/ARM/irq_armv7m.s b/CMSIS/RTOS2/RTX/Source/ARM/irq_armv7m.s
index c47e2d5..f484efd 100644
--- a/CMSIS/RTOS2/RTX/Source/ARM/irq_armv7m.s
+++ b/CMSIS/RTOS2/RTX/Source/ARM/irq_armv7m.s
@@ -1,5 +1,5 @@
;/*
-; * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+; * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
@@ -24,10 +24,6 @@
; */
- IF :LNOT::DEF:RTX_STACK_CHECK
-RTX_STACK_CHECK EQU 0
- ENDIF
-
IF ({FPU}="FPv4-SP") || ({FPU}="VFPv4_D16") || ({FPU}="VFPv4_SP_D16") || ({FPU}="FPv5-SP") || ({FPU}="FPv5_D16")
FPU_USED EQU 1
ELSE
@@ -37,11 +33,13 @@
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
TCB_SP_OFS EQU 56 ; TCB.SP offset
TCB_SF_OFS EQU 34 ; TCB.stack_frame offset
+TCB_ZONE_OFS EQU 68 ; TCB.zone offset
FPCCR EQU 0xE000EF34 ; FPCCR Address
osRtxErrorStackOverflow\
EQU 1 ; Stack overflow
+osRtxErrorSVC EQU 6 ; Invalid SVC function called
PRESERVE8
@@ -60,10 +58,18 @@
EXPORT SVC_Handler
IMPORT osRtxUserSVC
IMPORT osRtxInfo
- IF RTX_STACK_CHECK != 0
+ IF :DEF:RTX_STACK_CHECK
IMPORT osRtxThreadStackCheck
IMPORT osRtxKernelErrorNotify
ENDIF
+ IF :DEF:RTX_SVC_PTR_CHECK
+ IMPORT |Image$$RTX_SVC_VENEERS$$Base|
+ IMPORT |Image$$RTX_SVC_VENEERS$$Length|
+ IMPORT osRtxKernelErrorNotify
+ ENDIF
+ IF :DEF:RTX_EXECUTION_ZONE
+ IMPORT osZoneSetup_Callback
+ ENDIF
TST LR,#0x04 ; Determine return stack from EXC_RETURN bit 2
ITE EQ
@@ -75,6 +81,30 @@
CMP R1,#0 ; Check SVC number
BNE SVC_User ; Branch if not SVC 0
+ IF :DEF:RTX_SVC_PTR_CHECK
+
+ LDR R12,[R0,#16] ; Load function address from stack
+ SUB R1,R12,#1 ; Clear T-bit of function address
+ LSLS R2,R1,#30 ; Check if 4-byte aligned
+ BEQ SVC_PtrBoundsCheck ; Branch if address is aligned
+
+SVC_PtrInvalid
+ PUSH {R0,LR} ; Save SP and EXC_RETURN
+ MOV R0,#osRtxErrorSVC ; Parameter: code
+ MOV R1,R12 ; Parameter: object_id
+ BL osRtxKernelErrorNotify ; Call osRtxKernelErrorNotify
+ POP {R12,LR} ; Restore SP and EXC_RETURN
+ B SVC_Context ; Branch to context handling
+
+SVC_PtrBoundsCheck
+ LDR R2,=|Image$$RTX_SVC_VENEERS$$Base|
+ LDR R3,=|Image$$RTX_SVC_VENEERS$$Length|
+ SUB R2,R1,R2 ; Subtract SVC table base address
+ CMP R2,R3 ; Compare with SVC table boundaries
+ BHS SVC_PtrInvalid ; Branch if address is out of bounds
+
+ ENDIF
+
PUSH {R0,LR} ; Save SP and EXC_RETURN
LDM R0,{R0-R3,R12} ; Load function parameters and address from stack
BLX R12 ; Call service function
@@ -105,7 +135,7 @@
ENDIF
SVC_ContextSave
- IF RTX_STACK_CHECK != 0
+ IF :DEF:RTX_STACK_CHECK
SUB R12,R12,#32 ; Calculate SP: space for R4..R11
IF FPU_USED != 0
TST LR,#0x10 ; Determine stack frame from EXC_RETURN bit 4
@@ -122,13 +152,14 @@
CBNZ R0,SVC_ContextSaveRegs ; Branch when stack check is ok
IF FPU_USED != 0
- MOV R4,R1 ; Save osRtxInfo.thread.run.curr
+ MOV R4,R1 ; Assign osRtxInfo.thread.run.curr to R4
ENDIF
MOV R0,#osRtxErrorStackOverflow ; Parameter: r0=code, r1=object_id
BL osRtxKernelErrorNotify ; Call osRtxKernelErrorNotify
LDR R3,=osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.thread.run
LDR R2,[R3,#4] ; Load osRtxInfo.thread.run: next
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
+ MOVS R1,#0 ; Simulate deleted running thread
IF FPU_USED != 0
LDRB LR,[R4,#TCB_SF_OFS] ; Load stack frame information
B SVC_FP_LazyState ; Branch to FP lazy state handling
@@ -157,9 +188,21 @@
ENDIF
SVC_ContextRestore
- LDR R0,[R2,#TCB_SP_OFS] ; Load SP
+ MOVS R4,R2 ; Assign osRtxInfo.thread.run.next to R4, clear Z flag
+ IF :DEF:RTX_EXECUTION_ZONE
+ LDRB R0,[R2,#TCB_ZONE_OFS] ; Load osRtxInfo.thread.run.next: zone
+ CBZ R1,SVC_ZoneSetup ; Branch if running thread is deleted (Z flag unchanged)
+ LDRB R1,[R1,#TCB_ZONE_OFS] ; Load osRtxInfo.thread.run.curr: zone
+ CMP R0,R1 ; Check if next:zone == curr:zone
+
+SVC_ZoneSetup
+ IT NE ; If zone has changed or running thread is deleted
+ BLNE osZoneSetup_Callback ; Setup zone for next thread
+ ENDIF
+
+ LDR R0,[R4,#TCB_SP_OFS] ; Load SP
IF FPU_USED != 0
- LDRB R1,[R2,#TCB_SF_OFS] ; Load stack frame information
+ LDRB R1,[R4,#TCB_SF_OFS] ; Load stack frame information
ORN LR,R1,#0xFF ; Set EXC_RETURN
TST LR,#0x10 ; Determine stack frame from EXC_RETURN bit 4
IT EQ ; If extended stack frame
@@ -220,4 +263,18 @@
ENDP
+ IF :DEF:RTX_SAFETY_FEATURES
+
+osFaultResume PROC
+ EXPORT osFaultResume
+
+ MRS R12,PSP ; Save PSP to R12
+ B SVC_Context ; Branch to context handling
+
+ ALIGN
+ ENDP
+
+ ENDIF
+
+
END
diff --git a/CMSIS/RTOS2/RTX/Source/ARM/irq_armv8mbl.s b/CMSIS/RTOS2/RTX/Source/ARM/irq_armv8mbl.s
index 55d29d3..132ea37 100644
--- a/CMSIS/RTOS2/RTX/Source/ARM/irq_armv8mbl.s
+++ b/CMSIS/RTOS2/RTX/Source/ARM/irq_armv8mbl.s
@@ -1,5 +1,5 @@
;/*
-; * Copyright (c) 2016-2021 Arm Limited. All rights reserved.
+; * Copyright (c) 2016-2023 Arm Limited. All rights reserved.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
@@ -24,10 +24,6 @@
; */
- IF :LNOT::DEF:RTX_STACK_CHECK
-RTX_STACK_CHECK EQU 0
- ENDIF
-
IF :LNOT::DEF:DOMAIN_NS
DOMAIN_NS EQU 0
ENDIF
@@ -37,9 +33,11 @@
TCB_SP_OFS EQU 56 ; TCB.SP offset
TCB_SF_OFS EQU 34 ; TCB.stack_frame offset
TCB_TZM_OFS EQU 64 ; TCB.tz_memory offset
+TCB_ZONE_OFS EQU 68 ; TCB.zone offset
osRtxErrorStackOverflow\
EQU 1 ; Stack overflow
+osRtxErrorSVC EQU 6 ; Invalid SVC function called
PRESERVE8
@@ -58,10 +56,18 @@
EXPORT SVC_Handler
IMPORT osRtxUserSVC
IMPORT osRtxInfo
- IF RTX_STACK_CHECK != 0
+ IF :DEF:RTX_STACK_CHECK
IMPORT osRtxThreadStackCheck
IMPORT osRtxKernelErrorNotify
ENDIF
+ IF :DEF:RTX_SVC_PTR_CHECK
+ IMPORT |Image$$RTX_SVC_VENEERS$$Base|
+ IMPORT |Image$$RTX_SVC_VENEERS$$Length|
+ IMPORT osRtxKernelErrorNotify
+ ENDIF
+ IF :DEF:RTX_EXECUTION_ZONE
+ IMPORT osZoneSetup_Callback
+ ENDIF
IF DOMAIN_NS != 0
IMPORT TZ_LoadContext_S
IMPORT TZ_StoreContext_S
@@ -79,6 +85,30 @@
CMP R1,#0 ; Check SVC number
BNE SVC_User ; Branch if not SVC 0
+ IF :DEF:RTX_SVC_PTR_CHECK
+
+ SUBS R1,R7,#0x01 ; Clear T-bit of function address
+ LSLS R2,R1,#29 ; Check if 8-byte aligned
+ BEQ SVC_PtrBoundsCheck ; Branch if address is aligned
+
+SVC_PtrInvalid
+ PUSH {R0,LR} ; Save SP and EXC_RETURN
+ MOVS R0,#osRtxErrorSVC ; Parameter: code
+ MOV R1,R7 ; Parameter: object_id
+ BL osRtxKernelErrorNotify ; Call osRtxKernelErrorNotify
+ POP {R2,R3} ; Restore SP and EXC_RETURN
+ MOV LR,R3 ; Set EXC_RETURN
+ B SVC_Context ; Branch to context handling
+
+SVC_PtrBoundsCheck
+ LDR R2,=|Image$$RTX_SVC_VENEERS$$Base|
+ LDR R3,=|Image$$RTX_SVC_VENEERS$$Length|
+ SUBS R2,R1,R2 ; Subtract SVC table base address
+ CMP R2,R3 ; Compare with SVC table boundaries
+ BHS SVC_PtrInvalid ; Branch if address is out of bounds
+
+ ENDIF
+
PUSH {R0,LR} ; Save SP and EXC_RETURN
LDMIA R0,{R0-R3} ; Load function parameters from stack
BLX R7 ; Call service function
@@ -115,7 +145,7 @@
BMI SVC_ContextSaveSP ; Branch if secure
ENDIF
- IF RTX_STACK_CHECK != 0
+ IF :DEF:RTX_STACK_CHECK
SUBS R0,R0,#32 ; Calculate SP: space for R4..R11
SVC_ContextSaveSP
@@ -137,6 +167,7 @@
LDR R3,=osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.thread.run
LDR R2,[R3,#4] ; Load osRtxInfo.thread.run: next
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
+ MOVS R1,#0 ; Simulate deleted running thread
B SVC_ContextRestore ; Branch to context restore handling
SVC_ContextSaveRegs
@@ -171,25 +202,37 @@
ENDIF
SVC_ContextRestore
+ MOVS R4,R2 ; Assign osRtxInfo.thread.run.next to R4
+ IF :DEF:RTX_EXECUTION_ZONE
+ MOVS R3,#TCB_ZONE_OFS ; Get TCB.zone offset
+ LDRB R0,[R2,R3] ; Load osRtxInfo.thread.run.next: zone
+ CBZ R1,SVC_ZoneSetup ; Branch if running thread is deleted
+ LDRB R1,[R1,R3] ; Load osRtxInfo.thread.run.curr: zone
+ CMP R0,R1 ; Check if next:zone == curr:zone
+ BEQ SVC_ContextRestore_S ; Branch if zone has not changed
+
+SVC_ZoneSetup
+ BL osZoneSetup_Callback ; Setup zone for next thread
+ ENDIF
+
+SVC_ContextRestore_S
IF DOMAIN_NS != 0
- LDR R0,[R2,#TCB_TZM_OFS] ; Load TrustZone memory identifier
+ LDR R0,[R4,#TCB_TZM_OFS] ; Load TrustZone memory identifier
CBZ R0,SVC_ContextRestore_NS ; Branch if there is no secure context
- PUSH {R2,R3} ; Save registers
BL TZ_LoadContext_S ; Load secure context
- POP {R2,R3} ; Restore registers
ENDIF
SVC_ContextRestore_NS
- LDR R0,[R2,#TCB_SM_OFS] ; Load stack memory base
+ LDR R0,[R4,#TCB_SM_OFS] ; Load stack memory base
MSR PSPLIM,R0 ; Set PSPLIM
- MOV R0,R2 ; osRtxInfo.thread.run.next
+ MOV R0,R4 ; osRtxInfo.thread.run.next
ADDS R0,R0,#TCB_SF_OFS ; Adjust address
LDRB R3,[R0] ; Load stack frame information
MOVS R0,#0xFF
MVNS R0,R0 ; R0=0xFFFFFF00
ORRS R3,R3,R0
MOV LR,R3 ; Set EXC_RETURN
- LDR R0,[R2,#TCB_SP_OFS] ; Load SP
+ LDR R0,[R4,#TCB_SP_OFS] ; Load SP
IF DOMAIN_NS != 0
LSLS R3,R3,#25 ; Check domain of interrupted thread
BMI SVC_ContextRestoreSP ; Branch if secure
@@ -265,4 +308,17 @@
ENDP
+ IF :DEF:RTX_SAFETY_FEATURES
+
+osFaultResume PROC
+ EXPORT osFaultResume
+
+ B SVC_Context ; Branch to context handling
+
+ ALIGN
+ ENDP
+
+ ENDIF
+
+
END
diff --git a/CMSIS/RTOS2/RTX/Source/ARM/irq_armv8mml.s b/CMSIS/RTOS2/RTX/Source/ARM/irq_armv8mml.s
index 318fa4a..e3c9807 100644
--- a/CMSIS/RTOS2/RTX/Source/ARM/irq_armv8mml.s
+++ b/CMSIS/RTOS2/RTX/Source/ARM/irq_armv8mml.s
@@ -1,5 +1,5 @@
;/*
-; * Copyright (c) 2016-2021 Arm Limited. All rights reserved.
+; * Copyright (c) 2016-2023 Arm Limited. All rights reserved.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
@@ -24,15 +24,11 @@
; */
- IF :LNOT::DEF:RTX_STACK_CHECK
-RTX_STACK_CHECK EQU 0
- ENDIF
-
IF :LNOT::DEF:DOMAIN_NS
DOMAIN_NS EQU 0
ENDIF
- IF ({FPU}="FPv5-SP") || ({FPU}="FPv5_D16")
+ IF ({FPU}="FPv4-SP") || ({FPU}="VFPv4_D16") || ({FPU}="VFPv4_SP_D16") || ({FPU}="FPv5-SP") || ({FPU}="FPv5_D16")
FPU_USED EQU 1
ELSE
FPU_USED EQU 0
@@ -43,11 +39,13 @@
TCB_SP_OFS EQU 56 ; TCB.SP offset
TCB_SF_OFS EQU 34 ; TCB.stack_frame offset
TCB_TZM_OFS EQU 64 ; TCB.tz_memory offset
+TCB_ZONE_OFS EQU 68 ; TCB.zone offset
FPCCR EQU 0xE000EF34 ; FPCCR Address
osRtxErrorStackOverflow\
EQU 1 ; Stack overflow
+osRtxErrorSVC EQU 6 ; Invalid SVC function called
PRESERVE8
@@ -66,10 +64,18 @@
EXPORT SVC_Handler
IMPORT osRtxUserSVC
IMPORT osRtxInfo
- IF RTX_STACK_CHECK != 0
+ IF :DEF:RTX_STACK_CHECK
IMPORT osRtxThreadStackCheck
IMPORT osRtxKernelErrorNotify
ENDIF
+ IF :DEF:RTX_SVC_PTR_CHECK
+ IMPORT |Image$$RTX_SVC_VENEERS$$Base|
+ IMPORT |Image$$RTX_SVC_VENEERS$$Length|
+ IMPORT osRtxKernelErrorNotify
+ ENDIF
+ IF :DEF:RTX_EXECUTION_ZONE
+ IMPORT osZoneSetup_Callback
+ ENDIF
IF DOMAIN_NS != 0
IMPORT TZ_LoadContext_S
IMPORT TZ_StoreContext_S
@@ -85,6 +91,30 @@
CMP R1,#0 ; Check SVC number
BNE SVC_User ; Branch if not SVC 0
+ IF :DEF:RTX_SVC_PTR_CHECK
+
+ LDR R12,[R0,#16] ; Load function address from stack
+ SUB R1,R12,#1 ; Clear T-bit of function address
+ LSLS R2,R1,#30 ; Check if 4-byte aligned
+ BEQ SVC_PtrBoundsCheck ; Branch if address is aligned
+
+SVC_PtrInvalid
+ PUSH {R0,LR} ; Save SP and EXC_RETURN
+ MOV R0,#osRtxErrorSVC ; Parameter: code
+ MOV R1,R12 ; Parameter: object_id
+ BL osRtxKernelErrorNotify ; Call osRtxKernelErrorNotify
+ POP {R12,LR} ; Restore SP and EXC_RETURN
+ B SVC_Context ; Branch to context handling
+
+SVC_PtrBoundsCheck
+ LDR R2,=|Image$$RTX_SVC_VENEERS$$Base|
+ LDR R3,=|Image$$RTX_SVC_VENEERS$$Length|
+ SUB R2,R1,R2 ; Subtract SVC table base address
+ CMP R2,R3 ; Compare with SVC table boundaries
+ BHS SVC_PtrInvalid ; Branch if address is out of bounds
+
+ ENDIF
+
PUSH {R0,LR} ; Save SP and EXC_RETURN
LDM R0,{R0-R3,R12} ; Load function parameters and address from stack
BLX R12 ; Call service function
@@ -129,7 +159,7 @@
BNE SVC_ContextSaveSP ; Branch if secure
ENDIF
- IF RTX_STACK_CHECK != 0
+ IF :DEF:RTX_STACK_CHECK
SUB R12,R12,#32 ; Calculate SP: space for R4..R11
IF FPU_USED != 0
TST LR,#0x10 ; Determine stack frame from EXC_RETURN bit 4
@@ -148,13 +178,14 @@
CBNZ R0,SVC_ContextSaveRegs ; Branch when stack check is ok
IF FPU_USED != 0
- MOV R4,R1 ; Save osRtxInfo.thread.run.curr
+ MOV R4,R1 ; Assign osRtxInfo.thread.run.curr to R4
ENDIF
MOV R0,#osRtxErrorStackOverflow ; Parameter: r0=code, r1=object_id
BL osRtxKernelErrorNotify ; Call osRtxKernelErrorNotify
LDR R3,=osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.thread.run
LDR R2,[R3,#4] ; Load osRtxInfo.thread.run: next
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
+ MOVS R1,#0 ; Simulate deleted running thread
IF FPU_USED != 0
LDRB LR,[R4,#TCB_SF_OFS] ; Load stack frame information
B SVC_FP_LazyState ; Branch to FP lazy state handling
@@ -188,19 +219,29 @@
ENDIF
SVC_ContextRestore
+ MOVS R4,R2 ; Assign osRtxInfo.thread.run.next to R4, clear Z flag
+ IF :DEF:RTX_EXECUTION_ZONE
+ LDRB R0,[R2,#TCB_ZONE_OFS] ; Load osRtxInfo.thread.run.next: zone
+ CBZ R1,SVC_ZoneSetup ; Branch if running thread is deleted (Z flag unchanged)
+ LDRB R1,[R1,#TCB_ZONE_OFS] ; Load osRtxInfo.thread.run.curr: zone
+ CMP R0,R1 ; Check if next:zone == curr:zone
+
+SVC_ZoneSetup
+ IT NE ; If zone has changed or running thread is deleted
+ BLNE osZoneSetup_Callback ; Setup zone for next thread
+ ENDIF
+
IF DOMAIN_NS != 0
- LDR R0,[R2,#TCB_TZM_OFS] ; Load TrustZone memory identifier
- CBZ R0,SVC_ContextRestore_NS; Branch if there is no secure context
- PUSH {R2,R3} ; Save registers
+ LDR R0,[R4,#TCB_TZM_OFS] ; Load TrustZone memory identifier
+ CBZ R0,SVC_ContextRestore_NS ; Branch if there is no secure context
BL TZ_LoadContext_S ; Load secure context
- POP {R2,R3} ; Restore registers
ENDIF
SVC_ContextRestore_NS
- LDR R0,[R2,#TCB_SP_OFS] ; Load SP
- LDR R1,[R2,#TCB_SM_OFS] ; Load stack memory base
+ LDR R0,[R4,#TCB_SP_OFS] ; Load SP
+ LDR R1,[R4,#TCB_SM_OFS] ; Load stack memory base
MSR PSPLIM,R1 ; Set PSPLIM
- LDRB R1,[R2,#TCB_SF_OFS] ; Load stack frame information
+ LDRB R1,[R4,#TCB_SF_OFS] ; Load stack frame information
ORN LR,R1,#0xFF ; Set EXC_RETURN
IF DOMAIN_NS != 0
@@ -268,4 +309,18 @@
ENDP
+ IF :DEF:RTX_SAFETY_FEATURES
+
+osFaultResume PROC
+ EXPORT osFaultResume
+
+ MRS R12,PSP ; Save PSP to R12
+ B SVC_Context ; Branch to context handling
+
+ ALIGN
+ ENDP
+
+ ENDIF
+
+
END
diff --git a/CMSIS/RTOS2/RTX/Source/GCC/irq_armv6m.S b/CMSIS/RTOS2/RTX/Source/GCC/irq_armv6m.S
index ef4fa75..413a9ce 100644
--- a/CMSIS/RTOS2/RTX/Source/GCC/irq_armv6m.S
+++ b/CMSIS/RTOS2/RTX/Source/GCC/irq_armv6m.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -28,10 +28,12 @@
#include "rtx_def.h"
- .equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
- .equ TCB_SP_OFS, 56 // TCB.SP offset
+ .equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
+ .equ TCB_SP_OFS, 56 // TCB.SP offset
+ .equ TCB_ZONE_OFS, 68 // TCB.zone offset
.equ osRtxErrorStackOverflow, 1 // Stack overflow
+ .equ osRtxErrorSVC, 6 // Invalid SVC function called
.section ".rodata"
.global irqRtxLib // Non weak library reference
@@ -64,6 +66,30 @@
cmp r1,#0 // Check SVC number
bne SVC_User // Branch if not SVC 0
+ #ifdef RTX_SVC_PTR_CHECK
+
+ subs r1,r7,#0x01 // Clear T-bit of function address
+ lsls r2,r1,#29 // Check if 8-byte aligned
+ beq SVC_PtrBoundsCheck // Branch if address is aligned
+
+SVC_PtrInvalid:
+ push {r0,lr} // Save SP and EXC_RETURN
+ movs r0,#osRtxErrorSVC // Parameter: code
+ mov r1,r7 // Parameter: object_id
+ bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
+ pop {r2,r3} // Restore SP and EXC_RETURN
+ mov lr,r3 // Set EXC_RETURN
+ b SVC_Context // Branch to context handling
+
+SVC_PtrBoundsCheck:
+ ldr r2,=Image$$RTX_SVC_VENEERS$$Base
+ ldr r3,=Image$$RTX_SVC_VENEERS$$Length
+ subs r2,r1,r2 // Subtract SVC table base address
+ cmp r2,r3 // Compare with SVC table boundaries
+ bhs SVC_PtrInvalid // Branch if address is out of bounds
+
+ #endif // RTX_SVC_PTR_CHECK
+
push {r0,lr} // Save SP and EXC_RETURN
ldmia r0,{r0-r3} // Load function parameters from stack
blx r7 // Call service function
@@ -101,6 +127,7 @@
ldr r3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.thread.run
ldr r2,[r3,#4] // Load osRtxInfo.thread.run: next
str r2,[r3] // osRtxInfo.thread.run: curr = next
+ movs r1,#0 // Simulate deleted running thread
b SVC_ContextRestore // Branch to context restore handling
SVC_ContextSaveRegs:
@@ -116,7 +143,22 @@
stmia r0!,{r4-r7} // Save R8..R11
SVC_ContextRestore:
- ldr r0,[r2,#TCB_SP_OFS] // Load SP
+ movs r4,r2 // Assign osRtxInfo.thread.run.next to R4
+ #ifdef RTX_EXECUTION_ZONE
+ movs r3,#TCB_ZONE_OFS // Get TCB.zone offset
+ ldrb r0,[r2,r3] // Load osRtxInfo.thread.run.next: zone
+ cmp r1,#0
+ beq SVC_ZoneSetup // Branch if running thread is deleted
+ ldrb r1,[r1,r3] // Load osRtxInfo.thread.run.curr: zone
+ cmp r0,r1 // Check if next:zone == curr:zone
+ beq SVC_ContextRestore_N // Branch if zone has not changed
+
+SVC_ZoneSetup:
+ bl osZoneSetup_Callback // Setup zone for next thread
+ #endif // RTX_EXECUTION_ZONE
+
+SVC_ContextRestore_N:
+ ldr r0,[r4,#TCB_SP_OFS] // Load SP
adds r0,r0,#16 // Adjust address
ldmia r0!,{r4-r7} // Restore R8..R11
mov r8,r4
@@ -194,4 +236,21 @@
.size SysTick_Handler, .-SysTick_Handler
+ #ifdef RTX_SAFETY_FEATURES
+
+ .thumb_func
+ .type osFaultResume, %function
+ .global osFaultResume
+ .fnstart
+ .cantunwind
+osFaultResume:
+
+ b SVC_Context // Branch to context handling
+
+ .fnend
+ .size osFaultResume, .-osFaultResume
+
+ #endif // RTX_SAFETY_FEATURES
+
+
.end
diff --git a/CMSIS/RTOS2/RTX/Source/GCC/irq_armv7m.S b/CMSIS/RTOS2/RTX/Source/GCC/irq_armv7m.S
index daf9871..49298cc 100644
--- a/CMSIS/RTOS2/RTX/Source/GCC/irq_armv7m.S
+++ b/CMSIS/RTOS2/RTX/Source/GCC/irq_armv7m.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -34,13 +34,15 @@
.equ FPU_USED, 0
#endif
- .equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
- .equ TCB_SP_OFS, 56 // TCB.SP offset
- .equ TCB_SF_OFS, 34 // TCB.stack_frame offset
+ .equ I_T_RUN_OFS, 20 // osRtxInfo.thread.run offset
+ .equ TCB_SP_OFS, 56 // TCB.SP offset
+ .equ TCB_SF_OFS, 34 // TCB.stack_frame offset
+ .equ TCB_ZONE_OFS, 68 // TCB.zone offset
.equ FPCCR, 0xE000EF34 // FPCCR Address
.equ osRtxErrorStackOverflow, 1 // Stack overflow
+ .equ osRtxErrorSVC, 6 // Invalid SVC function called
.section ".rodata"
.global irqRtxLib // Non weak library reference
@@ -71,6 +73,30 @@
cmp r1,#0 // Check SVC number
bne SVC_User // Branch if not SVC 0
+ #ifdef RTX_SVC_PTR_CHECK
+
+ ldr r12,[r0,#16] // Load function address from stack
+ sub r1,r12,#1 // Clear T-bit of function address
+ lsls r2,r1,#30 // Check if 4-byte aligned
+ beq SVC_PtrBoundsCheck // Branch if address is aligned
+
+SVC_PtrInvalid:
+ push {r0,lr} // Save SP and EXC_RETURN
+ mov r0,#osRtxErrorSVC // Parameter: code
+ mov r1,r12 // Parameter: object_id
+ bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
+ pop {r12,lr} // Restore SP and EXC_RETURN
+ b SVC_Context // Branch to context handling
+
+SVC_PtrBoundsCheck:
+ ldr r2,=Image$$RTX_SVC_VENEERS$$Base
+ ldr r3,=Image$$RTX_SVC_VENEERS$$Length
+ sub r2,r1,r2 // Subtract SVC table base address
+ cmp r2,r3 // Compare with SVC table boundaries
+ bhs SVC_PtrInvalid // Branch if address is out of bounds
+
+ #endif // RTX_SVC_PTR_CHECK
+
push {r0,lr} // Save SP and EXC_RETURN
ldm r0,{r0-r3,r12} // Load function parameters and address from stack
blx r12 // Call service function
@@ -118,13 +144,14 @@
cbnz r0,SVC_ContextSaveRegs // Branch when stack check is ok
.if (FPU_USED != 0)
- mov r4,r1 // Save osRtxInfo.thread.run.curr
+ mov r4,r1 // Assign osRtxInfo.thread.run.curr to R4
.endif
mov r0,#osRtxErrorStackOverflow // Parameter: r0=code, r1=object_id
bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
ldr r3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.thread.run
ldr r2,[r3,#4] // Load osRtxInfo.thread.run: next
str r2,[r3] // osRtxInfo.thread.run: curr = next
+ movs r1,#0 // Simulate deleted running thread
.if (FPU_USED != 0)
ldrb lr,[r4,#TCB_SF_OFS] // Load stack frame information
b SVC_FP_LazyState // Branch to FP lazy state handling
@@ -153,9 +180,21 @@
#endif // RTX_STACK_CHECK
SVC_ContextRestore:
- ldr r0,[r2,#TCB_SP_OFS] // Load SP
+ movs r4,r2 // Assign osRtxInfo.thread.run.next to R4, clear Z flag
+ #ifdef RTX_EXECUTION_ZONE
+ ldrb r0,[r2,#TCB_ZONE_OFS] // Load osRtxInfo.thread.run.next: zone
+ cbz r1,SVC_ZoneSetup // Branch if running thread is deleted (Z flag unchanged)
+ ldrb r1,[r1,#TCB_ZONE_OFS] // Load osRtxInfo.thread.run.curr: zone
+ cmp r0,r1 // Check if next:zone == curr:zone
+
+SVC_ZoneSetup:
+ it ne // If zone has changed or running thread is deleted
+ blne osZoneSetup_Callback // Setup zone for next thread
+ #endif // RTX_EXECUTION_ZONE
+
+ ldr r0,[r4,#TCB_SP_OFS] // Load SP
.if (FPU_USED != 0)
- ldrb r1,[r2,#TCB_SF_OFS] // Load stack frame information
+ ldrb r1,[r4,#TCB_SF_OFS] // Load stack frame information
orn lr,r1,#0xFF // Set EXC_RETURN
tst lr,#0x10 // Determine stack frame from EXC_RETURN bit 4
it eq // If extended stack frame
@@ -222,4 +261,22 @@
.size SysTick_Handler, .-SysTick_Handler
+ #ifdef RTX_SAFETY_FEATURES
+
+ .thumb_func
+ .type osFaultResume, %function
+ .global osFaultResume
+ .fnstart
+ .cantunwind
+osFaultResume:
+
+ mrs r12,psp // Save PSP to R12
+ b SVC_Context // Branch to context handling
+
+ .fnend
+ .size osFaultResume, .-osFaultResume
+
+ #endif // RTX_SAFETY_FEATURES
+
+
.end
diff --git a/CMSIS/RTOS2/RTX/Source/GCC/irq_armv8mbl.S b/CMSIS/RTOS2/RTX/Source/GCC/irq_armv8mbl.S
index 74591a6..c10846f 100644
--- a/CMSIS/RTOS2/RTX/Source/GCC/irq_armv8mbl.S
+++ b/CMSIS/RTOS2/RTX/Source/GCC/irq_armv8mbl.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2016-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -37,8 +37,10 @@
.equ TCB_SP_OFS, 56 // TCB.SP offset
.equ TCB_SF_OFS, 34 // TCB.stack_frame offset
.equ TCB_TZM_OFS, 64 // TCB.tz_memory offset
+ .equ TCB_ZONE_OFS,68 // TCB.zone offset
.equ osRtxErrorStackOverflow, 1 // Stack overflow
+ .equ osRtxErrorSVC, 6 // Invalid SVC function called
.section ".rodata"
.global irqRtxLib // Non weak library reference
@@ -71,6 +73,30 @@
cmp r1,#0 // Check SVC number
bne SVC_User // Branch if not SVC 0
+ #ifdef RTX_SVC_PTR_CHECK
+
+ subs r1,r7,#0x01 // Clear T-bit of function address
+ lsls r2,r1,#29 // Check if 8-byte aligned
+ beq SVC_PtrBoundsCheck // Branch if address is aligned
+
+SVC_PtrInvalid:
+ push {r0,lr} // Save SP and EXC_RETURN
+ movs r0,#osRtxErrorSVC // Parameter: code
+ mov r1,r7 // Parameter: object_id
+ bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
+ pop {r2,r3} // Restore SP and EXC_RETURN
+ mov lr,r3 // Set EXC_RETURN
+ b SVC_Context // Branch to context handling
+
+SVC_PtrBoundsCheck:
+ ldr r2,=Image$$RTX_SVC_VENEERS$$Base
+ ldr r3,=Image$$RTX_SVC_VENEERS$$Length
+ subs r2,r1,r2 // Subtract SVC table base address
+ cmp r2,r3 // Compare with SVC table boundaries
+ bhs SVC_PtrInvalid // Branch if address is out of bounds
+
+ #endif // RTX_SVC_PTR_CHECK
+
push {r0,lr} // Save SP and EXC_RETURN
ldmia r0,{r0-r3} // Load function parameters from stack
blx r7 // Call service function
@@ -129,6 +155,7 @@
ldr r3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.thread.run
ldr r2,[r3,#4] // Load osRtxInfo.thread.run: next
str r2,[r3] // osRtxInfo.thread.run: curr = next
+ movs r1,#0 // Simulate deleted running thread
b SVC_ContextRestore // Branch to context restore handling
SVC_ContextSaveRegs:
@@ -163,25 +190,37 @@
#endif // RTX_STACK_CHECK
SVC_ContextRestore:
+ movs r4,r2 // Assign osRtxInfo.thread.run.next to R4
+ #ifdef RTX_EXECUTION_ZONE
+ movs r3,#TCB_ZONE_OFS // Get TCB.zone offset
+ ldrb r0,[r2,r3] // Load osRtxInfo.thread.run.next: zone
+ cbz r1,SVC_ZoneSetup // Branch if running thread is deleted
+ ldrb r1,[r1,r3] // Load osRtxInfo.thread.run.curr: zone
+ cmp r0,r1 // Check if next:zone == curr:zone
+ beq SVC_ContextRestore_S // Branch if zone has not changed
+
+SVC_ZoneSetup:
+ bl osZoneSetup_Callback // Setup zone for next thread
+ #endif // RTX_EXECUTION_ZONE
+
+SVC_ContextRestore_S:
#if (DOMAIN_NS != 0)
- ldr r0,[r2,#TCB_TZM_OFS] // Load TrustZone memory identifier
+ ldr r0,[r4,#TCB_TZM_OFS] // Load TrustZone memory identifier
cbz r0,SVC_ContextRestore_NS // Branch if there is no secure context
- push {r2,r3} // Save registers
bl TZ_LoadContext_S // Load secure context
- pop {r2,r3} // Restore registers
#endif
SVC_ContextRestore_NS:
- ldr r0,[r2,#TCB_SM_OFS] // Load stack memory base
+ ldr r0,[r4,#TCB_SM_OFS] // Load stack memory base
msr psplim,r0 // Set PSPLIM
- mov r0,r2 // osRtxInfo.thread.run.next
+ mov r0,r4 // osRtxInfo.thread.run.next
adds r0,r0,#TCB_SF_OFS // Adjust address
ldrb r3,[r0] // Load stack frame information
movs r0,#0xFF
mvns r0,r0 // R0=0xFFFFFF00
orrs r3,r3,r0
mov lr,r3 // Set EXC_RETURN
- ldr r0,[r2,#TCB_SP_OFS] // Load SP
+ ldr r0,[r4,#TCB_SP_OFS] // Load SP
#if (DOMAIN_NS != 0)
lsls r3,r3,#25 // Check domain of interrupted thread
bmi SVC_ContextRestoreSP // Branch if secure
@@ -263,4 +302,21 @@
.size SysTick_Handler, .-SysTick_Handler
+ #ifdef RTX_SAFETY_FEATURES
+
+ .thumb_func
+ .type osFaultResume, %function
+ .global osFaultResume
+ .fnstart
+ .cantunwind
+osFaultResume:
+
+ b SVC_Context // Branch to context handling
+
+ .fnend
+ .size osFaultResume, .-osFaultResume
+
+ #endif // RTX_SAFETY_FEATURES
+
+
.end
diff --git a/CMSIS/RTOS2/RTX/Source/GCC/irq_armv8mml.S b/CMSIS/RTOS2/RTX/Source/GCC/irq_armv8mml.S
index f2d6fea..4e3e6dd 100644
--- a/CMSIS/RTOS2/RTX/Source/GCC/irq_armv8mml.S
+++ b/CMSIS/RTOS2/RTX/Source/GCC/irq_armv8mml.S
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2016-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -49,10 +49,12 @@
.equ TCB_SP_OFS, 56 // TCB.SP offset
.equ TCB_SF_OFS, 34 // TCB.stack_frame offset
.equ TCB_TZM_OFS, 64 // TCB.tz_memory offset
+ .equ TCB_ZONE_OFS,68 // TCB.zone offset
.equ FPCCR, 0xE000EF34 // FPCCR Address
.equ osRtxErrorStackOverflow, 1 // Stack overflow
+ .equ osRtxErrorSVC, 6 // Invalid SVC function called
.section ".rodata"
.global irqRtxLib // Non weak library reference
@@ -83,6 +85,30 @@
cmp r1,#0 // Check SVC number
bne SVC_User // Branch if not SVC 0
+ #ifdef RTX_SVC_PTR_CHECK
+
+ ldr r12,[r0,#16] // Load function address from stack
+ sub r1,r12,#1 // Clear T-bit of function address
+ lsls r2,r1,#30 // Check if 4-byte aligned
+ beq SVC_PtrBoundsCheck // Branch if address is aligned
+
+SVC_PtrInvalid:
+ push {r0,lr} // Save SP and EXC_RETURN
+ mov r0,#osRtxErrorSVC // Parameter: code
+ mov r1,r12 // Parameter: object_id
+ bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
+ pop {r12,lr} // Restore SP and EXC_RETURN
+ b SVC_Context // Branch to context handling
+
+SVC_PtrBoundsCheck:
+ ldr r2,=Image$$RTX_SVC_VENEERS$$Base
+ ldr r3,=Image$$RTX_SVC_VENEERS$$Length
+ sub r2,r1,r2 // Subtract SVC table base address
+ cmp r2,r3 // Compare with SVC table boundaries
+ bhs SVC_PtrInvalid // Branch if address is out of bounds
+
+ #endif // RTX_SVC_PTR_CHECK
+
push {r0,lr} // Save SP and EXC_RETURN
ldm r0,{r0-r3,r12} // Load function parameters and address from stack
blx r12 // Call service function
@@ -146,13 +172,14 @@
cbnz r0,SVC_ContextSaveRegs // Branch when stack check is ok
.if (FPU_USED != 0) || (MVE_USED != 0)
- mov r4,r1 // Save osRtxInfo.thread.run.curr
+ mov r4,r1 // Assign osRtxInfo.thread.run.curr to R4
.endif
mov r0,#osRtxErrorStackOverflow // Parameter: r0=code, r1=object_id
bl osRtxKernelErrorNotify // Call osRtxKernelErrorNotify
ldr r3,=osRtxInfo+I_T_RUN_OFS // Load address of osRtxInfo.thread.run
ldr r2,[r3,#4] // Load osRtxInfo.thread.run: next
str r2,[r3] // osRtxInfo.thread.run: curr = next
+ movs r1,#0 // Simulate deleted running thread
.if (FPU_USED != 0) || (MVE_USED != 0)
ldrb lr,[r4,#TCB_SF_OFS] // Load stack frame information
b SVC_FP_LazyState // Branch to FP lazy state handling
@@ -186,19 +213,29 @@
#endif // RTX_STACK_CHECK
SVC_ContextRestore:
+ movs r4,r2 // Assign osRtxInfo.thread.run.next to R4, clear Z flag
+ #ifdef RTX_EXECUTION_ZONE
+ ldrb r0,[r2,#TCB_ZONE_OFS] // Load osRtxInfo.thread.run.next: zone
+ cbz r1,SVC_ZoneSetup // Branch if running thread is deleted (Z flag unchanged)
+ ldrb r1,[r1,#TCB_ZONE_OFS] // Load osRtxInfo.thread.run.curr: zone
+ cmp r0,r1 // Check if next:zone == curr:zone
+
+SVC_ZoneSetup:
+ it ne // If zone has changed or running thread is deleted
+ blne osZoneSetup_Callback // Setup zone for next thread
+ #endif // RTX_EXECUTION_ZONE
+
#if (DOMAIN_NS != 0)
- ldr r0,[r2,#TCB_TZM_OFS] // Load TrustZone memory identifier
+ ldr r0,[r4,#TCB_TZM_OFS] // Load TrustZone memory identifier
cbz r0,SVC_ContextRestore_NS // Branch if there is no secure context
- push {r2,r3} // Save registers
bl TZ_LoadContext_S // Load secure context
- pop {r2,r3} // Restore registers
#endif
SVC_ContextRestore_NS:
- ldr r0,[r2,#TCB_SP_OFS] // Load SP
- ldr r1,[r2,#TCB_SM_OFS] // Load stack memory base
+ ldr r0,[r4,#TCB_SP_OFS] // Load SP
+ ldr r1,[r4,#TCB_SM_OFS] // Load stack memory base
msr psplim,r1 // Set PSPLIM
- ldrb r1,[r2,#TCB_SF_OFS] // Load stack frame information
+ ldrb r1,[r4,#TCB_SF_OFS] // Load stack frame information
orn lr,r1,#0xFF // Set EXC_RETURN
#if (DOMAIN_NS != 0)
tst lr,#0x40 // Check domain of interrupted thread
@@ -271,4 +308,22 @@
.size SysTick_Handler, .-SysTick_Handler
+ #ifdef RTX_SAFETY_FEATURES
+
+ .thumb_func
+ .type osFaultResume, %function
+ .global osFaultResume
+ .fnstart
+ .cantunwind
+osFaultResume:
+
+ mrs r12,psp // Save PSP to R12
+ b SVC_Context // Branch to context handling
+
+ .fnend
+ .size osFaultResume, .-osFaultResume
+
+ #endif // RTX_SAFETY_FEATURES
+
+
.end
diff --git a/CMSIS/RTOS2/RTX/Source/IAR/irq_armv6m.s b/CMSIS/RTOS2/RTX/Source/IAR/irq_armv6m.s
index a85322d..fa65825 100644
--- a/CMSIS/RTOS2/RTX/Source/IAR/irq_armv6m.s
+++ b/CMSIS/RTOS2/RTX/Source/IAR/irq_armv6m.s
@@ -1,5 +1,5 @@
;/*
-; * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+; * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
@@ -31,9 +31,11 @@
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
TCB_SP_OFS EQU 56 ; TCB.SP offset
+TCB_ZONE_OFS EQU 68 ; TCB.zone offset
osRtxErrorStackOverflow\
EQU 1 ; Stack overflow
+osRtxErrorSVC EQU 6 ; Invalid SVC function called
PRESERVE8
@@ -56,6 +58,14 @@
IMPORT osRtxThreadStackCheck
IMPORT osRtxKernelErrorNotify
#endif
+ #ifdef RTX_SVC_PTR_CHECK
+ IMPORT |Image$$RTX_SVC_VENEERS$$Base|
+ IMPORT |Image$$RTX_SVC_VENEERS$$Length|
+ IMPORT osRtxKernelErrorNotify
+ #endif
+ #ifdef RTX_EXECUTION_ZONE
+ IMPORT osZoneSetup_Callback
+ #endif
MOV R0,LR
LSRS R0,R0,#3 ; Determine return stack from EXC_RETURN bit 2
@@ -69,6 +79,30 @@
CMP R1,#0 ; Check SVC number
BNE SVC_User ; Branch if not SVC 0
+ #ifdef RTX_SVC_PTR_CHECK
+
+ SUBS R1,R7,#0x01 ; Clear T-bit of function address
+ LSLS R2,R1,#29 ; Check if 8-byte aligned
+ BEQ SVC_PtrBoundsCheck ; Branch if address is aligned
+
+SVC_PtrInvalid
+ PUSH {R0,LR} ; Save SP and EXC_RETURN
+ MOVS R0,#osRtxErrorSVC ; Parameter: code
+ MOV R1,R7 ; Parameter: object_id
+ BL osRtxKernelErrorNotify ; Call osRtxKernelErrorNotify
+ POP {R2,R3} ; Restore SP and EXC_RETURN
+ MOV LR,R3 ; Set EXC_RETURN
+ B SVC_Context ; Branch to context handling
+
+SVC_PtrBoundsCheck
+ LDR R2,=|Image$$RTX_SVC_VENEERS$$Base|
+ LDR R3,=|Image$$RTX_SVC_VENEERS$$Length|
+ SUBS R2,R1,R2 ; Subtract SVC table base address
+ CMP R2,R3 ; Compare with SVC table boundaries
+ BHS SVC_PtrInvalid ; Branch if address is out of bounds
+
+ #endif
+
PUSH {R0,LR} ; Save SP and EXC_RETURN
LDMIA R0,{R0-R3} ; Load function parameters from stack
BLX R7 ; Call service function
@@ -106,6 +140,7 @@
LDR R3,=osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.thread.run
LDR R2,[R3,#4] ; Load osRtxInfo.thread.run: next
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
+ MOVS R1,#0 ; Simulate deleted running thread
B SVC_ContextRestore ; Branch to context restore handling
SVC_ContextSaveRegs
@@ -121,7 +156,22 @@
STMIA R0!,{R4-R7} ; Save R8..R11
SVC_ContextRestore
- LDR R0,[R2,#TCB_SP_OFS] ; Load SP
+ MOVS R4,R2 ; Assign osRtxInfo.thread.run.next to R4
+ #ifdef RTX_EXECUTION_ZONE
+ MOVS R3,#TCB_ZONE_OFS ; Get TCB.zone offset
+ LDRB R0,[R2,R3] ; Load osRtxInfo.thread.run.next: zone
+ CMP R1,#0
+ BEQ SVC_ZoneSetup ; Branch if running thread is deleted
+ LDRB R1,[R1,R3] ; Load osRtxInfo.thread.run.curr: zone
+ CMP R0,R1 ; Check if next:zone == curr:zone
+ BEQ SVC_ContextRestore_N ; Branch if zone has not changed
+
+SVC_ZoneSetup
+ BL osZoneSetup_Callback ; Setup zone for next thread
+ #endif
+
+SVC_ContextRestore_N
+ LDR R0,[R4,#TCB_SP_OFS] ; Load SP
ADDS R0,R0,#16 ; Adjust address
LDMIA R0!,{R4-R7} ; Restore R8..R11
MOV R8,R4
@@ -184,4 +234,17 @@
B SVC_Context ; Branch to context handling
+ #ifdef RTX_SAFETY_FEATURES
+
+osFaultResume PROC
+ EXPORT osFaultResume
+
+ B SVC_Context ; Branch to context handling
+
+ ALIGN
+ ENDP
+
+ #endif
+
+
END
diff --git a/CMSIS/RTOS2/RTX/Source/IAR/irq_armv7m.s b/CMSIS/RTOS2/RTX/Source/IAR/irq_armv7m.s
index 7903d10..89a6a12 100644
--- a/CMSIS/RTOS2/RTX/Source/IAR/irq_armv7m.s
+++ b/CMSIS/RTOS2/RTX/Source/IAR/irq_armv7m.s
@@ -1,5 +1,5 @@
;/*
-; * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+; * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
@@ -38,11 +38,13 @@
I_T_RUN_OFS EQU 20 ; osRtxInfo.thread.run offset
TCB_SP_OFS EQU 56 ; TCB.SP offset
TCB_SF_OFS EQU 34 ; TCB.stack_frame offset
+TCB_ZONE_OFS EQU 68 ; TCB.zone offset
FPCCR EQU 0xE000EF34 ; FPCCR Address
osRtxErrorStackOverflow\
EQU 1 ; Stack overflow
+osRtxErrorSVC EQU 6 ; Invalid SVC function called
PRESERVE8
@@ -65,6 +67,14 @@
IMPORT osRtxThreadStackCheck
IMPORT osRtxKernelErrorNotify
#endif
+ #ifdef RTX_SVC_PTR_CHECK
+ IMPORT |Image$$RTX_SVC_VENEERS$$Base|
+ IMPORT |Image$$RTX_SVC_VENEERS$$Length|
+ IMPORT osRtxKernelErrorNotify
+ #endif
+ #ifdef RTX_EXECUTION_ZONE
+ IMPORT osZoneSetup_Callback
+ #endif
TST LR,#0x04 ; Determine return stack from EXC_RETURN bit 2
ITE EQ
@@ -76,6 +86,30 @@
CMP R1,#0 ; Check SVC number
BNE SVC_User ; Branch if not SVC 0
+ #ifdef RTX_SVC_PTR_CHECK
+
+ LDR R12,[R0,#16] ; Load function address from stack
+ SUB R1,R12,#1 ; Clear T-bit of function address
+ LSLS R2,R1,#30 ; Check if 4-byte aligned
+ BEQ SVC_PtrBoundsCheck ; Branch if address is aligned
+
+SVC_PtrInvalid
+ PUSH {R0,LR} ; Save SP and EXC_RETURN
+ MOV R0,#osRtxErrorSVC ; Parameter: code
+ MOV R1,R12 ; Parameter: object_id
+ BL osRtxKernelErrorNotify ; Call osRtxKernelErrorNotify
+ POP {R12,LR} ; Restore SP and EXC_RETURN
+ B SVC_Context ; Branch to context handling
+
+SVC_PtrBoundsCheck
+ LDR R2,=|Image$$RTX_SVC_VENEERS$$Base|
+ LDR R3,=|Image$$RTX_SVC_VENEERS$$Length|
+ SUB R2,R1,R2 ; Subtract SVC table base address
+ CMP R2,R3 ; Compare with SVC table boundaries
+ BHS SVC_PtrInvalid ; Branch if address is out of bounds
+
+ #endif
+
PUSH {R0,LR} ; Save SP and EXC_RETURN
LDM R0,{R0-R3,R12} ; Load function parameters and address from stack
BLX R12 ; Call service function
@@ -123,13 +157,14 @@
CBNZ R0,SVC_ContextSaveRegs ; Branch when stack check is ok
#if (FPU_USED != 0)
- MOV R4,R1 ; Save osRtxInfo.thread.run.curr
+ MOV R4,R1 ; Assign osRtxInfo.thread.run.curr to R4
#endif
MOV R0,#osRtxErrorStackOverflow ; Parameter: r0=code, r1=object_id
BL osRtxKernelErrorNotify ; Call osRtxKernelErrorNotify
LDR R3,=osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.thread.run
LDR R2,[R3,#4] ; Load osRtxInfo.thread.run: next
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
+ MOVS R1,#0 ; Simulate deleted running thread
#if (FPU_USED != 0)
LDRB LR,[R4,#TCB_SF_OFS] ; Load stack frame information
B SVC_FP_LazyState ; Branch to FP lazy state handling
@@ -158,9 +193,21 @@
#endif
SVC_ContextRestore
- LDR R0,[R2,#TCB_SP_OFS] ; Load SP
+ MOVS R4,R2 ; Assign osRtxInfo.thread.run.next to R4, clear Z flag
+ #ifdef RTX_EXECUTION_ZONE
+ LDRB R0,[R2,#TCB_ZONE_OFS] ; Load osRtxInfo.thread.run.next: zone
+ CBZ R1,SVC_ZoneSetup ; Branch if running thread is deleted (Z flag unchanged)
+ LDRB R1,[R1,#TCB_ZONE_OFS] ; Load osRtxInfo.thread.run.curr: zone
+ CMP R0,R1 ; Check if next:zone == curr:zone
+
+SVC_ZoneSetup
+ IT NE ; If zone has changed or running thread is deleted
+ BLNE osZoneSetup_Callback ; Setup zone for next thread
+ #endif
+
+ LDR R0,[R4,#TCB_SP_OFS] ; Load SP
#if (FPU_USED != 0)
- LDRB R1,[R2,#TCB_SF_OFS] ; Load stack frame information
+ LDRB R1,[R4,#TCB_SF_OFS] ; Load stack frame information
ORN LR,R1,#0xFF ; Set EXC_RETURN
TST LR,#0x10 ; Determine stack frame from EXC_RETURN bit 4
IT EQ ; If extended stack frame
@@ -212,4 +259,18 @@
B SVC_Context ; Branch to context handling
+ #ifdef RTX_SAFETY_FEATURES
+
+osFaultResume PROC
+ EXPORT osFaultResume
+
+ MRS R12,PSP ; Save PSP to R12
+ B SVC_Context ; Branch to context handling
+
+ ALIGN
+ ENDP
+
+ #endif
+
+
END
diff --git a/CMSIS/RTOS2/RTX/Source/IAR/irq_armv8mbl.s b/CMSIS/RTOS2/RTX/Source/IAR/irq_armv8mbl.s
index 5ee2e8b..362fad1 100644
--- a/CMSIS/RTOS2/RTX/Source/IAR/irq_armv8mbl.s
+++ b/CMSIS/RTOS2/RTX/Source/IAR/irq_armv8mbl.s
@@ -1,5 +1,5 @@
;/*
-; * Copyright (c) 2016-2021 Arm Limited. All rights reserved.
+; * Copyright (c) 2016-2023 Arm Limited. All rights reserved.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
@@ -38,9 +38,11 @@
TCB_SP_OFS EQU 56 ; TCB.SP offset
TCB_SF_OFS EQU 34 ; TCB.stack_frame offset
TCB_TZM_OFS EQU 64 ; TCB.tz_memory offset
+TCB_ZONE_OFS EQU 68 ; TCB.zone offset
osRtxErrorStackOverflow\
EQU 1 ; Stack overflow
+osRtxErrorSVC EQU 6 ; Invalid SVC function called
PRESERVE8
@@ -63,6 +65,14 @@
IMPORT osRtxThreadStackCheck
IMPORT osRtxKernelErrorNotify
#endif
+ #ifdef RTX_SVC_PTR_CHECK
+ IMPORT |Image$$RTX_SVC_VENEERS$$Base|
+ IMPORT |Image$$RTX_SVC_VENEERS$$Length|
+ IMPORT osRtxKernelErrorNotify
+ #endif
+ #ifdef RTX_EXECUTION_ZONE
+ IMPORT osZoneSetup_Callback
+ #endif
#if (DOMAIN_NS != 0)
IMPORT TZ_LoadContext_S
IMPORT TZ_StoreContext_S
@@ -80,6 +90,30 @@
CMP R1,#0 ; Check SVC number
BNE SVC_User ; Branch if not SVC 0
+ #ifdef RTX_SVC_PTR_CHECK
+
+ SUBS R1,R7,#0x01 ; Clear T-bit of function address
+ LSLS R2,R1,#29 ; Check if 8-byte aligned
+ BEQ SVC_PtrBoundsCheck ; Branch if address is aligned
+
+SVC_PtrInvalid
+ PUSH {R0,LR} ; Save SP and EXC_RETURN
+ MOVS R0,#osRtxErrorSVC ; Parameter: code
+ MOV R1,R7 ; Parameter: object_id
+ BL osRtxKernelErrorNotify ; Call osRtxKernelErrorNotify
+ POP {R2,R3} ; Restore SP and EXC_RETURN
+ MOV LR,R3 ; Set EXC_RETURN
+ B SVC_Context ; Branch to context handling
+
+SVC_PtrBoundsCheck
+ LDR R2,=|Image$$RTX_SVC_VENEERS$$Base|
+ LDR R3,=|Image$$RTX_SVC_VENEERS$$Length|
+ SUBS R2,R1,R2 ; Subtract SVC table base address
+ CMP R2,R3 ; Compare with SVC table boundaries
+ BHS SVC_PtrInvalid ; Branch if address is out of bounds
+
+ #endif
+
PUSH {R0,LR} ; Save SP and EXC_RETURN
LDMIA R0,{R0-R3} ; Load function parameters from stack
BLX R7 ; Call service function
@@ -138,6 +172,7 @@
LDR R3,=osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.thread.run
LDR R2,[R3,#4] ; Load osRtxInfo.thread.run: next
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
+ MOVS R1,#0 ; Simulate deleted running thread
B SVC_ContextRestore ; Branch to context restore handling
SVC_ContextSaveRegs
@@ -172,25 +207,37 @@
#endif
SVC_ContextRestore
+ MOVS R4,R2 ; Assign osRtxInfo.thread.run.next to R4
+ #ifdef RTX_EXECUTION_ZONE
+ MOVS R3,#TCB_ZONE_OFS ; Get TCB.zone offset
+ LDRB R0,[R2,R3] ; Load osRtxInfo.thread.run.next: zone
+ CBZ R1,SVC_ZoneSetup ; Branch if running thread is deleted
+ LDRB R1,[R1,R3] ; Load osRtxInfo.thread.run.curr: zone
+ CMP R0,R1 ; Check if next:zone == curr:zone
+ BEQ SVC_ContextRestore_S ; Branch if zone has not changed
+
+SVC_ZoneSetup
+ BL osZoneSetup_Callback ; Setup zone for next thread
+ #endif
+
+SVC_ContextRestore_S
#if (DOMAIN_NS != 0)
- LDR R0,[R2,#TCB_TZM_OFS] ; Load TrustZone memory identifier
+ LDR R0,[R4,#TCB_TZM_OFS] ; Load TrustZone memory identifier
CBZ R0,SVC_ContextRestore_NS ; Branch if there is no secure context
- PUSH {R2,R3} ; Save registers
BL TZ_LoadContext_S ; Load secure context
- POP {R2,R3} ; Restore registers
#endif
SVC_ContextRestore_NS
- LDR R0,[R2,#TCB_SM_OFS] ; Load stack memory base
+ LDR R0,[R4,#TCB_SM_OFS] ; Load stack memory base
MSR PSPLIM,R0 ; Set PSPLIM
- MOV R0,R2 ; osRtxInfo.thread.run.next
+ MOV R0,R4 ; osRtxInfo.thread.run.next
ADDS R0,R0,#TCB_SF_OFS ; Adjust address
LDRB R3,[R0] ; Load stack frame information
MOVS R0,#0xFF
MVNS R0,R0 ; R0=0xFFFFFF00
ORRS R3,R3,R0
MOV LR,R3 ; Set EXC_RETURN
- LDR R0,[R2,#TCB_SP_OFS] ; Load SP
+ LDR R0,[R4,#TCB_SP_OFS] ; Load SP
#if (DOMAIN_NS != 0)
LSLS R3,R3,#25 ; Check domain of interrupted thread
BMI SVC_ContextRestoreSP ; Branch if secure
@@ -256,4 +303,17 @@
B SVC_Context ; Branch to context handling
+ #ifdef RTX_SAFETY_FEATURES
+
+osFaultResume PROC
+ EXPORT osFaultResume
+
+ B SVC_Context ; Branch to context handling
+
+ ALIGN
+ ENDP
+
+ #endif
+
+
END
diff --git a/CMSIS/RTOS2/RTX/Source/IAR/irq_armv8mml.s b/CMSIS/RTOS2/RTX/Source/IAR/irq_armv8mml.s
index 57733f3..35e8df9 100644
--- a/CMSIS/RTOS2/RTX/Source/IAR/irq_armv8mml.s
+++ b/CMSIS/RTOS2/RTX/Source/IAR/irq_armv8mml.s
@@ -1,5 +1,5 @@
;/*
-; * Copyright (c) 2016-2021 Arm Limited. All rights reserved.
+; * Copyright (c) 2016-2023 Arm Limited. All rights reserved.
; *
; * SPDX-License-Identifier: Apache-2.0
; *
@@ -50,11 +50,13 @@
TCB_SP_OFS EQU 56 ; TCB.SP offset
TCB_SF_OFS EQU 34 ; TCB.stack_frame offset
TCB_TZM_OFS EQU 64 ; TCB.tz_memory offset
+TCB_ZONE_OFS EQU 68 ; TCB.zone offset
FPCCR EQU 0xE000EF34 ; FPCCR Address
osRtxErrorStackOverflow\
EQU 1 ; Stack overflow
+osRtxErrorSVC EQU 6 ; Invalid SVC function called
PRESERVE8
@@ -77,6 +79,14 @@
IMPORT osRtxThreadStackCheck
IMPORT osRtxKernelErrorNotify
#endif
+ #ifdef RTX_SVC_PTR_CHECK
+ IMPORT |Image$$RTX_SVC_VENEERS$$Base|
+ IMPORT |Image$$RTX_SVC_VENEERS$$Length|
+ IMPORT osRtxKernelErrorNotify
+ #endif
+ #ifdef RTX_EXECUTION_ZONE
+ IMPORT osZoneSetup_Callback
+ #endif
#if (DOMAIN_NS != 0)
IMPORT TZ_LoadContext_S
IMPORT TZ_StoreContext_S
@@ -92,6 +102,30 @@
CMP R1,#0 ; Check SVC number
BNE SVC_User ; Branch if not SVC 0
+ #ifdef RTX_SVC_PTR_CHECK
+
+ LDR R12,[R0,#16] ; Load function address from stack
+ SUB R1,R12,#1 ; Clear T-bit of function address
+ LSLS R2,R1,#30 ; Check if 4-byte aligned
+ BEQ SVC_PtrBoundsCheck ; Branch if address is aligned
+
+SVC_PtrInvalid
+ PUSH {R0,LR} ; Save SP and EXC_RETURN
+ MOV R0,#osRtxErrorSVC ; Parameter: code
+ MOV R1,R12 ; Parameter: object_id
+ BL osRtxKernelErrorNotify ; Call osRtxKernelErrorNotify
+ POP {R12,LR} ; Restore SP and EXC_RETURN
+ B SVC_Context ; Branch to context handling
+
+SVC_PtrBoundsCheck
+ LDR R2,=|Image$$RTX_SVC_VENEERS$$Base|
+ LDR R3,=|Image$$RTX_SVC_VENEERS$$Length|
+ SUB R2,R1,R2 ; Subtract SVC table base address
+ CMP R2,R3 ; Compare with SVC table boundaries
+ BHS SVC_PtrInvalid ; Branch if address is out of bounds
+
+ #endif
+
PUSH {R0,LR} ; Save SP and EXC_RETURN
LDM R0,{R0-R3,R12} ; Load function parameters and address from stack
BLX R12 ; Call service function
@@ -155,13 +189,14 @@
CBNZ R0,SVC_ContextSaveRegs ; Branch when stack check is ok
#if ((FPU_USED != 0) || (MVE_USED != 0))
- MOV R4,R1 ; Save osRtxInfo.thread.run.curr
+ MOV R4,R1 ; Assign osRtxInfo.thread.run.curr to R4
#endif
MOV R0,#osRtxErrorStackOverflow ; Parameter: r0=code, r1=object_id
BL osRtxKernelErrorNotify ; Call osRtxKernelErrorNotify
LDR R3,=osRtxInfo+I_T_RUN_OFS ; Load address of osRtxInfo.thread.run
LDR R2,[R3,#4] ; Load osRtxInfo.thread.run: next
STR R2,[R3] ; osRtxInfo.thread.run: curr = next
+ MOVS R1,#0 ; Simulate deleted running thread
#if ((FPU_USED != 0) || (MVE_USED != 0))
LDRB LR,[R4,#TCB_SF_OFS] ; Load stack frame information
B SVC_FP_LazyState ; Branch to FP lazy state handling
@@ -196,19 +231,28 @@
#endif
SVC_ContextRestore
+ MOVS R4,R2 ; Assign osRtxInfo.thread.run.next to R4, clear Z flag
+ #ifdef RTX_EXECUTION_ZONE
+ LDRB R0,[R2,#TCB_ZONE_OFS] ; Load osRtxInfo.thread.run.next: zone
+ CBZ R1,SVC_ZoneSetup ; Branch if running thread is deleted (Z flag unchanged)
+ LDRB R1,[R1,#TCB_ZONE_OFS] ; Load osRtxInfo.thread.run.curr: zone
+ CMP R0,R1 ; Check if next:zone == curr:zone
+
+SVC_ZoneSetup
+ IT NE ; If zone has changed or running thread is deleted
+ BLNE osZoneSetup_Callback ; Setup zone for next thread
+ #endif
#if (DOMAIN_NS != 0)
- LDR R0,[R2,#TCB_TZM_OFS] ; Load TrustZone memory identifier
- CBZ R0,SVC_ContextRestore_NS; Branch if there is no secure context
- PUSH {R2,R3} ; Save registers
+ LDR R0,[R4,#TCB_TZM_OFS] ; Load TrustZone memory identifier
+ CBZ R0,SVC_ContextRestore_NS ; Branch if there is no secure context
BL TZ_LoadContext_S ; Load secure context
- POP {R2,R3} ; Restore registers
#endif
SVC_ContextRestore_NS
- LDR R0,[R2,#TCB_SP_OFS] ; Load SP
- LDR R1,[R2,#TCB_SM_OFS] ; Load stack memory base
+ LDR R0,[R4,#TCB_SP_OFS] ; Load SP
+ LDR R1,[R4,#TCB_SM_OFS] ; Load stack memory base
MSR PSPLIM,R1 ; Set PSPLIM
- LDRB R1,[R2,#TCB_SF_OFS] ; Load stack frame information
+ LDRB R1,[R4,#TCB_SF_OFS] ; Load stack frame information
ORN LR,R1,#0xFF ; Set EXC_RETURN
#if (DOMAIN_NS != 0)
@@ -267,4 +311,18 @@
B SVC_Context ; Branch to context handling
+ #ifdef RTX_SAFETY_FEATURES
+
+osFaultResume PROC
+ EXPORT osFaultResume
+
+ MRS R12,PSP ; Save PSP to R12
+ B SVC_Context ; Branch to context handling
+
+ ALIGN
+ ENDP
+
+ #endif
+
+
END
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_core_cm.h b/CMSIS/RTOS2/RTX/Source/rtx_core_cm.h
index b1c0156..20a0d8b 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_core_cm.h
+++ b/CMSIS/RTOS2/RTX/Source/rtx_core_cm.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2022 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -118,6 +118,18 @@
return ((__get_CONTROL() & 1U) == 0U);
}
+/// Set thread Privileged mode
+/// \param[in] privileged true=privileged, false=unprivileged
+__STATIC_INLINE void SetPrivileged (bool_t privileged) {
+ if (privileged) {
+ // Privileged Thread mode & PSP
+ __set_CONTROL(0x02U);
+ } else {
+ // Unprivileged Thread mode & PSP
+ __set_CONTROL(0x03U);
+ }
+}
+
/// Check if in Exception
/// \return true=exception, false=thread
__STATIC_INLINE bool_t IsException (void) {
@@ -361,8 +373,13 @@
#define SVC_ArgR(n,a) \
register uint32_t __r##n __ASM("r"#n) = (uint32_t)a
+#if (defined(RTX_SVC_PTR_CHECK) && !defined(_lint))
#define SVC_ArgF(f) \
-register uint32_t __rf __ASM(SVC_RegF) = (uint32_t)f
+register uint32_t __rf __ASM(SVC_RegF) = (uint32_t)jmpRtx##f
+#else
+#define SVC_ArgF(f) \
+register uint32_t __rf __ASM(SVC_RegF) = (uint32_t)svcRtx##f
+#endif
#define SVC_In0 "r"(__rf)
#define SVC_In1 "r"(__rf),"r"(__r0)
@@ -379,71 +396,117 @@
#define SVC_Call0(in, out, cl) \
__ASM volatile ("svc 0" : out : in : cl)
+#if (defined(RTX_SVC_PTR_CHECK) && !defined(_lint))
+#if ((defined(__ARM_ARCH_7M__) && (__ARM_ARCH_7M__ != 0)) || \
+ (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ != 0)) || \
+ (defined(__ARM_ARCH_8M_MAIN__) && (__ARM_ARCH_8M_MAIN__ != 0)) || \
+ (defined(__ARM_ARCH_8_1M_MAIN__) && (__ARM_ARCH_8_1M_MAIN__ != 0)))
+#define SVC_Jump(f) \
+ __ASM volatile ( \
+ ".align 2\n\t" \
+ "b.w %[adr]" : : [adr] "X" (f) \
+ )
+#elif ((defined(__ARM_ARCH_6M__) && (__ARM_ARCH_6M__ != 0)) || \
+ (defined(__ARM_ARCH_8M_BASE__) && (__ARM_ARCH_8M_BASE__ != 0)))
+#define SVC_Jump(f) \
+ __ASM volatile ( \
+ ".align 3\n\t" \
+ "ldr r7,1f\n\t" \
+ "bx r7\n" \
+ "1: .word %[adr]" : : [adr] "X" (f) \
+ )
+#endif
+#define SVC_Veneer_Prototye(f) \
+__STATIC_INLINE void jmpRtx##f (void);
+#define SVC_Veneer_Function(f) \
+__attribute__((naked,section(".text.os.svc.veneer."#f))) \
+__STATIC_INLINE void jmpRtx##f (void) { \
+ SVC_Jump(svcRtx##f); \
+}
+#else
+#define SVC_Veneer_Prototye(f)
+#define SVC_Veneer_Function(f)
+#endif
+
#define SVC0_0N(f,t) \
+SVC_Veneer_Prototye(f) \
__attribute__((always_inline)) \
__STATIC_INLINE t __svc##f (void) { \
- SVC_ArgF(svcRtx##f); \
+ SVC_ArgF(f); \
SVC_Call0(SVC_In0, SVC_Out0, SVC_CL1); \
-}
+} \
+SVC_Veneer_Function(f)
#define SVC0_0(f,t) \
+SVC_Veneer_Prototye(f) \
__attribute__((always_inline)) \
__STATIC_INLINE t __svc##f (void) { \
SVC_ArgN(0); \
- SVC_ArgF(svcRtx##f); \
+ SVC_ArgF(f); \
SVC_Call0(SVC_In0, SVC_Out1, SVC_CL0); \
return (t) __r0; \
-}
+} \
+SVC_Veneer_Function(f)
#define SVC0_1N(f,t,t1) \
+SVC_Veneer_Prototye(f) \
__attribute__((always_inline)) \
__STATIC_INLINE t __svc##f (t1 a1) { \
SVC_ArgR(0,a1); \
- SVC_ArgF(svcRtx##f); \
+ SVC_ArgF(f); \
SVC_Call0(SVC_In1, SVC_Out1, SVC_CL0); \
-}
+} \
+SVC_Veneer_Function(f)
#define SVC0_1(f,t,t1) \
+SVC_Veneer_Prototye(f) \
__attribute__((always_inline)) \
__STATIC_INLINE t __svc##f (t1 a1) { \
SVC_ArgR(0,a1); \
- SVC_ArgF(svcRtx##f); \
+ SVC_ArgF(f); \
SVC_Call0(SVC_In1, SVC_Out1, SVC_CL0); \
return (t) __r0; \
-}
+} \
+SVC_Veneer_Function(f)
#define SVC0_2(f,t,t1,t2) \
+SVC_Veneer_Prototye(f) \
__attribute__((always_inline)) \
__STATIC_INLINE t __svc##f (t1 a1, t2 a2) { \
SVC_ArgR(0,a1); \
SVC_ArgR(1,a2); \
- SVC_ArgF(svcRtx##f); \
+ SVC_ArgF(f); \
SVC_Call0(SVC_In2, SVC_Out1, SVC_CL0); \
return (t) __r0; \
-}
+} \
+SVC_Veneer_Function(f)
#define SVC0_3(f,t,t1,t2,t3) \
+SVC_Veneer_Prototye(f) \
__attribute__((always_inline)) \
__STATIC_INLINE t __svc##f (t1 a1, t2 a2, t3 a3) { \
SVC_ArgR(0,a1); \
SVC_ArgR(1,a2); \
SVC_ArgR(2,a3); \
- SVC_ArgF(svcRtx##f); \
+ SVC_ArgF(f); \
SVC_Call0(SVC_In3, SVC_Out1, SVC_CL0); \
return (t) __r0; \
-}
+} \
+SVC_Veneer_Function(f)
#define SVC0_4(f,t,t1,t2,t3,t4) \
+SVC_Veneer_Prototye(f) \
__attribute__((always_inline)) \
__STATIC_INLINE t __svc##f (t1 a1, t2 a2, t3 a3, t4 a4) { \
SVC_ArgR(0,a1); \
SVC_ArgR(1,a2); \
SVC_ArgR(2,a3); \
SVC_ArgR(3,a4); \
- SVC_ArgF(svcRtx##f); \
+ SVC_ArgF(f); \
SVC_Call0(SVC_In4, SVC_Out1, SVC_CL0); \
return (t) __r0; \
-}
+} \
+SVC_Veneer_Function(f)
#endif
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_evflags.c b/CMSIS/RTOS2/RTX/Source/rtx_evflags.c
index f2300e9..bc47fa1 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_evflags.c
+++ b/CMSIS/RTOS2/RTX/Source/rtx_evflags.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -133,6 +133,94 @@
return event_flags;
}
+/// Verify that Event Flags object pointer is valid.
+/// \param[in] ef event flags object.
+/// \return true - valid, false - invalid.
+static bool_t IsEventFlagsPtrValid (const os_event_flags_t *ef) {
+#ifdef RTX_OBJ_PTR_CHECK
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ uint32_t cb_start = (uint32_t)&__os_evflags_cb_start__;
+ uint32_t cb_length = (uint32_t)&__os_evflags_cb_length__;
+
+ // Check the section boundaries
+ if (((uint32_t)ef - cb_start) >= cb_length) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+ // Check the object alignment
+ if ((((uint32_t)ef - cb_start) % sizeof(os_event_flags_t)) != 0U) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#else
+ // Check NULL pointer
+ if (ef == NULL) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+
+// ==== Library functions ====
+
+/// Destroy an Event Flags object.
+/// \param[in] ef event flags object.
+static void osRtxEventFlagsDestroy (os_event_flags_t *ef) {
+
+ // Mark object as invalid
+ ef->id = osRtxIdInvalid;
+
+ // Free object memory
+ if ((ef->flags & osRtxFlagSystemObject) != 0U) {
+#ifdef RTX_OBJ_PTR_CHECK
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.event_flags, ef);
+#else
+ if (osRtxInfo.mpi.event_flags != NULL) {
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.event_flags, ef);
+ } else {
+ (void)osRtxMemoryFree(osRtxInfo.mem.common, ef);
+ }
+#endif
+#ifdef RTX_OBJ_MEM_USAGE
+ osRtxEventFlagsMemUsage.cnt_free++;
+#endif
+ }
+
+ EvrRtxEventFlagsDestroyed(ef);
+}
+
+#ifdef RTX_SAFETY_CLASS
+/// Delete an Event Flags safety class.
+/// \param[in] safety_class safety class.
+/// \param[in] mode safety mode.
+void osRtxEventFlagsDeleteClass (uint32_t safety_class, uint32_t mode) {
+ os_event_flags_t *ef;
+ os_thread_t *thread;
+ uint32_t length;
+
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ ef = (os_event_flags_t *)(uint32_t)&__os_evflags_cb_start__;
+ length = (uint32_t)&__os_evflags_cb_length__;
+ while (length >= sizeof(os_event_flags_t)) {
+ if ( (ef->id == osRtxIdEventFlags) &&
+ ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((ef->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((ef->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)))) {
+ while (ef->thread_list != NULL) {
+ thread = osRtxThreadListGet(osRtxObject(ef));
+ osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
+ }
+ osRtxEventFlagsDestroy(ef);
+ }
+ length -= sizeof(os_event_flags_t);
+ ef++;
+ }
+}
+#endif
+
// ==== Post ISR processing ====
@@ -163,18 +251,35 @@
/// Create and Initialize an Event Flags object.
/// \note API identical to osEventFlagsNew
static osEventFlagsId_t svcRtxEventFlagsNew (const osEventFlagsAttr_t *attr) {
- os_event_flags_t *ef;
- uint8_t flags;
- const char *name;
+ os_event_flags_t *ef;
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread = osRtxThreadGetRunning();
+ uint32_t attr_bits;
+#endif
+ uint8_t flags;
+ const char *name;
// Process attributes
if (attr != NULL) {
- name = attr->name;
+ name = attr->name;
+#ifdef RTX_SAFETY_CLASS
+ attr_bits = attr->attr_bits;
+#endif
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
- ef = attr->cb_mem;
+ ef = attr->cb_mem;
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) <
+ (uint8_t)((attr_bits & osSafetyClass_Msk) >> osSafetyClass_Pos))) {
+ EvrRtxEventFlagsError(NULL, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return NULL;
+ }
+ }
+#endif
if (ef != NULL) {
- //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
- if ((((uint32_t)ef & 3U) != 0U) || (attr->cb_size < sizeof(os_event_flags_t))) {
+ if (!IsEventFlagsPtrValid(ef) || (attr->cb_size != sizeof(os_event_flags_t))) {
EvrRtxEventFlagsError(NULL, osRtxErrorInvalidControlBlock);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -187,8 +292,11 @@
}
}
} else {
- name = NULL;
- ef = NULL;
+ name = NULL;
+#ifdef RTX_SAFETY_CLASS
+ attr_bits = 0U;
+#endif
+ ef = NULL;
}
// Allocate object memory if not provided
@@ -196,9 +304,11 @@
if (osRtxInfo.mpi.event_flags != NULL) {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
ef = osRtxMemoryPoolAlloc(osRtxInfo.mpi.event_flags);
+#ifndef RTX_OBJ_PTR_CHECK
} else {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
ef = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_event_flags_t), 1U);
+#endif
}
#ifdef RTX_OBJ_MEM_USAGE
if (ef != NULL) {
@@ -219,9 +329,21 @@
// Initialize control block
ef->id = osRtxIdEventFlags;
ef->flags = flags;
+ ef->attr = 0U;
ef->name = name;
ef->thread_list = NULL;
ef->event_flags = 0U;
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ ef->attr |= (uint8_t)((attr_bits & osSafetyClass_Msk) >>
+ (osSafetyClass_Pos - osRtxAttrClass_Pos));
+ } else {
+ // Inherit safety class from the running thread
+ if (thread != NULL) {
+ ef->attr |= (uint8_t)(thread->attr & osRtxAttrClass_Msk);
+ }
+ }
+#endif
// Register post ISR processing function
osRtxInfo.post_process.event_flags = osRtxEventFlagsPostProcess;
@@ -240,7 +362,7 @@
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
// Check parameters
- if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) {
+ if (!IsEventFlagsPtrValid(ef) || (ef->id != osRtxIdEventFlags)) {
EvrRtxEventFlagsGetName(ef, NULL);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -261,13 +383,24 @@
uint32_t event_flags0;
// Check parameters
- if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
+ if (!IsEventFlagsPtrValid(ef) || (ef->id != osRtxIdEventFlags) ||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return ((uint32_t)osErrorParameter);
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (ef->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxEventFlagsError(ef, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return ((uint32_t)osErrorSafetyClass);
+ }
+#endif
+
// Set Event Flags
event_flags = EventFlagsSet(ef, flags);
@@ -298,17 +431,31 @@
/// Clear the specified Event Flags.
/// \note API identical to osEventFlagsClear
static uint32_t svcRtxEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags) {
- os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
- uint32_t event_flags;
+ os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread;
+#endif
+ uint32_t event_flags;
// Check parameters
- if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
+ if (!IsEventFlagsPtrValid(ef) || (ef->id != osRtxIdEventFlags) ||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return ((uint32_t)osErrorParameter);
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (ef->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxEventFlagsError(ef, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return ((uint32_t)osErrorSafetyClass);
+ }
+#endif
+
// Clear Event Flags
event_flags = EventFlagsClear(ef, flags);
@@ -323,7 +470,7 @@
os_event_flags_t *ef = osRtxEventFlagsId(ef_id);
// Check parameters
- if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) {
+ if (!IsEventFlagsPtrValid(ef) || (ef->id != osRtxIdEventFlags)) {
EvrRtxEventFlagsGet(ef, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -342,13 +489,24 @@
uint32_t event_flags;
// Check parameters
- if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
+ if (!IsEventFlagsPtrValid(ef) || (ef->id != osRtxIdEventFlags) ||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return ((uint32_t)osErrorParameter);
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (ef->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxEventFlagsError(ef, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return ((uint32_t)osErrorSafetyClass);
+ }
+#endif
+
// Check Event Flags
event_flags = EventFlagsCheck(ef, flags, options);
if (event_flags != 0U) {
@@ -384,12 +542,23 @@
os_thread_t *thread;
// Check parameters
- if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) {
+ if (!IsEventFlagsPtrValid(ef) || (ef->id != osRtxIdEventFlags)) {
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (ef->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxEventFlagsError(ef, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Unblock waiting threads
if (ef->thread_list != NULL) {
do {
@@ -399,22 +568,7 @@
osRtxThreadDispatch(NULL);
}
- // Mark object as invalid
- ef->id = osRtxIdInvalid;
-
- // Free object memory
- if ((ef->flags & osRtxFlagSystemObject) != 0U) {
- if (osRtxInfo.mpi.event_flags != NULL) {
- (void)osRtxMemoryPoolFree(osRtxInfo.mpi.event_flags, ef);
- } else {
- (void)osRtxMemoryFree(osRtxInfo.mem.common, ef);
- }
-#ifdef RTX_OBJ_MEM_USAGE
- osRtxEventFlagsMemUsage.cnt_free++;
-#endif
- }
-
- EvrRtxEventFlagsDestroyed(ef);
+ osRtxEventFlagsDestroy(ef);
return osOK;
}
@@ -441,7 +595,7 @@
uint32_t event_flags;
// Check parameters
- if ((ef == NULL) || (ef->id != osRtxIdEventFlags) ||
+ if (!IsEventFlagsPtrValid(ef) || (ef->id != osRtxIdEventFlags) ||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
@@ -467,7 +621,7 @@
uint32_t event_flags;
// Check parameters
- if ((ef == NULL) || (ef->id != osRtxIdEventFlags) || (timeout != 0U) ||
+ if (!IsEventFlagsPtrValid(ef) || (ef->id != osRtxIdEventFlags) || (timeout != 0U) ||
((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) {
EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
@@ -508,10 +662,9 @@
const char *name;
if (IsException() || IsIrqMasked()) {
- EvrRtxEventFlagsGetName(ef_id, NULL);
- name = NULL;
+ name = svcRtxEventFlagsGetName(ef_id);
} else {
- name = __svcEventFlagsGetName(ef_id);
+ name = __svcEventFlagsGetName(ef_id);
}
return name;
}
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_evr.c b/CMSIS/RTOS2/RTX/Source/rtx_evr.c
index 55b55a7..ec0671f 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_evr.c
+++ b/CMSIS/RTOS2/RTX/Source/rtx_evr.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -59,11 +59,14 @@
#define EvtRtxKernelSuspended EventID(EventLevelOp, EvtRtxKernelNo, 0x10U)
#define EvtRtxKernelResume EventID(EventLevelAPI, EvtRtxKernelNo, 0x11U)
#define EvtRtxKernelResumed EventID(EventLevelOp, EvtRtxKernelNo, 0x12U)
+#define EvtRtxKernelProtect EventID(EventLevelAPI, EvtRtxKernelNo, 0x17U)
+#define EvtRtxKernelProtected EventID(EventLevelOp, EvtRtxKernelNo, 0x18U)
#define EvtRtxKernelGetTickCount EventID(EventLevelAPI, EvtRtxKernelNo, 0x13U)
#define EvtRtxKernelGetTickFreq EventID(EventLevelAPI, EvtRtxKernelNo, 0x14U)
#define EvtRtxKernelGetSysTimerCount EventID(EventLevelAPI, EvtRtxKernelNo, 0x15U)
#define EvtRtxKernelGetSysTimerFreq EventID(EventLevelAPI, EvtRtxKernelNo, 0x16U)
#define EvtRtxKernelErrorNotify EventID(EventLevelError, EvtRtxKernelNo, 0x19U)
+#define EvtRtxKernelDestroyClass EventID(EventLevelAPI, EvtRtxKernelNo, 0x1AU)
/// Event IDs for "RTX Thread"
#define EvtRtxThreadError EventID(EventLevelError, EvtRtxThreadNo, 0x00U)
@@ -71,6 +74,8 @@
#define EvtRtxThreadCreated_Addr EventID(EventLevelOp, EvtRtxThreadNo, 0x03U)
#define EvtRtxThreadCreated_Name EventID(EventLevelOp, EvtRtxThreadNo, 0x2CU)
#define EvtRtxThreadGetName EventID(EventLevelAPI, EvtRtxThreadNo, 0x04U)
+#define EvtRtxThreadGetClass EventID(EventLevelAPI, EvtRtxThreadNo, 0x30U)
+#define EvtRtxThreadGetZone EventID(EventLevelAPI, EvtRtxThreadNo, 0x31U)
#define EvtRtxThreadGetId EventID(EventLevelAPI, EvtRtxThreadNo, 0x06U)
#define EvtRtxThreadGetState EventID(EventLevelAPI, EvtRtxThreadNo, 0x07U)
#define EvtRtxThreadGetStackSize EventID(EventLevelAPI, EvtRtxThreadNo, 0x08U)
@@ -95,8 +100,16 @@
#define EvtRtxThreadExit EventID(EventLevelAPI, EvtRtxThreadNo, 0x1AU)
#define EvtRtxThreadTerminate EventID(EventLevelAPI, EvtRtxThreadNo, 0x1BU)
#define EvtRtxThreadDestroyed EventID(EventLevelOp, EvtRtxThreadNo, 0x1CU)
+#define EvtRtxThreadFeedWatchdog EventID(EventLevelAPI, EvtRtxThreadNo, 0x2EU)
+#define EvtRtxThreadFeedWatchdogDone EventID(EventLevelOp, EvtRtxThreadNo, 0x2FU)
+#define EvtRtxThreadProtectPrivileged EventID(EventLevelAPI, EvtRtxThreadNo, 0x32U)
+#define EvtRtxThreadPrivilegedProtected EventID(EventLevelOp, EvtRtxThreadNo, 0x33U)
#define EvtRtxThreadGetCount EventID(EventLevelAPI, EvtRtxThreadNo, 0x1DU)
#define EvtRtxThreadEnumerate EventID(EventLevelAPI, EvtRtxThreadNo, 0x1EU)
+#define EvtRtxThreadSuspendClass EventID(EventLevelAPI, EvtRtxThreadNo, 0x34U)
+#define EvtRtxThreadResumeClass EventID(EventLevelAPI, EvtRtxThreadNo, 0x35U)
+#define EvtRtxThreadTerminateZone EventID(EventLevelAPI, EvtRtxThreadNo, 0x36U)
+#define EvtRtxThreadWatchdogExpired EventID(EventLevelError, EvtRtxThreadNo, 0x37U)
/// Event IDs for "RTX Thread Flags"
#define EvtRtxThreadFlagsError EventID(EventLevelError, EvtRtxThreadFlagsNo, 0x00U)
@@ -492,6 +505,24 @@
}
#endif
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_KERNEL != 0) && !defined(EVR_RTX_KERNEL_PROTECT_DISABLE))
+__WEAK void EvrRtxKernelProtect (uint32_t safety_class) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxKernelProtect, safety_class, 0U);
+#else
+ (void)safety_class;
+#endif
+}
+#endif
+
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_KERNEL != 0) && !defined(EVR_RTX_KERNEL_PROTECTED_DISABLE))
+__WEAK void EvrRtxKernelProtected (void) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxKernelProtected, 0U, 0U);
+#endif
+}
+#endif
+
#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_KERNEL != 0) && !defined(EVR_RTX_KERNEL_GET_TICK_COUNT_DISABLE))
__WEAK void EvrRtxKernelGetTickCount (uint32_t count) {
#if defined(RTE_Compiler_EventRecorder)
@@ -543,6 +574,17 @@
}
#endif
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_KERNEL != 0) && !defined(EVR_RTX_KERNEL_DESTROY_CLASS_DISABLE))
+__WEAK void EvrRtxKernelDestroyClass (uint32_t safety_class, uint32_t mode) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxKernelDestroyClass, safety_class, mode);
+#else
+ (void)safety_class;
+ (void)mode;
+#endif
+}
+#endif
+
// ==== Thread Events ====
@@ -596,6 +638,28 @@
}
#endif
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_GET_CLASS_DISABLE))
+__WEAK void EvrRtxThreadGetClass (osThreadId_t thread_id, uint32_t safety_class) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxThreadGetClass, (uint32_t)thread_id, safety_class);
+#else
+ (void)thread_id;
+ (void)safety_class;
+#endif
+}
+#endif
+
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_GET_ZONE_DISABLE))
+__WEAK void EvrRtxThreadGetZone (osThreadId_t thread_id, uint32_t zone) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxThreadGetZone, (uint32_t)thread_id, zone);
+#else
+ (void)thread_id;
+ (void)zone;
+#endif
+}
+#endif
+
#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_GET_ID_DISABLE))
__WEAK void EvrRtxThreadGetId (osThreadId_t thread_id) {
#if defined(RTE_Compiler_EventRecorder)
@@ -842,6 +906,40 @@
}
#endif
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_FEED_WATCHDOG_DISABLE))
+__WEAK void EvrRtxThreadFeedWatchdog (uint32_t ticks) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxThreadFeedWatchdog, ticks, 0U);
+#else
+ (void)ticks;
+#endif
+}
+#endif
+
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_FEED_WATCHDOG_DONE_DISABLE))
+__WEAK void EvrRtxThreadFeedWatchdogDone (void) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxThreadFeedWatchdogDone, 0U, 0U);
+#endif
+}
+#endif
+
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_PROTECT_PRIVILEGED_DISABLE))
+__WEAK void EvrRtxThreadProtectPrivileged (void) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxThreadProtectPrivileged, 0U, 0U);
+#endif
+}
+#endif
+
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_PRIVILEGED_PROTECTED_DISABLE))
+__WEAK void EvrRtxThreadPrivilegedProtected (void) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxThreadPrivilegedProtected, 0U, 0U);
+#endif
+}
+#endif
+
#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_GET_COUNT_DISABLE))
__WEAK void EvrRtxThreadGetCount (uint32_t count) {
#if defined(RTE_Compiler_EventRecorder)
@@ -864,6 +962,48 @@
}
#endif
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_SUSPEND_CLASS_DISABLE))
+__WEAK void EvrRtxThreadSuspendClass (uint32_t safety_class, uint32_t mode) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxThreadSuspendClass, safety_class, (uint32_t)mode);
+#else
+ (void)safety_class;
+ (void)mode;
+#endif
+}
+#endif
+
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_RESUME_CLASS_DISABLE))
+__WEAK void EvrRtxThreadResumeClass (uint32_t safety_class, uint32_t mode) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxThreadResumeClass, safety_class, (uint32_t)mode);
+#else
+ (void)safety_class;
+ (void)mode;
+#endif
+}
+#endif
+
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_TERMINATE_ZONE_DISABLE))
+__WEAK void EvrRtxThreadTerminateZone (uint32_t zone) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxThreadTerminateZone, zone, 0U);
+#else
+ (void)zone;
+#endif
+}
+#endif
+
+#if (!defined(EVR_RTX_DISABLE) && (OS_EVR_THREAD != 0) && !defined(EVR_RTX_THREAD_WATCHDOG_EXPIRED_DISABLE))
+__WEAK void EvrRtxThreadWatchdogExpired (osThreadId_t thread_id) {
+#if defined(RTE_Compiler_EventRecorder)
+ (void)EventRecord2(EvtRtxThreadWatchdogExpired, (uint32_t)thread_id, 0U);
+#else
+ (void)thread_id;
+#endif
+}
+#endif
+
// ==== Thread Flags Events ====
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_kernel.c b/CMSIS/RTOS2/RTX/Source/rtx_kernel.c
index f7b24f9..50f3610 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_kernel.c
+++ b/CMSIS/RTOS2/RTX/Source/rtx_kernel.c
@@ -76,6 +76,16 @@
delay = thread->delay;
}
+#ifdef RTX_THREAD_WATCHDOG
+ // Check Thread Watchdog list
+ thread = osRtxInfo.thread.wdog_list;
+ if (thread != NULL) {
+ if (thread->wdog_tick < delay) {
+ delay = thread->wdog_tick;
+ }
+ }
+#endif
+
// Check Active Timer list
timer = osRtxInfo.timer.list;
if (timer != NULL) {
@@ -115,6 +125,7 @@
#endif
// Initialize osRtxInfo
+ (void)memset(&osRtxInfo.kernel, 0, sizeof(osRtxInfo) - offsetof(osRtxInfo_t, kernel));
osRtxInfo.isr_queue.data = osRtxConfig.isr_queue.data;
osRtxInfo.isr_queue.max = osRtxConfig.isr_queue.max;
@@ -274,14 +285,6 @@
thread = osRtxThreadListGet(&osRtxInfo.thread.ready);
osRtxThreadSwitch(thread);
- if ((osRtxConfig.flags & osRtxConfigPrivilegedMode) != 0U) {
- // Privileged Thread mode & PSP
- __set_CONTROL(0x02U);
- } else {
- // Unprivileged Thread mode & PSP
- __set_CONTROL(0x03U);
- }
-
osRtxInfo.kernel.state = osRtxKernelRunning;
EvrRtxKernelStarted();
@@ -296,6 +299,15 @@
switch (osRtxInfo.kernel.state) {
case osRtxKernelRunning:
+#ifdef RTX_SAFETY_CLASS
+ // Check the safety class
+ if ((osRtxThreadGetRunning()->attr >> osRtxAttrClass_Pos) <
+ (osRtxInfo.kernel.protect >> osRtxKernelProtectClass_Pos)) {
+ EvrRtxKernelError((int32_t)osErrorSafetyClass);
+ lock = (int32_t)osErrorSafetyClass;
+ break;
+ }
+#endif
osRtxInfo.kernel.state = osRtxKernelLocked;
EvrRtxKernelLocked(0);
lock = 0;
@@ -343,6 +355,15 @@
switch (osRtxInfo.kernel.state) {
case osRtxKernelRunning:
case osRtxKernelLocked:
+#ifdef RTX_SAFETY_CLASS
+ // Check the safety class
+ if ((osRtxThreadGetRunning()->attr >> osRtxAttrClass_Pos) <
+ (osRtxInfo.kernel.protect >> osRtxKernelProtectClass_Pos)) {
+ EvrRtxKernelError((int32_t)osErrorSafetyClass);
+ lock_new = (int32_t)osErrorSafetyClass;
+ break;
+ }
+#endif
switch (lock) {
case 0:
osRtxInfo.kernel.state = osRtxKernelRunning;
@@ -379,6 +400,16 @@
return 0U;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check the safety class
+ if ((osRtxThreadGetRunning()->attr >> osRtxAttrClass_Pos) <
+ (osRtxInfo.kernel.protect >> osRtxKernelProtectClass_Pos)) {
+ EvrRtxKernelError((int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return 0U;
+ }
+#endif
+
KernelBlock();
osRtxInfo.kernel.state = osRtxKernelSuspended;
@@ -423,6 +454,14 @@
timer->tick -= ticks;
}
+#ifdef RTX_THREAD_WATCHDOG
+ // Update Thread Watchdog sleep ticks
+ thread = osRtxInfo.thread.wdog_list;
+ if (thread != NULL) {
+ thread->wdog_tick -= ticks;
+ }
+#endif
+
kernel_tick = osRtxInfo.kernel.tick + sleep_ticks;
osRtxInfo.kernel.tick += ticks;
@@ -436,6 +475,11 @@
if (osRtxInfo.timer.tick != NULL) {
osRtxInfo.timer.tick();
}
+
+#ifdef RTX_THREAD_WATCHDOG
+ // Process Watchdog Timers
+ osRtxThreadWatchdogTick();
+#endif
}
osRtxInfo.kernel.state = osRtxKernelRunning;
@@ -447,6 +491,196 @@
EvrRtxKernelResumed();
}
+#ifdef RTX_SAFETY_CLASS
+
+/// Protect the RTOS Kernel scheduler access.
+/// \note API identical to osKernelProtect
+static osStatus_t svcRtxKernelProtect (uint32_t safety_class) {
+ uint32_t thread_class;
+ osStatus_t status;
+
+ // Check parameters
+ if (safety_class > 0x0FU) {
+ EvrRtxKernelError((int32_t)osErrorParameter);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorParameter;
+ }
+
+ switch (osRtxInfo.kernel.state) {
+ case osRtxKernelInactive:
+ EvrRtxKernelError(osRtxErrorKernelNotReady);
+ status = osError;
+ break;
+ case osRtxKernelReady:
+ osRtxInfo.kernel.protect &= (uint8_t)~osRtxKernelProtectClass_Msk;
+ osRtxInfo.kernel.protect |= (uint8_t)(safety_class << osRtxKernelProtectClass_Pos);
+ EvrRtxKernelProtected();
+ status = osOK;
+ break;
+ case osRtxKernelRunning:
+ // Check the safety class
+ thread_class = (uint32_t)osRtxThreadGetRunning()->attr >> osRtxAttrClass_Pos;
+ if ((safety_class > thread_class) ||
+ (thread_class < ((uint32_t)osRtxInfo.kernel.protect >> osRtxKernelProtectClass_Pos))) {
+ EvrRtxKernelError((int32_t)osErrorSafetyClass);
+ status = osErrorSafetyClass;
+ break;
+ }
+ osRtxInfo.kernel.protect &= (uint8_t)~osRtxKernelProtectClass_Msk;
+ osRtxInfo.kernel.protect |= (uint8_t)(safety_class << osRtxKernelProtectClass_Pos);
+ EvrRtxKernelProtected();
+ status = osOK;
+ break;
+ case osRtxKernelLocked:
+ case osRtxKernelSuspended:
+ EvrRtxKernelError(osRtxErrorKernelNotRunning);
+ status = osError;
+ break;
+ default:
+ // Should never come here
+ status = osError;
+ break;
+ }
+
+ return status;
+}
+
+/// Destroy objects for specified safety classes.
+/// \note API identical to osKernelDestroyClass
+static osStatus_t svcRtxKernelDestroyClass (uint32_t safety_class, uint32_t mode) {
+ os_thread_t *thread;
+ os_thread_t *thread_next;
+
+ // Check parameters
+ if (safety_class > 0x0FU) {
+ EvrRtxKernelError((int32_t)osErrorParameter);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorParameter;
+ }
+
+ // Check running thread safety class (when called from thread)
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) && IsSVCallIrq()) {
+ if ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ (((thread->attr >> osRtxAttrClass_Pos) + 1U) < (uint8_t)safety_class))) {
+ EvrRtxKernelError((int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+ }
+
+ // Delete RTOS objects for safety class
+ osRtxMutexDeleteClass(safety_class, mode);
+ osRtxSemaphoreDeleteClass(safety_class, mode);
+ osRtxMemoryPoolDeleteClass(safety_class, mode);
+ osRtxMessageQueueDeleteClass(safety_class, mode);
+ osRtxEventFlagsDeleteClass(safety_class, mode);
+ osRtxTimerDeleteClass(safety_class, mode);
+
+ // Threads in Wait List
+ thread = osRtxInfo.thread.wait_list;
+ while (thread != NULL) {
+ thread_next = thread->delay_next;
+ if ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class))) {
+ osRtxThreadListRemove(thread);
+ osRtxThreadDelayRemove(thread);
+#ifdef RTX_THREAD_WATCHDOG
+ osRtxThreadWatchdogRemove(thread);
+#endif
+ osRtxMutexOwnerRelease(thread->mutex_list);
+ osRtxThreadJoinWakeup(thread);
+ osRtxThreadDestroy(thread);
+ }
+ thread = thread_next;
+ }
+
+ // Threads in Delay List
+ thread = osRtxInfo.thread.delay_list;
+ while (thread != NULL) {
+ thread_next = thread->delay_next;
+ if ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class))) {
+ osRtxThreadListRemove(thread);
+ osRtxThreadDelayRemove(thread);
+#ifdef RTX_THREAD_WATCHDOG
+ osRtxThreadWatchdogRemove(thread);
+#endif
+ osRtxMutexOwnerRelease(thread->mutex_list);
+ osRtxThreadJoinWakeup(thread);
+ osRtxThreadDestroy(thread);
+ }
+ thread = thread_next;
+ }
+
+ // Threads in Ready List
+ thread = osRtxInfo.thread.ready.thread_list;
+ while (thread != NULL) {
+ thread_next = thread->thread_next;
+ if ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class))) {
+ osRtxThreadListRemove(thread);
+#ifdef RTX_THREAD_WATCHDOG
+ osRtxThreadWatchdogRemove(thread);
+#endif
+ osRtxMutexOwnerRelease(thread->mutex_list);
+ osRtxThreadJoinWakeup(thread);
+ osRtxThreadDestroy(thread);
+ }
+ thread = thread_next;
+ }
+
+ // Running Thread
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)))) {
+ if ((osRtxKernelGetState() != osRtxKernelRunning) ||
+ (osRtxInfo.thread.ready.thread_list == NULL)) {
+ osRtxThreadDispatch(NULL);
+ EvrRtxKernelError((int32_t)osErrorResource);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorResource;
+ }
+#ifdef RTX_THREAD_WATCHDOG
+ osRtxThreadWatchdogRemove(thread);
+#endif
+ osRtxMutexOwnerRelease(thread->mutex_list);
+ osRtxThreadJoinWakeup(thread);
+ // Switch to next Ready Thread
+ osRtxThreadSwitch(osRtxThreadListGet(&osRtxInfo.thread.ready));
+ // Update Stack Pointer
+ thread->sp = __get_PSP();
+#ifdef RTX_STACK_CHECK
+ // Check Stack usage
+ if (!osRtxThreadStackCheck(thread)) {
+ osRtxThreadSetRunning(osRtxInfo.thread.run.next);
+ (void)osRtxKernelErrorNotify(osRtxErrorStackOverflow, thread);
+ }
+#endif
+ // Mark running thread as deleted
+ osRtxThreadSetRunning(NULL);
+ // Destroy Thread
+ osRtxThreadDestroy(thread);
+ } else {
+ osRtxThreadDispatch(NULL);
+ }
+
+ return osOK;
+}
+
+#endif
+
/// Get the RTOS kernel tick count.
/// \note API identical to osKernelGetTickCount
static uint32_t svcRtxKernelGetTickCount (void) {
@@ -496,6 +730,10 @@
SVC0_1 (KernelRestoreLock, int32_t, int32_t)
SVC0_0 (KernelSuspend, uint32_t)
SVC0_1N(KernelResume, void, uint32_t)
+#ifdef RTX_SAFETY_CLASS
+SVC0_1 (KernelProtect, osStatus_t, uint32_t)
+SVC0_2 (KernelDestroyClass, osStatus_t, uint32_t, uint32_t)
+#endif
SVC0_0 (KernelGetState, osKernelState_t)
SVC0_0 (KernelGetTickCount, uint32_t)
SVC0_0 (KernelGetTickFreq, uint32_t)
@@ -644,6 +882,42 @@
}
}
+#ifdef RTX_SAFETY_CLASS
+
+/// Protect the RTOS Kernel scheduler access.
+osStatus_t osKernelProtect (uint32_t safety_class) {
+ osStatus_t status;
+
+ EvrRtxKernelProtect(safety_class);
+ if (IsException() || IsIrqMasked()) {
+ EvrRtxKernelError((int32_t)osErrorISR);
+ status = osErrorISR;
+ } else {
+ status = __svcKernelProtect(safety_class);
+ }
+ return status;
+}
+
+/// Destroy RTOS objects for specified safety classes.
+osStatus_t osKernelDestroyClass (uint32_t safety_class, uint32_t mode) {
+ osStatus_t status;
+
+ EvrRtxKernelDestroyClass(safety_class, mode);
+ if (IsException() || IsIrqMasked()) {
+ if (IsTickIrq(osRtxInfo.tick_irqn)) {
+ status = svcRtxKernelDestroyClass(safety_class, mode);
+ } else {
+ EvrRtxKernelError((int32_t)osErrorISR);
+ status = osErrorISR;
+ }
+ } else {
+ status = __svcKernelDestroyClass(safety_class, mode);
+ }
+ return status;
+}
+
+#endif
+
/// Get the RTOS kernel tick count.
uint32_t osKernelGetTickCount (void) {
uint32_t count;
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_lib.c b/CMSIS/RTOS2/RTX/Source/rtx_lib.c
index 81ed07d..07a9f48 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_lib.c
+++ b/CMSIS/RTOS2/RTX/Source/rtx_lib.c
@@ -126,11 +126,18 @@
// Idle Thread Attributes
static const osThreadAttr_t os_idle_thread_attr = {
+ //lint -e{835} -e{845} "Zero argument to operator"
#if defined(OS_IDLE_THREAD_NAME)
OS_IDLE_THREAD_NAME,
#else
NULL,
#endif
+#ifdef RTX_SAFETY_CLASS
+ osSafetyClass((uint32_t)OS_IDLE_THREAD_CLASS) |
+#endif
+#ifdef RTX_EXECUTION_ZONE
+ osThreadZone((uint32_t)OS_IDLE_THREAD_ZONE) |
+#endif
osThreadDetached,
&os_idle_thread_cb,
(uint32_t)sizeof(os_idle_thread_cb),
@@ -183,11 +190,18 @@
// Timer Thread Attributes
static const osThreadAttr_t os_timer_thread_attr = {
+ //lint -e{835} -e{845} "Zero argument to operator"
#if defined(OS_TIMER_THREAD_NAME)
OS_TIMER_THREAD_NAME,
#else
NULL,
#endif
+#ifdef RTX_SAFETY_CLASS
+ osSafetyClass((uint32_t)OS_TIMER_THREAD_CLASS) |
+#endif
+#ifdef RTX_EXECUTION_ZONE
+ osThreadZone((uint32_t)OS_TIMER_THREAD_ZONE) |
+#endif
osThreadDetached,
&os_timer_thread_cb,
(uint32_t)sizeof(os_timer_thread_cb),
@@ -213,7 +227,11 @@
// Timer Message Queue Attributes
static const osMessageQueueAttr_t os_timer_mq_attr = {
+ //lint -e{835} -e{845} "Zero argument to operator"
NULL,
+#ifdef RTX_SAFETY_CLASS
+ osSafetyClass((uint32_t)OS_TIMER_THREAD_CLASS) |
+#endif
0U,
&os_timer_mq_cb,
(uint32_t)sizeof(os_timer_mq_cb),
@@ -435,6 +453,24 @@
#if (OS_STACK_WATERMARK != 0)
| osRtxConfigStackWatermark
#endif
+#ifdef RTX_SAFETY_FEATURES
+ | osRtxConfigSafetyFeatures
+ #ifdef RTX_SAFETY_CLASS
+ | osRtxConfigSafetyClass
+ #endif
+ #ifdef RTX_EXECUTION_ZONE
+ | osRtxConfigExecutionZone
+ #endif
+ #ifdef RTX_THREAD_WATCHDOG
+ | osRtxConfigThreadWatchdog
+ #endif
+ #ifdef RTX_OBJ_PTR_CHECK
+ | osRtxConfigObjPtrCheck
+ #endif
+ #ifdef RTX_SVC_PTR_CHECK
+ | osRtxConfigSVCPtrCheck
+ #endif
+#endif
,
(uint32_t)OS_TICK_FREQ,
#if (OS_ROBIN_ENABLE != 0)
@@ -543,6 +579,31 @@
extern void * const osRtxUserSVC[];
__WEAK void * const osRtxUserSVC[1] = { (void *)0 };
+#if (defined(RTX_SAFETY_CLASS) && defined(RTX_OBJ_PTR_CHECK) && \
+ !((OS_TIMER_THREAD_STACK_SIZE != 0) && (OS_TIMER_CB_QUEUE != 0)))
+extern void osRtxTimerDeleteClass(uint32_t safety_class, uint32_t mode);
+// Default Timer Delete Class Function.
+__WEAK void osRtxTimerDeleteClass(uint32_t safety_class, uint32_t mode) {
+ (void)safety_class;
+ (void)mode;
+}
+#endif
+
+#ifdef RTX_THREAD_WATCHDOG
+// Default Watchdog Alarm Handler.
+__WEAK uint32_t osWatchdogAlarm_Handler (osThreadId_t thread_id) {
+ (void)thread_id;
+ return 0U;
+}
+#endif
+
+#ifdef RTX_EXECUTION_ZONE
+// Default Zone Setup Function.
+__WEAK void osZoneSetup_Callback (uint32_t zone) {
+ (void)zone;
+}
+#endif
+
// OS Sections
// ===========
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_lib.h b/CMSIS/RTOS2/RTX/Source/rtx_lib.h
index 54cfcf7..5af8221 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_lib.h
+++ b/CMSIS/RTOS2/RTX/Source/rtx_lib.h
@@ -54,6 +54,75 @@
#define os_message_queue_t osRtxMessageQueue_t
#define os_object_t osRtxObject_t
+
+// ==== Library sections ====
+
+#if defined(__CC_ARM) || \
+ (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
+// Referenced through linker
+//lint -esym(528, __os_thread_cb_start__, __os_thread_cb_length__)
+//lint -esym(528, __os_timer_cb_start__, __os_timer_cb_length__)
+//lint -esym(528, __os_evflags_cb_start__, __os_evflags_cb_length__)
+//lint -esym(528, __os_mutex_cb_start__, __os_mutex_cb_length__)
+//lint -esym(528, __os_semaphore_cb_start__, __os_semaphore_cb_length__)
+//lint -esym(528, __os_mempool_cb_start__, __os_mempool_cb_length__)
+//lint -esym(528, __os_msgqueue_cb_start__, __os_msgqueue_cb_length__)
+// Accessed through linker
+//lint -esym(551, __os_thread_cb_start__, __os_thread_cb_length__)
+//lint -esym(551, __os_timer_cb_start__, __os_timer_cb_length__)
+//lint -esym(551, __os_evflags_cb_start__, __os_evflags_cb_length__)
+//lint -esym(551, __os_mutex_cb_start__, __os_mutex_cb_length__)
+//lint -esym(551, __os_semaphore_cb_start__, __os_semaphore_cb_length__)
+//lint -esym(551, __os_mempool_cb_start__, __os_mempool_cb_length__)
+//lint -esym(551, __os_msgqueue_cb_start__, __os_msgqueue_cb_length__)
+// Initialized through linker
+//lint -esym(728, __os_thread_cb_start__, __os_thread_cb_length__)
+//lint -esym(728, __os_timer_cb_start__, __os_timer_cb_length__)
+//lint -esym(728, __os_evflags_cb_start__, __os_evflags_cb_length__)
+//lint -esym(728, __os_mutex_cb_start__, __os_mutex_cb_length__)
+//lint -esym(728, __os_semaphore_cb_start__, __os_semaphore_cb_length__)
+//lint -esym(728, __os_mempool_cb_start__, __os_mempool_cb_length__)
+//lint -esym(728, __os_msgqueue_cb_start__, __os_msgqueue_cb_length__)
+// Global scope
+//lint -esym(9003, __os_thread_cb_start__, __os_thread_cb_length__)
+//lint -esym(9003, __os_timer_cb_start__, __os_timer_cb_length__)
+//lint -esym(9003, __os_evflags_cb_start__, __os_evflags_cb_length__)
+//lint -esym(9003, __os_mutex_cb_start__, __os_mutex_cb_length__)
+//lint -esym(9003, __os_semaphore_cb_start__, __os_semaphore_cb_length__)
+//lint -esym(9003, __os_mempool_cb_start__, __os_mempool_cb_length__)
+//lint -esym(9003, __os_msgqueue_cb_start__, __os_msgqueue_cb_length__)
+static const uint32_t __os_thread_cb_start__ __attribute__((weakref(".bss.os.thread.cb$$Base")));
+static const uint32_t __os_thread_cb_length__ __attribute__((weakref(".bss.os.thread.cb$$Length")));
+static const uint32_t __os_timer_cb_start__ __attribute__((weakref(".bss.os.timer.cb$$Base")));
+static const uint32_t __os_timer_cb_length__ __attribute__((weakref(".bss.os.timer.cb$$Length")));
+static const uint32_t __os_evflags_cb_start__ __attribute__((weakref(".bss.os.evflags.cb$$Base")));
+static const uint32_t __os_evflags_cb_length__ __attribute__((weakref(".bss.os.evflags.cb$$Length")));
+static const uint32_t __os_mutex_cb_start__ __attribute__((weakref(".bss.os.mutex.cb$$Base")));
+static const uint32_t __os_mutex_cb_length__ __attribute__((weakref(".bss.os.mutex.cb$$Length")));
+static const uint32_t __os_semaphore_cb_start__ __attribute__((weakref(".bss.os.semaphore.cb$$Base")));
+static const uint32_t __os_semaphore_cb_length__ __attribute__((weakref(".bss.os.semaphore.cb$$Length")));
+static const uint32_t __os_mempool_cb_start__ __attribute__((weakref(".bss.os.mempool.cb$$Base")));
+static const uint32_t __os_mempool_cb_length__ __attribute__((weakref(".bss.os.mempool.cb$$Length")));
+static const uint32_t __os_msgqueue_cb_start__ __attribute__((weakref(".bss.os.msgqueue.cb$$Base")));
+static const uint32_t __os_msgqueue_cb_length__ __attribute__((weakref(".bss.os.msgqueue.cb$$Length")));
+#else
+extern const uint32_t __os_thread_cb_start__ __attribute__((weak));
+extern const uint32_t __os_thread_cb_length__ __attribute__((weak));
+extern const uint32_t __os_timer_cb_start__ __attribute__((weak));
+extern const uint32_t __os_timer_cb_length__ __attribute__((weak));
+extern const uint32_t __os_evflags_cb_start__ __attribute__((weak));
+extern const uint32_t __os_evflags_cb_length__ __attribute__((weak));
+extern const uint32_t __os_mutex_cb_start__ __attribute__((weak));
+extern const uint32_t __os_mutex_cb_length__ __attribute__((weak));
+extern const uint32_t __os_semaphore_cb_start__ __attribute__((weak));
+extern const uint32_t __os_semaphore_cb_length__ __attribute__((weak));
+extern const uint32_t __os_mempool_cb_start__ __attribute__((weak));
+extern const uint32_t __os_mempool_cb_length__ __attribute__((weak));
+extern const uint32_t __os_msgqueue_cb_start__ __attribute__((weak));
+extern const uint32_t __os_msgqueue_cb_length__ __attribute__((weak));
+#endif
+
+
// ==== Inline functions ====
// Thread ID
@@ -175,33 +244,64 @@
// ==== Library functions ====
// Kernel Library functions
-extern void osRtxKernelBeforeInit (void);
+extern void osRtxKernelBeforeInit (void);
// Thread Library functions
-extern void osRtxThreadListPut (os_object_t *object, os_thread_t *thread);
-extern os_thread_t *osRtxThreadListGet (os_object_t *object);
-extern void osRtxThreadListSort (os_thread_t *thread);
-extern void osRtxThreadListRemove (os_thread_t *thread);
-extern void osRtxThreadReadyPut (os_thread_t *thread);
-extern void osRtxThreadDelayTick (void);
-extern uint32_t *osRtxThreadRegPtr (const os_thread_t *thread);
-extern void osRtxThreadSwitch (os_thread_t *thread);
-extern void osRtxThreadDispatch (os_thread_t *thread);
-extern void osRtxThreadWaitExit (os_thread_t *thread, uint32_t ret_val, bool_t dispatch);
-extern bool_t osRtxThreadWaitEnter (uint8_t state, uint32_t timeout);
+extern void osRtxThreadListPut (os_object_t *object, os_thread_t *thread);
+extern os_thread_t *osRtxThreadListGet (os_object_t *object);
+extern void osRtxThreadListSort (os_thread_t *thread);
+extern void osRtxThreadListRemove (os_thread_t *thread);
+extern void osRtxThreadReadyPut (os_thread_t *thread);
+//lint -esym(759,osRtxThreadDelayRemove) "Prototype in header"
+//lint -esym(765,osRtxThreadDelayRemove) "Global scope"
+extern void osRtxThreadDelayRemove (os_thread_t *thread);
+extern void osRtxThreadDelayTick (void);
+extern uint32_t *osRtxThreadRegPtr (const os_thread_t *thread);
+extern void osRtxThreadSwitch (os_thread_t *thread);
+extern void osRtxThreadDispatch (os_thread_t *thread);
+extern void osRtxThreadWaitExit (os_thread_t *thread, uint32_t ret_val, bool_t dispatch);
+extern bool_t osRtxThreadWaitEnter (uint8_t state, uint32_t timeout);
#ifdef RTX_STACK_CHECK
-extern bool_t osRtxThreadStackCheck (const os_thread_t *thread);
+extern bool_t osRtxThreadStackCheck (const os_thread_t *thread);
#endif
-extern void osRtxThreadBeforeFree (os_thread_t *thread);
-extern bool_t osRtxThreadStartup (void);
+#ifdef RTX_THREAD_WATCHDOG
+//lint -esym(759,osRtxThreadWatchdogRemove) "Prototype in header"
+//lint -esym(765,osRtxThreadWatchdogRemove) "Global scope"
+extern void osRtxThreadWatchdogRemove(const os_thread_t *thread);
+extern void osRtxThreadWatchdogTick (void);
+#endif
+//lint -esym(759,osRtxThreadJoinWakeup) "Prototype in header"
+//lint -esym(765,osRtxThreadJoinWakeup) "Global scope"
+extern void osRtxThreadJoinWakeup (const os_thread_t *thread);
+//lint -esym(759,osRtxThreadDestroy) "Prototype in header"
+//lint -esym(765,osRtxThreadDestroy) "Global scope"
+extern void osRtxThreadDestroy (os_thread_t *thread);
+extern void osRtxThreadBeforeFree (os_thread_t *thread);
+extern bool_t osRtxThreadStartup (void);
// Timer Library functions
-extern int32_t osRtxTimerSetup (void);
-extern void osRtxTimerThread (void *argument);
+extern int32_t osRtxTimerSetup (void);
+extern void osRtxTimerThread (void *argument);
+#ifdef RTX_SAFETY_CLASS
+extern void osRtxTimerDeleteClass (uint32_t safety_class, uint32_t mode);
+#endif
// Mutex Library functions
extern void osRtxMutexOwnerRelease (os_mutex_t *mutex_list);
extern void osRtxMutexOwnerRestore (const os_mutex_t *mutex, const os_thread_t *thread_wakeup);
+#ifdef RTX_SAFETY_CLASS
+extern void osRtxMutexDeleteClass (uint32_t safety_class, uint32_t mode);
+#endif
+
+// Semaphore Library functions
+#ifdef RTX_SAFETY_CLASS
+extern void osRtxSemaphoreDeleteClass (uint32_t safety_class, uint32_t mode);
+#endif
+
+// Event Flags Library functions
+#ifdef RTX_SAFETY_CLASS
+extern void osRtxEventFlagsDeleteClass(uint32_t safety_class, uint32_t mode);
+#endif
// Memory Heap Library functions
extern uint32_t osRtxMemoryInit (void *mem, uint32_t size);
@@ -209,12 +309,18 @@
extern uint32_t osRtxMemoryFree (void *mem, void *block);
// Memory Pool Library functions
-extern uint32_t osRtxMemoryPoolInit (os_mp_info_t *mp_info, uint32_t block_count, uint32_t block_size, void *block_mem);
-extern void *osRtxMemoryPoolAlloc (os_mp_info_t *mp_info);
-extern osStatus_t osRtxMemoryPoolFree (os_mp_info_t *mp_info, void *block);
+extern uint32_t osRtxMemoryPoolInit (os_mp_info_t *mp_info, uint32_t block_count, uint32_t block_size, void *block_mem);
+extern void *osRtxMemoryPoolAlloc (os_mp_info_t *mp_info);
+extern osStatus_t osRtxMemoryPoolFree (os_mp_info_t *mp_info, void *block);
+#ifdef RTX_SAFETY_CLASS
+extern void osRtxMemoryPoolDeleteClass(uint32_t safety_class, uint32_t mode);
+#endif
// Message Queue Library functions
extern int32_t osRtxMessageQueueTimerSetup (void);
+#ifdef RTX_SAFETY_CLASS
+extern void osRtxMessageQueueDeleteClass(uint32_t safety_class, uint32_t mode);
+#endif
// System Library functions
extern void osRtxTick_Handler (void);
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_mempool.c b/CMSIS/RTOS2/RTX/Source/rtx_mempool.c
index 30c9248..6df2f87 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_mempool.c
+++ b/CMSIS/RTOS2/RTX/Source/rtx_mempool.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -34,6 +34,38 @@
#endif
+// ==== Helper functions ====
+
+/// Verify that Memory Pool object pointer is valid.
+/// \param[in] mp memory pool object.
+/// \return true - valid, false - invalid.
+static bool_t IsMemoryPoolPtrValid (const os_memory_pool_t *mp) {
+#ifdef RTX_OBJ_PTR_CHECK
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ uint32_t cb_start = (uint32_t)&__os_mempool_cb_start__;
+ uint32_t cb_length = (uint32_t)&__os_mempool_cb_length__;
+
+ // Check the section boundaries
+ if (((uint32_t)mp - cb_start) >= cb_length) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+ // Check the object alignment
+ if ((((uint32_t)mp - cb_start) % sizeof(os_memory_pool_t)) != 0U) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#else
+ // Check NULL pointer
+ if (mp == NULL) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+
// ==== Library functions ====
/// Initialize Memory Pool.
@@ -152,6 +184,67 @@
return osOK;
}
+/// Destroy a Memory Pool object.
+/// \param[in] mp memory pool object.
+static void osRtxMemoryPoolDestroy (os_memory_pool_t *mp) {
+
+ // Mark object as invalid
+ mp->id = osRtxIdInvalid;
+
+ // Free data memory
+ if ((mp->flags & osRtxFlagSystemMemory) != 0U) {
+ (void)osRtxMemoryFree(osRtxInfo.mem.mp_data, mp->mp_info.block_base);
+ }
+
+ // Free object memory
+ if ((mp->flags & osRtxFlagSystemObject) != 0U) {
+#ifdef RTX_OBJ_PTR_CHECK
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.memory_pool, mp);
+#else
+ if (osRtxInfo.mpi.memory_pool != NULL) {
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.memory_pool, mp);
+ } else {
+ (void)osRtxMemoryFree(osRtxInfo.mem.common, mp);
+ }
+#endif
+#ifdef RTX_OBJ_MEM_USAGE
+ osRtxMemoryPoolMemUsage.cnt_free++;
+#endif
+ }
+
+ EvrRtxMemoryPoolDestroyed(mp);
+}
+
+#ifdef RTX_SAFETY_CLASS
+/// Delete a Memory Pool safety class.
+/// \param[in] safety_class safety class.
+/// \param[in] mode safety mode.
+void osRtxMemoryPoolDeleteClass (uint32_t safety_class, uint32_t mode) {
+ os_memory_pool_t *mp;
+ os_thread_t *thread;
+ uint32_t length;
+
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ mp = (os_memory_pool_t *)(uint32_t)&__os_mempool_cb_start__;
+ length = (uint32_t)&__os_mempool_cb_length__;
+ while (length >= sizeof(os_memory_pool_t)) {
+ if ( (mp->id == osRtxIdMemoryPool) &&
+ ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((mp->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((mp->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)))) {
+ while (mp->thread_list != NULL) {
+ thread = osRtxThreadListGet(osRtxObject(mp));
+ osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
+ }
+ osRtxMemoryPoolDestroy(mp);
+ }
+ length -= sizeof(os_memory_pool_t);
+ mp++;
+ }
+}
+#endif
+
// ==== Post ISR processing ====
@@ -181,14 +274,18 @@
/// Create and Initialize a Memory Pool object.
/// \note API identical to osMemoryPoolNew
static osMemoryPoolId_t svcRtxMemoryPoolNew (uint32_t block_count, uint32_t block_size, const osMemoryPoolAttr_t *attr) {
- os_memory_pool_t *mp;
- void *mp_mem;
- uint32_t mp_size;
- uint32_t b_count;
- uint32_t b_size;
- uint32_t size;
- uint8_t flags;
- const char *name;
+ os_memory_pool_t *mp;
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread = osRtxThreadGetRunning();
+ uint32_t attr_bits;
+#endif
+ void *mp_mem;
+ uint32_t mp_size;
+ uint32_t b_count;
+ uint32_t b_size;
+ uint32_t size;
+ uint8_t flags;
+ const char *name;
// Check parameters
if ((block_count == 0U) || (block_size == 0U) ||
@@ -204,15 +301,28 @@
// Process attributes
if (attr != NULL) {
- name = attr->name;
+ name = attr->name;
+#ifdef RTX_SAFETY_CLASS
+ attr_bits = attr->attr_bits;
+#endif
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
- mp = attr->cb_mem;
+ mp = attr->cb_mem;
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
- mp_mem = attr->mp_mem;
- mp_size = attr->mp_size;
+ mp_mem = attr->mp_mem;
+ mp_size = attr->mp_size;
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) <
+ (uint8_t)((attr_bits & osSafetyClass_Msk) >> osSafetyClass_Pos))) {
+ EvrRtxMemoryPoolError(NULL, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return NULL;
+ }
+ }
+#endif
if (mp != NULL) {
- //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
- if ((((uint32_t)mp & 3U) != 0U) || (attr->cb_size < sizeof(os_memory_pool_t))) {
+ if (!IsMemoryPoolPtrValid(mp) || (attr->cb_size != sizeof(os_memory_pool_t))) {
EvrRtxMemoryPoolError(NULL, osRtxErrorInvalidControlBlock);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -239,9 +349,12 @@
}
}
} else {
- name = NULL;
- mp = NULL;
- mp_mem = NULL;
+ name = NULL;
+#ifdef RTX_SAFETY_CLASS
+ attr_bits = 0U;
+#endif
+ mp = NULL;
+ mp_mem = NULL;
}
// Allocate object memory if not provided
@@ -249,9 +362,11 @@
if (osRtxInfo.mpi.memory_pool != NULL) {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
mp = osRtxMemoryPoolAlloc(osRtxInfo.mpi.memory_pool);
+#ifndef RTX_OBJ_PTR_CHECK
} else {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
mp = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_memory_pool_t), 1U);
+#endif
}
#ifdef RTX_OBJ_MEM_USAGE
if (mp != NULL) {
@@ -274,11 +389,15 @@
mp_mem = osRtxMemoryAlloc(osRtxInfo.mem.mp_data, size, 0U);
if (mp_mem == NULL) {
if ((flags & osRtxFlagSystemObject) != 0U) {
+#ifdef RTX_OBJ_PTR_CHECK
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.memory_pool, mp);
+#else
if (osRtxInfo.mpi.memory_pool != NULL) {
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.memory_pool, mp);
} else {
(void)osRtxMemoryFree(osRtxInfo.mem.common, mp);
}
+#endif
#ifdef RTX_OBJ_MEM_USAGE
osRtxMemoryPoolMemUsage.cnt_free++;
#endif
@@ -294,8 +413,20 @@
// Initialize control block
mp->id = osRtxIdMemoryPool;
mp->flags = flags;
+ mp->attr = 0U;
mp->name = name;
mp->thread_list = NULL;
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ mp->attr |= (uint8_t)((attr_bits & osSafetyClass_Msk) >>
+ (osSafetyClass_Pos - osRtxAttrClass_Pos));
+ } else {
+ // Inherit safety class from the running thread
+ if (thread != NULL) {
+ mp->attr |= (uint8_t)(thread->attr & osRtxAttrClass_Msk);
+ }
+ }
+#endif
(void)osRtxMemoryPoolInit(&mp->mp_info, b_count, b_size, mp_mem);
// Register post ISR processing function
@@ -315,7 +446,7 @@
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
// Check parameters
- if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
+ if (!IsMemoryPoolPtrValid(mp) || (mp->id != osRtxIdMemoryPool)) {
EvrRtxMemoryPoolGetName(mp, NULL);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -329,16 +460,30 @@
/// Allocate a memory block from a Memory Pool.
/// \note API identical to osMemoryPoolAlloc
static void *svcRtxMemoryPoolAlloc (osMemoryPoolId_t mp_id, uint32_t timeout) {
- os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
- void *block;
+ os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread;
+#endif
+ void *block;
// Check parameters
- if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
+ if (!IsMemoryPoolPtrValid(mp) || (mp->id != osRtxIdMemoryPool)) {
EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (mp->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxMemoryPoolError(mp, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return NULL;
+ }
+#endif
+
// Allocate memory
block = osRtxMemoryPoolAlloc(&mp->mp_info);
if (block != NULL) {
@@ -370,12 +515,23 @@
osStatus_t status;
// Check parameters
- if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
+ if (!IsMemoryPoolPtrValid(mp) || (mp->id != osRtxIdMemoryPool)) {
EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (mp->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxMemoryPoolError(mp, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Free memory
status = osRtxMemoryPoolFree(&mp->mp_info, block);
if (status == osOK) {
@@ -405,7 +561,7 @@
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
// Check parameters
- if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
+ if (!IsMemoryPoolPtrValid(mp) || (mp->id != osRtxIdMemoryPool)) {
EvrRtxMemoryPoolGetCapacity(mp, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -422,7 +578,7 @@
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
// Check parameters
- if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
+ if (!IsMemoryPoolPtrValid(mp) || (mp->id != osRtxIdMemoryPool)) {
EvrRtxMemoryPoolGetBlockSize(mp, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -439,7 +595,7 @@
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
// Check parameters
- if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
+ if (!IsMemoryPoolPtrValid(mp) || (mp->id != osRtxIdMemoryPool)) {
EvrRtxMemoryPoolGetCount(mp, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -456,7 +612,7 @@
os_memory_pool_t *mp = osRtxMemoryPoolId(mp_id);
// Check parameters
- if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
+ if (!IsMemoryPoolPtrValid(mp) || (mp->id != osRtxIdMemoryPool)) {
EvrRtxMemoryPoolGetSpace(mp, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -474,12 +630,23 @@
os_thread_t *thread;
// Check parameters
- if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
+ if (!IsMemoryPoolPtrValid(mp) || (mp->id != osRtxIdMemoryPool)) {
EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (mp->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxMemoryPoolError(mp, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Unblock waiting threads
if (mp->thread_list != NULL) {
do {
@@ -489,27 +656,7 @@
osRtxThreadDispatch(NULL);
}
- // Mark object as invalid
- mp->id = osRtxIdInvalid;
-
- // Free data memory
- if ((mp->flags & osRtxFlagSystemMemory) != 0U) {
- (void)osRtxMemoryFree(osRtxInfo.mem.mp_data, mp->mp_info.block_base);
- }
-
- // Free object memory
- if ((mp->flags & osRtxFlagSystemObject) != 0U) {
- if (osRtxInfo.mpi.memory_pool != NULL) {
- (void)osRtxMemoryPoolFree(osRtxInfo.mpi.memory_pool, mp);
- } else {
- (void)osRtxMemoryFree(osRtxInfo.mem.common, mp);
- }
-#ifdef RTX_OBJ_MEM_USAGE
- osRtxMemoryPoolMemUsage.cnt_free++;
-#endif
- }
-
- EvrRtxMemoryPoolDestroyed(mp);
+ osRtxMemoryPoolDestroy(mp);
return osOK;
}
@@ -538,7 +685,7 @@
void *block;
// Check parameters
- if ((mp == NULL) || (mp->id != osRtxIdMemoryPool) || (timeout != 0U)) {
+ if (!IsMemoryPoolPtrValid(mp) || (mp->id != osRtxIdMemoryPool) || (timeout != 0U)) {
EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -563,7 +710,7 @@
osStatus_t status;
// Check parameters
- if ((mp == NULL) || (mp->id != osRtxIdMemoryPool)) {
+ if (!IsMemoryPoolPtrValid(mp) || (mp->id != osRtxIdMemoryPool)) {
EvrRtxMemoryPoolError(mp, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
@@ -604,10 +751,9 @@
const char *name;
if (IsException() || IsIrqMasked()) {
- EvrRtxMemoryPoolGetName(mp_id, NULL);
- name = NULL;
+ name = svcRtxMemoryPoolGetName(mp_id);
} else {
- name = __svcMemoryPoolGetName(mp_id);
+ name = __svcMemoryPoolGetName(mp_id);
}
return name;
}
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_msgqueue.c b/CMSIS/RTOS2/RTX/Source/rtx_msgqueue.c
index e2a7910..11e96c2 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_msgqueue.c
+++ b/CMSIS/RTOS2/RTX/Source/rtx_msgqueue.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -155,6 +155,99 @@
}
}
+/// Verify that Message Queue object pointer is valid.
+/// \param[in] mq message queue object.
+/// \return true - valid, false - invalid.
+static bool_t IsMessageQueuePtrValid (const os_message_queue_t *mq) {
+#ifdef RTX_OBJ_PTR_CHECK
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ uint32_t cb_start = (uint32_t)&__os_msgqueue_cb_start__;
+ uint32_t cb_length = (uint32_t)&__os_msgqueue_cb_length__;
+
+ // Check the section boundaries
+ if (((uint32_t)mq - cb_start) >= cb_length) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+ // Check the object alignment
+ if ((((uint32_t)mq - cb_start) % sizeof(os_message_queue_t)) != 0U) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#else
+ // Check NULL pointer
+ if (mq == NULL) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+
+// ==== Library functions ====
+
+/// Destroy a Message Queue object.
+/// \param[in] mq message queue object.
+static void osRtxMessageQueueDestroy (os_message_queue_t *mq) {
+
+ // Mark object as invalid
+ mq->id = osRtxIdInvalid;
+
+ // Free data memory
+ if ((mq->flags & osRtxFlagSystemMemory) != 0U) {
+ (void)osRtxMemoryFree(osRtxInfo.mem.mq_data, mq->mp_info.block_base);
+ }
+
+ // Free object memory
+ if ((mq->flags & osRtxFlagSystemObject) != 0U) {
+#ifdef RTX_OBJ_PTR_CHECK
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
+#else
+ if (osRtxInfo.mpi.message_queue != NULL) {
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
+ } else {
+ (void)osRtxMemoryFree(osRtxInfo.mem.common, mq);
+ }
+#endif
+#ifdef RTX_OBJ_MEM_USAGE
+ osRtxMessageQueueMemUsage.cnt_free++;
+#endif
+ }
+
+ EvrRtxMessageQueueDestroyed(mq);
+}
+
+#ifdef RTX_SAFETY_CLASS
+/// Delete a Message Queue safety class.
+/// \param[in] safety_class safety class.
+/// \param[in] mode safety mode.
+void osRtxMessageQueueDeleteClass (uint32_t safety_class, uint32_t mode) {
+ os_message_queue_t *mq;
+ os_thread_t *thread;
+ uint32_t length;
+
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ mq = (os_message_queue_t *)(uint32_t)&__os_msgqueue_cb_start__;
+ length = (uint32_t)&__os_msgqueue_cb_length__;
+ while (length >= sizeof(os_message_queue_t)) {
+ if ( (mq->id == osRtxIdMessageQueue) &&
+ ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((mq->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((mq->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)))) {
+ while (mq->thread_list != NULL) {
+ thread = osRtxThreadListGet(osRtxObject(mq));
+ osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
+ }
+ osRtxMessageQueueDestroy(mq);
+ }
+ length -= sizeof(os_message_queue_t);
+ mq++;
+ }
+}
+#endif
+
// ==== Post ISR processing ====
@@ -237,6 +330,10 @@
/// \note API identical to osMessageQueueNew
static osMessageQueueId_t svcRtxMessageQueueNew (uint32_t msg_count, uint32_t msg_size, const osMessageQueueAttr_t *attr) {
os_message_queue_t *mq;
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread = osRtxThreadGetRunning();
+ uint32_t attr_bits;
+#endif
void *mq_mem;
uint32_t mq_size;
uint32_t block_size;
@@ -257,15 +354,28 @@
// Process attributes
if (attr != NULL) {
- name = attr->name;
+ name = attr->name;
+#ifdef RTX_SAFETY_CLASS
+ attr_bits = attr->attr_bits;
+#endif
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
- mq = attr->cb_mem;
+ mq = attr->cb_mem;
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
- mq_mem = attr->mq_mem;
- mq_size = attr->mq_size;
+ mq_mem = attr->mq_mem;
+ mq_size = attr->mq_size;
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) <
+ (uint8_t)((attr_bits & osSafetyClass_Msk) >> osSafetyClass_Pos))) {
+ EvrRtxMessageQueueError(NULL, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return NULL;
+ }
+ }
+#endif
if (mq != NULL) {
- //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
- if ((((uint32_t)mq & 3U) != 0U) || (attr->cb_size < sizeof(os_message_queue_t))) {
+ if (!IsMessageQueuePtrValid(mq) || (attr->cb_size != sizeof(os_message_queue_t))) {
EvrRtxMessageQueueError(NULL, osRtxErrorInvalidControlBlock);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -292,9 +402,12 @@
}
}
} else {
- name = NULL;
- mq = NULL;
- mq_mem = NULL;
+ name = NULL;
+#ifdef RTX_SAFETY_CLASS
+ attr_bits = 0U;
+#endif
+ mq = NULL;
+ mq_mem = NULL;
}
// Allocate object memory if not provided
@@ -302,9 +415,11 @@
if (osRtxInfo.mpi.message_queue != NULL) {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
mq = osRtxMemoryPoolAlloc(osRtxInfo.mpi.message_queue);
+#ifndef RTX_OBJ_PTR_CHECK
} else {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
mq = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_message_queue_t), 1U);
+#endif
}
#ifdef RTX_OBJ_MEM_USAGE
if (mq != NULL) {
@@ -327,11 +442,15 @@
mq_mem = osRtxMemoryAlloc(osRtxInfo.mem.mq_data, size, 0U);
if (mq_mem == NULL) {
if ((flags & osRtxFlagSystemObject) != 0U) {
+#ifdef RTX_OBJ_PTR_CHECK
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
+#else
if (osRtxInfo.mpi.message_queue != NULL) {
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
} else {
(void)osRtxMemoryFree(osRtxInfo.mem.common, mq);
}
+#endif
#ifdef RTX_OBJ_MEM_USAGE
osRtxMessageQueueMemUsage.cnt_free++;
#endif
@@ -347,12 +466,24 @@
// Initialize control block
mq->id = osRtxIdMessageQueue;
mq->flags = flags;
+ mq->attr = 0U;
mq->name = name;
mq->thread_list = NULL;
mq->msg_size = msg_size;
mq->msg_count = 0U;
mq->msg_first = NULL;
mq->msg_last = NULL;
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ mq->attr |= (uint8_t)((attr_bits & osSafetyClass_Msk) >>
+ (osSafetyClass_Pos - osRtxAttrClass_Pos));
+ } else {
+ // Inherit safety class from the running thread
+ if (thread != NULL) {
+ mq->attr |= (uint8_t)(thread->attr & osRtxAttrClass_Msk);
+ }
+ }
+#endif
(void)osRtxMemoryPoolInit(&mq->mp_info, msg_count, block_size, mq_mem);
// Register post ISR processing function
@@ -372,7 +503,7 @@
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
// Check parameters
- if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
+ if (!IsMessageQueuePtrValid(mq) || (mq->id != osRtxIdMessageQueue)) {
EvrRtxMessageQueueGetName(mq, NULL);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -394,12 +525,23 @@
osStatus_t status;
// Check parameters
- if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
+ if (!IsMessageQueuePtrValid(mq) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (mq->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxMessageQueueError(mq, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Check if Thread is waiting to receive a Message
if ((mq->thread_list != NULL) && (mq->thread_list->state == osRtxThreadWaitingMessageGet)) {
EvrRtxMessageQueueInserted(mq, msg_ptr);
@@ -463,12 +605,23 @@
osStatus_t status;
// Check parameters
- if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
+ if (!IsMessageQueuePtrValid(mq) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL)) {
EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (mq->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxMessageQueueError(mq, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Get Message from Queue
msg = MessageQueueGet(mq);
if (msg != NULL) {
@@ -531,7 +684,7 @@
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
// Check parameters
- if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
+ if (!IsMessageQueuePtrValid(mq) || (mq->id != osRtxIdMessageQueue)) {
EvrRtxMessageQueueGetCapacity(mq, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -548,7 +701,7 @@
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
// Check parameters
- if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
+ if (!IsMessageQueuePtrValid(mq) || (mq->id != osRtxIdMessageQueue)) {
EvrRtxMessageQueueGetMsgSize(mq, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -565,7 +718,7 @@
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
// Check parameters
- if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
+ if (!IsMessageQueuePtrValid(mq) || (mq->id != osRtxIdMessageQueue)) {
EvrRtxMessageQueueGetCount(mq, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -582,7 +735,7 @@
os_message_queue_t *mq = osRtxMessageQueueId(mq_id);
// Check parameters
- if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
+ if (!IsMessageQueuePtrValid(mq) || (mq->id != osRtxIdMessageQueue)) {
EvrRtxMessageQueueGetSpace(mq, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -603,12 +756,23 @@
const void *ptr;
// Check parameters
- if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
+ if (!IsMessageQueuePtrValid(mq) || (mq->id != osRtxIdMessageQueue)) {
EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (mq->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxMessageQueueError(mq, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Remove Messages from Queue
for (;;) {
// Get Message from Queue
@@ -661,12 +825,23 @@
os_thread_t *thread;
// Check parameters
- if ((mq == NULL) || (mq->id != osRtxIdMessageQueue)) {
+ if (!IsMessageQueuePtrValid(mq) || (mq->id != osRtxIdMessageQueue)) {
EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (mq->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxMessageQueueError(mq, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Unblock waiting threads
if (mq->thread_list != NULL) {
do {
@@ -676,27 +851,7 @@
osRtxThreadDispatch(NULL);
}
- // Mark object as invalid
- mq->id = osRtxIdInvalid;
-
- // Free data memory
- if ((mq->flags & osRtxFlagSystemMemory) != 0U) {
- (void)osRtxMemoryFree(osRtxInfo.mem.mq_data, mq->mp_info.block_base);
- }
-
- // Free object memory
- if ((mq->flags & osRtxFlagSystemObject) != 0U) {
- if (osRtxInfo.mpi.message_queue != NULL) {
- (void)osRtxMemoryPoolFree(osRtxInfo.mpi.message_queue, mq);
- } else {
- (void)osRtxMemoryFree(osRtxInfo.mem.common, mq);
- }
-#ifdef RTX_OBJ_MEM_USAGE
- osRtxMessageQueueMemUsage.cnt_free++;
-#endif
- }
-
- EvrRtxMessageQueueDestroyed(mq);
+ osRtxMessageQueueDestroy(mq);
return osOK;
}
@@ -727,7 +882,7 @@
osStatus_t status;
// Check parameters
- if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
+ if (!IsMessageQueuePtrValid(mq) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
@@ -768,7 +923,7 @@
osStatus_t status;
// Check parameters
- if ((mq == NULL) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
+ if (!IsMessageQueuePtrValid(mq) || (mq->id != osRtxIdMessageQueue) || (msg_ptr == NULL) || (timeout != 0U)) {
EvrRtxMessageQueueError(mq, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
@@ -836,10 +991,9 @@
const char *name;
if (IsException() || IsIrqMasked()) {
- EvrRtxMessageQueueGetName(mq_id, NULL);
- name = NULL;
+ name = svcRtxMessageQueueGetName(mq_id);
} else {
- name = __svcMessageQueueGetName(mq_id);
+ name = __svcMessageQueueGetName(mq_id);
}
return name;
}
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_mutex.c b/CMSIS/RTOS2/RTX/Source/rtx_mutex.c
index fb889b4..6667188 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_mutex.c
+++ b/CMSIS/RTOS2/RTX/Source/rtx_mutex.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -34,6 +34,38 @@
#endif
+// ==== Helper functions ====
+
+/// Verify that Mutex object pointer is valid.
+/// \param[in] mutex mutex object.
+/// \return true - valid, false - invalid.
+static bool_t IsMutexPtrValid (const os_mutex_t *mutex) {
+#ifdef RTX_OBJ_PTR_CHECK
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ uint32_t cb_start = (uint32_t)&__os_mutex_cb_start__;
+ uint32_t cb_length = (uint32_t)&__os_mutex_cb_length__;
+
+ // Check the section boundaries
+ if (((uint32_t)mutex - cb_start) >= cb_length) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+ // Check the object alignment
+ if ((((uint32_t)mutex - cb_start) % sizeof(os_mutex_t)) != 0U) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#else
+ // Check NULL pointer
+ if (mutex == NULL) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+
// ==== Library functions ====
/// Release Mutex list when owner Thread terminates.
@@ -109,16 +141,125 @@
}
}
+/// Unlock Mutex owner when mutex is deleted.
+/// \param[in] mutex mutex object.
+/// \return true - successful, false - not locked.
+static bool_t osRtxMutexOwnerUnlock (os_mutex_t *mutex) {
+ const os_mutex_t *mutex0;
+ os_thread_t *thread;
+ int8_t priority;
+
+ // Check if Mutex is locked
+ if (mutex->lock == 0U) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+
+ thread = mutex->owner_thread;
+
+ // Remove Mutex from Thread owner list
+ if (mutex->owner_next != NULL) {
+ mutex->owner_next->owner_prev = mutex->owner_prev;
+ }
+ if (mutex->owner_prev != NULL) {
+ mutex->owner_prev->owner_next = mutex->owner_next;
+ } else {
+ thread->mutex_list = mutex->owner_next;
+ }
+
+ // Restore owner Thread priority
+ priority = thread->priority_base;
+ mutex0 = thread->mutex_list;
+ // Check Mutexes owned by Thread
+ while (mutex0 != NULL) {
+ if ((mutex0->attr & osMutexPrioInherit) != 0U) {
+ if ((mutex0->thread_list != NULL) && (mutex0->thread_list->priority > priority)) {
+ // Higher priority Thread is waiting for Mutex
+ priority = mutex0->thread_list->priority;
+ }
+ }
+ mutex0 = mutex0->owner_next;
+ }
+ if (thread->priority != priority) {
+ thread->priority = priority;
+ osRtxThreadListSort(thread);
+ }
+
+ // Unblock waiting threads
+ while (mutex->thread_list != NULL) {
+ thread = osRtxThreadListGet(osRtxObject(mutex));
+ osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
+ }
+
+ mutex->lock = 0U;
+
+ return TRUE;
+}
+
+/// Destroy a Mutex object.
+/// \param[in] mutex mutex object.
+static void osRtxMutexDestroy (os_mutex_t *mutex) {
+
+ // Mark object as invalid
+ mutex->id = osRtxIdInvalid;
+
+ // Free object memory
+ if ((mutex->flags & osRtxFlagSystemObject) != 0U) {
+#ifdef RTX_OBJ_PTR_CHECK
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.mutex, mutex);
+#else
+ if (osRtxInfo.mpi.mutex != NULL) {
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.mutex, mutex);
+ } else {
+ (void)osRtxMemoryFree(osRtxInfo.mem.common, mutex);
+ }
+#endif
+#ifdef RTX_OBJ_MEM_USAGE
+ osRtxMutexMemUsage.cnt_free++;
+#endif
+ }
+ EvrRtxMutexDestroyed(mutex);
+}
+
+#ifdef RTX_SAFETY_CLASS
+/// Delete a Mutex safety class.
+/// \param[in] safety_class safety class.
+/// \param[in] mode safety mode.
+void osRtxMutexDeleteClass (uint32_t safety_class, uint32_t mode) {
+ os_mutex_t *mutex;
+ uint32_t length;
+
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ mutex = (os_mutex_t *)(uint32_t)&__os_mutex_cb_start__;
+ length = (uint32_t)&__os_mutex_cb_length__;
+ while (length >= sizeof(os_mutex_t)) {
+ if ( (mutex->id == osRtxIdMutex) &&
+ ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((mutex->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((mutex->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)))) {
+ (void)osRtxMutexOwnerUnlock(mutex);
+ osRtxMutexDestroy(mutex);
+ }
+ length -= sizeof(os_mutex_t);
+ mutex++;
+ }
+}
+#endif
+
// ==== Service Calls ====
/// Create and Initialize a Mutex object.
/// \note API identical to osMutexNew
static osMutexId_t svcRtxMutexNew (const osMutexAttr_t *attr) {
- os_mutex_t *mutex;
- uint32_t attr_bits;
- uint8_t flags;
- const char *name;
+ os_mutex_t *mutex;
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread = osRtxThreadGetRunning();
+#endif
+ uint32_t attr_bits;
+ uint8_t flags;
+ const char *name;
// Process attributes
if (attr != NULL) {
@@ -126,9 +267,19 @@
attr_bits = attr->attr_bits;
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
mutex = attr->cb_mem;
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) <
+ (uint8_t)((attr_bits & osSafetyClass_Msk) >> osSafetyClass_Pos))) {
+ EvrRtxMutexError(NULL, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return NULL;
+ }
+ }
+#endif
if (mutex != NULL) {
- //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
- if ((((uint32_t)mutex & 3U) != 0U) || (attr->cb_size < sizeof(os_mutex_t))) {
+ if (!IsMutexPtrValid(mutex) || (attr->cb_size != sizeof(os_mutex_t))) {
EvrRtxMutexError(NULL, osRtxErrorInvalidControlBlock);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -151,9 +302,11 @@
if (osRtxInfo.mpi.mutex != NULL) {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
mutex = osRtxMemoryPoolAlloc(osRtxInfo.mpi.mutex);
+#ifndef RTX_OBJ_PTR_CHECK
} else {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
mutex = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_mutex_t), 1U);
+#endif
}
#ifdef RTX_OBJ_MEM_USAGE
if (mutex != NULL) {
@@ -174,14 +327,24 @@
// Initialize control block
mutex->id = osRtxIdMutex;
mutex->flags = flags;
- mutex->attr = (uint8_t)attr_bits;
+ mutex->attr = (uint8_t)(attr_bits & ~osRtxAttrClass_Msk);
mutex->name = name;
mutex->thread_list = NULL;
mutex->owner_thread = NULL;
mutex->owner_prev = NULL;
mutex->owner_next = NULL;
mutex->lock = 0U;
-
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ mutex->attr |= (uint8_t)((attr_bits & osSafetyClass_Msk) >>
+ (osSafetyClass_Pos - osRtxAttrClass_Pos));
+ } else {
+ // Inherit safety class from the running thread
+ if (thread != NULL) {
+ mutex->attr |= (uint8_t)(thread->attr & osRtxAttrClass_Msk);
+ }
+ }
+#endif
EvrRtxMutexCreated(mutex, mutex->name);
} else {
EvrRtxMutexError(NULL, (int32_t)osErrorNoMemory);
@@ -196,7 +359,7 @@
os_mutex_t *mutex = osRtxMutexId(mutex_id);
// Check parameters
- if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
+ if (!IsMutexPtrValid(mutex) || (mutex->id != osRtxIdMutex)) {
EvrRtxMutexGetName(mutex, NULL);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -223,12 +386,21 @@
}
// Check parameters
- if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
+ if (!IsMutexPtrValid(mutex) || (mutex->id != osRtxIdMutex)) {
EvrRtxMutexError(mutex, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ if ((thread->attr >> osRtxAttrClass_Pos) < (mutex->attr >> osRtxAttrClass_Pos)) {
+ EvrRtxMutexError(mutex, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Check if Mutex is not locked
if (mutex->lock == 0U) {
// Acquire Mutex
@@ -300,7 +472,7 @@
}
// Check parameters
- if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
+ if (!IsMutexPtrValid(mutex) || (mutex->id != osRtxIdMutex)) {
EvrRtxMutexError(mutex, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
@@ -381,7 +553,7 @@
os_mutex_t *mutex = osRtxMutexId(mutex_id);
// Check parameters
- if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
+ if (!IsMutexPtrValid(mutex) || (mutex->id != osRtxIdMutex)) {
EvrRtxMutexGetOwner(mutex, NULL);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -403,75 +575,34 @@
/// \note API identical to osMutexDelete
static osStatus_t svcRtxMutexDelete (osMutexId_t mutex_id) {
os_mutex_t *mutex = osRtxMutexId(mutex_id);
- const os_mutex_t *mutex0;
- os_thread_t *thread;
- int8_t priority;
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread;
+#endif
// Check parameters
- if ((mutex == NULL) || (mutex->id != osRtxIdMutex)) {
+ if (!IsMutexPtrValid(mutex) || (mutex->id != osRtxIdMutex)) {
EvrRtxMutexError(mutex, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
- // Check if Mutex is locked
- if (mutex->lock != 0U) {
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (mutex->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxMutexError(mutex, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
- thread = mutex->owner_thread;
-
- // Remove Mutex from Thread owner list
- if (mutex->owner_next != NULL) {
- mutex->owner_next->owner_prev = mutex->owner_prev;
- }
- if (mutex->owner_prev != NULL) {
- mutex->owner_prev->owner_next = mutex->owner_next;
- } else {
- thread->mutex_list = mutex->owner_next;
- }
-
- // Restore owner Thread priority
- priority = thread->priority_base;
- mutex0 = thread->mutex_list;
- // Check Mutexes owned by Thread
- while (mutex0 != NULL) {
- if ((mutex0->attr & osMutexPrioInherit) != 0U) {
- if ((mutex0->thread_list != NULL) && (mutex0->thread_list->priority > priority)) {
- // Higher priority Thread is waiting for Mutex
- priority = mutex0->thread_list->priority;
- }
- }
- mutex0 = mutex0->owner_next;
- }
- if (thread->priority != priority) {
- thread->priority = priority;
- osRtxThreadListSort(thread);
- }
-
- // Unblock waiting threads
- while (mutex->thread_list != NULL) {
- thread = osRtxThreadListGet(osRtxObject(mutex));
- osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
- }
-
+ // Unlock the mutex owner
+ if (osRtxMutexOwnerUnlock(mutex)) {
osRtxThreadDispatch(NULL);
}
- // Mark object as invalid
- mutex->id = osRtxIdInvalid;
-
- // Free object memory
- if ((mutex->flags & osRtxFlagSystemObject) != 0U) {
- if (osRtxInfo.mpi.mutex != NULL) {
- (void)osRtxMemoryPoolFree(osRtxInfo.mpi.mutex, mutex);
- } else {
- (void)osRtxMemoryFree(osRtxInfo.mem.common, mutex);
- }
-#ifdef RTX_OBJ_MEM_USAGE
- osRtxMutexMemUsage.cnt_free++;
-#endif
- }
-
- EvrRtxMutexDestroyed(mutex);
+ osRtxMutexDestroy(mutex);
return osOK;
}
@@ -508,10 +639,9 @@
const char *name;
if (IsException() || IsIrqMasked()) {
- EvrRtxMutexGetName(mutex_id, NULL);
- name = NULL;
+ name = svcRtxMutexGetName(mutex_id);
} else {
- name = __svcMutexGetName(mutex_id);
+ name = __svcMutexGetName(mutex_id);
}
return name;
}
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_semaphore.c b/CMSIS/RTOS2/RTX/Source/rtx_semaphore.c
index b96939a..1dbccf2 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_semaphore.c
+++ b/CMSIS/RTOS2/RTX/Source/rtx_semaphore.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -102,6 +102,93 @@
return ret;
}
+/// Verify that Semaphore object pointer is valid.
+/// \param[in] semaphore semaphore object.
+/// \return true - valid, false - invalid.
+static bool_t IsSemaphorePtrValid (const os_semaphore_t *semaphore) {
+#ifdef RTX_OBJ_PTR_CHECK
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ uint32_t cb_start = (uint32_t)&__os_semaphore_cb_start__;
+ uint32_t cb_length = (uint32_t)&__os_semaphore_cb_length__;
+
+ // Check the section boundaries
+ if (((uint32_t)semaphore - cb_start) >= cb_length) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+ // Check the object alignment
+ if ((((uint32_t)semaphore - cb_start) % sizeof(os_semaphore_t)) != 0U) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#else
+ // Check NULL pointer
+ if (semaphore == NULL) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+
+// ==== Library functions ====
+
+/// Destroy a Semaphore object.
+/// \param[in] semaphore semaphore object.
+static void osRtxSemaphoreDestroy (os_semaphore_t *semaphore) {
+
+ // Mark object as invalid
+ semaphore->id = osRtxIdInvalid;
+
+ // Free object memory
+ if ((semaphore->flags & osRtxFlagSystemObject) != 0U) {
+#ifdef RTX_OBJ_PTR_CHECK
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.semaphore, semaphore);
+#else
+ if (osRtxInfo.mpi.semaphore != NULL) {
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.semaphore, semaphore);
+ } else {
+ (void)osRtxMemoryFree(osRtxInfo.mem.common, semaphore);
+ }
+#endif
+#ifdef RTX_OBJ_MEM_USAGE
+ osRtxSemaphoreMemUsage.cnt_free++;
+#endif
+ }
+ EvrRtxSemaphoreDestroyed(semaphore);
+}
+
+#ifdef RTX_SAFETY_CLASS
+/// Delete a Semaphore safety class.
+/// \param[in] safety_class safety class.
+/// \param[in] mode safety mode.
+void osRtxSemaphoreDeleteClass (uint32_t safety_class, uint32_t mode) {
+ os_semaphore_t *semaphore;
+ os_thread_t *thread;
+ uint32_t length;
+
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ semaphore = (os_semaphore_t *)(uint32_t)&__os_semaphore_cb_start__;
+ length = (uint32_t)&__os_semaphore_cb_length__;
+ while (length >= sizeof(os_semaphore_t)) {
+ if ( (semaphore->id == osRtxIdSemaphore) &&
+ ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((semaphore->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((semaphore->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)))) {
+ while (semaphore->thread_list != NULL) {
+ thread = osRtxThreadListGet(osRtxObject(semaphore));
+ osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE);
+ }
+ osRtxSemaphoreDestroy(semaphore);
+ }
+ length -= sizeof(os_semaphore_t);
+ semaphore++;
+ }
+}
+#endif
+
// ==== Post ISR processing ====
@@ -128,9 +215,13 @@
/// Create and Initialize a Semaphore object.
/// \note API identical to osSemaphoreNew
static osSemaphoreId_t svcRtxSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr) {
- os_semaphore_t *semaphore;
- uint8_t flags;
- const char *name;
+ os_semaphore_t *semaphore;
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread = osRtxThreadGetRunning();
+ uint32_t attr_bits;
+#endif
+ uint8_t flags;
+ const char *name;
// Check parameters
if ((max_count == 0U) || (max_count > osRtxSemaphoreTokenLimit) || (initial_count > max_count)) {
@@ -142,11 +233,24 @@
// Process attributes
if (attr != NULL) {
name = attr->name;
+#ifdef RTX_SAFETY_CLASS
+ attr_bits = attr->attr_bits;
+#endif
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
semaphore = attr->cb_mem;
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) <
+ (uint8_t)((attr_bits & osSafetyClass_Msk) >> osSafetyClass_Pos))) {
+ EvrRtxSemaphoreError(NULL, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return NULL;
+ }
+ }
+#endif
if (semaphore != NULL) {
- //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
- if ((((uint32_t)semaphore & 3U) != 0U) || (attr->cb_size < sizeof(os_semaphore_t))) {
+ if (!IsSemaphorePtrValid(semaphore) || (attr->cb_size != sizeof(os_semaphore_t))) {
EvrRtxSemaphoreError(NULL, osRtxErrorInvalidControlBlock);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -160,6 +264,9 @@
}
} else {
name = NULL;
+#ifdef RTX_SAFETY_CLASS
+ attr_bits = 0U;
+#endif
semaphore = NULL;
}
@@ -168,9 +275,11 @@
if (osRtxInfo.mpi.semaphore != NULL) {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
semaphore = osRtxMemoryPoolAlloc(osRtxInfo.mpi.semaphore);
+#ifndef RTX_OBJ_PTR_CHECK
} else {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
semaphore = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_semaphore_t), 1U);
+#endif
}
#ifdef RTX_OBJ_MEM_USAGE
if (semaphore != NULL) {
@@ -191,10 +300,22 @@
// Initialize control block
semaphore->id = osRtxIdSemaphore;
semaphore->flags = flags;
+ semaphore->attr = 0U;
semaphore->name = name;
semaphore->thread_list = NULL;
semaphore->tokens = (uint16_t)initial_count;
semaphore->max_tokens = (uint16_t)max_count;
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ semaphore->attr |= (uint8_t)((attr_bits & osSafetyClass_Msk) >>
+ (osSafetyClass_Pos - osRtxAttrClass_Pos));
+ } else {
+ // Inherit safety class from the running thread
+ if (thread != NULL) {
+ semaphore->attr |= (uint8_t)(thread->attr & osRtxAttrClass_Msk);
+ }
+ }
+#endif
// Register post ISR processing function
osRtxInfo.post_process.semaphore = osRtxSemaphorePostProcess;
@@ -213,7 +334,7 @@
os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
// Check parameters
- if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
+ if (!IsSemaphorePtrValid(semaphore) || (semaphore->id != osRtxIdSemaphore)) {
EvrRtxSemaphoreGetName(semaphore, NULL);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -227,16 +348,30 @@
/// Acquire a Semaphore token or timeout if no tokens are available.
/// \note API identical to osSemaphoreAcquire
static osStatus_t svcRtxSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout) {
- os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
- osStatus_t status;
+ os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread;
+#endif
+ osStatus_t status;
// Check parameters
- if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
+ if (!IsSemaphorePtrValid(semaphore) || (semaphore->id != osRtxIdSemaphore)) {
EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (semaphore->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxSemaphoreError(semaphore, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Try to acquire token
if (SemaphoreTokenDecrement(semaphore) != 0U) {
EvrRtxSemaphoreAcquired(semaphore, semaphore->tokens);
@@ -269,12 +404,23 @@
osStatus_t status;
// Check parameters
- if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
+ if (!IsSemaphorePtrValid(semaphore) || (semaphore->id != osRtxIdSemaphore)) {
EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (semaphore->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxSemaphoreError(semaphore, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Check if Thread is waiting for a token
if (semaphore->thread_list != NULL) {
EvrRtxSemaphoreReleased(semaphore, semaphore->tokens);
@@ -303,7 +449,7 @@
os_semaphore_t *semaphore = osRtxSemaphoreId(semaphore_id);
// Check parameters
- if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
+ if (!IsSemaphorePtrValid(semaphore) || (semaphore->id != osRtxIdSemaphore)) {
EvrRtxSemaphoreGetCount(semaphore, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -321,12 +467,23 @@
os_thread_t *thread;
// Check parameters
- if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
+ if (!IsSemaphorePtrValid(semaphore) || (semaphore->id != osRtxIdSemaphore)) {
EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (semaphore->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxSemaphoreError(semaphore, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Unblock waiting threads
if (semaphore->thread_list != NULL) {
do {
@@ -336,22 +493,7 @@
osRtxThreadDispatch(NULL);
}
- // Mark object as invalid
- semaphore->id = osRtxIdInvalid;
-
- // Free object memory
- if ((semaphore->flags & osRtxFlagSystemObject) != 0U) {
- if (osRtxInfo.mpi.semaphore != NULL) {
- (void)osRtxMemoryPoolFree(osRtxInfo.mpi.semaphore, semaphore);
- } else {
- (void)osRtxMemoryFree(osRtxInfo.mem.common, semaphore);
- }
-#ifdef RTX_OBJ_MEM_USAGE
- osRtxSemaphoreMemUsage.cnt_free++;
-#endif
- }
-
- EvrRtxSemaphoreDestroyed(semaphore);
+ osRtxSemaphoreDestroy(semaphore);
return osOK;
}
@@ -377,7 +519,7 @@
osStatus_t status;
// Check parameters
- if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore) || (timeout != 0U)) {
+ if (!IsSemaphorePtrValid(semaphore) || (semaphore->id != osRtxIdSemaphore) || (timeout != 0U)) {
EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
@@ -404,7 +546,7 @@
osStatus_t status;
// Check parameters
- if ((semaphore == NULL) || (semaphore->id != osRtxIdSemaphore)) {
+ if (!IsSemaphorePtrValid(semaphore) || (semaphore->id != osRtxIdSemaphore)) {
EvrRtxSemaphoreError(semaphore, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
@@ -446,10 +588,9 @@
const char *name;
if (IsException() || IsIrqMasked()) {
- EvrRtxSemaphoreGetName(semaphore_id, NULL);
- name = NULL;
+ name = svcRtxSemaphoreGetName(semaphore_id);
} else {
- name = __svcSemaphoreGetName(semaphore_id);
+ name = __svcSemaphoreGetName(semaphore_id);
}
return name;
}
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_system.c b/CMSIS/RTOS2/RTX/Source/rtx_system.c
index bc969c8..2336039 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_system.c
+++ b/CMSIS/RTOS2/RTX/Source/rtx_system.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2021 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -132,6 +132,11 @@
osRtxInfo.timer.tick();
}
+#ifdef RTX_THREAD_WATCHDOG
+ // Process Watchdog Timers
+ osRtxThreadWatchdogTick();
+#endif
+
// Check Round Robin timeout
if (osRtxInfo.thread.robin.timeout != 0U) {
thread = osRtxInfo.thread.run.next;
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_thread.c b/CMSIS/RTOS2/RTX/Source/rtx_thread.c
index 55f5d63..b8f9a8e 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_thread.c
+++ b/CMSIS/RTOS2/RTX/Source/rtx_thread.c
@@ -33,6 +33,16 @@
{ 0U, 0U, 0U };
#endif
+// Runtime Class/Zone assignment table
+#if defined(RTX_EXECUTION_ZONE) && defined(RTX_SAFETY_CLASS)
+static uint8_t ThreadClassTable[64] __attribute__((section(".data.os"))) = { 0U };
+#endif
+
+// Watchdog Alarm Flag
+#if defined(RTX_THREAD_WATCHDOG) && defined(RTX_EXECUTION_ZONE)
+static uint8_t WatchdogAlarmFlag __attribute__((section(".data.os"))) = 0U;
+#endif
+
// ==== Helper functions ====
@@ -133,6 +143,71 @@
return thread_flags;
}
+/// Verify that Thread object pointer is valid.
+/// \param[in] thread thread object.
+/// \return true - valid, false - invalid.
+static bool_t IsThreadPtrValid (const os_thread_t *thread) {
+#ifdef RTX_OBJ_PTR_CHECK
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ uint32_t cb_start = (uint32_t)&__os_thread_cb_start__;
+ uint32_t cb_length = (uint32_t)&__os_thread_cb_length__;
+
+ // Check the section boundaries
+ if (((uint32_t)thread - cb_start) >= cb_length) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+ // Check the object alignment
+ if ((((uint32_t)thread - cb_start) % sizeof(os_thread_t)) != 0U) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#else
+ // Check NULL pointer
+ if (thread == NULL) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+#if defined(RTX_EXECUTION_ZONE) && defined(RTX_SAFETY_CLASS)
+/// Check if Thread Zone to Safety Class mapping is valid.
+/// \param[in] attr_bits thread attributes.
+/// \param[in] thread running thread.
+/// \return true - valid, false - not valid.
+static bool_t IsClassMappingValid (uint32_t attr_bits, const os_thread_t *thread) {
+ uint32_t safety_class;
+ uint32_t zone;
+
+ if ((attr_bits & osThreadZone_Valid) != 0U) {
+ zone = (attr_bits & osThreadZone_Msk) >> osThreadZone_Pos;
+ } else if (thread != NULL) {
+ zone = thread->zone;
+ } else {
+ zone = 0U;
+ }
+
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ safety_class = (attr_bits & osSafetyClass_Msk) >> osSafetyClass_Pos;
+ } else if (thread != NULL) {
+ safety_class = (uint32_t)thread->attr >> osRtxAttrClass_Pos;
+ } else {
+ safety_class = 0U;
+ }
+
+ // Check if zone is free or assigned to class
+ if ((ThreadClassTable[zone] == 0U) ||
+ (ThreadClassTable[zone] == (0x80U | safety_class))) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return TRUE;
+ }
+ // Invalid class to zone mapping
+ return FALSE;
+}
+#endif
+
// ==== Library functions ====
@@ -289,7 +364,7 @@
/// Remove a Thread from the Delay list.
/// \param[in] thread thread object.
-static void osRtxThreadDelayRemove (os_thread_t *thread) {
+void osRtxThreadDelayRemove (os_thread_t *thread) {
if (thread->delay == osWaitForever) {
if (thread->delay_next != NULL) {
@@ -415,6 +490,7 @@
void osRtxThreadSwitch (os_thread_t *thread) {
thread->state = osRtxThreadRunning;
+ SetPrivileged((bool_t)((thread->attr & osThreadPrivileged) != 0U));
osRtxInfo.thread.run.next = thread;
EvrRtxThreadSwitched(thread);
}
@@ -524,22 +600,109 @@
}
#endif
-#ifdef RTX_TF_M_EXTENSION
-/// Get TrustZone Module Identifier of running Thread.
-/// \return TrustZone Module Identifier.
-uint32_t osRtxTzGetModuleId (void) {
- os_thread_t *thread;
- uint32_t tz_module;
+#ifdef RTX_THREAD_WATCHDOG
- thread = osRtxThreadGetRunning();
- if (thread != NULL) {
- tz_module = thread->tz_module;
- } else {
- tz_module = 0U;
+/// Insert a Thread into the Watchdog list, sorted by tick (lowest at Head).
+/// \param[in] thread thread object.
+/// \param[in] ticks watchdog timeout.
+static void osRtxThreadWatchdogInsert (os_thread_t *thread, uint32_t ticks) {
+ os_thread_t *prev, *next;
+
+ if (ticks == 0U) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return;
}
-
- return tz_module;
+ prev = NULL;
+ next = osRtxInfo.thread.wdog_list;
+ while ((next != NULL) && ((next->wdog_tick <= ticks))) {
+ ticks -= next->wdog_tick;
+ prev = next;
+ next = next->wdog_next;
+ }
+ thread->wdog_tick = ticks;
+ thread->wdog_next = next;
+ if (next != NULL) {
+ next->wdog_tick -= ticks;
+ }
+ if (prev != NULL) {
+ prev->wdog_next = thread;
+ } else {
+ osRtxInfo.thread.wdog_list = thread;
+ }
}
+
+/// Remove a Thread from the Watchdog list.
+/// \param[in] thread thread object.
+void osRtxThreadWatchdogRemove (const os_thread_t *thread) {
+ os_thread_t *prev, *next;
+
+ prev = NULL;
+ next = osRtxInfo.thread.wdog_list;
+ while ((next != NULL) && (next != thread)) {
+ prev = next;
+ next = next->wdog_next;
+ }
+ if (next == NULL) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return;
+ }
+ if (thread->wdog_next != NULL) {
+ thread->wdog_next->wdog_tick += thread->wdog_tick;
+ }
+ if (prev != NULL) {
+ prev->wdog_next = thread->wdog_next;
+ } else {
+ osRtxInfo.thread.wdog_list = thread->wdog_next;
+ }
+}
+
+/// Process Watchdog Tick (executed each System Tick).
+void osRtxThreadWatchdogTick (void) {
+ os_thread_t *thread_running;
+ os_thread_t *thread;
+#ifdef RTX_SAFETY_CLASS
+ os_thread_t *next;
+#endif
+ uint32_t ticks;
+
+ thread = osRtxInfo.thread.wdog_list;
+ if (thread == NULL) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return;
+ }
+ thread->wdog_tick--;
+
+ if (thread->wdog_tick == 0U) {
+ // Call watchdog handler for all expired threads
+ thread_running = osRtxThreadGetRunning();
+ do {
+ osRtxThreadSetRunning(osRtxInfo.thread.run.next);
+#ifdef RTX_SAFETY_CLASS
+ // First the highest safety thread (sorted by Safety Class)
+ next = thread->wdog_next;
+ while ((next != NULL) && (next->wdog_tick == 0U)) {
+ if ((next->attr & osRtxAttrClass_Msk) > (thread->attr & osRtxAttrClass_Msk)) {
+ thread = next;
+ }
+ next = next->wdog_next;
+ }
+#endif
+ osRtxThreadWatchdogRemove(thread);
+ EvrRtxThreadWatchdogExpired(thread);
+#ifdef RTX_EXECUTION_ZONE
+ WatchdogAlarmFlag = 1U;
+#endif
+ ticks = osWatchdogAlarm_Handler(thread);
+#ifdef RTX_EXECUTION_ZONE
+ WatchdogAlarmFlag = 0U;
+#endif
+ osRtxThreadWatchdogInsert(thread, ticks);
+ thread = osRtxInfo.thread.wdog_list;
+ } while ((thread != NULL) && (thread->wdog_tick == 0U));
+ osRtxThreadSetRunning(thread_running);
+ }
+}
+
#endif
static __NO_RETURN void osThreadEntry (void *argument, osThreadFunc_t func) {
@@ -571,18 +734,21 @@
/// Create a thread and add it to Active Threads.
/// \note API identical to osThreadNew
static osThreadId_t svcRtxThreadNew (osThreadFunc_t func, void *argument, const osThreadAttr_t *attr) {
- os_thread_t *thread;
- uint32_t attr_bits;
- void *stack_mem;
- uint32_t stack_size;
- osPriority_t priority;
- uint8_t flags;
- const char *name;
- uint32_t *ptr;
- uint32_t n;
+ os_thread_t *thread;
+#if defined(RTX_SAFETY_CLASS) || defined(RTX_EXECUTION_ZONE)
+ const os_thread_t *thread_running = osRtxThreadGetRunning();
+#endif
+ uint32_t attr_bits;
+ void *stack_mem;
+ uint32_t stack_size;
+ osPriority_t priority;
+ uint8_t flags;
+ const char *name;
+ uint32_t *ptr;
+ uint32_t n;
#if (DOMAIN_NS == 1)
- TZ_ModuleId_t tz_module;
- TZ_MemoryId_t tz_memory;
+ TZ_ModuleId_t tz_module;
+ TZ_MemoryId_t tz_memory;
#endif
// Check parameters
@@ -605,9 +771,24 @@
#if (DOMAIN_NS == 1)
tz_module = attr->tz_module;
#endif
+ if (((attr_bits & osThreadPrivileged) != 0U) && ((attr_bits & osThreadUnprivileged) != 0U)) {
+ EvrRtxThreadError(NULL, (int32_t)osErrorParameter);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return NULL;
+ }
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ if ((thread_running != NULL) &&
+ ((thread_running->attr >> osRtxAttrClass_Pos) <
+ (uint8_t)((attr_bits & osSafetyClass_Msk) >> osSafetyClass_Pos))) {
+ EvrRtxThreadError(NULL, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return NULL;
+ }
+ }
+#endif
if (thread != NULL) {
- //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
- if ((((uint32_t)thread & 3U) != 0U) || (attr->cb_size < sizeof(os_thread_t))) {
+ if (!IsThreadPtrValid(thread) || (attr->cb_size != sizeof(os_thread_t))) {
EvrRtxThreadError(NULL, osRtxErrorInvalidControlBlock);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -648,6 +829,35 @@
#endif
}
+ // Set default privilege if not specified
+ if ((attr_bits & (osThreadPrivileged | osThreadUnprivileged)) == 0U) {
+ if ((osRtxConfig.flags & osRtxConfigPrivilegedMode) != 0U) {
+ attr_bits |= osThreadPrivileged;
+ } else {
+ attr_bits |= osThreadUnprivileged;
+ }
+ }
+
+#ifdef RTX_SAFETY_FEATURES
+ // Check privilege protection
+ if ((attr_bits & osThreadPrivileged) != 0U) {
+ if ((osRtxInfo.kernel.protect & osRtxKernelProtectPrivileged) != 0U) {
+ EvrRtxThreadError(NULL, osRtxErrorInvalidPrivilegedMode);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return NULL;
+ }
+ }
+#endif
+
+#if defined(RTX_EXECUTION_ZONE) && defined(RTX_SAFETY_CLASS)
+ // Check class to zone mapping
+ if (!IsClassMappingValid(attr_bits, thread_running)) {
+ EvrRtxThreadError(NULL, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return NULL;
+ }
+#endif
+
// Check stack size
if (stack_size != 0U) {
if (((stack_size & 7U) != 0U) || (stack_size < (64U + 8U)) || (stack_size > 0x7FFFFFFFU)) {
@@ -662,9 +872,11 @@
if (osRtxInfo.mpi.thread != NULL) {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
thread = osRtxMemoryPoolAlloc(osRtxInfo.mpi.thread);
+#ifndef RTX_OBJ_PTR_CHECK
} else {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
thread = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_thread_t), 1U);
+#endif
}
#ifdef RTX_OBJ_MEM_USAGE
if (thread != NULL) {
@@ -701,11 +913,15 @@
}
if (stack_mem == NULL) {
if ((flags & osRtxFlagSystemObject) != 0U) {
+#ifdef RTX_OBJ_PTR_CHECK
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.thread, thread);
+#else
if (osRtxInfo.mpi.thread != NULL) {
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.thread, thread);
} else {
(void)osRtxMemoryFree(osRtxInfo.mem.common, thread);
}
+#endif
#ifdef RTX_OBJ_MEM_USAGE
osRtxThreadMemUsage.cnt_free++;
#endif
@@ -729,11 +945,15 @@
}
}
if ((flags & osRtxFlagSystemObject) != 0U) {
+#ifdef RTX_OBJ_PTR_CHECK
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.thread, thread);
+#else
if (osRtxInfo.mpi.thread != NULL) {
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.thread, thread);
} else {
(void)osRtxMemoryFree(osRtxInfo.mem.common, thread);
}
+#endif
#ifdef RTX_OBJ_MEM_USAGE
osRtxThreadMemUsage.cnt_free++;
#endif
@@ -753,7 +973,7 @@
thread->id = osRtxIdThread;
thread->state = osRtxThreadReady;
thread->flags = flags;
- thread->attr = (uint8_t)attr_bits;
+ thread->attr = (uint8_t)(attr_bits & ~osRtxAttrClass_Msk);
thread->name = name;
thread->thread_next = NULL;
thread->thread_prev = NULL;
@@ -774,9 +994,39 @@
thread->thread_addr = (uint32_t)func;
#if (DOMAIN_NS == 1)
thread->tz_memory = tz_memory;
- #ifdef RTX_TF_M_EXTENSION
- thread->tz_module = tz_module;
#endif
+ #ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ thread->attr |= (uint8_t)((attr_bits & osSafetyClass_Msk) >>
+ (osSafetyClass_Pos - osRtxAttrClass_Pos));
+ } else {
+ // Inherit safety class from the running thread
+ if (thread_running != NULL) {
+ thread->attr |= (uint8_t)(thread_running->attr & osRtxAttrClass_Msk);
+ }
+ }
+ #endif
+ #ifdef RTX_EXECUTION_ZONE
+ if ((attr_bits & osThreadZone_Valid) != 0U) {
+ thread->zone = (uint8_t)((attr_bits & osThreadZone_Msk) >> osThreadZone_Pos);
+ } else {
+ // Inherit zone from the running thread
+ if (thread_running != NULL) {
+ thread->zone = thread_running->zone;
+ } else {
+ thread->zone = 0U;
+ }
+ }
+ #endif
+ #if defined(RTX_EXECUTION_ZONE) && defined(RTX_SAFETY_CLASS)
+ // Update class to zone assignment table
+ if (ThreadClassTable[thread->zone] == 0U) {
+ ThreadClassTable[thread->zone] = (uint8_t)(0x80U | (thread->attr >> osRtxAttrClass_Pos));
+ }
+ #endif
+ #ifdef RTX_THREAD_WATCHDOG
+ thread->wdog_next = NULL;
+ thread->wdog_tick = 0U;
#endif
// Initialize stack
@@ -795,7 +1045,7 @@
}
ptr[14] = (uint32_t)osThreadEntry; // PC
ptr[15] = xPSR_InitVal(
- (bool_t)((osRtxConfig.flags & osRtxConfigPrivilegedMode) != 0U),
+ (bool_t)((attr_bits & osThreadPrivileged) != 0U),
(bool_t)(((uint32_t)func & 1U) != 0U)
); // xPSR
ptr[8] = (uint32_t)argument; // R0
@@ -822,7 +1072,7 @@
os_thread_t *thread = osRtxThreadId(thread_id);
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread)) {
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread)) {
EvrRtxThreadGetName(thread, NULL);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -833,6 +1083,44 @@
return thread->name;
}
+#ifdef RTX_SAFETY_CLASS
+/// Get safety class of a thread.
+/// \note API identical to osThreadGetClass
+static uint32_t svcRtxThreadGetClass (osThreadId_t thread_id) {
+ os_thread_t *thread = osRtxThreadId(thread_id);
+
+ // Check parameters
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread)) {
+ EvrRtxThreadGetClass(thread, osErrorId);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorId;
+ }
+
+ EvrRtxThreadGetClass(thread, (uint32_t)thread->attr >> osRtxAttrClass_Pos);
+
+ return ((uint32_t)thread->attr >> osRtxAttrClass_Pos);
+}
+#endif
+
+#ifdef RTX_EXECUTION_ZONE
+/// Get zone of a thread.
+/// \note API identical to osThreadGetZone
+static uint32_t svcRtxThreadGetZone (osThreadId_t thread_id) {
+ os_thread_t *thread = osRtxThreadId(thread_id);
+
+ // Check parameters
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread)) {
+ EvrRtxThreadGetZone(thread, osErrorId);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorId;
+ }
+
+ EvrRtxThreadGetZone(thread, thread->zone);
+
+ return thread->zone;
+}
+#endif
+
/// Return the thread ID of the current running thread.
/// \note API identical to osThreadGetId
static osThreadId_t svcRtxThreadGetId (void) {
@@ -850,7 +1138,7 @@
osThreadState_t state;
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread)) {
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread)) {
EvrRtxThreadGetState(thread, osThreadError);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osThreadError;
@@ -869,7 +1157,7 @@
os_thread_t *thread = osRtxThreadId(thread_id);
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread)) {
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread)) {
EvrRtxThreadGetStackSize(thread, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -888,7 +1176,7 @@
uint32_t space;
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread)) {
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread)) {
EvrRtxThreadGetStackSpace(thread, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -921,16 +1209,30 @@
/// Change priority of a thread.
/// \note API identical to osThreadSetPriority
static osStatus_t svcRtxThreadSetPriority (osThreadId_t thread_id, osPriority_t priority) {
- os_thread_t *thread = osRtxThreadId(thread_id);
+ os_thread_t *thread = osRtxThreadId(thread_id);
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread_running;
+#endif
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread) ||
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread) ||
(priority < osPriorityIdle) || (priority > osPriorityISR)) {
EvrRtxThreadError(thread, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread_running = osRtxThreadGetRunning();
+ if ((thread_running != NULL) &&
+ ((thread_running->attr >> osRtxAttrClass_Pos) < (thread->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxThreadError(thread, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Check object state
if (thread->state == osRtxThreadTerminated) {
EvrRtxThreadError(thread, (int32_t)osErrorResource);
@@ -956,7 +1258,7 @@
osPriority_t priority;
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread)) {
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread)) {
EvrRtxThreadGetPriority(thread, osPriorityError);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osPriorityError;
@@ -1000,16 +1302,30 @@
/// Suspend execution of a thread.
/// \note API identical to osThreadSuspend
static osStatus_t svcRtxThreadSuspend (osThreadId_t thread_id) {
- os_thread_t *thread = osRtxThreadId(thread_id);
- osStatus_t status;
+ os_thread_t *thread = osRtxThreadId(thread_id);
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread_running;
+#endif
+ osStatus_t status;
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread)) {
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread)) {
EvrRtxThreadError(thread, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread_running = osRtxThreadGetRunning();
+ if ((thread_running != NULL) &&
+ ((thread_running->attr >> osRtxAttrClass_Pos) < (thread->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxThreadError(thread, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Check object state
switch (thread->state & osRtxThreadStateMask) {
case osRtxThreadRunning:
@@ -1056,15 +1372,29 @@
/// Resume execution of a thread.
/// \note API identical to osThreadResume
static osStatus_t svcRtxThreadResume (osThreadId_t thread_id) {
- os_thread_t *thread = osRtxThreadId(thread_id);
+ os_thread_t *thread = osRtxThreadId(thread_id);
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread_running;
+#endif
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread)) {
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread)) {
EvrRtxThreadError(thread, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread_running = osRtxThreadGetRunning();
+ if ((thread_running != NULL) &&
+ ((thread_running->attr >> osRtxAttrClass_Pos) < (thread->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxThreadError(thread, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Check object state
if ((thread->state & osRtxThreadStateMask) != osRtxThreadBlocked) {
EvrRtxThreadError(thread, (int32_t)osErrorResource);
@@ -1084,7 +1414,7 @@
/// Wakeup a thread waiting to join.
/// \param[in] thread thread object.
-static void osRtxThreadJoinWakeup (os_thread_t *thread) {
+void osRtxThreadJoinWakeup (const os_thread_t *thread) {
if (thread->thread_join != NULL) {
osRtxThreadWaitExit(thread->thread_join, (uint32_t)osOK, FALSE);
@@ -1123,11 +1453,15 @@
// Free object memory
if ((thread->flags & osRtxFlagSystemObject) != 0U) {
+#ifdef RTX_OBJ_PTR_CHECK
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.thread, thread);
+#else
if (osRtxInfo.mpi.thread != NULL) {
(void)osRtxMemoryPoolFree(osRtxInfo.mpi.thread, thread);
} else {
(void)osRtxMemoryFree(osRtxInfo.mem.common, thread);
}
+#endif
#ifdef RTX_OBJ_MEM_USAGE
osRtxThreadMemUsage.cnt_free++;
#endif
@@ -1136,7 +1470,7 @@
/// Destroy a Thread.
/// \param[in] thread thread object.
-static void osRtxThreadDestroy (os_thread_t *thread) {
+void osRtxThreadDestroy (os_thread_t *thread) {
if ((thread->attr & osThreadJoinable) == 0U) {
osRtxThreadFree(thread);
@@ -1156,15 +1490,29 @@
/// Detach a thread (thread storage can be reclaimed when thread terminates).
/// \note API identical to osThreadDetach
static osStatus_t svcRtxThreadDetach (osThreadId_t thread_id) {
- os_thread_t *thread = osRtxThreadId(thread_id);
+ os_thread_t *thread = osRtxThreadId(thread_id);
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread_running;
+#endif
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread)) {
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread)) {
EvrRtxThreadError(thread, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread_running = osRtxThreadGetRunning();
+ if ((thread_running != NULL) &&
+ ((thread_running->attr >> osRtxAttrClass_Pos) < (thread->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxThreadError(thread, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Check object attributes
if ((thread->attr & osThreadJoinable) == 0U) {
EvrRtxThreadError(thread, osRtxErrorThreadNotJoinable);
@@ -1192,12 +1540,23 @@
osStatus_t status;
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread)) {
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread)) {
EvrRtxThreadError(thread, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread_running = osRtxThreadGetRunning();
+ if ((thread_running != NULL) &&
+ ((thread_running->attr >> osRtxAttrClass_Pos) < (thread->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxThreadError(thread, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Check object attributes
if ((thread->attr & osThreadJoinable) == 0U) {
EvrRtxThreadError(thread, osRtxErrorThreadNotJoinable);
@@ -1249,6 +1608,11 @@
// Get running thread
thread = osRtxThreadGetRunning();
+#ifdef RTX_THREAD_WATCHDOG
+ // Remove Thread from the Watchdog list
+ osRtxThreadWatchdogRemove(thread);
+#endif
+
// Release owned Mutexes
osRtxMutexOwnerRelease(thread->mutex_list);
@@ -1278,16 +1642,30 @@
/// Terminate execution of a thread.
/// \note API identical to osThreadTerminate
static osStatus_t svcRtxThreadTerminate (osThreadId_t thread_id) {
- os_thread_t *thread = osRtxThreadId(thread_id);
- osStatus_t status;
+ os_thread_t *thread = osRtxThreadId(thread_id);
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread_running;
+#endif
+ osStatus_t status;
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread)) {
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread)) {
EvrRtxThreadError(thread, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread_running = osRtxThreadGetRunning();
+ if ((thread_running != NULL) &&
+ ((thread_running->attr >> osRtxAttrClass_Pos) < (thread->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxThreadError(thread, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Check object state
switch (thread->state & osRtxThreadStateMask) {
case osRtxThreadRunning:
@@ -1317,6 +1695,11 @@
}
if (status == osOK) {
+#ifdef RTX_THREAD_WATCHDOG
+ // Remove Thread from the Watchdog list
+ osRtxThreadWatchdogRemove(thread);
+#endif
+
// Release owned Mutexes
osRtxMutexOwnerRelease(thread->mutex_list);
@@ -1348,6 +1731,326 @@
return status;
}
+#ifdef RTX_THREAD_WATCHDOG
+/// Feed watchdog of the current running thread.
+/// \note API identical to osThreadFeedWatchdog
+static osStatus_t svcRtxThreadFeedWatchdog (uint32_t ticks) {
+ os_thread_t *thread;
+
+ // Check running thread
+ thread = osRtxThreadGetRunning();
+ if (thread == NULL) {
+ EvrRtxThreadError(NULL, osRtxErrorKernelNotRunning);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osError;
+ }
+
+ osRtxThreadWatchdogRemove(thread);
+ osRtxThreadWatchdogInsert(thread, ticks);
+
+ EvrRtxThreadFeedWatchdogDone();
+
+ return osOK;
+}
+#endif
+
+#ifdef RTX_SAFETY_FEATURES
+/// Protect the creation of privileged threads.
+/// \note API identical to osThreadProtectPrivileged
+static osStatus_t svcRtxThreadProtectPrivileged (void) {
+
+ // Check that Kernel is initialized
+ if (osRtxKernelGetState() == osRtxKernelInactive) {
+ EvrRtxThreadError(NULL, osRtxErrorKernelNotReady);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osError;
+ }
+
+ osRtxInfo.kernel.protect |= osRtxKernelProtectPrivileged;
+
+ EvrRtxThreadPrivilegedProtected();
+
+ return osOK;
+}
+#endif
+
+#ifdef RTX_SAFETY_CLASS
+
+/// Suspend execution of threads for specified safety classes.
+/// \note API identical to osThreadSuspendClass
+static osStatus_t svcRtxThreadSuspendClass (uint32_t safety_class, uint32_t mode) {
+ os_thread_t *thread;
+ os_thread_t *thread_next;
+
+ // Check parameters
+ if (safety_class > 0x0FU) {
+ EvrRtxThreadError(NULL, (int32_t)osErrorParameter);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorParameter;
+ }
+
+ // Check running thread safety class (when called from thread)
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) && IsSVCallIrq()) {
+ if ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ (((thread->attr >> osRtxAttrClass_Pos) + 1U) < (uint8_t)safety_class))) {
+ EvrRtxThreadError(NULL, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+ }
+
+ // Threads in Wait List
+ thread = osRtxInfo.thread.wait_list;
+ while (thread != NULL) {
+ thread_next = thread->delay_next;
+ if ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class))) {
+ osRtxThreadListRemove(thread);
+ thread->state = osRtxThreadBlocked;
+ EvrRtxThreadSuspended(thread);
+ }
+ thread = thread_next;
+ }
+
+ // Threads in Delay List
+ thread = osRtxInfo.thread.delay_list;
+ while (thread != NULL) {
+ thread_next = thread->delay_next;
+ if ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class))) {
+ osRtxThreadListRemove(thread);
+ osRtxThreadDelayRemove(thread);
+ thread->state = osRtxThreadBlocked;
+ osRtxThreadDelayInsert(thread, osWaitForever);
+ EvrRtxThreadSuspended(thread);
+ }
+ thread = thread_next;
+ }
+
+ // Threads in Ready List
+ thread = osRtxInfo.thread.ready.thread_list;
+ while (thread != NULL) {
+ thread_next = thread->thread_next;
+ if ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class))) {
+ osRtxThreadListRemove(thread);
+ thread->state = osRtxThreadBlocked;
+ osRtxThreadDelayInsert(thread, osWaitForever);
+ EvrRtxThreadSuspended(thread);
+ }
+ thread = thread_next;
+ }
+
+ // Running Thread
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)))) {
+ if ((osRtxKernelGetState() == osRtxKernelRunning) &&
+ (osRtxInfo.thread.ready.thread_list != NULL)) {
+ thread->state = osRtxThreadBlocked;
+ osRtxThreadDelayInsert(thread, osWaitForever);
+ EvrRtxThreadSuspended(thread);
+ osRtxThreadSwitch(osRtxThreadListGet(&osRtxInfo.thread.ready));
+ } else {
+ EvrRtxThreadError(thread, (int32_t)osErrorResource);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorResource;
+ }
+ }
+
+ return osOK;
+}
+
+/// Resume execution of threads for specified safety classes.
+/// \note API identical to osThreadResumeClass
+static osStatus_t svcRtxThreadResumeClass (uint32_t safety_class, uint32_t mode) {
+ os_thread_t *thread;
+ os_thread_t *thread_next;
+
+ // Check parameters
+ if (safety_class > 0x0FU) {
+ EvrRtxThreadError(NULL, (int32_t)osErrorParameter);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorParameter;
+ }
+
+ // Check running thread safety class (when called from thread)
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) && IsSVCallIrq()) {
+ if ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ (((thread->attr >> osRtxAttrClass_Pos) + 1U) < (uint8_t)safety_class))) {
+ EvrRtxThreadError(NULL, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+ }
+
+ // Threads in Wait List
+ thread = osRtxInfo.thread.wait_list;
+ while (thread != NULL) {
+ thread_next = thread->delay_next;
+ if ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class))) {
+ // Wakeup Thread
+ osRtxThreadListRemove(thread);
+ osRtxThreadDelayRemove(thread);
+ osRtxThreadReadyPut(thread);
+ EvrRtxThreadResumed(thread);
+ }
+ thread = thread_next;
+ }
+
+ // Threads in Delay List
+ thread = osRtxInfo.thread.delay_list;
+ while (thread != NULL) {
+ thread_next = thread->delay_next;
+ if ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class))) {
+ // Wakeup Thread
+ osRtxThreadListRemove(thread);
+ osRtxThreadDelayRemove(thread);
+ osRtxThreadReadyPut(thread);
+ EvrRtxThreadResumed(thread);
+ }
+ thread = thread_next;
+ }
+
+ osRtxThreadDispatch(NULL);
+
+ return osOK;
+}
+
+#endif
+
+#ifdef RTX_EXECUTION_ZONE
+/// Terminate execution of threads assigned to a specified MPU protected zone.
+/// \note API identical to osThreadTerminateZone
+static osStatus_t svcRtxThreadTerminateZone (uint32_t zone) {
+ os_thread_t *thread;
+ os_thread_t *thread_next;
+
+#ifdef RTX_THREAD_WATCHDOG
+ // Check Watchdog Alarm Flag
+ if (WatchdogAlarmFlag != 0U) {
+ EvrRtxThreadError(NULL, (int32_t)osErrorISR);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorISR;
+ }
+#endif
+
+ // Check parameters
+ if (zone > 0x3FU) {
+ EvrRtxThreadError(NULL, (int32_t)osErrorParameter);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorParameter;
+ }
+
+ // Threads in Wait List
+ thread = osRtxInfo.thread.wait_list;
+ while (thread != NULL) {
+ thread_next = thread->delay_next;
+ if (thread->zone == zone) {
+ osRtxThreadListRemove(thread);
+ osRtxThreadDelayRemove(thread);
+#ifdef RTX_THREAD_WATCHDOG
+ osRtxThreadWatchdogRemove(thread);
+#endif
+ osRtxMutexOwnerRelease(thread->mutex_list);
+ osRtxThreadJoinWakeup(thread);
+ osRtxThreadDestroy(thread);
+ }
+ thread = thread_next;
+ }
+
+ // Threads in Delay List
+ thread = osRtxInfo.thread.delay_list;
+ while (thread != NULL) {
+ thread_next = thread->delay_next;
+ if (thread->zone == zone) {
+ osRtxThreadListRemove(thread);
+ osRtxThreadDelayRemove(thread);
+#ifdef RTX_THREAD_WATCHDOG
+ osRtxThreadWatchdogRemove(thread);
+#endif
+ osRtxMutexOwnerRelease(thread->mutex_list);
+ osRtxThreadJoinWakeup(thread);
+ osRtxThreadDestroy(thread);
+ }
+ thread = thread_next;
+ }
+
+ // Threads in Ready List
+ thread = osRtxInfo.thread.ready.thread_list;
+ while (thread != NULL) {
+ thread_next = thread->thread_next;
+ if (thread->zone == zone) {
+ osRtxThreadListRemove(thread);
+#ifdef RTX_THREAD_WATCHDOG
+ osRtxThreadWatchdogRemove(thread);
+#endif
+ osRtxMutexOwnerRelease(thread->mutex_list);
+ osRtxThreadJoinWakeup(thread);
+ osRtxThreadDestroy(thread);
+ }
+ thread = thread_next;
+ }
+
+ // Running Thread
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) && (thread->zone == zone)) {
+ if ((osRtxKernelGetState() != osRtxKernelRunning) ||
+ (osRtxInfo.thread.ready.thread_list == NULL)) {
+ osRtxThreadDispatch(NULL);
+ EvrRtxThreadError(thread, (int32_t)osErrorResource);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorResource;
+ }
+#ifdef RTX_THREAD_WATCHDOG
+ osRtxThreadWatchdogRemove(thread);
+#endif
+ osRtxMutexOwnerRelease(thread->mutex_list);
+ osRtxThreadJoinWakeup(thread);
+ // Switch to next Ready Thread
+ osRtxThreadSwitch(osRtxThreadListGet(&osRtxInfo.thread.ready));
+ // Update Stack Pointer
+ thread->sp = __get_PSP();
+#ifdef RTX_STACK_CHECK
+ // Check Stack usage
+ if (!osRtxThreadStackCheck(thread)) {
+ osRtxThreadSetRunning(osRtxInfo.thread.run.next);
+ (void)osRtxKernelErrorNotify(osRtxErrorStackOverflow, thread);
+ }
+#endif
+ // Mark running thread as deleted
+ osRtxThreadSetRunning(NULL);
+ // Destroy Thread
+ osRtxThreadDestroy(thread);
+ } else {
+ osRtxThreadDispatch(NULL);
+ }
+
+ return osOK;
+}
+#endif
+
/// Get number of active threads.
/// \note API identical to osThreadGetCount
static uint32_t svcRtxThreadGetCount (void) {
@@ -1430,12 +2133,15 @@
/// Set the specified Thread Flags of a thread.
/// \note API identical to osThreadFlagsSet
static uint32_t svcRtxThreadFlagsSet (osThreadId_t thread_id, uint32_t flags) {
- os_thread_t *thread = osRtxThreadId(thread_id);
- uint32_t thread_flags;
- uint32_t thread_flags0;
+ os_thread_t *thread = osRtxThreadId(thread_id);
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread_running;
+#endif
+ uint32_t thread_flags;
+ uint32_t thread_flags0;
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread) ||
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread) ||
((flags & ~(((uint32_t)1U << osRtxThreadFlagsLimit) - 1U)) != 0U)) {
EvrRtxThreadFlagsError(thread, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
@@ -1449,6 +2155,17 @@
return ((uint32_t)osErrorResource);
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread_running = osRtxThreadGetRunning();
+ if ((thread_running != NULL) &&
+ ((thread_running->attr >> osRtxAttrClass_Pos) < (thread->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxThreadFlagsError(thread, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return ((uint32_t)osErrorSafetyClass);
+ }
+#endif
+
// Set Thread Flags
thread_flags = ThreadFlagsSet(thread, flags);
@@ -1567,6 +2284,12 @@
//lint ++flb "Library Begin" [MISRA Note 11]
SVC0_3 (ThreadNew, osThreadId_t, osThreadFunc_t, void *, const osThreadAttr_t *)
SVC0_1 (ThreadGetName, const char *, osThreadId_t)
+#ifdef RTX_SAFETY_CLASS
+SVC0_1 (ThreadGetClass, uint32_t, osThreadId_t)
+#endif
+#ifdef RTX_EXECUTION_ZONE
+SVC0_1 (ThreadGetZone, uint32_t, osThreadId_t)
+#endif
SVC0_0 (ThreadGetId, osThreadId_t)
SVC0_1 (ThreadGetState, osThreadState_t, osThreadId_t)
SVC0_1 (ThreadGetStackSize, uint32_t, osThreadId_t)
@@ -1580,6 +2303,16 @@
SVC0_1 (ThreadJoin, osStatus_t, osThreadId_t)
SVC0_0N(ThreadExit, void)
SVC0_1 (ThreadTerminate, osStatus_t, osThreadId_t)
+#ifdef RTX_THREAD_WATCHDOG
+SVC0_1 (ThreadFeedWatchdog, osStatus_t, uint32_t)
+#endif
+#ifdef RTX_SAFETY_FEATURES
+SVC0_0 (ThreadProtectPrivileged, osStatus_t)
+#endif
+#ifdef RTX_SAFETY_CLASS
+SVC0_2 (ThreadSuspendClass, osStatus_t, uint32_t, uint32_t)
+SVC0_2 (ThreadResumeClass, osStatus_t, uint32_t, uint32_t)
+#endif
SVC0_0 (ThreadGetCount, uint32_t)
SVC0_2 (ThreadEnumerate, uint32_t, osThreadId_t *, uint32_t)
SVC0_2 (ThreadFlagsSet, uint32_t, osThreadId_t, uint32_t)
@@ -1599,7 +2332,7 @@
uint32_t thread_flags;
// Check parameters
- if ((thread == NULL) || (thread->id != osRtxIdThread) ||
+ if (!IsThreadPtrValid(thread) || (thread->id != osRtxIdThread) ||
((flags & ~(((uint32_t)1U << osRtxThreadFlagsLimit) - 1U)) != 0U)) {
EvrRtxThreadFlagsError(thread, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
@@ -1683,14 +2416,41 @@
const char *name;
if (IsException() || IsIrqMasked()) {
- EvrRtxThreadGetName(thread_id, NULL);
- name = NULL;
+ name = svcRtxThreadGetName(thread_id);
} else {
- name = __svcThreadGetName(thread_id);
+ name = __svcThreadGetName(thread_id);
}
return name;
}
+#ifdef RTX_SAFETY_CLASS
+/// Get safety class of a thread.
+uint32_t osThreadGetClass (osThreadId_t thread_id) {
+ uint32_t safety_class;
+
+ if (IsException() || IsIrqMasked()) {
+ safety_class = svcRtxThreadGetClass(thread_id);
+ } else {
+ safety_class = __svcThreadGetClass(thread_id);
+ }
+ return safety_class;
+}
+#endif
+
+#ifdef RTX_EXECUTION_ZONE
+/// Get zone of a thread.
+uint32_t osThreadGetZone (osThreadId_t thread_id) {
+ uint32_t zone;
+
+ if (IsException() || IsIrqMasked()) {
+ zone = svcRtxThreadGetZone(thread_id);
+ } else {
+ zone = __svcThreadGetZone(thread_id);
+ }
+ return zone;
+}
+#endif
+
/// Return the thread ID of the current running thread.
osThreadId_t osThreadGetId (void) {
osThreadId_t thread_id;
@@ -1861,6 +2621,99 @@
return status;
}
+#ifdef RTX_THREAD_WATCHDOG
+/// Feed watchdog of the current running thread.
+osStatus_t osThreadFeedWatchdog (uint32_t ticks) {
+ osStatus_t status;
+
+ EvrRtxThreadFeedWatchdog(ticks);
+ if (IsException() || IsIrqMasked()) {
+ EvrRtxThreadError(NULL, (int32_t)osErrorISR);
+ status = osErrorISR;
+ } else {
+ status = __svcThreadFeedWatchdog(ticks);
+ }
+ return status;
+}
+#endif
+
+#ifdef RTX_SAFETY_FEATURES
+/// Protect the creation of privileged threads.
+osStatus_t osThreadProtectPrivileged (void) {
+ osStatus_t status;
+
+ EvrRtxThreadProtectPrivileged();
+ if (IsException() || IsIrqMasked()) {
+ EvrRtxThreadError(NULL, (int32_t)osErrorISR);
+ status = osErrorISR;
+ } else {
+ status = __svcThreadProtectPrivileged();
+ }
+ return status;
+}
+#endif
+
+#ifdef RTX_SAFETY_CLASS
+
+/// Suspend execution of threads for specified safety classes.
+osStatus_t osThreadSuspendClass (uint32_t safety_class, uint32_t mode) {
+ osStatus_t status;
+
+ EvrRtxThreadSuspendClass(safety_class, mode);
+ if (IsException() || IsIrqMasked()) {
+ if (IsTickIrq(osRtxInfo.tick_irqn)) {
+ status = svcRtxThreadSuspendClass(safety_class, mode);
+ } else {
+ EvrRtxThreadError(NULL, (int32_t)osErrorISR);
+ status = osErrorISR;
+ }
+ } else {
+ status = __svcThreadSuspendClass(safety_class, mode);
+ }
+ return status;
+}
+
+/// Resume execution of threads for specified safety classes.
+osStatus_t osThreadResumeClass (uint32_t safety_class, uint32_t mode) {
+ osStatus_t status;
+
+ EvrRtxThreadResumeClass(safety_class, mode);
+ if (IsException() || IsIrqMasked()) {
+ if (IsTickIrq(osRtxInfo.tick_irqn)) {
+ status = svcRtxThreadResumeClass(safety_class, mode);
+ } else {
+ EvrRtxThreadError(NULL, (int32_t)osErrorISR);
+ status = osErrorISR;
+ }
+ } else {
+ status = __svcThreadResumeClass(safety_class, mode);
+ }
+ return status;
+}
+
+#endif
+
+#ifdef RTX_EXECUTION_ZONE
+/// Terminate execution of threads assigned to a specified MPU protected zone.
+osStatus_t osThreadTerminateZone (uint32_t zone) {
+ osStatus_t status;
+
+ EvrRtxThreadTerminateZone(zone);
+ if (IsException() || IsIrqMasked()) {
+ if (IsFault() || IsSVCallIrq() || IsPendSvIrq() || IsTickIrq(osRtxInfo.tick_irqn)) {
+ status = svcRtxThreadTerminateZone(zone);
+ } else {
+ EvrRtxThreadError(NULL, (int32_t)osErrorISR);
+ status = osErrorISR;
+ }
+ } else {
+ EvrRtxThreadError(osRtxThreadGetRunning(), (int32_t)osError);
+ status = osError;
+ }
+ return status;
+}
+#endif
+
/// Get number of active threads.
uint32_t osThreadGetCount (void) {
uint32_t count;
diff --git a/CMSIS/RTOS2/RTX/Source/rtx_timer.c b/CMSIS/RTOS2/RTX/Source/rtx_timer.c
index 8400687..11c16a1 100644
--- a/CMSIS/RTOS2/RTX/Source/rtx_timer.c
+++ b/CMSIS/RTOS2/RTX/Source/rtx_timer.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2022 Arm Limited. All rights reserved.
+ * Copyright (c) 2013-2023 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
@@ -88,6 +88,35 @@
osRtxInfo.timer.list = timer->next;
}
+/// Verify that Timer object pointer is valid.
+/// \param[in] timer timer object.
+/// \return true - valid, false - invalid.
+static bool_t IsTimerPtrValid (const os_timer_t *timer) {
+#ifdef RTX_OBJ_PTR_CHECK
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ uint32_t cb_start = (uint32_t)&__os_timer_cb_start__;
+ uint32_t cb_length = (uint32_t)&__os_timer_cb_length__;
+
+ // Check the section boundaries
+ if (((uint32_t)timer - cb_start) >= cb_length) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+ // Check the object alignment
+ if ((((uint32_t)timer - cb_start) % sizeof(os_timer_t)) != 0U) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#else
+ // Check NULL pointer
+ if (timer == NULL) {
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
// ==== Library functions ====
@@ -119,7 +148,7 @@
}
}
}
- if (timer->type == osRtxTimerPeriodic) {
+ if ((timer->attr & osRtxTimerPeriodic) != 0U) {
TimerInsert(timer, timer->load);
} else {
timer->state = osRtxTimerStopped;
@@ -164,14 +193,74 @@
}
}
+/// Destroy a Timer object.
+/// \param[in] timer timer object.
+static void osRtxTimerDestroy (os_timer_t *timer) {
+
+ // Mark object as inactive and invalid
+ timer->state = osRtxTimerInactive;
+ timer->id = osRtxIdInvalid;
+
+ // Free object memory
+ if ((timer->flags & osRtxFlagSystemObject) != 0U) {
+#ifdef RTX_OBJ_PTR_CHECK
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.timer, timer);
+#else
+ if (osRtxInfo.mpi.timer != NULL) {
+ (void)osRtxMemoryPoolFree(osRtxInfo.mpi.timer, timer);
+ } else {
+ (void)osRtxMemoryFree(osRtxInfo.mem.common, timer);
+ }
+#endif
+#ifdef RTX_OBJ_MEM_USAGE
+ osRtxTimerMemUsage.cnt_free++;
+#endif
+ }
+
+ EvrRtxTimerDestroyed(timer);
+}
+
+#ifdef RTX_SAFETY_CLASS
+/// Delete a Timer safety class.
+/// \param[in] safety_class safety class.
+/// \param[in] mode safety mode.
+void osRtxTimerDeleteClass (uint32_t safety_class, uint32_t mode) {
+ os_timer_t *timer;
+ uint32_t length;
+
+ //lint --e{923} --e{9078} "cast from pointer to unsigned int" [MISRA Note 7]
+ timer = (os_timer_t *)(uint32_t)&__os_timer_cb_start__;
+ length = (uint32_t)&__os_timer_cb_length__;
+ while (length >= sizeof(os_timer_t)) {
+ if ( (timer->id == osRtxIdTimer) &&
+ ((((mode & osSafetyWithSameClass) != 0U) &&
+ ((timer->attr >> osRtxAttrClass_Pos) == (uint8_t)safety_class)) ||
+ (((mode & osSafetyWithLowerClass) != 0U) &&
+ ((timer->attr >> osRtxAttrClass_Pos) < (uint8_t)safety_class)))) {
+ if (timer->state == osRtxTimerRunning) {
+ TimerRemove(timer);
+ }
+ osRtxTimerDestroy(timer);
+ }
+ length -= sizeof(os_timer_t);
+ timer++;
+ }
+}
+#endif
+
+
// ==== Service Calls ====
/// Create and Initialize a timer.
/// \note API identical to osTimerNew
static osTimerId_t svcRtxTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr) {
- os_timer_t *timer;
- uint8_t flags;
- const char *name;
+ os_timer_t *timer;
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread = osRtxThreadGetRunning();
+ uint32_t attr_bits;
+#endif
+ uint8_t flags;
+ const char *name;
// Check parameters
if ((func == NULL) || ((type != osTimerOnce) && (type != osTimerPeriodic))) {
@@ -182,12 +271,25 @@
// Process attributes
if (attr != NULL) {
- name = attr->name;
+ name = attr->name;
+#ifdef RTX_SAFETY_CLASS
+ attr_bits = attr->attr_bits;
+#endif
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 6]
- timer = attr->cb_mem;
+ timer = attr->cb_mem;
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) <
+ (uint8_t)((attr_bits & osSafetyClass_Msk) >> osSafetyClass_Pos))) {
+ EvrRtxTimerError(NULL, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return NULL;
+ }
+ }
+#endif
if (timer != NULL) {
- //lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note 7]
- if ((((uint32_t)timer & 3U) != 0U) || (attr->cb_size < sizeof(os_timer_t))) {
+ if (!IsTimerPtrValid(timer) || (attr->cb_size != sizeof(os_timer_t))) {
EvrRtxTimerError(NULL, osRtxErrorInvalidControlBlock);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -200,8 +302,11 @@
}
}
} else {
- name = NULL;
- timer = NULL;
+ name = NULL;
+#ifdef RTX_SAFETY_CLASS
+ attr_bits = 0U;
+#endif
+ timer = NULL;
}
// Allocate object memory if not provided
@@ -209,9 +314,11 @@
if (osRtxInfo.mpi.timer != NULL) {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
timer = osRtxMemoryPoolAlloc(osRtxInfo.mpi.timer);
+#ifndef RTX_OBJ_PTR_CHECK
} else {
//lint -e{9079} "conversion from pointer to void to pointer to other type" [MISRA Note 5]
timer = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_timer_t), 1U);
+#endif
}
#ifdef RTX_OBJ_MEM_USAGE
if (timer != NULL) {
@@ -233,7 +340,11 @@
timer->id = osRtxIdTimer;
timer->state = osRtxTimerStopped;
timer->flags = flags;
- timer->type = (uint8_t)type;
+ if (type == osTimerPeriodic) {
+ timer->attr = osRtxTimerPeriodic;
+ } else {
+ timer->attr = 0U;
+ }
timer->name = name;
timer->prev = NULL;
timer->next = NULL;
@@ -241,7 +352,17 @@
timer->load = 0U;
timer->finfo.func = func;
timer->finfo.arg = argument;
-
+#ifdef RTX_SAFETY_CLASS
+ if ((attr_bits & osSafetyClass_Valid) != 0U) {
+ timer->attr |= (uint8_t)((attr_bits & osSafetyClass_Msk) >>
+ (osSafetyClass_Pos - osRtxAttrClass_Pos));
+ } else {
+ // Inherit safety class from the running thread
+ if (thread != NULL) {
+ timer->attr |= (uint8_t)(thread->attr & osRtxAttrClass_Msk);
+ }
+ }
+#endif
EvrRtxTimerCreated(timer, timer->name);
} else {
EvrRtxTimerError(NULL, (int32_t)osErrorNoMemory);
@@ -256,7 +377,7 @@
os_timer_t *timer = osRtxTimerId(timer_id);
// Check parameters
- if ((timer == NULL) || (timer->id != osRtxIdTimer)) {
+ if (!IsTimerPtrValid(timer) || (timer->id != osRtxIdTimer)) {
EvrRtxTimerGetName(timer, NULL);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return NULL;
@@ -270,15 +391,29 @@
/// Start or restart a timer.
/// \note API identical to osTimerStart
static osStatus_t svcRtxTimerStart (osTimerId_t timer_id, uint32_t ticks) {
- os_timer_t *timer = osRtxTimerId(timer_id);
+ os_timer_t *timer = osRtxTimerId(timer_id);
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread;
+#endif
// Check parameters
- if ((timer == NULL) || (timer->id != osRtxIdTimer) || (ticks == 0U)) {
+ if (!IsTimerPtrValid(timer) || (timer->id != osRtxIdTimer) || (ticks == 0U)) {
EvrRtxTimerError(timer, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (timer->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxTimerError(timer, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
if (timer->state == osRtxTimerRunning) {
timer->load = ticks;
TimerRemove(timer);
@@ -303,15 +438,29 @@
/// Stop a timer.
/// \note API identical to osTimerStop
static osStatus_t svcRtxTimerStop (osTimerId_t timer_id) {
- os_timer_t *timer = osRtxTimerId(timer_id);
+ os_timer_t *timer = osRtxTimerId(timer_id);
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread;
+#endif
// Check parameters
- if ((timer == NULL) || (timer->id != osRtxIdTimer)) {
+ if (!IsTimerPtrValid(timer) || (timer->id != osRtxIdTimer)) {
EvrRtxTimerError(timer, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (timer->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxTimerError(timer, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
// Check object state
if (timer->state != osRtxTimerRunning) {
EvrRtxTimerError(timer, (int32_t)osErrorResource);
@@ -335,7 +484,7 @@
uint32_t is_running;
// Check parameters
- if ((timer == NULL) || (timer->id != osRtxIdTimer)) {
+ if (!IsTimerPtrValid(timer) || (timer->id != osRtxIdTimer)) {
EvrRtxTimerIsRunning(timer, 0U);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return 0U;
@@ -355,36 +504,34 @@
/// Delete a timer.
/// \note API identical to osTimerDelete
static osStatus_t svcRtxTimerDelete (osTimerId_t timer_id) {
- os_timer_t *timer = osRtxTimerId(timer_id);
+ os_timer_t *timer = osRtxTimerId(timer_id);
+#ifdef RTX_SAFETY_CLASS
+ const os_thread_t *thread;
+#endif
// Check parameters
- if ((timer == NULL) || (timer->id != osRtxIdTimer)) {
+ if (!IsTimerPtrValid(timer) || (timer->id != osRtxIdTimer)) {
EvrRtxTimerError(timer, (int32_t)osErrorParameter);
//lint -e{904} "Return statement before end of function" [MISRA Note 1]
return osErrorParameter;
}
+#ifdef RTX_SAFETY_CLASS
+ // Check running thread safety class
+ thread = osRtxThreadGetRunning();
+ if ((thread != NULL) &&
+ ((thread->attr >> osRtxAttrClass_Pos) < (timer->attr >> osRtxAttrClass_Pos))) {
+ EvrRtxTimerError(timer, (int32_t)osErrorSafetyClass);
+ //lint -e{904} "Return statement before end of function" [MISRA Note 1]
+ return osErrorSafetyClass;
+ }
+#endif
+
if (timer->state == osRtxTimerRunning) {
TimerRemove(timer);
}
- // Mark object as inactive and invalid
- timer->state = osRtxTimerInactive;
- timer->id = osRtxIdInvalid;
-
- // Free object memory
- if ((timer->flags & osRtxFlagSystemObject) != 0U) {
- if (osRtxInfo.mpi.timer != NULL) {
- (void)osRtxMemoryPoolFree(osRtxInfo.mpi.timer, timer);
- } else {
- (void)osRtxMemoryFree(osRtxInfo.mem.common, timer);
- }
-#ifdef RTX_OBJ_MEM_USAGE
- osRtxTimerMemUsage.cnt_free++;
-#endif
- }
-
- EvrRtxTimerDestroyed(timer);
+ osRtxTimerDestroy(timer);
return osOK;
}
@@ -421,10 +568,9 @@
const char *name;
if (IsException() || IsIrqMasked()) {
- EvrRtxTimerGetName(timer_id, NULL);
- name = NULL;
+ name = svcRtxTimerGetName(timer_id);
} else {
- name = __svcTimerGetName(timer_id);
+ name = __svcTimerGetName(timer_id);
}
return name;
}