Arm-Cortex-R82: Add MPU support (#1347)

* arm-cortex-r82: Add MPU support

This commit introduces support for the Memory Protection Unit (MPU)
to the ARM Cortex-R82 port. The MPU enhances system security
by allowing the definition of memory regions with specific access
permissions. The following changes have been made:
- Added MPU configuration functions in `port.c` to set up memory
  regions and their attributes.
- Updated `portASM.S` to include assembly routines for MPU
  and context switching with MPU support.
- Created `mpu_wrappers_v2_asm.c` to provide assembly wrappers for
  MPU operations.
- Updated `portmacro.h` to include MPU-related macros and definitions.
- Modified `task.h` to include MPU-related task attributes.
- Updated `CMakeLists.txt` to include the new MPU source file.
- Enhanced the `README.md` with instructions on MPU configuration.

Signed-off-by: Ahmed Ismail <Ahmed.Ismail@arm.com>

* cortex-r82: Minor code improvements

This commit includes minor code improvements to enhance readability
and maintainability of the Cortex-R82 port files. Changes include
refactoring variable names, optimizing comments, and improving code
structure without altering functionality.

Signed-off-by: Ahmed Ismail <Ahmed.Ismail@arm.com>

* tasks: Disable stack-depth check if MPU wrappers is set

This stack-depth check should not be performed for ports
where portUSING_MPU_WRAPPERS is set to 1.
In this case, pxTopOfStack and pxNewTCB->pxTopOfStack reside
in different memory regions: pxTopOfStack is in unprivileged SRAM,
while pxNewTCB->pxTopOfStack is in privileged SRAM.
This is because pxPortInitialiseStack() returns the address of
`ullContext` array rather than the decremented pxTopOfStack,
as is done in the non-MPU case.
Consequently, this check is not valid in this scenario.

Signed-off-by: Ahmed Ismail <Ahmed.Ismail@arm.com>

---------

Signed-off-by: Ahmed Ismail <Ahmed.Ismail@arm.com>
This commit is contained in:
Ahmed Ismail 2026-02-11 04:48:55 +00:00 committed by GitHub
parent d33d04b14c
commit 6cd736cfeb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 3130 additions and 504 deletions

View file

@ -1,7 +1,7 @@
/*
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* Copyright 2025 Arm Limited and/or its affiliates
* Copyright 2025-2026 Arm Limited and/or its affiliates
* <open-source-office@arm.com>
*
* SPDX-License-Identifier: MIT
@ -109,14 +109,21 @@
/**
* @brief SVC numbers.
*/
#define portSVC_YIELD 105
#define portSVC_START_FIRST_TASK 106
#define portSVC_DISABLE_INTERRUPTS 107
#define portSVC_ENABLE_INTERRUPTS 108
#define portSVC_GET_CORE_ID 109
#define portSVC_MASK_ALL_INTERRUPTS 110
#define portSVC_UNMASK_ALL_INTERRUPTS 111
#define portSVC_UNMASK_INTERRUPTS 112
#define portSVC_SYSTEM_CALL_EXIT 104
#define portSVC_YIELD 105
#define portSVC_START_FIRST_TASK 106
#define portSVC_DISABLE_INTERRUPTS 107
#define portSVC_ENABLE_INTERRUPTS 108
#define portSVC_GET_CORE_ID 109
#define portSVC_MASK_ALL_INTERRUPTS 110
#define portSVC_UNMASK_ALL_INTERRUPTS 111
#define portSVC_UNMASK_INTERRUPTS 112
#define portSVC_CHECK_PRIVILEGE 113
#define portSVC_SAVE_TASK_CONTEXT 114
#define portSVC_RESTORE_CONTEXT 115
#define portSVC_DELETE_CURRENT_TASK 116
#define portSVC_INTERRUPT_CORE 117
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
#define portYIELD() __asm volatile ( "SVC %0" : : "i" ( portSVC_YIELD ) : "memory" )
@ -132,22 +139,21 @@
extern UBaseType_t uxPortSetInterruptMaskFromISR( void );
extern void vPortClearInterruptMask( UBaseType_t uxNewMaskValue );
extern void vPortClearInterruptMaskFromISR( UBaseType_t uxNewMaskValue );
extern void vInterruptCore( uint32_t ulInterruptID, uint32_t ulCoreID );
extern void vInterruptCore( uint32_t ulInterruptID, uint8_t ucCoreID );
#endif /* if !defined(__ASSEMBLER__) */
/* Use SVC so this is safe from EL0. EL1 sites in the port use direct MSR. */\
/* Use SVC so this is safe from EL0. EL1 sites in the port use direct MSR. */
#define portDISABLE_INTERRUPTS() __asm volatile ( "SVC %0" : : "i" ( portSVC_DISABLE_INTERRUPTS ) : "memory" )
#define portENABLE_INTERRUPTS() __asm volatile ( "SVC %0" : : "i" ( portSVC_ENABLE_INTERRUPTS ) : "memory" )
/* In all GICs 255 can be written to the priority mask register to unmask all
* (but the lowest) interrupt priority. */
#define portUNMASK_VALUE ( 0xFFUL )
#if !defined(__ASSEMBLER__)
/* These macros do not globally disable/enable interrupts. They do mask off
* interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */
* interrupts that have a priority below configMAX_API_CALL_INTERRUPT_PRIORITY. */
#if ( configNUMBER_OF_CORES == 1 )
extern void vPortEnterCritical( void );
extern void vPortExitCritical( void );
@ -173,7 +179,7 @@
#if !defined(__ASSEMBLER__)
/* Prototype of the FreeRTOS tick handler. This must be installed as the
* handler for whichever peripheral is used to generate the RTOS tick. */
* handler for whichever peripheral is used to generate the RTOS tick. */
void FreeRTOS_Tick_Handler( void );
#endif /* if !defined(__ASSEMBLER__) */
@ -193,7 +199,8 @@
* nothing to prevent it from being called accidentally. */
#define vPortTaskUsesFPU()
#endif
#define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()
#define portTASK_USES_FLOATING_POINT() vPortTaskUsesFPU()
#define portLOWEST_INTERRUPT_PRIORITY ( ( ( uint32_t ) configUNIQUE_INTERRUPT_PRIORITIES ) - 1UL )
#define portLOWEST_USABLE_INTERRUPT_PRIORITY ( portLOWEST_INTERRUPT_PRIORITY - 1UL )
@ -205,12 +212,10 @@
#if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
/* Store/clear the ready priorities in a bit map. */
/* Store/clear the ready priorities in a bit map. */
#define portRECORD_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) |= ( 1UL << ( uxPriority ) )
#define portRESET_READY_PRIORITY( uxPriority, uxReadyPriorities ) ( uxReadyPriorities ) &= ~( 1UL << ( uxPriority ) )
/*-----------------------------------------------------------*/
#define portGET_HIGHEST_PRIORITY( uxTopPriority, uxReadyPriorities ) uxTopPriority = ( 31 - __builtin_clz( uxReadyPriorities ) )
#endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
@ -220,7 +225,7 @@
#define portASSERT_IF_INTERRUPT_PRIORITY_INVALID() vPortValidateInterruptPriority()
#endif /* configASSERT */
#define portNOP() __asm volatile ( "NOP" )
#define portNOP() __asm volatile ( "NOP" )
#define portINLINE __inline
/* The number of bits to shift for an interrupt priority is dependent on the
@ -246,6 +251,7 @@
#define portINTERRUPT_PRIORITY_REGISTER_OFFSET ( 0x400U )
#define portYIELD_CORE_INT_ID ( 0x0U )
#define portMAX_API_PRIORITY_MASK ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT )
#if ( configNUMBER_OF_CORES > 1 )
@ -258,36 +264,274 @@
} ePortRTOSLock;
extern volatile uint64_t ullCriticalNestings[ configNUMBER_OF_CORES ];
extern void vPortRecursiveLock( BaseType_t xCoreID,
extern void vPortRecursiveLock( uint8_t ucCoreID,
ePortRTOSLock eLockNum,
BaseType_t uxAcquire );
extern BaseType_t xPortGetCoreID( void );
extern uint8_t ucPortGetCoreID( void );
extern uint8_t ucPortGetCoreIDFromIsr( void );
#endif /* if !defined(__ASSEMBLER__) */
#define portSET_INTERRUPT_MASK() uxPortSetInterruptMask()
#define portCLEAR_INTERRUPT_MASK( x ) vPortClearInterruptMask( x )
#define portMAX_CORE_COUNT configNUMBER_OF_CORES
#define portGET_CORE_ID() xPortGetCoreID()
#define portMAX_CORE_COUNT configNUMBER_OF_CORES
#define portGET_CORE_ID() ucPortGetCoreID()
#define portGET_CORE_ID_FROM_ISR() ucPortGetCoreIDFromIsr()
/* Use SGI 0 as the yield core interrupt. */
#define portYIELD_CORE( xCoreID ) vInterruptCore( portYIELD_CORE_INT_ID, ( uint32_t ) xCoreID )
/* Use SGI 0 as the yield core interrupt. */
#define portYIELD_CORE( xCoreID ) vInterruptCore( portYIELD_CORE_INT_ID, ( uint8_t ) xCoreID )
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( xCoreID ), eIsrLock, pdFALSE )
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( xCoreID ), eIsrLock, pdTRUE )
#define portRELEASE_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdFALSE )
#define portGET_ISR_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eIsrLock, pdTRUE )
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( xCoreID ), eTaskLock, pdFALSE )
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( xCoreID ), eTaskLock, pdTRUE )
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ullCriticalNestings[ ( xCoreID ) ] )
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ullCriticalNestings[ ( xCoreID ) ] = ( x ) )
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ullCriticalNestings[ ( xCoreID ) ]++ )
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ullCriticalNestings[ ( xCoreID ) ]-- )
#define portRELEASE_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdFALSE )
#define portGET_TASK_LOCK( xCoreID ) vPortRecursiveLock( ( uint8_t ) xCoreID, eTaskLock, pdTRUE )
#define portGET_CRITICAL_NESTING_COUNT( xCoreID ) ( ullCriticalNestings[ ( uint8_t ) xCoreID ] )
#define portSET_CRITICAL_NESTING_COUNT( xCoreID, x ) ( ullCriticalNestings[ ( uint8_t ) xCoreID ] = ( x ) )
#define portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ullCriticalNestings[ ( uint8_t ) xCoreID ]++ )
#define portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ) ( ullCriticalNestings[ ( uint8_t ) xCoreID ]-- )
#endif /* configNUMBER_OF_CORES > 1 */
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )
/**
* @brief MPU specific constants.
*/
#if ( configENABLE_MPU == 1 )
#if !defined(__ASSEMBLER__)
extern BaseType_t xPortIsTaskPrivileged( void );
#endif /* if !defined(__ASSEMBLER__) */
/* Device memory attributes used in MAIR_EL1 registers.
*
* 8-bit values encoded as follows:
* Bit[7:4] - 0000 - Device Memory
* Bit[3:2] - 00 --> Device-nGnRnE
* 01 --> Device-nGnRE
* 10 --> Device-nGRE
* 11 --> Device-GRE
* Bit[1:0] - 00.
*/
#define portMPU_DEVICE_MEMORY_nGnRnE ( 0x00 )
#define portMPU_DEVICE_MEMORY_nGnRE ( 0x04 )
#define portMPU_DEVICE_MEMORY_nGRE ( 0x08 )
#define portMPU_DEVICE_MEMORY_GRE ( 0x0C )
/* MPU settings that can be overridden in FreeRTOSConfig.h. */
#ifndef configTOTAL_MPU_REGIONS
#define configTOTAL_MPU_REGIONS ( 16UL )
#endif
#define portPRIVILEGED_FLASH_REGION ( 0ULL ) /* Privileged flash region number. */
#define portUNPRIVILEGED_FLASH_REGION ( 1ULL ) /* Unprivileged flash region number. */
#define portUNPRIVILEGED_SYSCALLS_REGION ( 2ULL ) /* Unprivileged syscalls region number. */
#define portPRIVILEGED_RAM_REGION ( 3ULL ) /* Privileged RAM region number. */
#define portSTACK_REGION ( 4ULL ) /* Stack region number. */
#define portSTACK_REGION_INDEX ( 0ULL ) /* Stack region index in the xRegionSettings array. */
#define portFIRST_CONFIGURABLE_REGION ( 5ULL ) /* First user configurable region number. */
#define portLAST_CONFIGURABLE_REGION ( configTOTAL_MPU_REGIONS - 1UL )
#define portNUM_CONFIGURABLE_REGIONS ( ( portLAST_CONFIGURABLE_REGION - portFIRST_CONFIGURABLE_REGION ) + 1 )
#define portTOTAL_NUM_REGIONS ( portNUM_CONFIGURABLE_REGIONS + 1 ) /* Plus one to make space for the stack region. */
#if ( configENABLE_ACCESS_CONTROL_LIST == 1 )
#define portACL_ENTRY_SIZE_BITS ( 32UL )
#endif /* configENABLE_ACCESS_CONTROL_LIST == 1 */
#if !defined(__ASSEMBLER__)
/**
* @brief Settings to define an MPU region.
*/
typedef struct MPURegionSettings
{
uint64_t ullPrbarEl1; /**< PRBAR_EL1 for the region. */
uint64_t ullPrlarEl1; /**< PRLAR_EL1 for the region. */
} MPURegionSettings_t;
#ifndef configSYSTEM_CALL_STACK_SIZE
#define configSYSTEM_CALL_STACK_SIZE 128 /* must be defined to the desired size of the system call stack in words for using MPU wrappers v2. */
#endif
/**
* @brief System call info.
*/
typedef struct SYSTEM_CALL_INFO
{
/* Used to save both the user-mode stack pointer (SP_EL0) and link register (X30)
* at system call entry so they can be restored or referenced safely even if the task
* switches out while executing the system call.
*/
uint64_t ullLinkRegisterAtSystemCallEntry;
uint64_t ullUserSPAtSystemCallEntry;
} xSYSTEM_CALL_INFO;
#endif /* if !defined(__ASSEMBLER__) */
/**
* @brief Task context as stored in the TCB.
*/
#if ( configENABLE_FPU == 1 )
/*
* +-----------+------------+--------------------------------+-------------+------------------+
* | Q0-Q31 | FPSR, FPCR | CRITICAL_NESTING, FPU_CONTEXT | X0-X30, XZR | INIT_PSTATE, PC |
* +-----------+------------+--------------------------------+-------------+------------------+
*
* <-----------><-----------><-------------------------------><------------><----------------->
* 64 2 2 32 2
*/
#define MAX_CONTEXT_SIZE 102
#else /* #if ( configENABLE_FPU == 1 ) */
/*
* +--------------------------------+-------------+------------------+
* | CRITICAL_NESTING, FPU_CONTEXT | X0-X30, XZR | INIT_PSTATE, PC |
* +--------------------------------+-------------+------------------+
* <-------------------------------><------------><------------------>
* 2 32 2
*/
#define MAX_CONTEXT_SIZE 36
#endif /* #if ( configENABLE_FPU == 1 ) */
#if !defined(__ASSEMBLER__)
typedef struct MPU_SETTINGS
{
uint64_t ullTaskUnprivilegedSP; /* Task's unprivileged user stack pointer. */
uint64_t ullMairEl1; /* MAIR_EL1 for the task containing attributes. */
MPURegionSettings_t xRegionsSettings[ portTOTAL_NUM_REGIONS ]; /* Settings for tasks' regions. */
uint64_t ullContext[ MAX_CONTEXT_SIZE + configSYSTEM_CALL_STACK_SIZE ]; /* Task's saved context. */
uint64_t ullTaskFlags;
xSYSTEM_CALL_INFO xSystemCallInfo;
#if ( configENABLE_ACCESS_CONTROL_LIST == 1 )
uint32_t ulAccessControlList[ ( configPROTECTED_KERNEL_OBJECT_POOL_SIZE / portACL_ENTRY_SIZE_BITS ) + 1 ];
#endif /* configENABLE_ACCESS_CONTROL_LIST */
} xMPU_SETTINGS;
#endif /* if !defined(__ASSEMBLER__) */
#define portUSING_MPU_WRAPPERS ( 1 )
#define portPRIVILEGE_BIT ( 0x80000000UL )
/* Normal memory attributes used in MAIR_EL1 registers. */
#define portMPU_NORMAL_MEMORY_NON_CACHEABLE ( 0x44 ) /* Non-cacheable. */
#define portMPU_NORMAL_MEMORY_BUFFERABLE_CACHEABLE ( 0xFF ) /* Non-Transient, Write-back, Read-Allocate and Write-Allocate. */
#define portMPU_MAIR_EL1_ATTR0_POS ( 0UL )
#define portMPU_MAIR_EL1_ATTR0_MASK ( 0x00000000000000ffULL )
#define portMPU_MAIR_EL1_ATTR1_POS ( 8UL )
#define portMPU_MAIR_EL1_ATTR1_MASK ( 0x000000000000ff00ULL )
#define portMPU_MAIR_EL1_ATTR2_POS ( 16UL )
#define portMPU_MAIR_EL1_ATTR2_MASK ( 0x0000000000ff0000ULL )
#define portMPU_MAIR_EL1_ATTR3_POS ( 24UL )
#define portMPU_MAIR_EL1_ATTR3_MASK ( 0x00000000ff000000ULL )
#define portMPU_MAIR_EL1_ATTR4_POS ( 32UL )
#define portMPU_MAIR_EL1_ATTR4_MASK ( 0x000000ff00000000ULL )
#define portMPU_MAIR_EL1_ATTR5_POS ( 40UL )
#define portMPU_MAIR_EL1_ATTR5_MASK ( 0x0000ff0000000000ULL )
#define portMPU_MAIR_EL1_ATTR6_POS ( 48UL )
#define portMPU_MAIR_EL1_ATTR6_MASK ( 0x00ff000000000000ULL )
#define portMPU_MAIR_EL1_ATTR7_POS ( 56UL )
#define portMPU_MAIR_EL1_ATTR7_MASK ( 0xff00000000000000ULL )
#define portMPU_PRBAR_EL1_ADDRESS_MASK ( 0x0000FFFFFFFFFFC0ULL )
#define portMPU_PRLAR_EL1_ADDRESS_MASK ( 0x0000FFFFFFFFFFC0ULL )
#define portMPU_PRBAR_EL1_ACCESS_PERMISSIONS_MASK ( 3ULL<< 2ULL )
#define portMPU_REGION_NON_SHAREABLE ( 0ULL << 4ULL )
#define portMPU_REGION_OUTER_SHAREABLE ( 2ULL << 4ULL )
#define portMPU_REGION_INNER_SHAREABLE ( 3ULL << 4ULL )
#define portMPU_REGION_PRIVILEGED_READ_WRITE ( 0ULL << 2ULL )
#define portMPU_REGION_READ_WRITE ( 1ULL << 2ULL )
#define portMPU_REGION_PRIVILEGED_READ_ONLY ( 2ULL << 2ULL )
#define portMPU_REGION_READ_ONLY ( 3ULL << 2ULL )
#define portMPU_REGION_EXECUTE_NEVER ( 1ULL << 1ULL )
#define portMPU_PRLAR_EL1_ATTR_INDEX0 ( 0ULL << 1ULL )
#define portMPU_PRLAR_EL1_ATTR_INDEX1 ( 1ULL << 1ULL )
#define portMPU_PRLAR_EL1_ATTR_INDEX2 ( 2ULL << 1ULL )
#define portMPU_PRLAR_EL1_ATTR_INDEX3 ( 3ULL << 1ULL )
#define portMPU_PRLAR_EL1_ATTR_INDEX4 ( 4ULL << 1ULL )
#define portMPU_PRLAR_EL1_ATTR_INDEX5 ( 5ULL << 1ULL )
#define portMPU_PRLAR_EL1_ATTR_INDEX6 ( 6ULL << 1ULL )
#define portMPU_PRLAR_EL1_ATTR_INDEX7 ( 7ULL << 1ULL )
#define portMPU_PRLAR_EL1_REGION_ENABLE ( 1ULL )
#define portMPU_ENABLE_BIT ( 1ULL << 0ULL )
#define portMPU_PRIV_BACKGROUND_ENABLE_BIT ( 1ULL << 17ULL )
/* Max value that fits in a uint64_t type. */
#define portUINT64_MAX ( ~( ( uint64_t ) 0 ) )
#define portADD_UINT64_WILL_OVERFLOW( a, b ) ( ( a ) > ( portUINT64_MAX - ( b ) ) )
/* Extract first address of the MPU region as encoded in the
* PRBAR_EL1 register value. */
#define portEXTRACT_FIRST_ADDRESS_FROM_PRBAR_EL1( prbar_el1 ) \
( ( prbar_el1 ) & portMPU_PRBAR_EL1_ADDRESS_MASK )
/* Extract last address of the MPU region as encoded in the
* PRLAR_EL1 register value. */
#define portEXTRACT_LAST_ADDRESS_FROM_PRLAR_EL1( prlar_el1 ) \
( ( ( prlar_el1 ) & portMPU_PRLAR_EL1_ADDRESS_MASK ) | ~portMPU_PRLAR_EL1_ADDRESS_MASK )
/* Does addr lies within [start, end] address range? */
#define portIS_ADDRESS_WITHIN_RANGE( addr, start, end ) \
( ( ( addr ) >= ( start ) ) && ( ( addr ) <= ( end ) ) )
/* Is the access request satisfied by the available permissions? */
#define portIS_AUTHORIZED( accessRequest, permissions ) \
( ( ( permissions ) & ( accessRequest ) ) == accessRequest )
/**
* @brief Offsets in the task's stack (context).
*/
#if ( configUSE_TASK_FPU_SUPPORT == portTASK_HAVE_FPU_CONTEXT_BY_DEFAULT )
#define portOFFSET_TO_PC ( 68 )
#define portOFFSET_TO_LR ( 70 )
#define portOFFSET_TO_X0 ( 100 )
#define portOFFSET_TO_X1 ( 101 )
#define portOFFSET_TO_X2 ( 98 )
#define portOFFSET_TO_X3 ( 99 )
#else
#define portOFFSET_TO_PC ( 2 )
#define portOFFSET_TO_LR ( 4 )
#define portOFFSET_TO_X0 ( 34 )
#define portOFFSET_TO_X1 ( 35 )
#define portOFFSET_TO_X2 ( 32 )
#define portOFFSET_TO_X3 ( 33 )
#endif
/**
* @brief Flag used to mark that a Task is privileged.
*
* @ingroup Port Privilege
*/
#define portTASK_IS_PRIVILEGED_FLAG ( 1UL << 1UL )
/**
* @brief Checks whether or not the calling task is privileged.
*
* @return pdTRUE if the calling task is privileged, pdFALSE otherwise.
*/
#define portIS_TASK_PRIVILEGED() xPortIsTaskPrivileged()
#else
#define portPRIVILEGE_BIT ( 0x0UL )
#endif /* #if ( configENABLE_MPU == 1 ) */
#define portPSTATE_I_BIT ( 0x7 )
/* *INDENT-OFF* */
#ifdef __cplusplus
}