port.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  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 <limits.h>
  30. /* Scheduler includes. */
  31. #include "FreeRTOS.h"
  32. #include "task.h"
  33. #if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )
  34. /* Check the configuration. */
  35. #if ( configMAX_PRIORITIES > 32 )
  36. #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.
  37. #endif
  38. #endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
  39. #if ( configISR_STACK_SIZE < ( configMINIMAL_STACK_SIZE * 2 ) )
  40. #warning configISR_STACK_SIZE is probably too small!
  41. #endif /* ( configISR_STACK_SIZE < configMINIMAL_STACK_SIZE * 2 ) */
  42. #if ( ( configMAX_API_CALL_INTERRUPT_PRIORITY > portMAX_PRIORITY ) || ( configMAX_API_CALL_INTERRUPT_PRIORITY < 2 ) )
  43. #error configMAX_API_CALL_INTERRUPT_PRIORITY must be between 2 and 15
  44. #endif
  45. #if ( ( configSUPPORT_FPU == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) )
  46. #error configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 to use this port with an FPU
  47. #endif
  48. /* A critical section is exited when the critical section nesting count reaches
  49. * this value. */
  50. #define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
  51. /* Tasks are not created with a floating point context, but can be given a
  52. * floating point context after they have been created. A variable is stored as
  53. * part of the tasks context that holds portNO_FLOATING_POINT_CONTEXT if the task
  54. * does not have an FPU context, or any other value if the task does have an FPU
  55. * context. */
  56. #define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
  57. /* Only the IF bit is set so tasks start with interrupts enabled. */
  58. #define portINITIAL_EFLAGS ( 0x200UL )
  59. /* Error interrupts are at the highest priority vectors. */
  60. #define portAPIC_LVT_ERROR_VECTOR ( 0xfe )
  61. #define portAPIC_SPURIOUS_INT_VECTOR ( 0xff )
  62. /* EFLAGS bits. */
  63. #define portEFLAGS_IF ( 0x200UL )
  64. /* FPU context size if FSAVE is used. */
  65. #define portFPU_CONTEXT_SIZE_BYTES 108
  66. /* The expected size of each entry in the IDT. Used to check structure packing
  67. * is set correctly. */
  68. #define portEXPECTED_IDT_ENTRY_SIZE 8
  69. /* Default flags setting for entries in the IDT. */
  70. #define portIDT_FLAGS ( 0x8E )
  71. /* This is the lowest possible ISR vector available to application code. */
  72. #define portAPIC_MIN_ALLOWABLE_VECTOR ( 0x20 )
  73. /* If configASSERT() is defined then the system stack is filled with this value
  74. * to allow for a crude stack overflow check. */
  75. #define portSTACK_WORD ( 0xecececec )
  76. /*-----------------------------------------------------------*/
  77. /*
  78. * Starts the first task executing.
  79. */
  80. extern void vPortStartFirstTask( void );
  81. /*
  82. * Used to catch tasks that attempt to return from their implementing function.
  83. */
  84. static void prvTaskExitError( void );
  85. /*
  86. * Complete one descriptor in the IDT.
  87. */
  88. static void prvSetInterruptGate( uint8_t ucNumber,
  89. ISR_Handler_t pxHandlerFunction,
  90. uint8_t ucFlags );
  91. /*
  92. * The default handler installed in each IDT position.
  93. */
  94. extern void vPortCentralInterruptWrapper( void );
  95. /*
  96. * Handler for portYIELD().
  97. */
  98. extern void vPortYieldCall( void );
  99. /*
  100. * Configure the APIC to generate the RTOS tick.
  101. */
  102. static void prvSetupTimerInterrupt( void );
  103. /*
  104. * Tick interrupt handler.
  105. */
  106. extern void vPortTimerHandler( void );
  107. /*
  108. * Check an interrupt vector is not too high, too low, in use by FreeRTOS, or
  109. * already in use by the application.
  110. */
  111. static BaseType_t prvCheckValidityOfVectorNumber( uint32_t ulVectorNumber );
  112. /*-----------------------------------------------------------*/
  113. /* A variable is used to keep track of the critical section nesting. This
  114. * variable must be initialised to a non zero value to ensure interrupts don't
  115. * inadvertently become unmasked before the scheduler starts. It is set to zero
  116. * before the first task starts executing. */
  117. volatile uint32_t ulCriticalNesting = 9999UL;
  118. /* A structure used to map the various fields of an IDT entry into separate
  119. * structure members. */
  120. struct IDTEntry
  121. {
  122. uint16_t usISRLow; /* Low 16 bits of handler address. */
  123. uint16_t usSegmentSelector; /* Flat model means this is not changed. */
  124. uint8_t ucZero; /* Must be set to zero. */
  125. uint8_t ucFlags; /* Flags for this entry. */
  126. uint16_t usISRHigh; /* High 16 bits of handler address. */
  127. }
  128. __attribute__( ( packed ) );
  129. typedef struct IDTEntry IDTEntry_t;
  130. /* Use to pass the location of the IDT to the CPU. */
  131. struct IDTPointer
  132. {
  133. uint16_t usTableLimit;
  134. uint32_t ulTableBase; /* The address of the first entry in xInterruptDescriptorTable. */
  135. }
  136. __attribute__( ( __packed__ ) );
  137. typedef struct IDTPointer IDTPointer_t;
  138. /* The IDT itself. */
  139. static __attribute__( ( aligned( 32 ) ) ) IDTEntry_t xInterruptDescriptorTable[ portNUM_VECTORS ];
  140. #if ( configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 )
  141. /* A table in which application defined interrupt handlers are stored. These
  142. * are called by the central interrupt handler if a common interrupt entry
  143. * point it used. */
  144. static ISR_Handler_t xInterruptHandlerTable[ portNUM_VECTORS ] = { NULL };
  145. #endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
  146. #if ( configSUPPORT_FPU == 1 )
  147. /* Saved as part of the task context. If pucPortTaskFPUContextBuffer is NULL
  148. * then the task does not have an FPU context. If pucPortTaskFPUContextBuffer is
  149. * not NULL then it points to a buffer into which the FPU context can be saved. */
  150. uint8_t * pucPortTaskFPUContextBuffer __attribute__( ( used ) ) = pdFALSE;
  151. #endif /* configSUPPORT_FPU */
  152. /* The stack used by interrupt handlers. */
  153. static uint32_t ulSystemStack[ configISR_STACK_SIZE ] __attribute__( ( used ) ) = { 0 };
  154. /* Don't use the very top of the system stack so the return address
  155. * appears as 0 if the debugger tries to unwind the stack. */
  156. volatile uint32_t ulTopOfSystemStack __attribute__( ( used ) ) = ( uint32_t ) &( ulSystemStack[ configISR_STACK_SIZE - 5 ] );
  157. /* If a yield is requested from an interrupt or from a critical section then
  158. * the yield is not performed immediately, and ulPortYieldPending is set to pdTRUE
  159. * instead to indicate the yield should be performed at the end of the interrupt
  160. * when the critical section is exited. */
  161. volatile uint32_t ulPortYieldPending __attribute__( ( used ) ) = pdFALSE;
  162. /* Counts the interrupt nesting depth. Used to know when to switch to the
  163. * interrupt/system stack and when to save/restore a complete context. */
  164. volatile uint32_t ulInterruptNesting __attribute__( ( used ) ) = 0;
  165. /*-----------------------------------------------------------*/
  166. /*
  167. * See header file for description.
  168. */
  169. StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
  170. TaskFunction_t pxCode,
  171. void * pvParameters )
  172. {
  173. uint32_t ulCodeSegment;
  174. /* Setup the initial stack as expected by the portFREERTOS_INTERRUPT_EXIT macro. */
  175. *pxTopOfStack = 0x00;
  176. pxTopOfStack--;
  177. *pxTopOfStack = 0x00;
  178. pxTopOfStack--;
  179. /* Parameters first. */
  180. *pxTopOfStack = ( StackType_t ) pvParameters;
  181. pxTopOfStack--;
  182. /* There is nothing to return to so assert if attempting to use the return
  183. * address. */
  184. *pxTopOfStack = ( StackType_t ) prvTaskExitError;
  185. pxTopOfStack--;
  186. /* iret used to start the task pops up to here. */
  187. *pxTopOfStack = portINITIAL_EFLAGS;
  188. pxTopOfStack--;
  189. /* CS */
  190. __asm volatile ( "movl %%cs, %0" : "=r" ( ulCodeSegment ) );
  191. *pxTopOfStack = ulCodeSegment;
  192. pxTopOfStack--;
  193. /* First instruction in the task. */
  194. *pxTopOfStack = ( StackType_t ) pxCode;
  195. pxTopOfStack--;
  196. /* General purpose registers as expected by a POPA instruction. */
  197. *pxTopOfStack = 0xEA;
  198. pxTopOfStack--;
  199. *pxTopOfStack = 0xEC;
  200. pxTopOfStack--;
  201. *pxTopOfStack = 0xED1; /* EDX */
  202. pxTopOfStack--;
  203. *pxTopOfStack = 0xEB1; /* EBX */
  204. pxTopOfStack--;
  205. /* Hole for ESP. */
  206. pxTopOfStack--;
  207. *pxTopOfStack = 0x00; /* EBP */
  208. pxTopOfStack--;
  209. *pxTopOfStack = 0xE5; /* ESI */
  210. pxTopOfStack--;
  211. *pxTopOfStack = 0xeeeeeeee; /* EDI */
  212. #if ( configSUPPORT_FPU == 1 )
  213. {
  214. pxTopOfStack--;
  215. /* Buffer for FPU context, which is initialised to NULL as tasks are not
  216. * created with an FPU context. */
  217. *pxTopOfStack = portNO_FLOATING_POINT_CONTEXT;
  218. }
  219. #endif /* configSUPPORT_FPU */
  220. return pxTopOfStack;
  221. }
  222. /*-----------------------------------------------------------*/
  223. static void prvSetInterruptGate( uint8_t ucNumber,
  224. ISR_Handler_t pxHandlerFunction,
  225. uint8_t ucFlags )
  226. {
  227. uint16_t usCodeSegment;
  228. uint32_t ulBase = ( uint32_t ) pxHandlerFunction;
  229. xInterruptDescriptorTable[ ucNumber ].usISRLow = ( uint16_t ) ( ulBase & USHRT_MAX );
  230. xInterruptDescriptorTable[ ucNumber ].usISRHigh = ( uint16_t ) ( ( ulBase >> 16UL ) & USHRT_MAX );
  231. /* When the flat model is used the CS will never change. */
  232. __asm volatile ( "mov %%cs, %0" : "=r" ( usCodeSegment ) );
  233. xInterruptDescriptorTable[ ucNumber ].usSegmentSelector = usCodeSegment;
  234. xInterruptDescriptorTable[ ucNumber ].ucZero = 0;
  235. xInterruptDescriptorTable[ ucNumber ].ucFlags = ucFlags;
  236. }
  237. /*-----------------------------------------------------------*/
  238. void vPortSetupIDT( void )
  239. {
  240. uint32_t ulNum;
  241. IDTPointer_t xIDT;
  242. #if ( configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 )
  243. {
  244. for( ulNum = 0; ulNum < portNUM_VECTORS; ulNum++ )
  245. {
  246. /* If a handler has not already been installed on this vector. */
  247. if( ( xInterruptDescriptorTable[ ulNum ].usISRLow == 0x00 ) && ( xInterruptDescriptorTable[ ulNum ].usISRHigh == 0x00 ) )
  248. {
  249. prvSetInterruptGate( ( uint8_t ) ulNum, vPortCentralInterruptWrapper, portIDT_FLAGS );
  250. }
  251. }
  252. }
  253. #endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
  254. /* Set IDT address. */
  255. xIDT.ulTableBase = ( uint32_t ) xInterruptDescriptorTable;
  256. xIDT.usTableLimit = sizeof( xInterruptDescriptorTable ) - 1;
  257. /* Set IDT in CPU. */
  258. __asm volatile ( "lidt %0" ::"m" ( xIDT ) );
  259. }
  260. /*-----------------------------------------------------------*/
  261. static void prvTaskExitError( void )
  262. {
  263. /* A function that implements a task must not exit or attempt to return to
  264. * its caller as there is nothing to return to. If a task wants to exit it
  265. * should instead call vTaskDelete( NULL ).
  266. *
  267. * Artificially force an assert() to be triggered if configASSERT() is
  268. * defined, then stop here so application writers can catch the error. */
  269. configASSERT( ulCriticalNesting == ~0UL );
  270. portDISABLE_INTERRUPTS();
  271. for( ; ; )
  272. {
  273. }
  274. }
  275. /*-----------------------------------------------------------*/
  276. static void prvSetupTimerInterrupt( void )
  277. {
  278. extern void vPortAPICErrorHandlerWrapper( void );
  279. extern void vPortAPICSpuriousHandler( void );
  280. /* Initialise LAPIC to a well known state. */
  281. portAPIC_LDR = 0xFFFFFFFF;
  282. portAPIC_LDR = ( ( portAPIC_LDR & 0x00FFFFFF ) | 0x00000001 );
  283. portAPIC_LVT_TIMER = portAPIC_DISABLE;
  284. portAPIC_LVT_PERF = portAPIC_NMI;
  285. portAPIC_LVT_LINT0 = portAPIC_DISABLE;
  286. portAPIC_LVT_LINT1 = portAPIC_DISABLE;
  287. portAPIC_TASK_PRIORITY = 0;
  288. /* Install APIC timer ISR vector. */
  289. prvSetInterruptGate( ( uint8_t ) portAPIC_TIMER_INT_VECTOR, vPortTimerHandler, portIDT_FLAGS );
  290. /* Install API error handler. */
  291. prvSetInterruptGate( ( uint8_t ) portAPIC_LVT_ERROR_VECTOR, vPortAPICErrorHandlerWrapper, portIDT_FLAGS );
  292. /* Install Yield handler. */
  293. prvSetInterruptGate( ( uint8_t ) portAPIC_YIELD_INT_VECTOR, vPortYieldCall, portIDT_FLAGS );
  294. /* Install spurious interrupt vector. */
  295. prvSetInterruptGate( ( uint8_t ) portAPIC_SPURIOUS_INT_VECTOR, vPortAPICSpuriousHandler, portIDT_FLAGS );
  296. /* Enable the APIC, mapping the spurious interrupt at the same time. */
  297. portAPIC_SPURIOUS_INT = portAPIC_SPURIOUS_INT_VECTOR | portAPIC_ENABLE_BIT;
  298. /* Set timer error vector. */
  299. portAPIC_LVT_ERROR = portAPIC_LVT_ERROR_VECTOR;
  300. /* Set the interrupt frequency. */
  301. portAPIC_TMRDIV = portAPIC_DIV_16;
  302. portAPIC_TIMER_INITIAL_COUNT = ( ( configCPU_CLOCK_HZ >> 4UL ) / configTICK_RATE_HZ ) - 1UL;
  303. }
  304. /*-----------------------------------------------------------*/
  305. BaseType_t xPortStartScheduler( void )
  306. {
  307. BaseType_t xWord;
  308. /* Some versions of GCC require the -mno-ms-bitfields command line option
  309. * for packing to work. */
  310. configASSERT( sizeof( struct IDTEntry ) == portEXPECTED_IDT_ENTRY_SIZE );
  311. /* Fill part of the system stack with a known value to help detect stack
  312. * overflow. A few zeros are left so GDB doesn't get confused unwinding
  313. * the stack. */
  314. for( xWord = 0; xWord < configISR_STACK_SIZE - 20; xWord++ )
  315. {
  316. ulSystemStack[ xWord ] = portSTACK_WORD;
  317. }
  318. /* Initialise Interrupt Descriptor Table (IDT). */
  319. vPortSetupIDT();
  320. /* Initialise LAPIC and install system handlers. */
  321. prvSetupTimerInterrupt();
  322. /* Make sure the stack used by interrupts is aligned. */
  323. ulTopOfSystemStack &= ~portBYTE_ALIGNMENT_MASK;
  324. ulCriticalNesting = 0;
  325. /* Enable LAPIC Counter.*/
  326. portAPIC_LVT_TIMER = portAPIC_TIMER_PERIODIC | portAPIC_TIMER_INT_VECTOR;
  327. /* Sometimes needed. */
  328. portAPIC_TMRDIV = portAPIC_DIV_16;
  329. /* Should not return from the following function as the scheduler will then
  330. * be executing the tasks. */
  331. vPortStartFirstTask();
  332. return 0;
  333. }
  334. /*-----------------------------------------------------------*/
  335. void vPortEndScheduler( void )
  336. {
  337. /* Not implemented in ports where there is nothing to return to.
  338. * Artificially force an assert. */
  339. configASSERT( ulCriticalNesting == 1000UL );
  340. }
  341. /*-----------------------------------------------------------*/
  342. void vPortEnterCritical( void )
  343. {
  344. if( ulCriticalNesting == 0 )
  345. {
  346. #if ( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY )
  347. {
  348. __asm volatile ( "cli" );
  349. }
  350. #else
  351. {
  352. portAPIC_TASK_PRIORITY = portMAX_API_CALL_PRIORITY;
  353. configASSERT( portAPIC_TASK_PRIORITY == portMAX_API_CALL_PRIORITY );
  354. }
  355. #endif
  356. }
  357. /* Now that interrupts are disabled, ulCriticalNesting can be accessed
  358. * directly. Increment ulCriticalNesting to keep a count of how many times
  359. * portENTER_CRITICAL() has been called. */
  360. ulCriticalNesting++;
  361. }
  362. /*-----------------------------------------------------------*/
  363. void vPortExitCritical( void )
  364. {
  365. if( ulCriticalNesting > portNO_CRITICAL_NESTING )
  366. {
  367. /* Decrement the nesting count as the critical section is being
  368. * exited. */
  369. ulCriticalNesting--;
  370. /* If the nesting level has reached zero then all interrupt
  371. * priorities must be re-enabled. */
  372. if( ulCriticalNesting == portNO_CRITICAL_NESTING )
  373. {
  374. /* Critical nesting has reached zero so all interrupt priorities
  375. * should be unmasked. */
  376. #if ( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY )
  377. {
  378. __asm volatile ( "sti" );
  379. }
  380. #else
  381. {
  382. portAPIC_TASK_PRIORITY = 0;
  383. }
  384. #endif
  385. /* If a yield was pended from within the critical section then
  386. * perform the yield now. */
  387. if( ulPortYieldPending != pdFALSE )
  388. {
  389. ulPortYieldPending = pdFALSE;
  390. __asm volatile ( portYIELD_INTERRUPT );
  391. }
  392. }
  393. }
  394. }
  395. /*-----------------------------------------------------------*/
  396. uint32_t ulPortSetInterruptMask( void )
  397. {
  398. volatile uint32_t ulOriginalMask;
  399. /* Set mask to max syscall priority. */
  400. #if ( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY )
  401. {
  402. /* Return whether interrupts were already enabled or not. Pop adjusts
  403. * the stack first. */
  404. __asm volatile ( "pushf \t\n"
  405. "pop %0 \t\n"
  406. "cli "
  407. : "=rm" ( ulOriginalMask )::"memory" );
  408. ulOriginalMask &= portEFLAGS_IF;
  409. }
  410. #else
  411. {
  412. /* Return original mask. */
  413. ulOriginalMask = portAPIC_TASK_PRIORITY;
  414. portAPIC_TASK_PRIORITY = portMAX_API_CALL_PRIORITY;
  415. configASSERT( portAPIC_TASK_PRIORITY == portMAX_API_CALL_PRIORITY );
  416. }
  417. #endif /* if ( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY ) */
  418. return ulOriginalMask;
  419. }
  420. /*-----------------------------------------------------------*/
  421. void vPortClearInterruptMask( uint32_t ulNewMaskValue )
  422. {
  423. #if ( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY )
  424. {
  425. if( ulNewMaskValue != pdFALSE )
  426. {
  427. __asm volatile ( "sti" );
  428. }
  429. }
  430. #else
  431. {
  432. portAPIC_TASK_PRIORITY = ulNewMaskValue;
  433. configASSERT( portAPIC_TASK_PRIORITY == ulNewMaskValue );
  434. }
  435. #endif /* if ( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY ) */
  436. }
  437. /*-----------------------------------------------------------*/
  438. #if ( configSUPPORT_FPU == 1 )
  439. void vPortTaskUsesFPU( void )
  440. {
  441. /* A task is registering the fact that it needs an FPU context. Allocate a
  442. * buffer into which the context can be saved. */
  443. pucPortTaskFPUContextBuffer = ( uint8_t * ) pvPortMalloc( portFPU_CONTEXT_SIZE_BYTES );
  444. configASSERT( pucPortTaskFPUContextBuffer );
  445. /* Initialise the floating point registers. */
  446. __asm volatile ( "fninit" );
  447. }
  448. #endif /* configSUPPORT_FPU */
  449. /*-----------------------------------------------------------*/
  450. void vPortAPICErrorHandler( void )
  451. {
  452. /* Variable to hold the APIC error status for viewing in the debugger. */
  453. volatile uint32_t ulErrorStatus = 0;
  454. portAPIC_ERROR_STATUS = 0;
  455. ulErrorStatus = portAPIC_ERROR_STATUS;
  456. ( void ) ulErrorStatus;
  457. /* Force an assert. */
  458. configASSERT( ulCriticalNesting == ~0UL );
  459. }
  460. /*-----------------------------------------------------------*/
  461. #if ( configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 )
  462. void vPortCentralInterruptHandler( uint32_t ulVector )
  463. {
  464. if( ulVector < portNUM_VECTORS )
  465. {
  466. if( xInterruptHandlerTable[ ulVector ] != NULL )
  467. {
  468. ( xInterruptHandlerTable[ ulVector ] )();
  469. }
  470. }
  471. /* Check for a system stack overflow. */
  472. configASSERT( ulSystemStack[ 10 ] == portSTACK_WORD );
  473. configASSERT( ulSystemStack[ 12 ] == portSTACK_WORD );
  474. configASSERT( ulSystemStack[ 14 ] == portSTACK_WORD );
  475. }
  476. #endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
  477. /*-----------------------------------------------------------*/
  478. #if ( configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 )
  479. BaseType_t xPortRegisterCInterruptHandler( ISR_Handler_t pxHandler,
  480. uint32_t ulVectorNumber )
  481. {
  482. BaseType_t xReturn;
  483. xReturn = prvCheckValidityOfVectorNumber( ulVectorNumber );
  484. if( xReturn != pdFAIL )
  485. {
  486. /* Save the handler passed in by the application in the vector number
  487. * passed in. The addresses are then called from the central interrupt
  488. * handler. */
  489. xInterruptHandlerTable[ ulVectorNumber ] = pxHandler;
  490. }
  491. return xReturn;
  492. }
  493. #endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
  494. /*-----------------------------------------------------------*/
  495. BaseType_t xPortInstallInterruptHandler( ISR_Handler_t pxHandler,
  496. uint32_t ulVectorNumber )
  497. {
  498. BaseType_t xReturn;
  499. xReturn = prvCheckValidityOfVectorNumber( ulVectorNumber );
  500. if( xReturn != pdFAIL )
  501. {
  502. taskENTER_CRITICAL();
  503. {
  504. /* Update the IDT to include the application defined handler. */
  505. prvSetInterruptGate( ( uint8_t ) ulVectorNumber, ( ISR_Handler_t ) pxHandler, portIDT_FLAGS );
  506. }
  507. taskEXIT_CRITICAL();
  508. }
  509. return xReturn;
  510. }
  511. /*-----------------------------------------------------------*/
  512. static BaseType_t prvCheckValidityOfVectorNumber( uint32_t ulVectorNumber )
  513. {
  514. BaseType_t xReturn;
  515. /* Check validity of vector number. */
  516. if( ulVectorNumber >= portNUM_VECTORS )
  517. {
  518. /* Too high. */
  519. xReturn = pdFAIL;
  520. }
  521. else if( ulVectorNumber < portAPIC_MIN_ALLOWABLE_VECTOR )
  522. {
  523. /* Too low. */
  524. xReturn = pdFAIL;
  525. }
  526. else if( ulVectorNumber == portAPIC_TIMER_INT_VECTOR )
  527. {
  528. /* In use by FreeRTOS. */
  529. xReturn = pdFAIL;
  530. }
  531. else if( ulVectorNumber == portAPIC_YIELD_INT_VECTOR )
  532. {
  533. /* In use by FreeRTOS. */
  534. xReturn = pdFAIL;
  535. }
  536. else if( ulVectorNumber == portAPIC_LVT_ERROR_VECTOR )
  537. {
  538. /* In use by FreeRTOS. */
  539. xReturn = pdFAIL;
  540. }
  541. else if( ulVectorNumber == portAPIC_SPURIOUS_INT_VECTOR )
  542. {
  543. /* In use by FreeRTOS. */
  544. xReturn = pdFAIL;
  545. }
  546. #if ( configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 )
  547. else if( xInterruptHandlerTable[ ulVectorNumber ] != NULL )
  548. {
  549. /* Already in use by the application. */
  550. xReturn = pdFAIL;
  551. }
  552. #endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
  553. else
  554. {
  555. xReturn = pdPASS;
  556. }
  557. return xReturn;
  558. }
  559. /*-----------------------------------------------------------*/
  560. void vGenerateYieldInterrupt( void )
  561. {
  562. __asm volatile ( portYIELD_INTERRUPT );
  563. }