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