port.c 20 KB

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