port.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. /*
  2. * FreeRTOS Kernel <DEVELOPMENT BRANCH>
  3. * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * SPDX-License-Identifier: MIT
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  8. * this software and associated documentation files (the "Software"), to deal in
  9. * the Software without restriction, including without limitation the rights to
  10. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  11. * the Software, and to permit persons to whom the Software is furnished to do so,
  12. * subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in all
  15. * copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  19. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  20. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  21. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  22. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. *
  24. * https://www.FreeRTOS.org
  25. * https://github.com/FreeRTOS
  26. *
  27. */
  28. /* Standard includes. */
  29. #include <stdlib.h>
  30. #include <string.h>
  31. /* Scheduler includes. */
  32. #include "FreeRTOS.h"
  33. #include "task.h"
  34. #ifndef configINTERRUPT_CONTROLLER_BASE_ADDRESS
  35. #error "configINTERRUPT_CONTROLLER_BASE_ADDRESS must be defined. See www.FreeRTOS.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html"
  36. #endif
  37. #ifndef configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET
  38. #error "configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET must be defined. See www.FreeRTOS.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html"
  39. #endif
  40. #ifndef configUNIQUE_INTERRUPT_PRIORITIES
  41. #error "configUNIQUE_INTERRUPT_PRIORITIES must be defined. See www.FreeRTOS.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html"
  42. #endif
  43. #ifndef configSETUP_TICK_INTERRUPT
  44. #error "configSETUP_TICK_INTERRUPT() must be defined. See www.FreeRTOS.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html"
  45. #endif /* configSETUP_TICK_INTERRUPT */
  46. #ifndef configMAX_API_CALL_INTERRUPT_PRIORITY
  47. #error "configMAX_API_CALL_INTERRUPT_PRIORITY must be defined. See www.FreeRTOS.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors.html"
  48. #endif
  49. #if configMAX_API_CALL_INTERRUPT_PRIORITY == 0
  50. #error "configMAX_API_CALL_INTERRUPT_PRIORITY must not be set to 0"
  51. #endif
  52. #if configMAX_API_CALL_INTERRUPT_PRIORITY > configUNIQUE_INTERRUPT_PRIORITIES
  53. #error "configMAX_API_CALL_INTERRUPT_PRIORITY must be less than or equal to configUNIQUE_INTERRUPT_PRIORITIES as the lower the numeric priority value the higher the logical interrupt priority"
  54. #endif
  55. #if configUSE_PORT_OPTIMISED_TASK_SELECTION == 1
  56. /* Check the configuration. */
  57. #if ( configMAX_PRIORITIES > 32 )
  58. #error "configUSE_PORT_OPTIMISED_TASK_SELECTION can only be set to 1 when configMAX_PRIORITIES is less than or equal to 32. It is very rare that a system requires more than 10 to 15 difference priorities as tasks that share a priority will time slice."
  59. #endif
  60. #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
  61. /* In case security extensions are implemented. */
  62. #if configMAX_API_CALL_INTERRUPT_PRIORITY <= ( configUNIQUE_INTERRUPT_PRIORITIES / 2 )
  63. #error "configMAX_API_CALL_INTERRUPT_PRIORITY must be greater than ( configUNIQUE_INTERRUPT_PRIORITIES / 2 )"
  64. #endif
  65. /* Some vendor specific files default configCLEAR_TICK_INTERRUPT() in
  66. * portmacro.h. */
  67. #ifndef configCLEAR_TICK_INTERRUPT
  68. #define configCLEAR_TICK_INTERRUPT()
  69. #endif
  70. /* A critical section is exited when the critical section nesting count reaches
  71. * this value. */
  72. #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
  73. /* In all GICs 255 can be written to the priority mask register to unmask all
  74. * (but the lowest) interrupt priority. */
  75. #define portUNMASK_VALUE ( 0xFFUL )
  76. /* Tasks are not created with a floating point context, but can be given a
  77. * floating point context after they have been created. A variable is stored as
  78. * part of the tasks context that holds portNO_FLOATING_POINT_CONTEXT if the task
  79. * does not have an FPU context, or any other value if the task does have an FPU
  80. * context. */
  81. #define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
  82. /* Constants required to setup the initial task context. */
  83. #define portINITIAL_SPSR ( ( StackType_t ) 0x1f ) /* System mode, ARM mode, IRQ enabled FIQ enabled. */
  84. #define portTHUMB_MODE_BIT ( ( StackType_t ) 0x20 )
  85. #define portINTERRUPT_ENABLE_BIT ( 0x80UL )
  86. #define portTHUMB_MODE_ADDRESS ( 0x01UL )
  87. /* Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary
  88. * point is zero. */
  89. #define portBINARY_POINT_BITS ( ( uint8_t ) 0x03 )
  90. /* Masks all bits in the APSR other than the mode bits. */
  91. #define portAPSR_MODE_BITS_MASK ( 0x1F )
  92. /* The value of the mode bits in the APSR when the CPU is executing in user
  93. * mode. */
  94. #define portAPSR_USER_MODE ( 0x10 )
  95. /* The critical section macros only mask interrupts up to an application
  96. * determined priority level. Sometimes it is necessary to turn interrupt off in
  97. * the CPU itself before modifying certain hardware registers. */
  98. #define portCPU_IRQ_DISABLE() \
  99. __asm volatile ( "CPSID i" ::: "memory" ); \
  100. __asm volatile ( "DSB" ); \
  101. __asm volatile ( "ISB" );
  102. #define portCPU_IRQ_ENABLE() \
  103. __asm volatile ( "CPSIE i" ::: "memory" ); \
  104. __asm volatile ( "DSB" ); \
  105. __asm volatile ( "ISB" );
  106. /* Macro to unmask all interrupt priorities. */
  107. #define portCLEAR_INTERRUPT_MASK() \
  108. { \
  109. portCPU_IRQ_DISABLE(); \
  110. portICCPMR_PRIORITY_MASK_REGISTER = portUNMASK_VALUE; \
  111. __asm volatile ( "DSB \n" \
  112. "ISB \n" ); \
  113. portCPU_IRQ_ENABLE(); \
  114. }
  115. #define portINTERRUPT_PRIORITY_REGISTER_OFFSET 0x400UL
  116. #define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
  117. #define portBIT_0_SET ( ( uint8_t ) 0x01 )
  118. /* Let the user override the pre-loading of the initial LR with the address of
  119. * prvTaskExitError() in case it messes up unwinding of the stack in the
  120. * debugger. */
  121. #ifdef configTASK_RETURN_ADDRESS
  122. #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
  123. #else
  124. #define portTASK_RETURN_ADDRESS prvTaskExitError
  125. #endif
  126. /* The space on the stack required to hold the FPU registers. This is 32 64-bit
  127. * registers, plus a 32-bit status register. */
  128. #define portFPU_REGISTER_WORDS ( ( 32 * 2 ) + 1 )
  129. /*-----------------------------------------------------------*/
  130. /*
  131. * Starts the first task executing. This function is necessarily written in
  132. * assembly code so is implemented in portASM.s.
  133. */
  134. extern void vPortRestoreTaskContext( void );
  135. /*
  136. * Used to catch tasks that attempt to return from their implementing function.
  137. */
  138. static void prvTaskExitError( void );
  139. /*
  140. * If the application provides an implementation of vApplicationIRQHandler(),
  141. * then it will get called directly without saving the FPU registers on
  142. * interrupt entry, and this weak implementation of
  143. * vApplicationFPUSafeIRQHandler() is just provided to remove linkage errors -
  144. * it should never actually get called so its implementation contains a
  145. * call to configASSERT() that will always fail.
  146. *
  147. * If the application provides its own implementation of
  148. * vApplicationFPUSafeIRQHandler() then the implementation of
  149. * vApplicationIRQHandler() provided in portASM.S will save the FPU registers
  150. * before calling it.
  151. *
  152. * Therefore, if the application writer wants FPU registers to be saved on
  153. * interrupt entry their IRQ handler must be called
  154. * vApplicationFPUSafeIRQHandler(), and if the application writer does not want
  155. * FPU registers to be saved on interrupt entry their IRQ handler must be
  156. * called vApplicationIRQHandler().
  157. */
  158. void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR ) __attribute__( ( weak ) );
  159. /*-----------------------------------------------------------*/
  160. /* A variable is used to keep track of the critical section nesting. This
  161. * variable has to be stored as part of the task context and must be initialised to
  162. * a non zero value to ensure interrupts don't inadvertently become unmasked before
  163. * the scheduler starts. As it is stored as part of the task context it will
  164. * automatically be set to 0 when the first task is started. */
  165. volatile uint32_t ulCriticalNesting = 9999UL;
  166. /* Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero then
  167. * a floating point context must be saved and restored for the task. */
  168. volatile uint32_t ulPortTaskHasFPUContext = pdFALSE;
  169. /* Set to 1 to pend a context switch from an ISR. */
  170. volatile uint32_t ulPortYieldRequired = pdFALSE;
  171. /* Counts the interrupt nesting depth. A context switch is only performed if
  172. * if the nesting depth is 0. */
  173. volatile uint32_t ulPortInterruptNesting = 0UL;
  174. /* Used in the asm file. */
  175. __attribute__( ( used ) ) const uint32_t ulICCIARAddress = portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS;
  176. __attribute__( ( used ) ) const uint32_t ulICCEOIRAddress = portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS;
  177. __attribute__( ( used ) ) const uint32_t ulICCPMRAddress = portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS;
  178. __attribute__( ( used ) ) const uint32_t ulMaxAPIPriorityMask = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
  179. /*-----------------------------------------------------------*/
  180. /*
  181. * See header file for description.
  182. */
  183. StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
  184. TaskFunction_t pxCode,
  185. void * pvParameters )
  186. {
  187. /* Setup the initial stack of the task. The stack is set exactly as
  188. * expected by the portRESTORE_CONTEXT() macro.
  189. *
  190. * The fist real value on the stack is the status register, which is set for
  191. * system mode, with interrupts enabled. A few NULLs are added first to ensure
  192. * GDB does not try decoding a non-existent return address. */
  193. *pxTopOfStack = ( StackType_t ) NULL;
  194. pxTopOfStack--;
  195. *pxTopOfStack = ( StackType_t ) NULL;
  196. pxTopOfStack--;
  197. *pxTopOfStack = ( StackType_t ) NULL;
  198. pxTopOfStack--;
  199. *pxTopOfStack = ( StackType_t ) portINITIAL_SPSR;
  200. if( ( ( uint32_t ) pxCode & portTHUMB_MODE_ADDRESS ) != 0x00UL )
  201. {
  202. /* The task will start in THUMB mode. */
  203. *pxTopOfStack |= portTHUMB_MODE_BIT;
  204. }
  205. pxTopOfStack--;
  206. /* Next the return address, which in this case is the start of the task. */
  207. *pxTopOfStack = ( StackType_t ) pxCode;
  208. pxTopOfStack--;
  209. /* Next all the registers other than the stack pointer. */
  210. *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* R14 */
  211. pxTopOfStack--;
  212. *pxTopOfStack = ( StackType_t ) 0x12121212; /* R12 */
  213. pxTopOfStack--;
  214. *pxTopOfStack = ( StackType_t ) 0x11111111; /* R11 */
  215. pxTopOfStack--;
  216. *pxTopOfStack = ( StackType_t ) 0x10101010; /* R10 */
  217. pxTopOfStack--;
  218. *pxTopOfStack = ( StackType_t ) 0x09090909; /* R9 */
  219. pxTopOfStack--;
  220. *pxTopOfStack = ( StackType_t ) 0x08080808; /* R8 */
  221. pxTopOfStack--;
  222. *pxTopOfStack = ( StackType_t ) 0x07070707; /* R7 */
  223. pxTopOfStack--;
  224. *pxTopOfStack = ( StackType_t ) 0x06060606; /* R6 */
  225. pxTopOfStack--;
  226. *pxTopOfStack = ( StackType_t ) 0x05050505; /* R5 */
  227. pxTopOfStack--;
  228. *pxTopOfStack = ( StackType_t ) 0x04040404; /* R4 */
  229. pxTopOfStack--;
  230. *pxTopOfStack = ( StackType_t ) 0x03030303; /* R3 */
  231. pxTopOfStack--;
  232. *pxTopOfStack = ( StackType_t ) 0x02020202; /* R2 */
  233. pxTopOfStack--;
  234. *pxTopOfStack = ( StackType_t ) 0x01010101; /* R1 */
  235. pxTopOfStack--;
  236. *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
  237. pxTopOfStack--;
  238. /* The task will start with a critical nesting count of 0 as interrupts are
  239. * enabled. */
  240. *pxTopOfStack = portNO_CRITICAL_NESTING;
  241. #if ( configUSE_TASK_FPU_SUPPORT == 1 )
  242. {
  243. /* The task will start without a floating point context. A task that
  244. * uses the floating point hardware must call vPortTaskUsesFPU() before
  245. * executing any floating point instructions. */
  246. pxTopOfStack--;
  247. *pxTopOfStack = portNO_FLOATING_POINT_CONTEXT;
  248. }
  249. #elif ( configUSE_TASK_FPU_SUPPORT == 2 )
  250. {
  251. /* The task will start with a floating point context. Leave enough
  252. * space for the registers - and ensure they are initialised to 0. */
  253. pxTopOfStack -= portFPU_REGISTER_WORDS;
  254. memset( pxTopOfStack, 0x00, portFPU_REGISTER_WORDS * sizeof( StackType_t ) );
  255. pxTopOfStack--;
  256. *pxTopOfStack = pdTRUE;
  257. ulPortTaskHasFPUContext = pdTRUE;
  258. }
  259. #else /* if ( configUSE_TASK_FPU_SUPPORT == 1 ) */
  260. {
  261. #error "Invalid configUSE_TASK_FPU_SUPPORT setting - configUSE_TASK_FPU_SUPPORT must be set to 1, 2, or left undefined."
  262. }
  263. #endif /* if ( configUSE_TASK_FPU_SUPPORT == 1 ) */
  264. return pxTopOfStack;
  265. }
  266. /*-----------------------------------------------------------*/
  267. static void prvTaskExitError( void )
  268. {
  269. /* A function that implements a task must not exit or attempt to return to
  270. * its caller as there is nothing to return to. If a task wants to exit it
  271. * should instead call vTaskDelete( NULL ).
  272. *
  273. * Artificially force an assert() to be triggered if configASSERT() is
  274. * defined, then stop here so application writers can catch the error. */
  275. configASSERT( ulPortInterruptNesting == ~0UL );
  276. portDISABLE_INTERRUPTS();
  277. for( ; ; )
  278. {
  279. }
  280. }
  281. /*-----------------------------------------------------------*/
  282. BaseType_t xPortStartScheduler( void )
  283. {
  284. uint32_t ulAPSR;
  285. #if ( configASSERT_DEFINED == 1 )
  286. {
  287. volatile uint8_t ucOriginalPriority;
  288. volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + portINTERRUPT_PRIORITY_REGISTER_OFFSET );
  289. volatile uint8_t ucMaxPriorityValue;
  290. /* Determine how many priority bits are implemented in the GIC.
  291. *
  292. * Save the interrupt priority value that is about to be clobbered. */
  293. ucOriginalPriority = *pucFirstUserPriorityRegister;
  294. /* Determine the number of priority bits available. First write to
  295. * all possible bits. */
  296. *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
  297. /* Read the value back to see how many bits stuck. */
  298. ucMaxPriorityValue = *pucFirstUserPriorityRegister;
  299. /* Shift to the least significant bits. */
  300. while( ( ucMaxPriorityValue & portBIT_0_SET ) != portBIT_0_SET )
  301. {
  302. ucMaxPriorityValue >>= ( uint8_t ) 0x01;
  303. }
  304. /* Sanity check configUNIQUE_INTERRUPT_PRIORITIES matches the read
  305. * value. */
  306. configASSERT( ucMaxPriorityValue == portLOWEST_INTERRUPT_PRIORITY );
  307. /* Restore the clobbered interrupt priority register to its original
  308. * value. */
  309. *pucFirstUserPriorityRegister = ucOriginalPriority;
  310. }
  311. #endif /* configASSERT_DEFINED */
  312. /* Only continue if the CPU is not in User mode. The CPU must be in a
  313. * Privileged mode for the scheduler to start. */
  314. __asm volatile ( "MRS %0, APSR" : "=r" ( ulAPSR )::"memory" );
  315. ulAPSR &= portAPSR_MODE_BITS_MASK;
  316. configASSERT( ulAPSR != portAPSR_USER_MODE );
  317. if( ulAPSR != portAPSR_USER_MODE )
  318. {
  319. /* Only continue if the binary point value is set to its lowest possible
  320. * setting. See the comments in vPortValidateInterruptPriority() below for
  321. * more information. */
  322. configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
  323. if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE )
  324. {
  325. /* Interrupts are turned off in the CPU itself to ensure tick does
  326. * not execute while the scheduler is being started. Interrupts are
  327. * automatically turned back on in the CPU when the first task starts
  328. * executing. */
  329. portCPU_IRQ_DISABLE();
  330. /* Start the timer that generates the tick ISR. */
  331. configSETUP_TICK_INTERRUPT();
  332. /* Start the first task executing. */
  333. vPortRestoreTaskContext();
  334. }
  335. }
  336. /* Will only get here if vTaskStartScheduler() was called with the CPU in
  337. * a non-privileged mode or the binary point register was not set to its lowest
  338. * possible value. prvTaskExitError() is referenced to prevent a compiler
  339. * warning about it being defined but not referenced in the case that the user
  340. * defines their own exit address. */
  341. ( void ) prvTaskExitError;
  342. return 0;
  343. }
  344. /*-----------------------------------------------------------*/
  345. void vPortEndScheduler( void )
  346. {
  347. /* Not implemented in ports where there is nothing to return to.
  348. * Artificially force an assert. */
  349. configASSERT( ulCriticalNesting == 1000UL );
  350. }
  351. /*-----------------------------------------------------------*/
  352. void vPortEnterCritical( void )
  353. {
  354. /* Mask interrupts up to the max syscall interrupt priority. */
  355. ulPortSetInterruptMask();
  356. /* Now that interrupts are disabled, ulCriticalNesting can be accessed
  357. * directly. Increment ulCriticalNesting to keep a count of how many times
  358. * portENTER_CRITICAL() has been called. */
  359. ulCriticalNesting++;
  360. /* This is not the interrupt safe version of the enter critical function so
  361. * assert() if it is being called from an interrupt context. Only API
  362. * functions that end in "FromISR" can be used in an interrupt. Only assert if
  363. * the critical nesting count is 1 to protect against recursive calls if the
  364. * assert function also uses a critical section. */
  365. if( ulCriticalNesting == 1 )
  366. {
  367. configASSERT( ulPortInterruptNesting == 0 );
  368. }
  369. }
  370. /*-----------------------------------------------------------*/
  371. void vPortExitCritical( void )
  372. {
  373. if( ulCriticalNesting > portNO_CRITICAL_NESTING )
  374. {
  375. /* Decrement the nesting count as the critical section is being
  376. * exited. */
  377. ulCriticalNesting--;
  378. /* If the nesting level has reached zero then all interrupt
  379. * priorities must be re-enabled. */
  380. if( ulCriticalNesting == portNO_CRITICAL_NESTING )
  381. {
  382. /* Critical nesting has reached zero so all interrupt priorities
  383. * should be unmasked. */
  384. portCLEAR_INTERRUPT_MASK();
  385. }
  386. }
  387. }
  388. /*-----------------------------------------------------------*/
  389. void FreeRTOS_Tick_Handler( void )
  390. {
  391. /* Set interrupt mask before altering scheduler structures. The tick
  392. * handler runs at the lowest priority, so interrupts cannot already be masked,
  393. * so there is no need to save and restore the current mask value. It is
  394. * necessary to turn off interrupts in the CPU itself while the ICCPMR is being
  395. * updated. */
  396. portCPU_IRQ_DISABLE();
  397. portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
  398. __asm volatile ( "dsb \n"
  399. "isb \n" ::: "memory" );
  400. portCPU_IRQ_ENABLE();
  401. /* Increment the RTOS tick. */
  402. if( xTaskIncrementTick() != pdFALSE )
  403. {
  404. ulPortYieldRequired = pdTRUE;
  405. }
  406. /* Ensure all interrupt priorities are active again. */
  407. portCLEAR_INTERRUPT_MASK();
  408. configCLEAR_TICK_INTERRUPT();
  409. }
  410. /*-----------------------------------------------------------*/
  411. #if ( configUSE_TASK_FPU_SUPPORT != 2 )
  412. void vPortTaskUsesFPU( void )
  413. {
  414. uint32_t ulInitialFPSCR = 0;
  415. /* A task is registering the fact that it needs an FPU context. Set the
  416. * FPU flag (which is saved as part of the task context). */
  417. ulPortTaskHasFPUContext = pdTRUE;
  418. /* Initialise the floating point status register. */
  419. __asm volatile ( "FMXR FPSCR, %0" ::"r" ( ulInitialFPSCR ) : "memory" );
  420. }
  421. #endif /* configUSE_TASK_FPU_SUPPORT */
  422. /*-----------------------------------------------------------*/
  423. void vPortClearInterruptMask( uint32_t ulNewMaskValue )
  424. {
  425. if( ulNewMaskValue == pdFALSE )
  426. {
  427. portCLEAR_INTERRUPT_MASK();
  428. }
  429. }
  430. /*-----------------------------------------------------------*/
  431. uint32_t ulPortSetInterruptMask( void )
  432. {
  433. uint32_t ulReturn;
  434. /* Interrupt in the CPU must be turned off while the ICCPMR is being
  435. * updated. */
  436. portCPU_IRQ_DISABLE();
  437. if( portICCPMR_PRIORITY_MASK_REGISTER == ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) )
  438. {
  439. /* Interrupts were already masked. */
  440. ulReturn = pdTRUE;
  441. }
  442. else
  443. {
  444. ulReturn = pdFALSE;
  445. portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
  446. __asm volatile ( "dsb \n"
  447. "isb \n" ::: "memory" );
  448. }
  449. portCPU_IRQ_ENABLE();
  450. return ulReturn;
  451. }
  452. /*-----------------------------------------------------------*/
  453. #if ( configASSERT_DEFINED == 1 )
  454. void vPortValidateInterruptPriority( void )
  455. {
  456. /* The following assertion will fail if a service routine (ISR) for
  457. * an interrupt that has been assigned a priority above
  458. * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
  459. * function. ISR safe FreeRTOS API functions must *only* be called
  460. * from interrupts that have been assigned a priority at or below
  461. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
  462. *
  463. * Numerically low interrupt priority numbers represent logically high
  464. * interrupt priorities, therefore the priority of the interrupt must
  465. * be set to a value equal to or numerically *higher* than
  466. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
  467. *
  468. * FreeRTOS maintains separate thread and ISR API functions to ensure
  469. * interrupt entry is as fast and simple as possible. */
  470. configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
  471. /* Priority grouping: The interrupt controller (GIC) allows the bits
  472. * that define each interrupt's priority to be split between bits that
  473. * define the interrupt's pre-emption priority bits and bits that define
  474. * the interrupt's sub-priority. For simplicity all bits must be defined
  475. * to be pre-emption priority bits. The following assertion will fail if
  476. * this is not the case (if some bits represent a sub-priority).
  477. *
  478. * The priority grouping is configured by the GIC's binary point register
  479. * (ICCBPR). Writing 0 to ICCBPR will ensure it is set to its lowest
  480. * possible value (which may be above 0). */
  481. configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
  482. }
  483. #endif /* configASSERT_DEFINED */
  484. /*-----------------------------------------------------------*/
  485. void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR )
  486. {
  487. ( void ) ulICCIAR;
  488. configASSERT( ( volatile void * ) NULL );
  489. }