X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=FreeRTOS%2FSource%2Fportable%2FGCC%2FARM_CM3_MPU%2Fport.c;h=6917addcadabe73ec7350925692530ba24e3348f;hb=b15dfacb6026af3b0ba697e5753844923b468d2b;hp=15f46d02f018b6bc54c5db474b9dd609d7f77466;hpb=bb2faca82c580d60469d268594bdc3cb26a632b3;p=freertos diff --git a/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c b/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c index 15f46d02f..6917addca 100644 --- a/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c +++ b/FreeRTOS/Source/portable/GCC/ARM_CM3_MPU/port.c @@ -1,97 +1,69 @@ /* - FreeRTOS V8.0.1 - Copyright (C) 2014 Real Time Engineers Ltd. - All rights reserved - - VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION. - - *************************************************************************** - * * - * FreeRTOS provides completely free yet professionally developed, * - * robust, strictly quality controlled, supported, and cross * - * platform software that has become a de facto standard. * - * * - * Help yourself get started quickly and support the FreeRTOS * - * project by purchasing a FreeRTOS tutorial book, reference * - * manual, or both from: http://www.FreeRTOS.org/Documentation * - * * - * Thank you! * - * * - *************************************************************************** - - This file is part of the FreeRTOS distribution. - - FreeRTOS is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License (version 2) as published by the - Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception. - - >>! NOTE: The modification to the GPL is included to allow you to !<< - >>! distribute a combined work that includes FreeRTOS without being !<< - >>! obliged to provide the source code for proprietary components !<< - >>! outside of the FreeRTOS kernel. !<< - - FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. Full license text is available from the following - link: http://www.freertos.org/a00114.html - - 1 tab == 4 spaces! - - *************************************************************************** - * * - * Having a problem? Start by reading the FAQ "My application does * - * not run, what could be wrong?" * - * * - * http://www.FreeRTOS.org/FAQHelp.html * - * * - *************************************************************************** - - http://www.FreeRTOS.org - Documentation, books, training, latest versions, - license and Real Time Engineers Ltd. contact details. - - http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products, - including FreeRTOS+Trace - an indispensable productivity tool, a DOS - compatible FAT file system, and our tiny thread aware UDP/IP stack. - - http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High - Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS - licenses offer ticketed support, indemnification and middleware. - - http://www.SafeRTOS.com - High Integrity Systems also provide a safety - engineered and independently SIL3 certified version for use in safety and - mission critical applications that require provable dependability. - - 1 tab == 4 spaces! -*/ + * FreeRTOS Kernel V10.3.0 + * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * http://www.FreeRTOS.org + * http://aws.amazon.com/freertos + * + * 1 tab == 4 spaces! + */ /*----------------------------------------------------------- * Implementation of functions defined in portable.h for the ARM CM3 port. *----------------------------------------------------------*/ /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining -all the API functions to use the MPU wrappers. That should only be done when -task.h is included from an application file. */ + * all the API functions to use the MPU wrappers. That should only be done when + * task.h is included from an application file. */ #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE /* Scheduler includes. */ #include "FreeRTOS.h" #include "task.h" -#include "queue.h" #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE +#ifndef configSYSTICK_CLOCK_HZ + #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ + /* Ensure the SysTick is clocked at the same frequency as the core. */ + #define portNVIC_SYSTICK_CLK ( 1UL << 2UL ) +#else + /* The way the SysTick is clocked is not modified in case it is not the same + * as the core. */ + #define portNVIC_SYSTICK_CLK ( 0 ) +#endif + /* Constants required to access and manipulate the NVIC. */ -#define portNVIC_SYSTICK_CTRL ( ( volatile uint32_t * ) 0xe000e010 ) -#define portNVIC_SYSTICK_LOAD ( ( volatile uint32_t * ) 0xe000e014 ) -#define portNVIC_SYSPRI2 ( ( volatile uint32_t * ) 0xe000ed20 ) -#define portNVIC_SYSPRI1 ( ( volatile uint32_t * ) 0xe000ed1c ) -#define portNVIC_SYS_CTRL_STATE ( ( volatile uint32_t * ) 0xe000ed24 ) +#define portNVIC_SYSTICK_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000e010 ) ) +#define portNVIC_SYSTICK_LOAD_REG ( * ( ( volatile uint32_t * ) 0xe000e014 ) ) +#define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) ) +#define portNVIC_SYSPRI2_REG ( * ( ( volatile uint32_t * ) 0xe000ed20 ) ) +#define portNVIC_SYSPRI1_REG ( * ( ( volatile uint32_t * ) 0xe000ed1c ) ) +#define portNVIC_SYS_CTRL_STATE_REG ( * ( ( volatile uint32_t * ) 0xe000ed24 ) ) #define portNVIC_MEM_FAULT_ENABLE ( 1UL << 16UL ) /* Constants required to access and manipulate the MPU. */ -#define portMPU_TYPE ( ( volatile uint32_t * ) 0xe000ed90 ) -#define portMPU_REGION_BASE_ADDRESS ( ( volatile uint32_t * ) 0xe000ed9C ) -#define portMPU_REGION_ATTRIBUTE ( ( volatile uint32_t * ) 0xe000edA0 ) -#define portMPU_CTRL ( ( volatile uint32_t * ) 0xe000ed94 ) +#define portMPU_TYPE_REG ( * ( ( volatile uint32_t * ) 0xe000ed90 ) ) +#define portMPU_REGION_BASE_ADDRESS_REG ( * ( ( volatile uint32_t * ) 0xe000ed9C ) ) +#define portMPU_REGION_ATTRIBUTE_REG ( * ( ( volatile uint32_t * ) 0xe000edA0 ) ) +#define portMPU_CTRL_REG ( * ( ( volatile uint32_t * ) 0xe000ed94 ) ) #define portEXPECTED_MPU_TYPE_VALUE ( 8UL << 8UL ) /* 8 regions, unified. */ #define portMPU_ENABLE ( 0x01UL ) #define portMPU_BACKGROUND_ENABLE ( 1UL << 2UL ) @@ -102,33 +74,34 @@ task.h is included from an application file. */ #define portPERIPHERALS_END_ADDRESS 0x5FFFFFFFUL /* Constants required to access and manipulate the SysTick. */ -#define portNVIC_SYSTICK_CLK ( 0x00000004UL ) #define portNVIC_SYSTICK_INT ( 0x00000002UL ) #define portNVIC_SYSTICK_ENABLE ( 0x00000001UL ) #define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL ) #define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL ) -#define portNVIC_SVC_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL ) +#define portNVIC_SVC_PRI ( ( ( uint32_t ) configMAX_SYSCALL_INTERRUPT_PRIORITY - 1UL ) << 24UL ) /* Constants required to set up the initial stack. */ #define portINITIAL_XPSR ( 0x01000000 ) #define portINITIAL_CONTROL_IF_UNPRIVILEGED ( 0x03 ) #define portINITIAL_CONTROL_IF_PRIVILEGED ( 0x02 ) +/* Constants required to check the validity of an interrupt priority. */ +#define portFIRST_USER_INTERRUPT_NUMBER ( 16 ) +#define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 ) +#define portAIRCR_REG ( * ( ( volatile uint32_t * ) 0xE000ED0C ) ) +#define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff ) +#define portTOP_BIT_OF_BYTE ( ( uint8_t ) 0x80 ) +#define portMAX_PRIGROUP_BITS ( ( uint8_t ) 7 ) +#define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL ) +#define portPRIGROUP_SHIFT ( 8UL ) + /* Offsets in the stack to the parameters when inside the SVC handler. */ #define portOFFSET_TO_PC ( 6 ) -/* Set the privilege level to user mode if xRunningPrivileged is false. */ -#define portRESET_PRIVILEGE( xRunningPrivileged ) if( xRunningPrivileged != pdTRUE ) __asm volatile ( " mrs r0, control \n orr r0, #1 \n msr control, r0" :::"r0" ) - -/* Each task maintains its own interrupt status in the critical nesting -variable. Note this is not saved as part of the task context as context -switches can only occur when uxCriticalNesting is zero. */ -static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; - -/* - * Setup the timer to generate the tick interrupts. - */ -static void prvSetupTimerInterrupt( void ) PRIVILEGED_FUNCTION; +/* For strict compliance with the Cortex-M spec the task start address should + * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */ +#define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL ) +/*-----------------------------------------------------------*/ /* * Configure a number of standard MPU regions that are used by all tasks. @@ -143,11 +116,11 @@ static void prvSetupMPU( void ) PRIVILEGED_FUNCTION; static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes ) PRIVILEGED_FUNCTION; /* - * Checks to see if being called from the context of an unprivileged task, and - * if so raises the privilege level and returns false - otherwise does nothing - * other than return true. + * Setup the timer to generate the tick interrupts. The implementation in this + * file is weak to allow application writers to change the timer used to + * generate the tick interrupt. */ -static BaseType_t prvRaisePrivilege( void ) __attribute__(( naked )); +void vPortSetupTimerInterrupt( void ); /* * Standard FreeRTOS exception handlers. @@ -167,57 +140,52 @@ static void prvRestoreContextOfFirstTask( void ) __attribute__(( naked )) PRIVIL */ static void prvSVCHandler( uint32_t *pulRegisters ) __attribute__(( noinline )) PRIVILEGED_FUNCTION; -/* - * Prototypes for all the MPU wrappers. +/** + * @brief Checks whether or not the processor is privileged. + * + * @return 1 if the processor is already privileged, 0 otherwise. + */ +BaseType_t xIsPrivileged( void ) __attribute__ (( naked )); + +/** + * @brief Lowers the privilege level by setting the bit 0 of the CONTROL + * register. + * + * Bit 0 of the CONTROL register defines the privilege level of Thread Mode. + * Bit[0] = 0 --> The processor is running privileged + * Bit[0] = 1 --> The processor is running unprivileged. + */ +void vResetPrivilege( void ) __attribute__ (( naked )); + +/** + * @brief Calls the port specific code to raise the privilege. + * + * @return pdFALSE if privilege was raised, pdTRUE otherwise. + */ +extern BaseType_t xPortRaisePrivilege( void ); + +/** + * @brief If xRunningPrivileged is not pdTRUE, calls the port specific + * code to reset the privilege, otherwise does nothing. */ -BaseType_t MPU_xTaskGenericCreate( TaskFunction_t pvTaskCode, const char * const pcName, uint16_t usStackDepth, void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pxCreatedTask, StackType_t *puxStackBuffer, const MemoryRegion_t * const xRegions ); -void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const xRegions ); -void MPU_vTaskDelete( TaskHandle_t pxTaskToDelete ); -void MPU_vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, TickType_t xTimeIncrement ); -void MPU_vTaskDelay( TickType_t xTicksToDelay ); -UBaseType_t MPU_uxTaskPriorityGet( TaskHandle_t pxTask ); -void MPU_vTaskPrioritySet( TaskHandle_t pxTask, UBaseType_t uxNewPriority ); -eTaskState MPU_eTaskGetState( TaskHandle_t pxTask ); -void MPU_vTaskSuspend( TaskHandle_t pxTaskToSuspend ); -void MPU_vTaskResume( TaskHandle_t pxTaskToResume ); -void MPU_vTaskSuspendAll( void ); -BaseType_t MPU_xTaskResumeAll( void ); -TickType_t MPU_xTaskGetTickCount( void ); -UBaseType_t MPU_uxTaskGetNumberOfTasks( void ); -void MPU_vTaskList( char *pcWriteBuffer ); -void MPU_vTaskGetRunTimeStats( char *pcWriteBuffer ); -void MPU_vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxTagValue ); -TaskHookFunction_t MPU_xTaskGetApplicationTaskTag( TaskHandle_t xTask ); -BaseType_t MPU_xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ); -UBaseType_t MPU_uxTaskGetStackHighWaterMark( TaskHandle_t xTask ); -TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void ); -BaseType_t MPU_xTaskGetSchedulerState( void ); -TaskHandle_t MPU_xTaskGetIdleTaskHandle( void ); -UBaseType_t MPU_uxTaskGetSystemState( TaskStatus_t *pxTaskStatusArray, UBaseType_t uxArraySize, uint32_t *pulTotalRunTime ); -QueueHandle_t MPU_xQueueGenericCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize, uint8_t ucQueueType ); -BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, BaseType_t xCopyPosition ); -BaseType_t MPU_xQueueGenericReset( QueueHandle_t pxQueue, BaseType_t xNewQueue ); -UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t pxQueue ); -BaseType_t MPU_xQueueGenericReceive( QueueHandle_t pxQueue, void * const pvBuffer, TickType_t xTicksToWait, BaseType_t xJustPeeking ); -QueueHandle_t MPU_xQueueCreateMutex( void ); -QueueHandle_t MPU_xQueueCreateCountingSemaphore( UBaseType_t uxCountValue, UBaseType_t uxInitialCount ); -BaseType_t MPU_xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xBlockTime ); -BaseType_t MPU_xQueueGiveMutexRecursive( QueueHandle_t xMutex ); -BaseType_t MPU_xQueueAltGenericSend( QueueHandle_t pxQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, BaseType_t xCopyPosition ); -BaseType_t MPU_xQueueAltGenericReceive( QueueHandle_t pxQueue, void * const pvBuffer, TickType_t xTicksToWait, BaseType_t xJustPeeking ); -void MPU_vQueueAddToRegistry( QueueHandle_t xQueue, char *pcName ); -void MPU_vQueueDelete( QueueHandle_t xQueue ); -void *MPU_pvPortMalloc( size_t xSize ); -void MPU_vPortFree( void *pv ); -void MPU_vPortInitialiseBlocks( void ); -size_t MPU_xPortGetFreeHeapSize( void ); -QueueSetHandle_t MPU_xQueueCreateSet( UBaseType_t uxEventQueueLength ); -QueueSetMemberHandle_t MPU_xQueueSelectFromSet( QueueSetHandle_t xQueueSet, TickType_t xBlockTimeTicks ); -BaseType_t MPU_xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ); -BaseType_t MPU_xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ); -BaseType_t MPU_xQueuePeekFromISR( QueueHandle_t xQueue, void * const pvBuffer ); -void* MPU_xQueueGetMutexHolder( QueueHandle_t xSemaphore ); +extern void vPortResetPrivilege( BaseType_t xRunningPrivileged ); +/*-----------------------------------------------------------*/ + +/* Each task maintains its own interrupt status in the critical nesting + * variable. Note this is not saved as part of the task context as context + * switches can only occur when uxCriticalNesting is zero. */ +static UBaseType_t uxCriticalNesting = 0xaaaaaaaa; +/* + * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure + * FreeRTOS API functions are not called from interrupts that have been assigned + * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY. + */ +#if ( configASSERT_DEFINED == 1 ) + static uint8_t ucMaxSysCallPriority = 0; + static uint32_t ulMaxPRIGROUPValue = 0; + static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16; +#endif /* configASSERT_DEFINED */ /*-----------------------------------------------------------*/ /* @@ -226,11 +194,11 @@ void* MPU_xQueueGetMutexHolder( QueueHandle_t xSemaphore ); StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters, BaseType_t xRunPrivileged ) { /* Simulate the stack frame as it would be created by a context switch - interrupt. */ + * interrupt. */ pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */ *pxTopOfStack = portINITIAL_XPSR; /* xPSR */ pxTopOfStack--; - *pxTopOfStack = ( StackType_t ) pxCode; /* PC */ + *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */ pxTopOfStack--; *pxTopOfStack = 0; /* LR */ pxTopOfStack -= 5; /* R12, R3, R2 and R1. */ @@ -264,7 +232,7 @@ void vPortSVCHandler( void ) " mrs r0, psp \n" #endif " b %0 \n" - ::"i"(prvSVCHandler):"r0" + ::"i"(prvSVCHandler):"r0", "memory" ); } /*-----------------------------------------------------------*/ @@ -272,34 +240,68 @@ void vPortSVCHandler( void ) static void prvSVCHandler( uint32_t *pulParam ) { uint8_t ucSVCNumber; +uint32_t ulPC; +#if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) + #if defined( __ARMCC_VERSION ) + /* Declaration when these variable are defined in code instead of being + * exported from linker scripts. */ + extern uint32_t * __syscalls_flash_start__; + extern uint32_t * __syscalls_flash_end__; + #else + /* Declaration when these variable are exported from linker scripts. */ + extern uint32_t __syscalls_flash_start__[]; + extern uint32_t __syscalls_flash_end__[]; + #endif /* #if defined( __ARMCC_VERSION ) */ +#endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */ + + /* The stack contains: r0, r1, r2, r3, r12, LR, PC and xPSR. The first + * argument (r0) is pulParam[ 0 ]. */ + ulPC = pulParam[ portOFFSET_TO_PC ]; + ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ]; - /* The stack contains: r0, r1, r2, r3, r12, r14, the return address and - xPSR. The first argument (r0) is pulParam[ 0 ]. */ - ucSVCNumber = ( ( uint8_t * ) pulParam[ portOFFSET_TO_PC ] )[ -2 ]; switch( ucSVCNumber ) { - case portSVC_START_SCHEDULER : *(portNVIC_SYSPRI1) |= portNVIC_SVC_PRI; + case portSVC_START_SCHEDULER : portNVIC_SYSPRI1_REG |= portNVIC_SVC_PRI; prvRestoreContextOfFirstTask(); break; - case portSVC_YIELD : *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + case portSVC_YIELD : portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; /* Barriers are normally not required - but do ensure the code is completely - within the specified behaviour for the - architecture. */ - __asm volatile( "dsb" ); + * but do ensure the code is completely + * within the specified behaviour for the + * architecture. */ + __asm volatile( "dsb" ::: "memory" ); __asm volatile( "isb" ); break; + + #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) + case portSVC_RAISE_PRIVILEGE : /* Only raise the privilege, if the + * svc was raised from any of the + * system calls. */ + if( ulPC >= ( uint32_t ) __syscalls_flash_start__ && + ulPC <= ( uint32_t ) __syscalls_flash_end__ ) + { + __asm volatile + ( + " mrs r1, control \n" /* Obtain current control value. */ + " bic r1, #1 \n" /* Set privilege bit. */ + " msr control, r1 \n" /* Write back new control value. */ + ::: "r1", "memory" + ); + } + break; + #else case portSVC_RAISE_PRIVILEGE : __asm volatile ( " mrs r1, control \n" /* Obtain current control value. */ " bic r1, #1 \n" /* Set privilege bit. */ " msr control, r1 \n" /* Write back new control value. */ - :::"r1" + ::: "r1", "memory" ); break; + #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */ default : /* Unknown SVC call. */ break; @@ -319,9 +321,23 @@ static void prvRestoreContextOfFirstTask( void ) " ldr r1, [r3] \n" " ldr r0, [r1] \n" /* The first item in the TCB is the task top of stack. */ " add r1, r1, #4 \n" /* Move onto the second item in the TCB... */ + " \n" + " dmb \n" /* Complete outstanding transfers before disabling MPU. */ + " ldr r2, =0xe000ed94 \n" /* MPU_CTRL register. */ + " ldr r3, [r2] \n" /* Read the value of MPU_CTRL. */ + " bic r3, #1 \n" /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */ + " str r3, [r2] \n" /* Disable MPU. */ + " \n" " ldr r2, =0xe000ed9c \n" /* Region Base Address register. */ " ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers. */ " stmia r2!, {r4-r11} \n" /* Write 4 sets of MPU registers. */ + " \n" + " ldr r2, =0xe000ed94 \n" /* MPU_CTRL register. */ + " ldr r3, [r2] \n" /* Read the value of MPU_CTRL. */ + " orr r3, #1 \n" /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */ + " str r3, [r2] \n" /* Enable MPU. */ + " dsb \n" /* Force memory writes before continuing. */ + " \n" " ldmia r0!, {r3, r4-r11} \n" /* Pop the registers that are not automatically saved on exception entry. */ " msr control, r3 \n" " msr psp, r0 \n" /* Restore the task stack pointer. */ @@ -330,7 +346,7 @@ static void prvRestoreContextOfFirstTask( void ) " ldr r14, =0xfffffffd \n" /* Load exec return code. */ " bx r14 \n" " \n" - " .align 2 \n" + " .align 4 \n" "pxCurrentTCBConst2: .word pxCurrentTCB \n" ); } @@ -342,26 +358,100 @@ static void prvRestoreContextOfFirstTask( void ) BaseType_t xPortStartScheduler( void ) { /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See - http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ + * http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) ); - /* Make PendSV and SysTick the same priority as the kernel. */ - *(portNVIC_SYSPRI2) |= portNVIC_PENDSV_PRI; - *(portNVIC_SYSPRI2) |= portNVIC_SYSTICK_PRI; + #if( configASSERT_DEFINED == 1 ) + { + volatile uint32_t ulOriginalPriority; + volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER ); + volatile uint8_t ucMaxPriorityValue; + + /* Determine the maximum priority from which ISR safe FreeRTOS API + * functions can be called. ISR safe functions are those that end in + * "FromISR". FreeRTOS maintains separate thread and ISR API functions + * to ensure interrupt entry is as fast and simple as possible. + + * Save the interrupt priority value that is about to be clobbered. */ + ulOriginalPriority = *pucFirstUserPriorityRegister; + + /* Determine the number of priority bits available. First write to all + * possible bits. */ + *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE; + + /* Read the value back to see how many bits stuck. */ + ucMaxPriorityValue = *pucFirstUserPriorityRegister; + + /* Use the same mask on the maximum system call priority. */ + ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue; + + /* Calculate the maximum acceptable priority group value for the number + * of bits read back. */ + ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS; + while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE ) + { + ulMaxPRIGROUPValue--; + ucMaxPriorityValue <<= ( uint8_t ) 0x01; + } + + #ifdef __NVIC_PRIO_BITS + { + /* Check the CMSIS configuration that defines the number of + * priority bits matches the number of priority bits actually queried + * from the hardware. */ + configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS ); + } + #endif + + #ifdef configPRIO_BITS + { + /* Check the FreeRTOS configuration that defines the number of + * priority bits matches the number of priority bits actually queried + * from the hardware. */ + configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS ); + } + #endif + + /* Shift the priority group value back to its position within the AIRCR + * register. */ + ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT; + ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK; + + /* Restore the clobbered interrupt priority register to its original + * value. */ + *pucFirstUserPriorityRegister = ulOriginalPriority; + } + #endif /* conifgASSERT_DEFINED */ + + /* Make PendSV and SysTick the same priority as the kernel, and the SVC + * handler higher priority so it can be used to exit a critical section (where + * lower priorities are masked). */ + portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; + portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; /* Configure the regions in the MPU that are common to all tasks. */ prvSetupMPU(); /* Start the timer that generates the tick ISR. Interrupts are disabled - here already. */ - prvSetupTimerInterrupt(); + * here already. */ + vPortSetupTimerInterrupt(); /* Initialise the critical nesting count ready for the first task. */ uxCriticalNesting = 0; /* Start the first task. */ - __asm volatile( " svc %0 \n" - :: "i" (portSVC_START_SCHEDULER) ); + __asm volatile( + " ldr r0, =0xE000ED08 \n" /* Use the NVIC offset register to locate the stack. */ + " ldr r0, [r0] \n" + " ldr r0, [r0] \n" + " msr msp, r0 \n" /* Set the msp back to the start of the stack. */ + " cpsie i \n" /* Globally enable interrupts. */ + " cpsie f \n" + " dsb \n" + " isb \n" + " svc %0 \n" /* System call to start first task. */ + " nop \n" + :: "i" (portSVC_START_SCHEDULER) : "memory" ); /* Should not get here! */ return 0; @@ -371,25 +461,25 @@ BaseType_t xPortStartScheduler( void ) void vPortEndScheduler( void ) { /* Not implemented in ports where there is nothing to return to. - Artificially force an assert. */ + * Artificially force an assert. */ configASSERT( uxCriticalNesting == 1000UL ); } /*-----------------------------------------------------------*/ void vPortEnterCritical( void ) { -BaseType_t xRunningPrivileged = prvRaisePrivilege(); +BaseType_t xRunningPrivileged = xPortRaisePrivilege(); portDISABLE_INTERRUPTS(); uxCriticalNesting++; - portRESET_PRIVILEGE( xRunningPrivileged ); + vPortResetPrivilege( xRunningPrivileged ); } /*-----------------------------------------------------------*/ void vPortExitCritical( void ) { -BaseType_t xRunningPrivileged = prvRaisePrivilege(); +BaseType_t xRunningPrivileged = xPortRaisePrivilege(); configASSERT( uxCriticalNesting ); uxCriticalNesting--; @@ -397,7 +487,7 @@ BaseType_t xRunningPrivileged = prvRaisePrivilege(); { portENABLE_INTERRUPTS(); } - portRESET_PRIVILEGE( xRunningPrivileged ); + vPortResetPrivilege( xRunningPrivileged ); } /*-----------------------------------------------------------*/ @@ -419,6 +509,8 @@ void xPortPendSVHandler( void ) " stmdb sp!, {r3, r14} \n" " mov r0, %0 \n" " msr basepri, r0 \n" + " dsb \n" + " isb \n" " bl vTaskSwitchContext \n" " mov r0, #0 \n" " msr basepri, r0 \n" @@ -427,16 +519,30 @@ void xPortPendSVHandler( void ) " ldr r1, [r3] \n" " ldr r0, [r1] \n" /* The first item in the TCB is the task top of stack. */ " add r1, r1, #4 \n" /* Move onto the second item in the TCB... */ + " \n" + " dmb \n" /* Complete outstanding transfers before disabling MPU. */ + " ldr r2, =0xe000ed94 \n" /* MPU_CTRL register. */ + " ldr r3, [r2] \n" /* Read the value of MPU_CTRL. */ + " bic r3, #1 \n" /* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */ + " str r3, [r2] \n" /* Disable MPU. */ + " \n" " ldr r2, =0xe000ed9c \n" /* Region Base Address register. */ " ldmia r1!, {r4-r11} \n" /* Read 4 sets of MPU registers. */ " stmia r2!, {r4-r11} \n" /* Write 4 sets of MPU registers. */ + " \n" + " ldr r2, =0xe000ed94 \n" /* MPU_CTRL register. */ + " ldr r3, [r2] \n" /* Read the value of MPU_CTRL. */ + " orr r3, #1 \n" /* r3 = r3 | 1 i.e. Set the bit 0 in r3. */ + " str r3, [r2] \n" /* Enable MPU. */ + " dsb \n" /* Force memory writes before continuing. */ + " \n" " ldmia r0!, {r3, r4-r11} \n" /* Pop the registers that are not automatically saved on exception entry. */ " msr control, r3 \n" " \n" " msr psp, r0 \n" " bx r14 \n" " \n" - " .align 2 \n" + " .align 4 \n" "pxCurrentTCBConst: .word pxCurrentTCB \n" ::"i"(configMAX_SYSCALL_INTERRUPT_PRIORITY) ); @@ -453,7 +559,7 @@ uint32_t ulDummy; if( xTaskIncrementTick() != pdFALSE ) { /* Pend a context switch. */ - *(portNVIC_INT_CTRL) = portNVIC_PENDSVSET; + portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT; } } portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy ); @@ -464,11 +570,15 @@ uint32_t ulDummy; * Setup the systick timer to generate the tick interrupts at the required * frequency. */ -static void prvSetupTimerInterrupt( void ) +__attribute__(( weak )) void vPortSetupTimerInterrupt( void ) { + /* Stop and clear the SysTick. */ + portNVIC_SYSTICK_CTRL_REG = 0UL; + portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL; + /* Configure SysTick to interrupt at the requested rate. */ - *(portNVIC_SYSTICK_LOAD) = ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; - *(portNVIC_SYSTICK_CTRL) = portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE; + portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL; + portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE ); } /*-----------------------------------------------------------*/ @@ -481,56 +591,56 @@ extern uint32_t __privileged_data_start__[]; extern uint32_t __privileged_data_end__[]; /* Check the expected MPU is present. */ - if( *portMPU_TYPE == portEXPECTED_MPU_TYPE_VALUE ) + if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE ) { /* First setup the entire flash for unprivileged read only access. */ - *portMPU_REGION_BASE_ADDRESS = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */ - ( portMPU_REGION_VALID ) | - ( portUNPRIVILEGED_FLASH_REGION ); + portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */ + ( portMPU_REGION_VALID ) | + ( portUNPRIVILEGED_FLASH_REGION ); - *portMPU_REGION_ATTRIBUTE = ( portMPU_REGION_READ_ONLY ) | + portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_ONLY ) | ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) | ( portMPU_REGION_ENABLE ); /* Setup the first 16K for privileged only access (even though less - than 10K is actually being used). This is where the kernel code is - placed. */ - *portMPU_REGION_BASE_ADDRESS = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */ - ( portMPU_REGION_VALID ) | - ( portPRIVILEGED_FLASH_REGION ); + * than 10K is actually being used). This is where the kernel code is + * placed. */ + portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */ + ( portMPU_REGION_VALID ) | + ( portPRIVILEGED_FLASH_REGION ); - *portMPU_REGION_ATTRIBUTE = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) | + portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) | ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | ( prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) | ( portMPU_REGION_ENABLE ); /* Setup the privileged data RAM region. This is where the kernel data - is placed. */ - *portMPU_REGION_BASE_ADDRESS = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */ - ( portMPU_REGION_VALID ) | - ( portPRIVILEGED_RAM_REGION ); + * is placed. */ + portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */ + ( portMPU_REGION_VALID ) | + ( portPRIVILEGED_RAM_REGION ); - *portMPU_REGION_ATTRIBUTE = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | + portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) | ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) | ( portMPU_REGION_ENABLE ); /* By default allow everything to access the general peripherals. The - system peripherals and registers are protected. */ - *portMPU_REGION_BASE_ADDRESS = ( portPERIPHERALS_START_ADDRESS ) | - ( portMPU_REGION_VALID ) | - ( portGENERAL_PERIPHERALS_REGION ); + * system peripherals and registers are protected. */ + portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) | + ( portMPU_REGION_VALID ) | + ( portGENERAL_PERIPHERALS_REGION ); - *portMPU_REGION_ATTRIBUTE = ( portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER ) | + portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER ) | ( prvGetMPURegionSizeSetting( portPERIPHERALS_END_ADDRESS - portPERIPHERALS_START_ADDRESS ) ) | ( portMPU_REGION_ENABLE ); /* Enable the memory fault exception. */ - *portNVIC_SYS_CTRL_STATE |= portNVIC_MEM_FAULT_ENABLE; + portNVIC_SYS_CTRL_STATE_REG |= portNVIC_MEM_FAULT_ENABLE; /* Enable the MPU with the background region configured. */ - *portMPU_CTRL |= ( portMPU_ENABLE | portMPU_BACKGROUND_ENABLE ); + portMPU_CTRL_REG |= ( portMPU_ENABLE | portMPU_BACKGROUND_ENABLE ); } } /*-----------------------------------------------------------*/ @@ -540,7 +650,7 @@ static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes ) uint32_t ulRegionSize, ulReturnValue = 4; /* 32 is the smallest region size, 31 is the largest valid value for - ulReturnValue. */ + * ulReturnValue. */ for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) ) { if( ulActualSizeInBytes <= ulRegionSize ) @@ -554,30 +664,42 @@ uint32_t ulRegionSize, ulReturnValue = 4; } /* Shift the code by one before returning so it can be written directly - into the the correct bit position of the attribute register. */ + * into the the correct bit position of the attribute register. */ return ( ulReturnValue << 1UL ); } /*-----------------------------------------------------------*/ -static BaseType_t prvRaisePrivilege( void ) +BaseType_t xIsPrivileged( void ) /* __attribute__ (( naked )) */ { __asm volatile ( - " mrs r0, control \n" - " tst r0, #1 \n" /* Is the task running privileged? */ - " itte ne \n" - " movne r0, #0 \n" /* CONTROL[0]!=0, return false. */ - " svcne %0 \n" /* Switch to privileged. */ - " moveq r0, #1 \n" /* CONTROL[0]==0, return true. */ - " bx lr \n" - :: "i" (portSVC_RAISE_PRIVILEGE) : "r0" + " mrs r0, control \n" /* r0 = CONTROL. */ + " tst r0, #1 \n" /* Perform r0 & 1 (bitwise AND) and update the conditions flag. */ + " ite ne \n" + " movne r0, #0 \n" /* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */ + " moveq r0, #1 \n" /* CONTROL[0]==0. Return true to indicate that the processor is privileged. */ + " bx lr \n" /* Return. */ + " \n" + " .align 4 \n" + ::: "r0", "memory" ); +} +/*-----------------------------------------------------------*/ - return 0; +void vResetPrivilege( void ) /* __attribute__ (( naked )) */ +{ + __asm volatile + ( + " mrs r0, control \n" /* r0 = CONTROL. */ + " orr r0, #1 \n" /* r0 = r0 | 1. */ + " msr control, r0 \n" /* CONTROL = r0. */ + " bx lr \n" /* Return to the caller. */ + :::"r0", "memory" + ); } /*-----------------------------------------------------------*/ -void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint16_t usStackDepth ) +void vPortStoreTaskMPUSettings( xMPU_SETTINGS *xMPUSettings, const struct xMEMORY_REGION * const xRegions, StackType_t *pxBottomOfStack, uint32_t ulStackDepth ) { extern uint32_t __SRAM_segment_start__[]; extern uint32_t __SRAM_segment_end__[]; @@ -589,7 +711,7 @@ uint32_t ul; if( xRegions == NULL ) { /* No MPU regions are specified so allow access to all RAM. */ - xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress = + xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress = ( ( uint32_t ) __SRAM_segment_start__ ) | /* Base address. */ ( portMPU_REGION_VALID ) | ( portSTACK_REGION ); @@ -601,7 +723,7 @@ uint32_t ul; ( portMPU_REGION_ENABLE ); /* Re-instate the privileged only RAM region as xRegion[ 0 ] will have - just removed the privileged only parameters. */ + * just removed the privileged only parameters. */ xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */ ( portMPU_REGION_VALID ) | @@ -623,10 +745,10 @@ uint32_t ul; else { /* This function is called automatically when the task is created - in - which case the stack region parameters will be valid. At all other - times the stack parameters will not be valid and it is assumed that the - stack region has already been configured. */ - if( usStackDepth > 0 ) + * which case the stack region parameters will be valid. At all other + * times the stack parameters will not be valid and it is assumed that the + * stack region has already been configured. */ + if( ulStackDepth > 0 ) { /* Define the region that allows access to the stack. */ xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress = @@ -636,7 +758,7 @@ uint32_t ul; xMPUSettings->xRegion[ 0 ].ulRegionAttribute = ( portMPU_REGION_READ_WRITE ) | /* Read and write. */ - ( prvGetMPURegionSizeSetting( ( uint32_t ) usStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) | + ( prvGetMPURegionSizeSetting( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) | ( portMPU_REGION_CACHEABLE_BUFFERABLE ) | ( portMPU_REGION_ENABLE ); } @@ -648,8 +770,8 @@ uint32_t ul; if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL ) { /* Translate the generic region definition contained in - xRegions into the CM3 specific MPU settings that are then - stored in xMPUSettings. */ + * xRegions into the CM3 specific MPU settings that are then + * stored in xMPUSettings. */ xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) | ( portMPU_REGION_VALID ) | @@ -673,574 +795,63 @@ uint32_t ul; } /*-----------------------------------------------------------*/ -BaseType_t MPU_xTaskGenericCreate( TaskFunction_t pvTaskCode, const char * const pcName, uint16_t usStackDepth, void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pxCreatedTask, StackType_t *puxStackBuffer, const MemoryRegion_t * const xRegions ) -{ -BaseType_t xReturn; -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xTaskGenericCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask, puxStackBuffer, xRegions ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; -} -/*-----------------------------------------------------------*/ - -void MPU_vTaskAllocateMPURegions( TaskHandle_t xTask, const MemoryRegion_t * const xRegions ) -{ -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vTaskAllocateMPURegions( xTask, xRegions ); - portRESET_PRIVILEGE( xRunningPrivileged ); -} -/*-----------------------------------------------------------*/ - -#if ( INCLUDE_vTaskDelete == 1 ) - void MPU_vTaskDelete( TaskHandle_t pxTaskToDelete ) - { - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vTaskDelete( pxTaskToDelete ); - portRESET_PRIVILEGE( xRunningPrivileged ); - } -#endif -/*-----------------------------------------------------------*/ - -#if ( INCLUDE_vTaskDelayUntil == 1 ) - void MPU_vTaskDelayUntil( TickType_t * const pxPreviousWakeTime, TickType_t xTimeIncrement ) - { - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vTaskDelayUntil( pxPreviousWakeTime, xTimeIncrement ); - portRESET_PRIVILEGE( xRunningPrivileged ); - } -#endif -/*-----------------------------------------------------------*/ - -#if ( INCLUDE_vTaskDelay == 1 ) - void MPU_vTaskDelay( TickType_t xTicksToDelay ) - { - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vTaskDelay( xTicksToDelay ); - portRESET_PRIVILEGE( xRunningPrivileged ); - } -#endif -/*-----------------------------------------------------------*/ - -#if ( INCLUDE_uxTaskPriorityGet == 1 ) - UBaseType_t MPU_uxTaskPriorityGet( TaskHandle_t pxTask ) - { - UBaseType_t uxReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - uxReturn = uxTaskPriorityGet( pxTask ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return uxReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( INCLUDE_vTaskPrioritySet == 1 ) - void MPU_vTaskPrioritySet( TaskHandle_t pxTask, UBaseType_t uxNewPriority ) - { - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vTaskPrioritySet( pxTask, uxNewPriority ); - portRESET_PRIVILEGE( xRunningPrivileged ); - } -#endif -/*-----------------------------------------------------------*/ - -#if ( INCLUDE_eTaskGetState == 1 ) - eTaskState MPU_eTaskGetState( TaskHandle_t pxTask ) - { - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - eTaskState eReturn; - - eReturn = eTaskGetState( pxTask ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return eReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) - TaskHandle_t MPU_xTaskGetIdleTaskHandle( void ) - { - TaskHandle_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xTaskGetIdleTaskHandle(); - portRESET_PRIVILEGE( xRunningPrivileged ); - return eReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( INCLUDE_vTaskSuspend == 1 ) - void MPU_vTaskSuspend( TaskHandle_t pxTaskToSuspend ) - { - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vTaskSuspend( pxTaskToSuspend ); - portRESET_PRIVILEGE( xRunningPrivileged ); - } -#endif -/*-----------------------------------------------------------*/ - -#if ( INCLUDE_vTaskSuspend == 1 ) - void MPU_vTaskResume( TaskHandle_t pxTaskToResume ) - { - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vTaskResume( pxTaskToResume ); - portRESET_PRIVILEGE( xRunningPrivileged ); - } -#endif -/*-----------------------------------------------------------*/ - -void MPU_vTaskSuspendAll( void ) -{ -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vTaskSuspendAll(); - portRESET_PRIVILEGE( xRunningPrivileged ); -} -/*-----------------------------------------------------------*/ - -BaseType_t MPU_xTaskResumeAll( void ) -{ -BaseType_t xReturn; -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xTaskResumeAll(); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; -} -/*-----------------------------------------------------------*/ - -TickType_t MPU_xTaskGetTickCount( void ) -{ -TickType_t xReturn; -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xTaskGetTickCount(); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; -} -/*-----------------------------------------------------------*/ - -UBaseType_t MPU_uxTaskGetNumberOfTasks( void ) -{ -UBaseType_t uxReturn; -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - uxReturn = uxTaskGetNumberOfTasks(); - portRESET_PRIVILEGE( xRunningPrivileged ); - return uxReturn; -} -/*-----------------------------------------------------------*/ - -#if ( configUSE_TRACE_FACILITY == 1 ) - void MPU_vTaskList( char *pcWriteBuffer ) - { - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vTaskList( pcWriteBuffer ); - portRESET_PRIVILEGE( xRunningPrivileged ); - } -#endif -/*-----------------------------------------------------------*/ - -#if ( configGENERATE_RUN_TIME_STATS == 1 ) - void MPU_vTaskGetRunTimeStats( char *pcWriteBuffer ) - { - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vTaskGetRunTimeStats( pcWriteBuffer ); - portRESET_PRIVILEGE( xRunningPrivileged ); - } -#endif -/*-----------------------------------------------------------*/ - -#if ( configUSE_APPLICATION_TASK_TAG == 1 ) - void MPU_vTaskSetApplicationTaskTag( TaskHandle_t xTask, TaskHookFunction_t pxTagValue ) - { - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vTaskSetApplicationTaskTag( xTask, pxTagValue ); - portRESET_PRIVILEGE( xRunningPrivileged ); - } -#endif -/*-----------------------------------------------------------*/ - -#if ( configUSE_APPLICATION_TASK_TAG == 1 ) - TaskHookFunction_t MPU_xTaskGetApplicationTaskTag( TaskHandle_t xTask ) - { - TaskHookFunction_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xTaskGetApplicationTaskTag( xTask ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( configUSE_APPLICATION_TASK_TAG == 1 ) - BaseType_t MPU_xTaskCallApplicationTaskHook( TaskHandle_t xTask, void *pvParameter ) - { - BaseType_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xTaskCallApplicationTaskHook( xTask, pvParameter ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( configUSE_TRACE_FACILITY == 1 ) - UBaseType_t MPU_uxTaskGetSystemState( TaskStatus_t *pxTaskStatusArray, UBaseType_t uxArraySize, uint32_t *pulTotalRunTime ) - { - UBaseType_t uxReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - uxReturn = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, pulTotalRunTime ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) - UBaseType_t MPU_uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) - { - UBaseType_t uxReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - uxReturn = uxTaskGetStackHighWaterMark( xTask ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return uxReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) - TaskHandle_t MPU_xTaskGetCurrentTaskHandle( void ) - { - TaskHandle_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xTaskGetCurrentTaskHandle(); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( INCLUDE_xTaskGetSchedulerState == 1 ) - BaseType_t MPU_xTaskGetSchedulerState( void ) - { - BaseType_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xTaskGetSchedulerState(); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -QueueHandle_t MPU_xQueueGenericCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize, uint8_t ucQueueType ) -{ -QueueHandle_t xReturn; -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xQueueGenericCreate( uxQueueLength, uxItemSize, ucQueueType ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; -} -/*-----------------------------------------------------------*/ - -BaseType_t MPU_xQueueGenericReset( QueueHandle_t pxQueue, BaseType_t xNewQueue ) -{ -BaseType_t xReturn; -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xQueueGenericReset( pxQueue, xNewQueue ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; -} -/*-----------------------------------------------------------*/ - -BaseType_t MPU_xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, BaseType_t xCopyPosition ) -{ -BaseType_t xReturn; -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, xCopyPosition ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; -} -/*-----------------------------------------------------------*/ - -UBaseType_t MPU_uxQueueMessagesWaiting( const QueueHandle_t pxQueue ) -{ -BaseType_t xRunningPrivileged = prvRaisePrivilege(); -UBaseType_t uxReturn; - - uxReturn = uxQueueMessagesWaiting( pxQueue ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return uxReturn; -} -/*-----------------------------------------------------------*/ - -BaseType_t MPU_xQueueGenericReceive( QueueHandle_t pxQueue, void * const pvBuffer, TickType_t xTicksToWait, BaseType_t xJustPeeking ) -{ -BaseType_t xRunningPrivileged = prvRaisePrivilege(); -BaseType_t xReturn; - - xReturn = xQueueGenericReceive( pxQueue, pvBuffer, xTicksToWait, xJustPeeking ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; -} -/*-----------------------------------------------------------*/ - -BaseType_t MPU_xQueuePeekFromISR( QueueHandle_t pxQueue, void * const pvBuffer ) -{ -BaseType_t xRunningPrivileged = prvRaisePrivilege(); -BaseType_t xReturn; - - xReturn = xQueuePeekFromISR( pxQueue, pvBuffer ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; -} -/*-----------------------------------------------------------*/ - -void* MPU_xQueueGetMutexHolder( QueueHandle_t xSemaphore ) -{ -BaseType_t xRunningPrivileged = prvRaisePrivilege(); -void * xReturn; - - xReturn = ( void * ) xQueueGetMutexHolder( xSemaphore ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; -} -/*-----------------------------------------------------------*/ +#if( configASSERT_DEFINED == 1 ) -#if ( configUSE_MUTEXES == 1 ) - QueueHandle_t MPU_xQueueCreateMutex( void ) + void vPortValidateInterruptPriority( void ) { - QueueHandle_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); + uint32_t ulCurrentInterrupt; + uint8_t ucCurrentPriority; - xReturn = xQueueCreateMutex( queueQUEUE_TYPE_MUTEX ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if configUSE_COUNTING_SEMAPHORES == 1 - QueueHandle_t MPU_xQueueCreateCountingSemaphore( UBaseType_t uxCountValue, UBaseType_t uxInitialCount ) - { - QueueHandle_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xQueueCreateCountingSemaphore( uxCountValue, uxInitialCount ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( configUSE_MUTEXES == 1 ) - BaseType_t MPU_xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xBlockTime ) - { - BaseType_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xQueueTakeMutexRecursive( xMutex, xBlockTime ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( configUSE_MUTEXES == 1 ) - BaseType_t MPU_xQueueGiveMutexRecursive( QueueHandle_t xMutex ) - { - BaseType_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); + /* Obtain the number of the currently executing interrupt. */ + __asm volatile( "mrs %0, ipsr" : "=r"( ulCurrentInterrupt ) :: "memory" ); - xReturn = xQueueGiveMutexRecursive( xMutex ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( configUSE_QUEUE_SETS == 1 ) - QueueSetHandle_t MPU_xQueueCreateSet( UBaseType_t uxEventQueueLength ) - { - QueueSetHandle_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xQueueCreateSet( uxEventQueueLength ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( configUSE_QUEUE_SETS == 1 ) - QueueSetMemberHandle_t MPU_xQueueSelectFromSet( QueueSetHandle_t xQueueSet, TickType_t xBlockTimeTicks ) - { - QueueSetMemberHandle_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xQueueSelectFromSet( xQueueSet, xBlockTimeTicks ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( configUSE_QUEUE_SETS == 1 ) - BaseType_t MPU_xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) - { - BaseType_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xQueueAddToSet( xQueueOrSemaphore, xQueueSet ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if ( configUSE_QUEUE_SETS == 1 ) - BaseType_t MPU_xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, QueueSetHandle_t xQueueSet ) - { - BaseType_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xQueueRemoveFromSet( xQueueOrSemaphore, xQueueSet ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if configUSE_ALTERNATIVE_API == 1 - BaseType_t MPU_xQueueAltGenericSend( QueueHandle_t pxQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, BaseType_t xCopyPosition ) - { - BaseType_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = BaseType_t xQueueAltGenericSend( pxQueue, pvItemToQueue, xTicksToWait, xCopyPosition ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if configUSE_ALTERNATIVE_API == 1 - BaseType_t MPU_xQueueAltGenericReceive( QueueHandle_t pxQueue, void * const pvBuffer, TickType_t xTicksToWait, BaseType_t xJustPeeking ) - { - BaseType_t xReturn; - BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xQueueAltGenericReceive( pxQueue, pvBuffer, xTicksToWait, xJustPeeking ); - portRESET_PRIVILEGE( xRunningPrivileged ); - return xReturn; - } -#endif -/*-----------------------------------------------------------*/ - -#if configQUEUE_REGISTRY_SIZE > 0 - void MPU_vQueueAddToRegistry( QueueHandle_t xQueue, char *pcName ) - { - BaseType_t xRunningPrivileged = prvRaisePrivilege(); + /* Is the interrupt number a user defined interrupt? */ + if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER ) + { + /* Look up the interrupt's priority. */ + ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ]; + + /* The following assertion will fail if a service routine (ISR) for + * an interrupt that has been assigned a priority above + * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API + * function. ISR safe FreeRTOS API functions must *only* be called + * from interrupts that have been assigned a priority at or below + * configMAX_SYSCALL_INTERRUPT_PRIORITY. + + * Numerically low interrupt priority numbers represent logically high + * interrupt priorities, therefore the priority of the interrupt must + * be set to a value equal to or numerically *higher* than + * configMAX_SYSCALL_INTERRUPT_PRIORITY. + + * Interrupts that use the FreeRTOS API must not be left at their + * default priority of zero as that is the highest possible priority, + * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY, + * and therefore also guaranteed to be invalid. + + * FreeRTOS maintains separate thread and ISR API functions to ensure + * interrupt entry is as fast and simple as possible. + + * The following links provide detailed information: + * http://www.freertos.org/RTOS-Cortex-M3-M4.html + * http://www.freertos.org/FAQHelp.html */ + configASSERT( ucCurrentPriority >= ucMaxSysCallPriority ); + } - vQueueAddToRegistry( xQueue, pcName ); + /* Priority grouping: The interrupt controller (NVIC) allows the bits + * that define each interrupt's priority to be split between bits that + * define the interrupt's pre-emption priority bits and bits that define + * the interrupt's sub-priority. For simplicity all bits must be defined + * to be pre-emption priority bits. The following assertion will fail if + * this is not the case (if some bits represent a sub-priority). - portRESET_PRIVILEGE( xRunningPrivileged ); + * If the application only uses CMSIS libraries for interrupt + * configuration then the correct setting can be achieved on all Cortex-M + * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the + * scheduler. Note however that some vendor specific peripheral libraries + * assume a non-zero priority group setting, in which cases using a value + * of zero will result in unpredicable behaviour. */ + configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue ); } -#endif -/*-----------------------------------------------------------*/ - -void MPU_vQueueDelete( QueueHandle_t xQueue ) -{ -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vQueueDelete( xQueue ); - portRESET_PRIVILEGE( xRunningPrivileged ); -} +#endif /* configASSERT_DEFINED */ /*-----------------------------------------------------------*/ - -void *MPU_pvPortMalloc( size_t xSize ) -{ -void *pvReturn; -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - pvReturn = pvPortMalloc( xSize ); - - portRESET_PRIVILEGE( xRunningPrivileged ); - - return pvReturn; -} -/*-----------------------------------------------------------*/ - -void MPU_vPortFree( void *pv ) -{ -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vPortFree( pv ); - - portRESET_PRIVILEGE( xRunningPrivileged ); -} -/*-----------------------------------------------------------*/ - -void MPU_vPortInitialiseBlocks( void ) -{ -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - vPortInitialiseBlocks(); - - portRESET_PRIVILEGE( xRunningPrivileged ); -} -/*-----------------------------------------------------------*/ - -size_t MPU_xPortGetFreeHeapSize( void ) -{ -size_t xReturn; -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - xReturn = xPortGetFreeHeapSize(); - - portRESET_PRIVILEGE( xRunningPrivileged ); - - return xReturn; -} - -/* Functions that the application writer wants to execute in privileged mode -can be defined in application_defined_privileged_functions.h. The functions -must take the same format as those above whereby the privilege state on exit -equals the privilege state on entry. For example: - -void MPU_FunctionName( [parameters ] ) -{ -BaseType_t xRunningPrivileged = prvRaisePrivilege(); - - FunctionName( [parameters ] ); - - portRESET_PRIVILEGE( xRunningPrivileged ); -} -*/ - -#if configINCLUDE_APPLICATION_DEFINED_PRIVILEGED_FUNCTIONS == 1 - #include "application_defined_privileged_functions.h" -#endif -