diff --git a/portable/CMakeLists.txt b/portable/CMakeLists.txt index ffbb6164c..0ba95d9a4 100644 --- a/portable/CMakeLists.txt +++ b/portable/CMakeLists.txt @@ -75,6 +75,12 @@ add_library(freertos_kernel_port OBJECT GCC/ARM_AARCH64_SRE/port.c GCC/ARM_AARCH64_SRE/portASM.S> + # ARMv9-A port for GCC (SVE2, MTE, PAC, BTI) + $<$: + GCC/ARM_AARCH64_ARMV9/port.c + GCC/ARM_AARCH64_ARMV9/mte_port.c + GCC/ARM_AARCH64_ARMV9/portASM.S> + # ARMv6-M port for GCC $<$: GCC/ARM_CM0/port.c @@ -1014,6 +1020,9 @@ target_include_directories(freertos_kernel_port_headers INTERFACE $<$:${CMAKE_CURRENT_LIST_DIR}/GCC/ARM_AARCH64> $<$:${CMAKE_CURRENT_LIST_DIR}/GCC/ARM_AARCH64_SRE> + # ARMv9-A port for GCC + $<$:${CMAKE_CURRENT_LIST_DIR}/GCC/ARM_AARCH64_ARMV9> + # ARMv6-M port for GCC $<$:${CMAKE_CURRENT_LIST_DIR}/GCC/ARM_CM0> diff --git a/portable/GCC/ARM_AARCH64_ARMV9/mte_port.c b/portable/GCC/ARM_AARCH64_ARMV9/mte_port.c index 644cdfea9..cc268e90b 100644 --- a/portable/GCC/ARM_AARCH64_ARMV9/mte_port.c +++ b/portable/GCC/ARM_AARCH64_ARMV9/mte_port.c @@ -19,6 +19,8 @@ void * pvPortMallocTagged( size_t xSize ) { + /* MISRA Ref 11.5.1 [Void pointer assignment] */ + /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */ void * pv = pvPortMalloc( xSize ); if( pv == NULL ) @@ -31,6 +33,9 @@ void * pvPortMallocTagged( size_t xSize ) /* Tag all 16-byte granules in the allocation */ size_t xRounded = ( xSize + 15U ) & ~15U; + + /* MISRA Ref 11.5.1 [Void pointer assignment] */ + /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */ uint8_t * pucTagPtr = ( uint8_t * ) pv; for( size_t i = 0; i < xRounded; i += 16U ) @@ -49,11 +54,15 @@ void vPortFreeTagged( void * pv ) } /* Strip tag (top byte) to recover the canonical address for the allocator */ + /* MISRA Ref 11.6.1 [Pointer to integer conversion] */ + /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-116 */ uintptr_t xAddr = ( uintptr_t ) pv & 0x00FFFFFFFFFFFFFFULL; void * pvUntagged = ( void * ) xAddr; /* Re-tag freed region with tag 0 (use-after-free detection). * Tag the first 64 bytes (covers most small allocations). */ + /* MISRA Ref 11.5.1 [Void pointer assignment] */ + /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */ uint8_t * pucPtr = ( uint8_t * ) pvUntagged; for( size_t i = 0; i < 64U; i += 16U ) @@ -70,6 +79,8 @@ void vPortFreeTagged( void * pv ) void vPortMteTagStack( StackType_t * pxStack, uint32_t ulStackDepth ) { + /* MISRA Ref 11.5.1 [Void pointer assignment] */ + /* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-115 */ void * pvAddr = ( void * ) pxStack; size_t xBytes = ( size_t ) ulStackDepth * sizeof( StackType_t ); diff --git a/portable/GCC/ARM_AARCH64_ARMV9/port.c b/portable/GCC/ARM_AARCH64_ARMV9/port.c index b85ab46ee..a68f4b6d9 100644 --- a/portable/GCC/ARM_AARCH64_ARMV9/port.c +++ b/portable/GCC/ARM_AARCH64_ARMV9/port.c @@ -30,6 +30,20 @@ #include #include +/* + * MISRA C:2012 Deviations for this port file: + * + * MISRA Ref 4.3.1 [Inline assembly usage] + * Rationale: This is a hardware port — inline assembly is required + * to access AArch64 system registers (GIC, generic timer, PAC keys, + * MTE configuration) that have no C-language equivalent. + * + * MISRA Ref 11.1.1, 11.5.1, 11.6.1 [Pointer type conversions] + * Rationale: Pointer casts between void*, integer types, and function + * pointers are required for stack initialisation, MTE tag manipulation, + * and setting task entry points in the initial context frame. + */ + /* Scheduler includes. */ #include "FreeRTOS.h" #include "task.h" @@ -162,20 +176,30 @@ void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR ) __attribute__((weak) ); * a non zero value to ensure interrupts don't inadvertently become unmasked before * the scheduler starts. As it is stored as part of the task context it will * automatically be set to 0 when the first task is started. */ +/* MISRA Ref 8.4.1 [Declaration shall be visible] */ +/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-84 */ volatile uint64_t ullCriticalNesting = 9999ULL; /* Saved as part of the task context. If ullPortTaskHasFPUContext is non-zero * then floating point context must be saved and restored for the task. */ +/* MISRA Ref 8.4.1 [Declaration shall be visible] */ +/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-84 */ uint64_t ullPortTaskHasFPUContext = pdFALSE; /* Set to 1 to pend a context switch from an ISR. */ +/* MISRA Ref 8.4.1 [Declaration shall be visible] */ +/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-84 */ uint64_t ullPortYieldRequired = pdFALSE; /* Counts the interrupt nesting depth. A context switch is only performed if * if the nesting depth is 0. */ +/* MISRA Ref 8.4.1 [Declaration shall be visible] */ +/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-84 */ uint64_t ullPortInterruptNesting = 0; /* Used in the ASM code. */ +/* MISRA Ref 8.4.1 [Declaration shall be visible] */ +/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#rule-84 */ __attribute__( ( used ) ) const uint64_t ullMaxAPIPriorityMask = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ); /*-----------------------------------------------------------*/ @@ -287,12 +311,12 @@ StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack, * when configARMV9_PAC_DETERMINISTIC_KEYS is defined (for testing). */ { uint64_t k0, k1, k2, k3, k4, k5, k6, k7; - #if ( defined( configARMV9_PAC_DETERMINISTIC_KEYS ) && configARMV9_PAC_DETERMINISTIC_KEYS == 1 ) + #if ( ( defined( configARMV9_PAC_DETERMINISTIC_KEYS ) ) && ( configARMV9_PAC_DETERMINISTIC_KEYS == 1 ) ) { /* Deterministic PRNG for reproducible test runs. * xorshift64* seeded from the stack address. */ static uint64_t ullPacPrngState = 0xA5A5A5A5DEADBEEFULL; - #define PAC_PRNG_NEXT( s ) do { (s) ^= (s) >> 12; (s) ^= (s) << 25; (s) ^= (s) >> 27; (s) *= 0x2545F4914F6CDD1DULL; } while(0) + #define PAC_PRNG_NEXT( s ) do { (s) ^= ((s) >> 12); (s) ^= ((s) << 25); (s) ^= ((s) >> 27); (s) *= 0x2545F4914F6CDD1DULL; } while(0) PAC_PRNG_NEXT( ullPacPrngState ); k0 = ullPacPrngState; PAC_PRNG_NEXT( ullPacPrngState ); k1 = ullPacPrngState; PAC_PRNG_NEXT( ullPacPrngState ); k2 = ullPacPrngState; @@ -422,7 +446,7 @@ void vPortEndScheduler( void ) void vPortEnterCritical( void ) { /* Mask interrupts up to the max syscall interrupt priority. */ - uxPortSetInterruptMask(); + ( void ) uxPortSetInterruptMask(); /* Now interrupts are disabled ullCriticalNesting can be accessed * directly. Increment ullCriticalNesting to keep a count of how many times @@ -470,6 +494,7 @@ void FreeRTOS_Tick_Handler( void ) /* s3_0_c12_c11_3 is ICC_RPR_EL1. */ __asm volatile ( "MRS %0, s3_0_c12_c11_3" : "=r" ( ullRunningInterruptPriority ) ); configASSERT( ullRunningInterruptPriority == ( portLOWEST_USABLE_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) ); + ( void ) ullRunningInterruptPriority; } #endif @@ -618,10 +643,10 @@ void vPortTaskRegeneratePACKeys( void ) * Called from task context. Keys take effect immediately (MSR + ISB). */ uint64_t k0, k1, k2, k3, k4, k5, k6, k7; - #if ( defined( configARMV9_PAC_DETERMINISTIC_KEYS ) && configARMV9_PAC_DETERMINISTIC_KEYS == 1 ) + #if ( ( defined( configARMV9_PAC_DETERMINISTIC_KEYS ) ) && ( configARMV9_PAC_DETERMINISTIC_KEYS == 1 ) ) { static uint64_t ullRegenState = 0xDEADC0DEBEEF1234ULL; - #define PAC_REGEN_NEXT( s ) do { (s) ^= (s) >> 12; (s) ^= (s) << 25; (s) ^= (s) >> 27; (s) *= 0x2545F4914F6CDD1DULL; } while(0) + #define PAC_REGEN_NEXT( s ) do { (s) ^= ((s) >> 12); (s) ^= ((s) << 25); (s) ^= ((s) >> 27); (s) *= 0x2545F4914F6CDD1DULL; } while(0) PAC_REGEN_NEXT( ullRegenState ); k0 = ullRegenState; PAC_REGEN_NEXT( ullRegenState ); k1 = ullRegenState; PAC_REGEN_NEXT( ullRegenState ); k2 = ullRegenState; diff --git a/portable/GCC/ARM_AARCH64_ARMV9/portmacro.h b/portable/GCC/ARM_AARCH64_ARMV9/portmacro.h index 11daad1d0..8971d96b9 100644 --- a/portable/GCC/ARM_AARCH64_ARMV9/portmacro.h +++ b/portable/GCC/ARM_AARCH64_ARMV9/portmacro.h @@ -59,7 +59,7 @@ typedef portBASE_TYPE BaseType_t; typedef uint64_t UBaseType_t; typedef uint64_t TickType_t; -#define portMAX_DELAY ( ( TickType_t ) 0xffffffffffffffff ) +#define portMAX_DELAY ( ( TickType_t ) 0xffffffffffffffffULL ) /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do * not need to be guarded with a critical section. */ @@ -105,6 +105,13 @@ extern UBaseType_t uxPortSetInterruptMask( void ); extern void vPortClearInterruptMask( UBaseType_t uxNewMaskValue ); extern void vPortInstallFreeRTOSVectorTable( void ); +/* Port variables accessed from portASM.S. */ +extern volatile uint64_t ullCriticalNesting; +extern uint64_t ullPortTaskHasFPUContext; +extern uint64_t ullPortYieldRequired; +extern uint64_t ullPortInterruptNesting; +extern const uint64_t ullMaxAPIPriorityMask; + #define portDISABLE_INTERRUPTS() \ __asm volatile ( "MSR DAIFSET, #2" ::: "memory" ); \ __asm volatile ( "DSB SY" ); \ @@ -140,6 +147,10 @@ void FreeRTOS_Tick_Handler( void ); * themselves an FPU context before using any FPU instructions. If * configUSE_TASK_FPU_SUPPORT is set to 2 then all tasks will have an FPU context * by default. */ +#ifndef configUSE_TASK_FPU_SUPPORT + #define configUSE_TASK_FPU_SUPPORT 1 +#endif + #if ( configUSE_TASK_FPU_SUPPORT != 2 ) void vPortTaskUsesFPU( void ); #else @@ -214,7 +225,15 @@ void FreeRTOS_Tick_Handler( void ); void *pvPortMallocTagged( size_t xSize ); void vPortFreeTagged( void *pv ); /* Transparent redirect: all pvPortMalloc/vPortFree calls get MTE tagging. - * Excluded from allocator implementation files via PORTMEMORY_IMPLEMENTATION. */ + * Excluded from allocator implementation files via PORTMEMORY_IMPLEMENTATION. + * + * MISRA Ref 5.8.1 [Identifier with external linkage reused as macro] + * Rationale: The macro redirect keeps all MTE logic isolated in the port + * directory without modifying shared upstream kernel files (heap_4.c). + * An alternative that would eliminate this deviation is to integrate the + * MTE tagging directly into heap_4.c, guarded by configARMV9_MTE_HEAP. + * That approach trades this violation for a modification to a shared file + * with associated rebase/merge risk and cross-platform #include concerns. */ #if !defined( PORTMEMORY_IMPLEMENTATION ) #define pvPortMalloc pvPortMallocTagged #define vPortFree vPortFreeTagged