port.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874
  1. /*
  2. * FreeRTOS Kernel V10.4.3 LTS Patch 2
  3. * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. * this software and associated documentation files (the "Software"), to deal in
  7. * the Software without restriction, including without limitation the rights to
  8. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. * the Software, and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * https://www.FreeRTOS.org
  23. * https://github.com/FreeRTOS
  24. *
  25. */
  26. /*-----------------------------------------------------------
  27. * Implementation of functions defined in portable.h for the ARM CM3 MPU port.
  28. *----------------------------------------------------------*/
  29. /* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
  30. * all the API functions to use the MPU wrappers. That should only be done when
  31. * task.h is included from an application file. */
  32. #define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
  33. /* Scheduler includes. */
  34. #include "FreeRTOS.h"
  35. #include "task.h"
  36. #undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
  37. #ifndef configSYSTICK_CLOCK_HZ
  38. #define configSYSTICK_CLOCK_HZ configCPU_CLOCK_HZ
  39. /* Ensure the SysTick is clocked at the same frequency as the core. */
  40. #define portNVIC_SYSTICK_CLK ( 1UL << 2UL )
  41. #else
  42. /* The way the SysTick is clocked is not modified in case it is not the same
  43. * as the core. */
  44. #define portNVIC_SYSTICK_CLK ( 0 )
  45. #endif
  46. /* Constants required to access and manipulate the NVIC. */
  47. #define portNVIC_SYSTICK_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000e010 ) )
  48. #define portNVIC_SYSTICK_LOAD_REG ( *( ( volatile uint32_t * ) 0xe000e014 ) )
  49. #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( *( ( volatile uint32_t * ) 0xe000e018 ) )
  50. #define portNVIC_SHPR3_REG ( *( ( volatile uint32_t * ) 0xe000ed20 ) )
  51. #define portNVIC_SHPR2_REG ( *( ( volatile uint32_t * ) 0xe000ed1c ) )
  52. #define portNVIC_SYS_CTRL_STATE_REG ( *( ( volatile uint32_t * ) 0xe000ed24 ) )
  53. #define portNVIC_MEM_FAULT_ENABLE ( 1UL << 16UL )
  54. /* Constants required to access and manipulate the MPU. */
  55. #define portMPU_TYPE_REG ( *( ( volatile uint32_t * ) 0xe000ed90 ) )
  56. #define portMPU_REGION_BASE_ADDRESS_REG ( *( ( volatile uint32_t * ) 0xe000ed9C ) )
  57. #define portMPU_REGION_ATTRIBUTE_REG ( *( ( volatile uint32_t * ) 0xe000edA0 ) )
  58. #define portMPU_CTRL_REG ( *( ( volatile uint32_t * ) 0xe000ed94 ) )
  59. #define portEXPECTED_MPU_TYPE_VALUE ( 8UL << 8UL ) /* 8 regions, unified. */
  60. #define portMPU_ENABLE ( 0x01UL )
  61. #define portMPU_BACKGROUND_ENABLE ( 1UL << 2UL )
  62. #define portPRIVILEGED_EXECUTION_START_ADDRESS ( 0UL )
  63. #define portMPU_REGION_VALID ( 0x10UL )
  64. #define portMPU_REGION_ENABLE ( 0x01UL )
  65. #define portPERIPHERALS_START_ADDRESS 0x40000000UL
  66. #define portPERIPHERALS_END_ADDRESS 0x5FFFFFFFUL
  67. /* Constants required to access and manipulate the SysTick. */
  68. #define portNVIC_SYSTICK_INT ( 0x00000002UL )
  69. #define portNVIC_SYSTICK_ENABLE ( 0x00000001UL )
  70. #define portNVIC_PENDSV_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
  71. #define portNVIC_SYSTICK_PRI ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )
  72. #define portNVIC_SVC_PRI ( ( ( uint32_t ) configMAX_SYSCALL_INTERRUPT_PRIORITY - 1UL ) << 24UL )
  73. /* Constants required to set up the initial stack. */
  74. #define portINITIAL_XPSR ( 0x01000000 )
  75. #define portINITIAL_CONTROL_IF_UNPRIVILEGED ( 0x03 )
  76. #define portINITIAL_CONTROL_IF_PRIVILEGED ( 0x02 )
  77. /* Constants required to check the validity of an interrupt priority. */
  78. #define portFIRST_USER_INTERRUPT_NUMBER ( 16 )
  79. #define portNVIC_IP_REGISTERS_OFFSET_16 ( 0xE000E3F0 )
  80. #define portAIRCR_REG ( *( ( volatile uint32_t * ) 0xE000ED0C ) )
  81. #define portMAX_8_BIT_VALUE ( ( uint8_t ) 0xff )
  82. #define portTOP_BIT_OF_BYTE ( ( uint8_t ) 0x80 )
  83. #define portMAX_PRIGROUP_BITS ( ( uint8_t ) 7 )
  84. #define portPRIORITY_GROUP_MASK ( 0x07UL << 8UL )
  85. #define portPRIGROUP_SHIFT ( 8UL )
  86. /* Offsets in the stack to the parameters when inside the SVC handler. */
  87. #define portOFFSET_TO_PC ( 6 )
  88. /* For strict compliance with the Cortex-M spec the task start address should
  89. * have bit-0 clear, as it is loaded into the PC on exit from an ISR. */
  90. #define portSTART_ADDRESS_MASK ( ( StackType_t ) 0xfffffffeUL )
  91. /*-----------------------------------------------------------*/
  92. /*
  93. * Configure a number of standard MPU regions that are used by all tasks.
  94. */
  95. static void prvSetupMPU( void ) PRIVILEGED_FUNCTION;
  96. /*
  97. * Return the smallest MPU region size that a given number of bytes will fit
  98. * into. The region size is returned as the value that should be programmed
  99. * into the region attribute register for that region.
  100. */
  101. static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes ) PRIVILEGED_FUNCTION;
  102. /*
  103. * Setup the timer to generate the tick interrupts. The implementation in this
  104. * file is weak to allow application writers to change the timer used to
  105. * generate the tick interrupt.
  106. */
  107. void vPortSetupTimerInterrupt( void );
  108. /*
  109. * Standard FreeRTOS exception handlers.
  110. */
  111. void xPortPendSVHandler( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
  112. void xPortSysTickHandler( void ) __attribute__( ( optimize( "3" ) ) ) PRIVILEGED_FUNCTION;
  113. void vPortSVCHandler( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
  114. /*
  115. * Starts the scheduler by restoring the context of the first task to run.
  116. */
  117. static void prvRestoreContextOfFirstTask( void ) __attribute__( ( naked ) ) PRIVILEGED_FUNCTION;
  118. /*
  119. * C portion of the SVC handler. The SVC handler is split between an asm entry
  120. * and a C wrapper for simplicity of coding and maintenance.
  121. */
  122. static void prvSVCHandler( uint32_t * pulRegisters ) __attribute__( ( noinline ) ) PRIVILEGED_FUNCTION;
  123. /**
  124. * @brief Checks whether or not the processor is privileged.
  125. *
  126. * @return 1 if the processor is already privileged, 0 otherwise.
  127. */
  128. BaseType_t xIsPrivileged( void ) __attribute__( ( naked ) );
  129. /**
  130. * @brief Lowers the privilege level by setting the bit 0 of the CONTROL
  131. * register.
  132. *
  133. * Bit 0 of the CONTROL register defines the privilege level of Thread Mode.
  134. * Bit[0] = 0 --> The processor is running privileged
  135. * Bit[0] = 1 --> The processor is running unprivileged.
  136. */
  137. void vResetPrivilege( void ) __attribute__( ( naked ) );
  138. /**
  139. * @brief Enter critical section.
  140. */
  141. void vPortEnterCritical( void ) FREERTOS_SYSTEM_CALL;
  142. /**
  143. * @brief Exit from critical section.
  144. */
  145. void vPortExitCritical( void ) FREERTOS_SYSTEM_CALL;
  146. /*-----------------------------------------------------------*/
  147. /* Each task maintains its own interrupt status in the critical nesting
  148. * variable. Note this is not saved as part of the task context as context
  149. * switches can only occur when uxCriticalNesting is zero. */
  150. static UBaseType_t uxCriticalNesting = 0xaaaaaaaa;
  151. /*
  152. * Used by the portASSERT_IF_INTERRUPT_PRIORITY_INVALID() macro to ensure
  153. * FreeRTOS API functions are not called from interrupts that have been assigned
  154. * a priority above configMAX_SYSCALL_INTERRUPT_PRIORITY.
  155. */
  156. #if ( configASSERT_DEFINED == 1 )
  157. static uint8_t ucMaxSysCallPriority = 0;
  158. static uint32_t ulMaxPRIGROUPValue = 0;
  159. static const volatile uint8_t * const pcInterruptPriorityRegisters = ( const volatile uint8_t * const ) portNVIC_IP_REGISTERS_OFFSET_16;
  160. #endif /* configASSERT_DEFINED */
  161. /*-----------------------------------------------------------*/
  162. /*
  163. * See header file for description.
  164. */
  165. StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
  166. TaskFunction_t pxCode,
  167. void * pvParameters,
  168. BaseType_t xRunPrivileged )
  169. {
  170. /* Simulate the stack frame as it would be created by a context switch
  171. * interrupt. */
  172. pxTopOfStack--; /* Offset added to account for the way the MCU uses the stack on entry/exit of interrupts. */
  173. *pxTopOfStack = portINITIAL_XPSR; /* xPSR */
  174. pxTopOfStack--;
  175. *pxTopOfStack = ( ( StackType_t ) pxCode ) & portSTART_ADDRESS_MASK; /* PC */
  176. pxTopOfStack--;
  177. *pxTopOfStack = 0; /* LR */
  178. pxTopOfStack -= 5; /* R12, R3, R2 and R1. */
  179. *pxTopOfStack = ( StackType_t ) pvParameters; /* R0 */
  180. pxTopOfStack -= 9; /* R11, R10, R9, R8, R7, R6, R5 and R4. */
  181. if( xRunPrivileged == pdTRUE )
  182. {
  183. *pxTopOfStack = portINITIAL_CONTROL_IF_PRIVILEGED;
  184. }
  185. else
  186. {
  187. *pxTopOfStack = portINITIAL_CONTROL_IF_UNPRIVILEGED;
  188. }
  189. return pxTopOfStack;
  190. }
  191. /*-----------------------------------------------------------*/
  192. void vPortSVCHandler( void )
  193. {
  194. /* Assumes psp was in use. */
  195. __asm volatile
  196. (
  197. #ifndef USE_PROCESS_STACK /* Code should not be required if a main() is using the process stack. */
  198. " tst lr, #4 \n"
  199. " ite eq \n"
  200. " mrseq r0, msp \n"
  201. " mrsne r0, psp \n"
  202. #else
  203. " mrs r0, psp \n"
  204. #endif
  205. " b %0 \n"
  206. ::"i" ( prvSVCHandler ) : "r0", "memory"
  207. );
  208. }
  209. /*-----------------------------------------------------------*/
  210. static void prvSVCHandler( uint32_t * pulParam )
  211. {
  212. uint8_t ucSVCNumber;
  213. uint32_t ulPC;
  214. #if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
  215. #if defined( __ARMCC_VERSION )
  216. /* Declaration when these variable are defined in code instead of being
  217. * exported from linker scripts. */
  218. extern uint32_t * __syscalls_flash_start__;
  219. extern uint32_t * __syscalls_flash_end__;
  220. #else
  221. /* Declaration when these variable are exported from linker scripts. */
  222. extern uint32_t __syscalls_flash_start__[];
  223. extern uint32_t __syscalls_flash_end__[];
  224. #endif /* #if defined( __ARMCC_VERSION ) */
  225. #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
  226. /* The stack contains: r0, r1, r2, r3, r12, LR, PC and xPSR. The first
  227. * argument (r0) is pulParam[ 0 ]. */
  228. ulPC = pulParam[ portOFFSET_TO_PC ];
  229. ucSVCNumber = ( ( uint8_t * ) ulPC )[ -2 ];
  230. switch( ucSVCNumber )
  231. {
  232. case portSVC_START_SCHEDULER:
  233. portNVIC_SHPR2_REG |= portNVIC_SVC_PRI;
  234. prvRestoreContextOfFirstTask();
  235. break;
  236. case portSVC_YIELD:
  237. portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
  238. /* Barriers are normally not required
  239. * but do ensure the code is completely
  240. * within the specified behaviour for the
  241. * architecture. */
  242. __asm volatile ( "dsb" ::: "memory" );
  243. __asm volatile ( "isb" );
  244. break;
  245. #if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 )
  246. case portSVC_RAISE_PRIVILEGE: /* Only raise the privilege, if the
  247. * svc was raised from any of the
  248. * system calls. */
  249. if( ( ulPC >= ( uint32_t ) __syscalls_flash_start__ ) &&
  250. ( ulPC <= ( uint32_t ) __syscalls_flash_end__ ) )
  251. {
  252. __asm volatile
  253. (
  254. " mrs r1, control \n"/* Obtain current control value. */
  255. " bic r1, #1 \n"/* Set privilege bit. */
  256. " msr control, r1 \n"/* Write back new control value. */
  257. ::: "r1", "memory"
  258. );
  259. }
  260. break;
  261. #else /* if ( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
  262. case portSVC_RAISE_PRIVILEGE:
  263. __asm volatile
  264. (
  265. " mrs r1, control \n"/* Obtain current control value. */
  266. " bic r1, #1 \n"/* Set privilege bit. */
  267. " msr control, r1 \n"/* Write back new control value. */
  268. ::: "r1", "memory"
  269. );
  270. break;
  271. #endif /* #if( configENFORCE_SYSTEM_CALLS_FROM_KERNEL_ONLY == 1 ) */
  272. default: /* Unknown SVC call. */
  273. break;
  274. }
  275. }
  276. /*-----------------------------------------------------------*/
  277. static void prvRestoreContextOfFirstTask( void )
  278. {
  279. __asm volatile
  280. (
  281. " ldr r0, =0xE000ED08 \n"/* Use the NVIC offset register to locate the stack. */
  282. " ldr r0, [r0] \n"
  283. " ldr r0, [r0] \n"
  284. " msr msp, r0 \n"/* Set the msp back to the start of the stack. */
  285. " ldr r3, pxCurrentTCBConst2 \n"/* Restore the context. */
  286. " ldr r1, [r3] \n"
  287. " ldr r0, [r1] \n"/* The first item in the TCB is the task top of stack. */
  288. " add r1, r1, #4 \n"/* Move onto the second item in the TCB... */
  289. " \n"
  290. " dmb \n"/* Complete outstanding transfers before disabling MPU. */
  291. " ldr r2, =0xe000ed94 \n"/* MPU_CTRL register. */
  292. " ldr r3, [r2] \n"/* Read the value of MPU_CTRL. */
  293. " bic r3, #1 \n"/* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
  294. " str r3, [r2] \n"/* Disable MPU. */
  295. " \n"
  296. " ldr r2, =0xe000ed9c \n"/* Region Base Address register. */
  297. " ldmia r1!, {r4-r11} \n"/* Read 4 sets of MPU registers. */
  298. " stmia r2!, {r4-r11} \n"/* Write 4 sets of MPU registers. */
  299. " \n"
  300. " ldr r2, =0xe000ed94 \n"/* MPU_CTRL register. */
  301. " ldr r3, [r2] \n"/* Read the value of MPU_CTRL. */
  302. " orr r3, #1 \n"/* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
  303. " str r3, [r2] \n"/* Enable MPU. */
  304. " dsb \n"/* Force memory writes before continuing. */
  305. " \n"
  306. " ldmia r0!, {r3, r4-r11} \n"/* Pop the registers that are not automatically saved on exception entry. */
  307. " msr control, r3 \n"
  308. " msr psp, r0 \n"/* Restore the task stack pointer. */
  309. " mov r0, #0 \n"
  310. " msr basepri, r0 \n"
  311. " ldr r14, =0xfffffffd \n"/* Load exec return code. */
  312. " bx r14 \n"
  313. " \n"
  314. " .align 4 \n"
  315. "pxCurrentTCBConst2: .word pxCurrentTCB \n"
  316. );
  317. }
  318. /*-----------------------------------------------------------*/
  319. /*
  320. * See header file for description.
  321. */
  322. BaseType_t xPortStartScheduler( void )
  323. {
  324. /* configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to 0. See
  325. * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
  326. configASSERT( ( configMAX_SYSCALL_INTERRUPT_PRIORITY ) );
  327. #if ( configASSERT_DEFINED == 1 )
  328. {
  329. volatile uint32_t ulOriginalPriority;
  330. volatile uint8_t * const pucFirstUserPriorityRegister = ( volatile uint8_t * const ) ( portNVIC_IP_REGISTERS_OFFSET_16 + portFIRST_USER_INTERRUPT_NUMBER );
  331. volatile uint8_t ucMaxPriorityValue;
  332. /* Determine the maximum priority from which ISR safe FreeRTOS API
  333. * functions can be called. ISR safe functions are those that end in
  334. * "FromISR". FreeRTOS maintains separate thread and ISR API functions
  335. * to ensure interrupt entry is as fast and simple as possible.
  336. *
  337. * Save the interrupt priority value that is about to be clobbered. */
  338. ulOriginalPriority = *pucFirstUserPriorityRegister;
  339. /* Determine the number of priority bits available. First write to all
  340. * possible bits. */
  341. *pucFirstUserPriorityRegister = portMAX_8_BIT_VALUE;
  342. /* Read the value back to see how many bits stuck. */
  343. ucMaxPriorityValue = *pucFirstUserPriorityRegister;
  344. /* Use the same mask on the maximum system call priority. */
  345. ucMaxSysCallPriority = configMAX_SYSCALL_INTERRUPT_PRIORITY & ucMaxPriorityValue;
  346. /* Calculate the maximum acceptable priority group value for the number
  347. * of bits read back. */
  348. ulMaxPRIGROUPValue = portMAX_PRIGROUP_BITS;
  349. while( ( ucMaxPriorityValue & portTOP_BIT_OF_BYTE ) == portTOP_BIT_OF_BYTE )
  350. {
  351. ulMaxPRIGROUPValue--;
  352. ucMaxPriorityValue <<= ( uint8_t ) 0x01;
  353. }
  354. #ifdef __NVIC_PRIO_BITS
  355. {
  356. /* Check the CMSIS configuration that defines the number of
  357. * priority bits matches the number of priority bits actually queried
  358. * from the hardware. */
  359. configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == __NVIC_PRIO_BITS );
  360. }
  361. #endif
  362. #ifdef configPRIO_BITS
  363. {
  364. /* Check the FreeRTOS configuration that defines the number of
  365. * priority bits matches the number of priority bits actually queried
  366. * from the hardware. */
  367. configASSERT( ( portMAX_PRIGROUP_BITS - ulMaxPRIGROUPValue ) == configPRIO_BITS );
  368. }
  369. #endif
  370. /* Shift the priority group value back to its position within the AIRCR
  371. * register. */
  372. ulMaxPRIGROUPValue <<= portPRIGROUP_SHIFT;
  373. ulMaxPRIGROUPValue &= portPRIORITY_GROUP_MASK;
  374. /* Restore the clobbered interrupt priority register to its original
  375. * value. */
  376. *pucFirstUserPriorityRegister = ulOriginalPriority;
  377. }
  378. #endif /* conifgASSERT_DEFINED */
  379. /* Make PendSV and SysTick the same priority as the kernel, and the SVC
  380. * handler higher priority so it can be used to exit a critical section (where
  381. * lower priorities are masked). */
  382. portNVIC_SHPR3_REG |= portNVIC_PENDSV_PRI;
  383. portNVIC_SHPR3_REG |= portNVIC_SYSTICK_PRI;
  384. /* Configure the regions in the MPU that are common to all tasks. */
  385. prvSetupMPU();
  386. /* Start the timer that generates the tick ISR. Interrupts are disabled
  387. * here already. */
  388. vPortSetupTimerInterrupt();
  389. /* Initialise the critical nesting count ready for the first task. */
  390. uxCriticalNesting = 0;
  391. /* Start the first task. */
  392. __asm volatile (
  393. " ldr r0, =0xE000ED08 \n"/* Use the NVIC offset register to locate the stack. */
  394. " ldr r0, [r0] \n"
  395. " ldr r0, [r0] \n"
  396. " msr msp, r0 \n"/* Set the msp back to the start of the stack. */
  397. " cpsie i \n"/* Globally enable interrupts. */
  398. " cpsie f \n"
  399. " dsb \n"
  400. " isb \n"
  401. " svc %0 \n"/* System call to start first task. */
  402. " nop \n"
  403. " .ltorg \n"
  404. ::"i" ( portSVC_START_SCHEDULER ) : "memory" );
  405. /* Should not get here! */
  406. return 0;
  407. }
  408. /*-----------------------------------------------------------*/
  409. void vPortEndScheduler( void )
  410. {
  411. /* Not implemented in ports where there is nothing to return to.
  412. * Artificially force an assert. */
  413. configASSERT( uxCriticalNesting == 1000UL );
  414. }
  415. /*-----------------------------------------------------------*/
  416. void vPortEnterCritical( void )
  417. {
  418. BaseType_t xRunningPrivileged;
  419. xPortRaisePrivilege( xRunningPrivileged );
  420. portDISABLE_INTERRUPTS();
  421. uxCriticalNesting++;
  422. vPortResetPrivilege( xRunningPrivileged );
  423. }
  424. /*-----------------------------------------------------------*/
  425. void vPortExitCritical( void )
  426. {
  427. BaseType_t xRunningPrivileged;
  428. xPortRaisePrivilege( xRunningPrivileged );
  429. configASSERT( uxCriticalNesting );
  430. uxCriticalNesting--;
  431. if( uxCriticalNesting == 0 )
  432. {
  433. portENABLE_INTERRUPTS();
  434. }
  435. vPortResetPrivilege( xRunningPrivileged );
  436. }
  437. /*-----------------------------------------------------------*/
  438. void xPortPendSVHandler( void )
  439. {
  440. /* This is a naked function. */
  441. __asm volatile
  442. (
  443. " mrs r0, psp \n"
  444. " \n"
  445. " ldr r3, pxCurrentTCBConst \n"/* Get the location of the current TCB. */
  446. " ldr r2, [r3] \n"
  447. " \n"
  448. " mrs r1, control \n"
  449. " stmdb r0!, {r1, r4-r11} \n"/* Save the remaining registers. */
  450. " str r0, [r2] \n"/* Save the new top of stack into the first member of the TCB. */
  451. " \n"
  452. " stmdb sp!, {r3, r14} \n"
  453. " mov r0, %0 \n"
  454. " msr basepri, r0 \n"
  455. " dsb \n"
  456. " isb \n"
  457. " bl vTaskSwitchContext \n"
  458. " mov r0, #0 \n"
  459. " msr basepri, r0 \n"
  460. " ldmia sp!, {r3, r14} \n"
  461. " \n"/* Restore the context. */
  462. " ldr r1, [r3] \n"
  463. " ldr r0, [r1] \n"/* The first item in the TCB is the task top of stack. */
  464. " add r1, r1, #4 \n"/* Move onto the second item in the TCB... */
  465. " \n"
  466. " dmb \n"/* Complete outstanding transfers before disabling MPU. */
  467. " ldr r2, =0xe000ed94 \n"/* MPU_CTRL register. */
  468. " ldr r3, [r2] \n"/* Read the value of MPU_CTRL. */
  469. " bic r3, #1 \n"/* r3 = r3 & ~1 i.e. Clear the bit 0 in r3. */
  470. " str r3, [r2] \n"/* Disable MPU. */
  471. " \n"
  472. " ldr r2, =0xe000ed9c \n"/* Region Base Address register. */
  473. " ldmia r1!, {r4-r11} \n"/* Read 4 sets of MPU registers. */
  474. " stmia r2!, {r4-r11} \n"/* Write 4 sets of MPU registers. */
  475. " \n"
  476. " ldr r2, =0xe000ed94 \n"/* MPU_CTRL register. */
  477. " ldr r3, [r2] \n"/* Read the value of MPU_CTRL. */
  478. " orr r3, #1 \n"/* r3 = r3 | 1 i.e. Set the bit 0 in r3. */
  479. " str r3, [r2] \n"/* Enable MPU. */
  480. " dsb \n"/* Force memory writes before continuing. */
  481. " \n"
  482. " ldmia r0!, {r3, r4-r11} \n"/* Pop the registers that are not automatically saved on exception entry. */
  483. " msr control, r3 \n"
  484. " \n"
  485. " msr psp, r0 \n"
  486. " bx r14 \n"
  487. " \n"
  488. " .align 4 \n"
  489. "pxCurrentTCBConst: .word pxCurrentTCB \n"
  490. ::"i" ( configMAX_SYSCALL_INTERRUPT_PRIORITY )
  491. );
  492. }
  493. /*-----------------------------------------------------------*/
  494. void xPortSysTickHandler( void )
  495. {
  496. uint32_t ulDummy;
  497. ulDummy = portSET_INTERRUPT_MASK_FROM_ISR();
  498. {
  499. /* Increment the RTOS tick. */
  500. if( xTaskIncrementTick() != pdFALSE )
  501. {
  502. /* Pend a context switch. */
  503. portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
  504. }
  505. }
  506. portCLEAR_INTERRUPT_MASK_FROM_ISR( ulDummy );
  507. }
  508. /*-----------------------------------------------------------*/
  509. /*
  510. * Setup the systick timer to generate the tick interrupts at the required
  511. * frequency.
  512. */
  513. __attribute__( ( weak ) ) void vPortSetupTimerInterrupt( void )
  514. {
  515. /* Stop and clear the SysTick. */
  516. portNVIC_SYSTICK_CTRL_REG = 0UL;
  517. portNVIC_SYSTICK_CURRENT_VALUE_REG = 0UL;
  518. /* Configure SysTick to interrupt at the requested rate. */
  519. portNVIC_SYSTICK_LOAD_REG = ( configSYSTICK_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL;
  520. portNVIC_SYSTICK_CTRL_REG = ( portNVIC_SYSTICK_CLK | portNVIC_SYSTICK_INT | portNVIC_SYSTICK_ENABLE );
  521. }
  522. /*-----------------------------------------------------------*/
  523. static void prvSetupMPU( void )
  524. {
  525. extern uint32_t __privileged_functions_start__[];
  526. extern uint32_t __privileged_functions_end__[];
  527. extern uint32_t __FLASH_segment_start__[];
  528. extern uint32_t __FLASH_segment_end__[];
  529. extern uint32_t __privileged_data_start__[];
  530. extern uint32_t __privileged_data_end__[];
  531. /* Check the expected MPU is present. */
  532. if( portMPU_TYPE_REG == portEXPECTED_MPU_TYPE_VALUE )
  533. {
  534. /* First setup the unprivileged flash for unprivileged read only access. */
  535. portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __FLASH_segment_start__ ) | /* Base address. */
  536. ( portMPU_REGION_VALID ) |
  537. ( portUNPRIVILEGED_FLASH_REGION );
  538. portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_ONLY ) |
  539. ( portMPU_REGION_CACHEABLE_BUFFERABLE ) |
  540. ( prvGetMPURegionSizeSetting( ( uint32_t ) __FLASH_segment_end__ - ( uint32_t ) __FLASH_segment_start__ ) ) |
  541. ( portMPU_REGION_ENABLE );
  542. /* Setup the privileged flash for privileged only access. This is where
  543. * the kernel code is * placed. */
  544. portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_functions_start__ ) | /* Base address. */
  545. ( portMPU_REGION_VALID ) |
  546. ( portPRIVILEGED_FLASH_REGION );
  547. portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_ONLY ) |
  548. ( portMPU_REGION_CACHEABLE_BUFFERABLE ) |
  549. ( prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_functions_end__ - ( uint32_t ) __privileged_functions_start__ ) ) |
  550. ( portMPU_REGION_ENABLE );
  551. /* Setup the privileged data RAM region. This is where the kernel data
  552. * is placed. */
  553. portMPU_REGION_BASE_ADDRESS_REG = ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
  554. ( portMPU_REGION_VALID ) |
  555. ( portPRIVILEGED_RAM_REGION );
  556. portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |
  557. ( portMPU_REGION_CACHEABLE_BUFFERABLE ) |
  558. prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |
  559. ( portMPU_REGION_ENABLE );
  560. /* By default allow everything to access the general peripherals. The
  561. * system peripherals and registers are protected. */
  562. portMPU_REGION_BASE_ADDRESS_REG = ( portPERIPHERALS_START_ADDRESS ) |
  563. ( portMPU_REGION_VALID ) |
  564. ( portGENERAL_PERIPHERALS_REGION );
  565. portMPU_REGION_ATTRIBUTE_REG = ( portMPU_REGION_READ_WRITE | portMPU_REGION_EXECUTE_NEVER ) |
  566. ( prvGetMPURegionSizeSetting( portPERIPHERALS_END_ADDRESS - portPERIPHERALS_START_ADDRESS ) ) |
  567. ( portMPU_REGION_ENABLE );
  568. /* Enable the memory fault exception. */
  569. portNVIC_SYS_CTRL_STATE_REG |= portNVIC_MEM_FAULT_ENABLE;
  570. /* Enable the MPU with the background region configured. */
  571. portMPU_CTRL_REG |= ( portMPU_ENABLE | portMPU_BACKGROUND_ENABLE );
  572. }
  573. }
  574. /*-----------------------------------------------------------*/
  575. static uint32_t prvGetMPURegionSizeSetting( uint32_t ulActualSizeInBytes )
  576. {
  577. uint32_t ulRegionSize, ulReturnValue = 4;
  578. /* 32 is the smallest region size, 31 is the largest valid value for
  579. * ulReturnValue. */
  580. for( ulRegionSize = 32UL; ulReturnValue < 31UL; ( ulRegionSize <<= 1UL ) )
  581. {
  582. if( ulActualSizeInBytes <= ulRegionSize )
  583. {
  584. break;
  585. }
  586. else
  587. {
  588. ulReturnValue++;
  589. }
  590. }
  591. /* Shift the code by one before returning so it can be written directly
  592. * into the the correct bit position of the attribute register. */
  593. return( ulReturnValue << 1UL );
  594. }
  595. /*-----------------------------------------------------------*/
  596. BaseType_t xIsPrivileged( void ) /* __attribute__ (( naked )) */
  597. {
  598. __asm volatile
  599. (
  600. " mrs r0, control \n"/* r0 = CONTROL. */
  601. " tst r0, #1 \n"/* Perform r0 & 1 (bitwise AND) and update the conditions flag. */
  602. " ite ne \n"
  603. " movne r0, #0 \n"/* CONTROL[0]!=0. Return false to indicate that the processor is not privileged. */
  604. " moveq r0, #1 \n"/* CONTROL[0]==0. Return true to indicate that the processor is privileged. */
  605. " bx lr \n"/* Return. */
  606. " \n"
  607. " .align 4 \n"
  608. ::: "r0", "memory"
  609. );
  610. }
  611. /*-----------------------------------------------------------*/
  612. void vResetPrivilege( void ) /* __attribute__ (( naked )) */
  613. {
  614. __asm volatile
  615. (
  616. " mrs r0, control \n"/* r0 = CONTROL. */
  617. " orr r0, #1 \n"/* r0 = r0 | 1. */
  618. " msr control, r0 \n"/* CONTROL = r0. */
  619. " bx lr \n"/* Return to the caller. */
  620. ::: "r0", "memory"
  621. );
  622. }
  623. /*-----------------------------------------------------------*/
  624. void vPortStoreTaskMPUSettings( xMPU_SETTINGS * xMPUSettings,
  625. const struct xMEMORY_REGION * const xRegions,
  626. StackType_t * pxBottomOfStack,
  627. uint32_t ulStackDepth )
  628. {
  629. extern uint32_t __SRAM_segment_start__[];
  630. extern uint32_t __SRAM_segment_end__[];
  631. extern uint32_t __privileged_data_start__[];
  632. extern uint32_t __privileged_data_end__[];
  633. int32_t lIndex;
  634. uint32_t ul;
  635. if( xRegions == NULL )
  636. {
  637. /* No MPU regions are specified so allow access to all RAM. */
  638. xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =
  639. ( ( uint32_t ) __SRAM_segment_start__ ) | /* Base address. */
  640. ( portMPU_REGION_VALID ) |
  641. ( portSTACK_REGION );
  642. xMPUSettings->xRegion[ 0 ].ulRegionAttribute =
  643. ( portMPU_REGION_READ_WRITE ) |
  644. ( portMPU_REGION_CACHEABLE_BUFFERABLE ) |
  645. ( prvGetMPURegionSizeSetting( ( uint32_t ) __SRAM_segment_end__ - ( uint32_t ) __SRAM_segment_start__ ) ) |
  646. ( portMPU_REGION_ENABLE );
  647. /* Re-instate the privileged only RAM region as xRegion[ 0 ] will have
  648. * just removed the privileged only parameters. */
  649. xMPUSettings->xRegion[ 1 ].ulRegionBaseAddress =
  650. ( ( uint32_t ) __privileged_data_start__ ) | /* Base address. */
  651. ( portMPU_REGION_VALID ) |
  652. ( portSTACK_REGION + 1 );
  653. xMPUSettings->xRegion[ 1 ].ulRegionAttribute =
  654. ( portMPU_REGION_PRIVILEGED_READ_WRITE ) |
  655. ( portMPU_REGION_CACHEABLE_BUFFERABLE ) |
  656. prvGetMPURegionSizeSetting( ( uint32_t ) __privileged_data_end__ - ( uint32_t ) __privileged_data_start__ ) |
  657. ( portMPU_REGION_ENABLE );
  658. /* Invalidate all other regions. */
  659. for( ul = 2; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
  660. {
  661. xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( portSTACK_REGION + ul ) | portMPU_REGION_VALID;
  662. xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;
  663. }
  664. }
  665. else
  666. {
  667. /* This function is called automatically when the task is created - in
  668. * which case the stack region parameters will be valid. At all other
  669. * times the stack parameters will not be valid and it is assumed that the
  670. * stack region has already been configured. */
  671. if( ulStackDepth > 0 )
  672. {
  673. /* Define the region that allows access to the stack. */
  674. xMPUSettings->xRegion[ 0 ].ulRegionBaseAddress =
  675. ( ( uint32_t ) pxBottomOfStack ) |
  676. ( portMPU_REGION_VALID ) |
  677. ( portSTACK_REGION ); /* Region number. */
  678. xMPUSettings->xRegion[ 0 ].ulRegionAttribute =
  679. ( portMPU_REGION_READ_WRITE ) | /* Read and write. */
  680. ( prvGetMPURegionSizeSetting( ulStackDepth * ( uint32_t ) sizeof( StackType_t ) ) ) |
  681. ( portMPU_REGION_CACHEABLE_BUFFERABLE ) |
  682. ( portMPU_REGION_ENABLE );
  683. }
  684. lIndex = 0;
  685. for( ul = 1; ul <= portNUM_CONFIGURABLE_REGIONS; ul++ )
  686. {
  687. if( ( xRegions[ lIndex ] ).ulLengthInBytes > 0UL )
  688. {
  689. /* Translate the generic region definition contained in
  690. * xRegions into the CM3 specific MPU settings that are then
  691. * stored in xMPUSettings. */
  692. xMPUSettings->xRegion[ ul ].ulRegionBaseAddress =
  693. ( ( uint32_t ) xRegions[ lIndex ].pvBaseAddress ) |
  694. ( portMPU_REGION_VALID ) |
  695. ( portSTACK_REGION + ul ); /* Region number. */
  696. xMPUSettings->xRegion[ ul ].ulRegionAttribute =
  697. ( prvGetMPURegionSizeSetting( xRegions[ lIndex ].ulLengthInBytes ) ) |
  698. ( xRegions[ lIndex ].ulParameters ) |
  699. ( portMPU_REGION_ENABLE );
  700. }
  701. else
  702. {
  703. /* Invalidate the region. */
  704. xMPUSettings->xRegion[ ul ].ulRegionBaseAddress = ( portSTACK_REGION + ul ) | portMPU_REGION_VALID;
  705. xMPUSettings->xRegion[ ul ].ulRegionAttribute = 0UL;
  706. }
  707. lIndex++;
  708. }
  709. }
  710. }
  711. /*-----------------------------------------------------------*/
  712. #if ( configASSERT_DEFINED == 1 )
  713. void vPortValidateInterruptPriority( void )
  714. {
  715. uint32_t ulCurrentInterrupt;
  716. uint8_t ucCurrentPriority;
  717. /* Obtain the number of the currently executing interrupt. */
  718. __asm volatile ( "mrs %0, ipsr" : "=r" ( ulCurrentInterrupt )::"memory" );
  719. /* Is the interrupt number a user defined interrupt? */
  720. if( ulCurrentInterrupt >= portFIRST_USER_INTERRUPT_NUMBER )
  721. {
  722. /* Look up the interrupt's priority. */
  723. ucCurrentPriority = pcInterruptPriorityRegisters[ ulCurrentInterrupt ];
  724. /* The following assertion will fail if a service routine (ISR) for
  725. * an interrupt that has been assigned a priority above
  726. * configMAX_SYSCALL_INTERRUPT_PRIORITY calls an ISR safe FreeRTOS API
  727. * function. ISR safe FreeRTOS API functions must *only* be called
  728. * from interrupts that have been assigned a priority at or below
  729. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
  730. *
  731. * Numerically low interrupt priority numbers represent logically high
  732. * interrupt priorities, therefore the priority of the interrupt must
  733. * be set to a value equal to or numerically *higher* than
  734. * configMAX_SYSCALL_INTERRUPT_PRIORITY.
  735. *
  736. * Interrupts that use the FreeRTOS API must not be left at their
  737. * default priority of zero as that is the highest possible priority,
  738. * which is guaranteed to be above configMAX_SYSCALL_INTERRUPT_PRIORITY,
  739. * and therefore also guaranteed to be invalid.
  740. *
  741. * FreeRTOS maintains separate thread and ISR API functions to ensure
  742. * interrupt entry is as fast and simple as possible.
  743. *
  744. * The following links provide detailed information:
  745. * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html
  746. * https://www.FreeRTOS.org/FAQHelp.html */
  747. configASSERT( ucCurrentPriority >= ucMaxSysCallPriority );
  748. }
  749. /* Priority grouping: The interrupt controller (NVIC) allows the bits
  750. * that define each interrupt's priority to be split between bits that
  751. * define the interrupt's pre-emption priority bits and bits that define
  752. * the interrupt's sub-priority. For simplicity all bits must be defined
  753. * to be pre-emption priority bits. The following assertion will fail if
  754. * this is not the case (if some bits represent a sub-priority).
  755. *
  756. * If the application only uses CMSIS libraries for interrupt
  757. * configuration then the correct setting can be achieved on all Cortex-M
  758. * devices by calling NVIC_SetPriorityGrouping( 0 ); before starting the
  759. * scheduler. Note however that some vendor specific peripheral libraries
  760. * assume a non-zero priority group setting, in which cases using a value
  761. * of zero will result in unpredicable behaviour. */
  762. configASSERT( ( portAIRCR_REG & portPRIORITY_GROUP_MASK ) <= ulMaxPRIGROUPValue );
  763. }
  764. #endif /* configASSERT_DEFINED */
  765. /*-----------------------------------------------------------*/