port.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  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. Refer to Cortex-A equivalent: http: /*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. Refer to Cortex-A equivalent: http: /*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. Refer to Cortex-A equivalent: http: /*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. Refer to Cortex-A equivalent: http: /*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. Refer to Cortex-A equivalent: http: /*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. /*
  66. * __ARM_FP is defined by the c preprocessor when FPU support is enabled,
  67. * usually with the -mfpu= argument and -mfloat-abi=.
  68. *
  69. * Note: Some implementations of the c standard library may use FPU registers
  70. * for generic memory operations (memcpy, etc).
  71. * When setting configUSE_TASK_FPU_SUPPORT == 1, care must be taken to
  72. * ensure that the FPU registers are not used without an FPU context.
  73. */
  74. #if ( configUSE_TASK_FPU_SUPPORT == 0 )
  75. #ifdef __ARM_FP
  76. #error __ARM_FP is defined, so configUSE_TASK_FPU_SUPPORT must be set to either to 1 or 2.
  77. #endif /* __ARM_FP */
  78. #elif ( configUSE_TASK_FPU_SUPPORT == 1 ) || ( configUSE_TASK_FPU_SUPPORT == 2 )
  79. #ifndef __ARM_FP
  80. #error __ARM_FP is not defined, so configUSE_TASK_FPU_SUPPORT must be set to 0.
  81. #endif /* __ARM_FP */
  82. #endif /* configUSE_TASK_FPU_SUPPORT */
  83. /*
  84. * Some vendor specific files default configCLEAR_TICK_INTERRUPT() in
  85. * portmacro.h.
  86. */
  87. #ifndef configCLEAR_TICK_INTERRUPT
  88. #define configCLEAR_TICK_INTERRUPT()
  89. #endif
  90. /*
  91. * A critical section is exited when the critical section nesting count reaches
  92. * this value.
  93. */
  94. #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
  95. /*
  96. * In all GICs 255 can be written to the priority mask register to unmask all
  97. * (but the lowest) interrupt priority.
  98. */
  99. #define portUNMASK_VALUE ( 0xFFUL )
  100. /*
  101. * Tasks are not created with a floating point context, but can be given a
  102. * floating point context after they have been created. A variable is stored as
  103. * part of the tasks context that holds portNO_FLOATING_POINT_CONTEXT if the task
  104. * does not have an FPU context, or any other value if the task does have an FPU
  105. * context.
  106. */
  107. #define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
  108. /* Constants required to setup the initial task context. */
  109. #define portINITIAL_SPSR ( ( StackType_t ) 0x1f ) /* System mode, ARM mode, IRQ enabled FIQ enabled. */
  110. #define portTHUMB_MODE_BIT ( ( StackType_t ) 0x20 )
  111. #define portINTERRUPT_ENABLE_BIT ( 0x80UL )
  112. #define portTHUMB_MODE_ADDRESS ( 0x01UL )
  113. /*
  114. * Used by portASSERT_IF_INTERRUPT_PRIORITY_INVALID() when ensuring the binary
  115. * point is zero.
  116. */
  117. #define portBINARY_POINT_BITS ( ( uint8_t ) 0x03 )
  118. /* Masks all bits in the APSR other than the mode bits. */
  119. #define portAPSR_MODE_BITS_MASK ( 0x1F )
  120. /* The value of the mode bits in the APSR when the CPU is executing in user
  121. * mode. */
  122. #define portAPSR_USER_MODE ( 0x10 )
  123. /* The critical section macros only mask interrupts up to an application
  124. * determined priority level. Sometimes it is necessary to turn interrupt off in
  125. * the CPU itself before modifying certain hardware registers. */
  126. #define portCPU_IRQ_DISABLE() \
  127. __asm volatile ( "CPSID i" ::: "memory" ); \
  128. __asm volatile ( "DSB" ); \
  129. __asm volatile ( "ISB" );
  130. #define portCPU_IRQ_ENABLE() \
  131. __asm volatile ( "CPSIE i" ::: "memory" ); \
  132. __asm volatile ( "DSB" ); \
  133. __asm volatile ( "ISB" );
  134. /* Macro to unmask all interrupt priorities. */
  135. #define portCLEAR_INTERRUPT_MASK() \
  136. { \
  137. portCPU_IRQ_DISABLE(); \
  138. portICCPMR_PRIORITY_MASK_REGISTER = portUNMASK_VALUE; \
  139. __asm volatile ( "DSB \n" \
  140. "ISB \n" ); \
  141. portCPU_IRQ_ENABLE(); \
  142. }
  143. #define portINTERRUPT_PRIORITY_REGISTER_OFFSET 0x400UL
  144. #define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
  145. #define portBIT_0_SET ( ( uint8_t ) 0x01 )
  146. /*
  147. * Let the user override the pre-loading of the initial LR with the address of
  148. * prvTaskExitError() in case is messes up unwinding of the stack in the
  149. * debugger.
  150. */
  151. #ifdef configTASK_RETURN_ADDRESS
  152. #define portTASK_RETURN_ADDRESS configTASK_RETURN_ADDRESS
  153. #else
  154. #define portTASK_RETURN_ADDRESS prvTaskExitError
  155. #endif
  156. #if ( configUSE_TASK_FPU_SUPPORT != 0 )
  157. /*
  158. * The space on the stack required to hold the FPU registers.
  159. *
  160. * The ARM Cortex R5 processor implements the VFPv3-D16 FPU
  161. * architecture. This includes only 16 double-precision registers,
  162. * instead of 32 as is in VFPv3. The register bank can be viewed
  163. * either as sixteen 64-bit double-word registers (D0-D15) or
  164. * thirty-two 32-bit single-word registers (S0-S31), in both cases
  165. * the size of the bank remains the same. The FPU has also a 32-bit
  166. * status register.
  167. */
  168. #define portFPU_REGISTER_WORDS ( ( 16 * 2 ) + 1 )
  169. #endif /* configUSE_TASK_FPU_SUPPORT != 0 */
  170. /*-----------------------------------------------------------*/
  171. /*
  172. * Starts the first task executing. This function is necessarily written in
  173. * assembly code so is implemented in portASM.s.
  174. */
  175. extern void vPortRestoreTaskContext( void );
  176. /*
  177. * Used to catch tasks that attempt to return from their implementing function.
  178. */
  179. static void prvTaskExitError( void );
  180. #if ( configUSE_TASK_FPU_SUPPORT != 0 )
  181. /*
  182. * If the application provides an implementation of vApplicationIRQHandler(),
  183. * then it will get called directly without saving the FPU registers on
  184. * interrupt entry, and this weak implementation of
  185. * vApplicationFPUSafeIRQHandler() is just provided to remove linkage errors -
  186. * it should never actually get called so its implementation contains a
  187. * call to configASSERT() that will always fail.
  188. *
  189. * If the application provides its own implementation of
  190. * vApplicationFPUSafeIRQHandler() then the implementation of
  191. * vApplicationIRQHandler() provided in portASM.S will save the FPU registers
  192. * before calling it.
  193. *
  194. * Therefore, if the application writer wants FPU registers to be saved on
  195. * interrupt entry their IRQ handler must be called
  196. * vApplicationFPUSafeIRQHandler(), and if the application writer does not want
  197. * FPU registers to be saved on interrupt entry their IRQ handler must be
  198. * called vApplicationIRQHandler().
  199. */
  200. void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR ) __attribute__( ( weak ) );
  201. #endif /* configUSE_TASK_FPU_SUPPORT != 0 */
  202. /*-----------------------------------------------------------*/
  203. /*
  204. * A variable is used to keep track of the critical section nesting. This
  205. * variable has to be stored as part of the task context and must be initialised to
  206. * a non zero value to ensure interrupts don't inadvertently become unmasked before
  207. * the scheduler starts. As it is stored as part of the task context it will
  208. * automatically be set to 0 when the first task is started.
  209. */
  210. volatile uint32_t ulCriticalNesting = 9999UL;
  211. #if ( configUSE_TASK_FPU_SUPPORT != 0 )
  212. /*
  213. * Saved as part of the task context. If ulPortTaskHasFPUContext is non-zero then
  214. * a floating point context must be saved and restored for the task.
  215. */
  216. uint32_t ulPortTaskHasFPUContext = pdFALSE;
  217. #endif /* configUSE_TASK_FPU_SUPPORT != 0 */
  218. /* Set to 1 to pend a context switch from an ISR. */
  219. uint32_t ulPortYieldRequired = pdFALSE;
  220. /*
  221. * Counts the interrupt nesting depth. A context switch is only performed if
  222. * if the nesting depth is 0.
  223. */
  224. uint32_t ulPortInterruptNesting = 0UL;
  225. /* Used in asm code. */
  226. __attribute__( ( used ) ) const uint32_t ulICCIAR = portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS;
  227. __attribute__( ( used ) ) const uint32_t ulICCEOIR = portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS;
  228. __attribute__( ( used ) ) const uint32_t ulICCPMR = portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS;
  229. __attribute__( ( used ) ) const uint32_t ulMaxAPIPriorityMask = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
  230. /*-----------------------------------------------------------*/
  231. /*
  232. * See header file for description.
  233. */
  234. StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
  235. TaskFunction_t pxCode,
  236. void * pvParameters )
  237. {
  238. /*
  239. * Setup the initial stack of the task. The stack is set exactly as
  240. * expected by the portRESTORE_CONTEXT() macro.
  241. *
  242. * The fist real value on the stack is the status register, which is set for
  243. * system mode, with interrupts enabled. A few NULLs are added first to ensure
  244. * GDB does not try decoding a non-existent return address.
  245. */
  246. *pxTopOfStack = ( StackType_t ) NULL;
  247. pxTopOfStack--;
  248. *pxTopOfStack = ( StackType_t ) NULL;
  249. pxTopOfStack--;
  250. *pxTopOfStack = ( StackType_t ) NULL;
  251. pxTopOfStack--;
  252. *pxTopOfStack = ( StackType_t ) portINITIAL_SPSR;
  253. if( ( ( uint32_t ) pxCode & portTHUMB_MODE_ADDRESS ) != 0x00UL )
  254. {
  255. /* The task will start in THUMB mode. */
  256. *pxTopOfStack |= portTHUMB_MODE_BIT;
  257. }
  258. pxTopOfStack--;
  259. /* Next the return address, which in this case is the start of the task. */
  260. *pxTopOfStack = ( StackType_t ) pxCode;
  261. pxTopOfStack--;
  262. /* Next all the registers other than the stack pointer. */
  263. *pxTopOfStack = ( StackType_t ) portTASK_RETURN_ADDRESS; /* R14 */
  264. pxTopOfStack--;
  265. *pxTopOfStack = ( StackType_t ) 0x12121212; /* R12 */
  266. pxTopOfStack--;
  267. *pxTopOfStack = ( StackType_t ) 0x11111111; /* R11 */
  268. pxTopOfStack--;
  269. *pxTopOfStack = ( StackType_t ) 0x10101010; /* R10 */
  270. pxTopOfStack--;
  271. *pxTopOfStack = ( StackType_t ) 0x09090909; /* R9 */
  272. pxTopOfStack--;
  273. *pxTopOfStack = ( StackType_t ) 0x08080808; /* R8 */
  274. pxTopOfStack--;
  275. *pxTopOfStack = ( StackType_t ) 0x07070707; /* R7 */
  276. pxTopOfStack--;
  277. *pxTopOfStack = ( StackType_t ) 0x06060606; /* R6 */
  278. pxTopOfStack--;
  279. *pxTopOfStack = ( StackType_t ) 0x05050505; /* R5 */
  280. pxTopOfStack--;
  281. *pxTopOfStack = ( StackType_t ) 0x04040404; /* R4 */
  282. pxTopOfStack--;
  283. *pxTopOfStack = ( StackType_t ) 0x03030303; /* R3 */
  284. pxTopOfStack--;
  285. *pxTopOfStack = ( StackType_t ) 0x02020202; /* R2 */
  286. pxTopOfStack--;
  287. *pxTopOfStack = ( StackType_t ) 0x01010101; /* R1 */
  288. pxTopOfStack--;
  289. *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
  290. /*
  291. * The task will start with a critical nesting count of 0 as interrupts are
  292. * enabled.
  293. */
  294. pxTopOfStack--;
  295. *pxTopOfStack = portNO_CRITICAL_NESTING;
  296. #if ( configUSE_TASK_FPU_SUPPORT == 1 )
  297. {
  298. /*
  299. * The task will start without a floating point context.
  300. * A task that uses the floating point hardware must call
  301. * vPortTaskUsesFPU() before executing any floating point
  302. * instructions.
  303. */
  304. pxTopOfStack--;
  305. *pxTopOfStack = portNO_FLOATING_POINT_CONTEXT;
  306. }
  307. #elif ( configUSE_TASK_FPU_SUPPORT == 2 )
  308. {
  309. /*
  310. * The task will start with a floating point context. Leave enough
  311. * space for the registers and ensure they are initialized to 0.
  312. */
  313. pxTopOfStack -= portFPU_REGISTER_WORDS;
  314. memset( pxTopOfStack, 0x00, portFPU_REGISTER_WORDS * sizeof( StackType_t ) );
  315. pxTopOfStack--;
  316. *pxTopOfStack = pdTRUE;
  317. ulPortTaskHasFPUContext = pdTRUE;
  318. }
  319. #elif ( configUSE_TASK_FPU_SUPPORT != 0 )
  320. {
  321. #error Invalid configUSE_TASK_FPU_SUPPORT setting - configUSE_TASK_FPU_SUPPORT must be set to 0, 1, or 2.
  322. }
  323. #endif /* configUSE_TASK_FPU_SUPPORT */
  324. return pxTopOfStack;
  325. }
  326. /*-----------------------------------------------------------*/
  327. static void prvTaskExitError( void )
  328. {
  329. /*
  330. * A function that implements a task must not exit or attempt to return to
  331. * its caller as there is nothing to return to. If a task wants to exit it
  332. * should instead call vTaskDelete( NULL ).
  333. *
  334. * Artificially force an assert() to be triggered if configASSERT() is
  335. * defined, then stop here so application writers can catch the error.
  336. */
  337. configASSERT( ulPortInterruptNesting == ~0UL );
  338. portDISABLE_INTERRUPTS();
  339. for( ; ; )
  340. {
  341. }
  342. }
  343. /*-----------------------------------------------------------*/
  344. #if ( configUSE_TASK_FPU_SUPPORT != 0 )
  345. void vApplicationFPUSafeIRQHandler( uint32_t ulICCIAR ) /* __attribute__( ( weak ) ) */
  346. {
  347. ( void ) ulICCIAR;
  348. configASSERT( ( volatile void * ) NULL );
  349. }
  350. #endif /* configUSE_TASK_FPU_SUPPORT != 0 */
  351. /*-----------------------------------------------------------*/
  352. BaseType_t xPortStartScheduler( void )
  353. {
  354. uint32_t ulAPSR, ulCycles = 8; /* 8 bits per byte. */
  355. #if ( configASSERT_DEFINED == 1 )
  356. {
  357. volatile uint8_t ucOriginalPriority;
  358. volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + portINTERRUPT_PRIORITY_REGISTER_OFFSET );
  359. volatile uint8_t ucMaxPriorityValue;
  360. /*
  361. * Determine how many priority bits are implemented in the GIC.
  362. * Save the interrupt priority value that is about to be clobbered.
  363. */
  364. ucOriginalPriority = *pucFirstUserPriorityRegister;
  365. /*
  366. * Determine the number of priority bits available. First write to
  367. * all possible bits.
  368. */
  369. *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
  370. /* Read the value back to see how many bits stuck. */
  371. ucMaxPriorityValue = *pucFirstUserPriorityRegister;
  372. /* Shift to the least significant bits. */
  373. while( ( ucMaxPriorityValue & portBIT_0_SET ) != portBIT_0_SET )
  374. {
  375. ucMaxPriorityValue >>= ( uint8_t ) 0x01;
  376. /*
  377. * If ulCycles reaches 0 then ucMaxPriorityValue must have been
  378. * read as 0, indicating a misconfiguration.
  379. */
  380. ulCycles--;
  381. if( ulCycles == 0 )
  382. {
  383. break;
  384. }
  385. }
  386. /*
  387. * Sanity check configUNIQUE_INTERRUPT_PRIORITIES matches the read
  388. * value.
  389. */
  390. configASSERT( ucMaxPriorityValue == portLOWEST_INTERRUPT_PRIORITY );
  391. /*
  392. * Restore the clobbered interrupt priority register to its original
  393. * value.
  394. */
  395. *pucFirstUserPriorityRegister = ucOriginalPriority;
  396. }
  397. #endif /* configASSERT_DEFINED */
  398. /*
  399. * Only continue if the CPU is not in User mode. The CPU must be in a
  400. * Privileged mode for the scheduler to start.
  401. */
  402. __asm volatile ( "MRS %0, APSR" : "=r" ( ulAPSR )::"memory" );
  403. ulAPSR &= portAPSR_MODE_BITS_MASK;
  404. configASSERT( ulAPSR != portAPSR_USER_MODE );
  405. if( ulAPSR != portAPSR_USER_MODE )
  406. {
  407. /*
  408. * Only continue if the binary point value is set to its lowest possible
  409. * setting. See the comments in vPortValidateInterruptPriority() below for
  410. * more information.
  411. */
  412. configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
  413. if( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE )
  414. {
  415. /*
  416. * Interrupts are turned off in the CPU itself to ensure tick does
  417. * not execute while the scheduler is being started. Interrupts are
  418. * automatically turned back on in the CPU when the first task starts
  419. * executing.
  420. */
  421. portCPU_IRQ_DISABLE();
  422. /* Start the timer that generates the tick ISR. */
  423. configSETUP_TICK_INTERRUPT();
  424. /* Start the first task executing. */
  425. vPortRestoreTaskContext();
  426. }
  427. }
  428. /*
  429. * Will only get here if vTaskStartScheduler() was called with the CPU in
  430. * a non-privileged mode or the binary point register was not set to its lowest
  431. * possible value. prvTaskExitError() is referenced to prevent a compiler
  432. * warning about it being defined but not referenced in the case that the user
  433. * defines their own exit address.
  434. */
  435. ( void ) prvTaskExitError;
  436. return 0;
  437. }
  438. /*-----------------------------------------------------------*/
  439. void vPortEndScheduler( void )
  440. {
  441. /*
  442. * Not implemented in ports where there is nothing to return to.
  443. * Artificially force an assert.
  444. */
  445. configASSERT( ulCriticalNesting == 1000UL );
  446. }
  447. /*-----------------------------------------------------------*/
  448. void vPortEnterCritical( void )
  449. {
  450. /* Mask interrupts up to the max syscall interrupt priority. */
  451. ulPortSetInterruptMask();
  452. /*
  453. * Now that interrupts are disabled, ulCriticalNesting can be accessed
  454. * directly. Increment ulCriticalNesting to keep a count of how many times
  455. * portENTER_CRITICAL() has been called.
  456. */
  457. ulCriticalNesting++;
  458. /*
  459. * This is not the interrupt safe version of the enter critical function so
  460. * assert() if it is being called from an interrupt context. Only API
  461. * functions that end in "FromISR" can be used in an interrupt. Only assert if
  462. * the critical nesting count is 1 to protect against recursive calls if the
  463. * assert function also uses a critical section.
  464. */
  465. if( ulCriticalNesting == 1 )
  466. {
  467. configASSERT( ulPortInterruptNesting == 0 );
  468. }
  469. }
  470. /*-----------------------------------------------------------*/
  471. void vPortExitCritical( void )
  472. {
  473. if( ulCriticalNesting > portNO_CRITICAL_NESTING )
  474. {
  475. /* Decrement the nesting count as the critical section is being exited. */
  476. ulCriticalNesting--;
  477. /*
  478. * If the nesting level has reached zero then all interrupt
  479. * priorities must be re-enabled.
  480. */
  481. if( ulCriticalNesting == portNO_CRITICAL_NESTING )
  482. {
  483. /*
  484. * Critical nesting has reached zero so all interrupt priorities
  485. * should be unmasked.
  486. */
  487. portCLEAR_INTERRUPT_MASK();
  488. }
  489. }
  490. }
  491. /*-----------------------------------------------------------*/
  492. void FreeRTOS_Tick_Handler( void )
  493. {
  494. /*
  495. * Set interrupt mask before altering scheduler structures. The tick
  496. * handler runs at the lowest priority, so interrupts cannot already be masked,
  497. * so there is no need to save and restore the current mask value. It is
  498. * necessary to turn off interrupts in the CPU itself while the ICCPMR is being
  499. * updated.
  500. */
  501. portCPU_IRQ_DISABLE();
  502. portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
  503. __asm volatile ( "dsb \n"
  504. "isb \n" ::: "memory" );
  505. portCPU_IRQ_ENABLE();
  506. /* Increment the RTOS tick. */
  507. if( xTaskIncrementTick() != pdFALSE )
  508. {
  509. ulPortYieldRequired = pdTRUE;
  510. }
  511. /* Ensure all interrupt priorities are active again. */
  512. portCLEAR_INTERRUPT_MASK();
  513. configCLEAR_TICK_INTERRUPT();
  514. }
  515. /*-----------------------------------------------------------*/
  516. #if ( configUSE_TASK_FPU_SUPPORT == 1 )
  517. void vPortTaskUsesFPU( void )
  518. {
  519. uint32_t ulInitialFPSCR = 0;
  520. /*
  521. * A task is registering the fact that it needs an FPU context. Set the
  522. * FPU flag (which is saved as part of the task context).
  523. */
  524. ulPortTaskHasFPUContext = pdTRUE;
  525. /* Initialise the floating point status register. */
  526. __asm volatile ( "FMXR FPSCR, %0" ::"r" ( ulInitialFPSCR ) : "memory" );
  527. }
  528. #endif /* configUSE_TASK_FPU_SUPPORT == 1 */
  529. /*-----------------------------------------------------------*/
  530. void vPortClearInterruptMask( uint32_t ulNewMaskValue )
  531. {
  532. if( ulNewMaskValue == pdFALSE )
  533. {
  534. portCLEAR_INTERRUPT_MASK();
  535. }
  536. }
  537. /*-----------------------------------------------------------*/
  538. uint32_t ulPortSetInterruptMask( void )
  539. {
  540. uint32_t ulReturn;
  541. /* Interrupts must be masked while ICCPMR is updated. */
  542. portCPU_IRQ_DISABLE();
  543. if( portICCPMR_PRIORITY_MASK_REGISTER == ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) )
  544. {
  545. /* Interrupts were already masked. */
  546. ulReturn = pdTRUE;
  547. }
  548. else
  549. {
  550. ulReturn = pdFALSE;
  551. portICCPMR_PRIORITY_MASK_REGISTER = ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
  552. __asm volatile ( "dsb \n"
  553. "isb \n" ::: "memory" );
  554. }
  555. portCPU_IRQ_ENABLE();
  556. return ulReturn;
  557. }
  558. /*-----------------------------------------------------------*/
  559. #if ( configASSERT_DEFINED == 1 )
  560. void vPortValidateInterruptPriority( void )
  561. {
  562. /*
  563. * The following assertion will fail if a service routine (ISR) for
  564. * an interrupt that has been assigned a priority above
  565. * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
  566. * function. ISR safe FreeRTOS API functions must *only* be called
  567. * from interrupts that have been assigned a priority at or below
  568. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
  569. *
  570. * Numerically low interrupt priority numbers represent logically high
  571. * interrupt priorities, therefore the priority of the interrupt must
  572. * be set to a value equal to or numerically *higher* than
  573. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
  574. *
  575. * FreeRTOS maintains separate thread and ISR API functions to ensure
  576. * interrupt entry is as fast and simple as possible.
  577. */
  578. configASSERT( portICCRPR_RUNNING_PRIORITY_REGISTER >= ( uint32_t ) ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ) );
  579. /*
  580. * Priority grouping: The interrupt controller (GIC) allows the bits
  581. * that define each interrupt's priority to be split between bits that
  582. * define the interrupt's pre-emption priority bits and bits that define
  583. * the interrupt's sub-priority. For simplicity all bits must be defined
  584. * to be pre-emption priority bits. The following assertion will fail if
  585. * this is not the case (if some bits represent a sub-priority).
  586. *
  587. * The priority grouping is configured by the GIC's binary point register
  588. * (ICCBPR). Writing 0 to ICCBPR will ensure it is set to its lowest
  589. * possible value (which may be above 0).
  590. */
  591. configASSERT( ( portICCBPR_BINARY_POINT_REGISTER & portBINARY_POINT_BITS ) <= portMAX_BINARY_POINT_VALUE );
  592. }
  593. #endif /* configASSERT_DEFINED */
  594. /*-----------------------------------------------------------*/