/*
* FreeRTOS Kernel V10 .3 .1
* Copyright ( C ) 2020 Amazon . com , Inc . or its affiliates . All Rights Reserved .
*
* Permission is hereby granted , free of charge , to any person obtaining a copy of
* this software and associated documentation files ( the " Software " ) , to deal in
* the Software without restriction , including without limitation the rights to
* use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies of
* the Software , and to permit persons to whom the Software is furnished to do so ,
* subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY , FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER
* IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*
* http : //www.FreeRTOS.org
* http : //aws.amazon.com/freertos
*
* 1 tab = = 4 spaces !
*/
/* Standard includes. */
# include <limits.h>
/* Scheduler includes. */
# include "FreeRTOS.h"
# include "task.h"
# if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 1 )
/* Check the configuration. */
# if( configMAX_PRIORITIES > 32 )
# 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.
# endif
# endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
# if( configISR_STACK_SIZE < ( configMINIMAL_STACK_SIZE * 2 ) )
# warning configISR_STACK_SIZE is probably too small!
# endif /* ( configISR_STACK_SIZE < configMINIMAL_STACK_SIZE * 2 ) */
# if( ( configMAX_API_CALL_INTERRUPT_PRIORITY > portMAX_PRIORITY ) || ( configMAX_API_CALL_INTERRUPT_PRIORITY < 2 ) )
# error configMAX_API_CALL_INTERRUPT_PRIORITY must be between 2 and 15
# endif
# if( ( configSUPPORT_FPU == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 0 ) )
# error configSUPPORT_DYNAMIC_ALLOCATION must be set to 1 to use this port with an FPU
# endif
/* A critical section is exited when the critical section nesting count reaches
this value . */
# define portNO_CRITICAL_NESTING ( ( uint32_t ) 0 )
/* Tasks are not created with a floating point context, but can be given a
floating point context after they have been created . A variable is stored as
part of the tasks context that holds portNO_FLOATING_POINT_CONTEXT if the task
does not have an FPU context , or any other value if the task does have an FPU
context . */
# define portNO_FLOATING_POINT_CONTEXT ( ( StackType_t ) 0 )
/* Only the IF bit is set so tasks start with interrupts enabled. */
# define portINITIAL_EFLAGS ( 0x200UL )
/* Error interrupts are at the highest priority vectors. */
# define portAPIC_LVT_ERROR_VECTOR ( 0xfe )
# define portAPIC_SPURIOUS_INT_VECTOR ( 0xff )
/* EFLAGS bits. */
# define portEFLAGS_IF ( 0x200UL )
/* FPU context size if FSAVE is used. */
# define portFPU_CONTEXT_SIZE_BYTES 108
/* The expected size of each entry in the IDT. Used to check structure packing
is set correctly . */
# define portEXPECTED_IDT_ENTRY_SIZE 8
/* Default flags setting for entries in the IDT. */
# define portIDT_FLAGS ( 0x8E )
/* This is the lowest possible ISR vector available to application code. */
# define portAPIC_MIN_ALLOWABLE_VECTOR ( 0x20 )
/* If configASSERT() is defined then the system stack is filled with this value
to allow for a crude stack overflow check . */
# define portSTACK_WORD ( 0xecececec )
/*-----------------------------------------------------------*/
/*
* Starts the first task executing .
*/
extern void vPortStartFirstTask ( void ) ;
/*
* Used to catch tasks that attempt to return from their implementing function .
*/
static void prvTaskExitError ( void ) ;
/*
* Complete one descriptor in the IDT .
*/
static void prvSetInterruptGate ( uint8_t ucNumber , ISR_Handler_t pxHandlerFunction , uint8_t ucFlags ) ;
/*
* The default handler installed in each IDT position .
*/
extern void vPortCentralInterruptWrapper ( void ) ;
/*
* Handler for portYIELD ( ) .
*/
extern void vPortYieldCall ( void ) ;
/*
* Configure the APIC to generate the RTOS tick .
*/
static void prvSetupTimerInterrupt ( void ) ;
/*
* Tick interrupt handler .
*/
extern void vPortTimerHandler ( void ) ;
/*
* Check an interrupt vector is not too high , too low , in use by FreeRTOS , or
* already in use by the application .
*/
static BaseType_t prvCheckValidityOfVectorNumber ( uint32_t ulVectorNumber ) ;
/*-----------------------------------------------------------*/
/* A variable is used to keep track of the critical section nesting. This
variable must be initialised to a non zero value to ensure interrupts don ' t
inadvertently become unmasked before the scheduler starts . It is set to zero
before the first task starts executing . */
volatile uint32_t ulCriticalNesting = 9999UL ;
/* A structure used to map the various fields of an IDT entry into separate
structure members . */
struct IDTEntry
{
uint16_t usISRLow ; /* Low 16 bits of handler address. */
uint16_t usSegmentSelector ; /* Flat model means this is not changed. */
uint8_t ucZero ; /* Must be set to zero. */
uint8_t ucFlags ; /* Flags for this entry. */
uint16_t usISRHigh ; /* High 16 bits of handler address. */
} __attribute__ ( ( packed ) ) ;
typedef struct IDTEntry IDTEntry_t ;
/* Use to pass the location of the IDT to the CPU. */
struct IDTPointer
{
uint16_t usTableLimit ;
uint32_t ulTableBase ; /* The address of the first entry in xInterruptDescriptorTable. */
} __attribute__ ( ( __packed__ ) ) ;
typedef struct IDTPointer IDTPointer_t ;
/* The IDT itself. */
static __attribute__ ( ( aligned ( 32 ) ) ) IDTEntry_t xInterruptDescriptorTable [ portNUM_VECTORS ] ;
# if ( configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 )
/* A table in which application defined interrupt handlers are stored. These
are called by the central interrupt handler if a common interrupt entry
point it used . */
static ISR_Handler_t xInterruptHandlerTable [ portNUM_VECTORS ] = { NULL } ;
# endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
# if ( configSUPPORT_FPU == 1 )
/* Saved as part of the task context. If pucPortTaskFPUContextBuffer is NULL
then the task does not have an FPU context . If pucPortTaskFPUContextBuffer is
not NULL then it points to a buffer into which the FPU context can be saved . */
uint8_t * pucPortTaskFPUContextBuffer __attribute__ ( ( used ) ) = pdFALSE ;
# endif /* configSUPPORT_FPU */
/* The stack used by interrupt handlers. */
static uint32_t ulSystemStack [ configISR_STACK_SIZE ] __attribute__ ( ( used ) ) = { 0 } ;
/* Don't use the very top of the system stack so the return address
appears as 0 if the debugger tries to unwind the stack . */
volatile uint32_t ulTopOfSystemStack __attribute__ ( ( used ) ) = ( uint32_t ) & ( ulSystemStack [ configISR_STACK_SIZE - 5 ] ) ;
/* If a yield is requested from an interrupt or from a critical section then
the yield is not performed immediately , and ulPortYieldPending is set to pdTRUE
instead to indicate the yield should be performed at the end of the interrupt
when the critical section is exited . */
volatile uint32_t ulPortYieldPending __attribute__ ( ( used ) ) = pdFALSE ;
/* Counts the interrupt nesting depth. Used to know when to switch to the
interrupt / system stack and when to save / restore a complete context . */
volatile uint32_t ulInterruptNesting __attribute__ ( ( used ) ) = 0 ;
/*-----------------------------------------------------------*/
/*
* See header file for description .
*/
StackType_t * pxPortInitialiseStack ( StackType_t * pxTopOfStack , TaskFunction_t pxCode , void * pvParameters )
{
uint32_t ulCodeSegment ;
/* Setup the initial stack as expected by the portFREERTOS_INTERRUPT_EXIT macro. */
* pxTopOfStack = 0x00 ;
pxTopOfStack - - ;
* pxTopOfStack = 0x00 ;
pxTopOfStack - - ;
/* Parameters first. */
* pxTopOfStack = ( StackType_t ) pvParameters ;
pxTopOfStack - - ;
/* There is nothing to return to so assert if attempting to use the return
address . */
* pxTopOfStack = ( StackType_t ) prvTaskExitError ;
pxTopOfStack - - ;
/* iret used to start the task pops up to here. */
* pxTopOfStack = portINITIAL_EFLAGS ;
pxTopOfStack - - ;
/* CS */
__asm volatile ( " movl %%cs, %0 " : " =r " ( ulCodeSegment ) ) ;
* pxTopOfStack = ulCodeSegment ;
pxTopOfStack - - ;
/* First instruction in the task. */
* pxTopOfStack = ( StackType_t ) pxCode ;
pxTopOfStack - - ;
/* General purpose registers as expected by a POPA instruction. */
* pxTopOfStack = 0xEA ;
pxTopOfStack - - ;
* pxTopOfStack = 0xEC ;
pxTopOfStack - - ;
* pxTopOfStack = 0xED1 ; /* EDX */
pxTopOfStack - - ;
* pxTopOfStack = 0xEB1 ; /* EBX */
pxTopOfStack - - ;
/* Hole for ESP. */
pxTopOfStack - - ;
* pxTopOfStack = 0x00 ; /* EBP */
pxTopOfStack - - ;
* pxTopOfStack = 0xE5 ; /* ESI */
pxTopOfStack - - ;
* pxTopOfStack = 0xeeeeeeee ; /* EDI */
# if ( configSUPPORT_FPU == 1 )
{
pxTopOfStack - - ;
/* Buffer for FPU context, which is initialised to NULL as tasks are not
created with an FPU context . */
* pxTopOfStack = portNO_FLOATING_POINT_CONTEXT ;
}
# endif /* configSUPPORT_FPU */
return pxTopOfStack ;
}
/*-----------------------------------------------------------*/
static void prvSetInterruptGate ( uint8_t ucNumber , ISR_Handler_t pxHandlerFunction , uint8_t ucFlags )
{
uint16_t usCodeSegment ;
uint32_t ulBase = ( uint32_t ) pxHandlerFunction ;
xInterruptDescriptorTable [ ucNumber ] . usISRLow = ( uint16_t ) ( ulBase & USHRT_MAX ) ;
xInterruptDescriptorTable [ ucNumber ] . usISRHigh = ( uint16_t ) ( ( ulBase > > 16UL ) & USHRT_MAX ) ;
/* When the flat model is used the CS will never change. */
__asm volatile ( " mov %%cs, %0 " : " =r " ( usCodeSegment ) ) ;
xInterruptDescriptorTable [ ucNumber ] . usSegmentSelector = usCodeSegment ;
xInterruptDescriptorTable [ ucNumber ] . ucZero = 0 ;
xInterruptDescriptorTable [ ucNumber ] . ucFlags = ucFlags ;
}
/*-----------------------------------------------------------*/
void vPortSetupIDT ( void )
{
uint32_t ulNum ;
IDTPointer_t xIDT ;
# if ( configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 )
{
for ( ulNum = 0 ; ulNum < portNUM_VECTORS ; ulNum + + )
{
/* If a handler has not already been installed on this vector. */
if ( ( xInterruptDescriptorTable [ ulNum ] . usISRLow = = 0x00 ) & & ( xInterruptDescriptorTable [ ulNum ] . usISRHigh = = 0x00 ) )
{
prvSetInterruptGate ( ( uint8_t ) ulNum , vPortCentralInterruptWrapper , portIDT_FLAGS ) ;
}
}
}
# endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
/* Set IDT address. */
xIDT . ulTableBase = ( uint32_t ) xInterruptDescriptorTable ;
xIDT . usTableLimit = sizeof ( xInterruptDescriptorTable ) - 1 ;
/* Set IDT in CPU. */
__asm volatile ( " lidt %0 " : : " m " ( xIDT ) ) ;
}
/*-----------------------------------------------------------*/
static void prvTaskExitError ( void )
{
/* A function that implements a task must not exit or attempt to return to
its caller as there is nothing to return to . If a task wants to exit it
should instead call vTaskDelete ( NULL ) .
Artificially force an assert ( ) to be triggered if configASSERT ( ) is
defined , then stop here so application writers can catch the error . */
configASSERT ( ulCriticalNesting = = ~ 0UL ) ;
portDISABLE_INTERRUPTS ( ) ;
for ( ; ; ) ;
}
/*-----------------------------------------------------------*/
static void prvSetupTimerInterrupt ( void )
{
extern void vPortAPICErrorHandlerWrapper ( void ) ;
extern void vPortAPICSpuriousHandler ( void ) ;
/* Initialise LAPIC to a well known state. */
portAPIC_LDR = 0xFFFFFFFF ;
portAPIC_LDR = ( ( portAPIC_LDR & 0x00FFFFFF ) | 0x00000001 ) ;
portAPIC_LVT_TIMER = portAPIC_DISABLE ;
portAPIC_LVT_PERF = portAPIC_NMI ;
portAPIC_LVT_LINT0 = portAPIC_DISABLE ;
portAPIC_LVT_LINT1 = portAPIC_DISABLE ;
portAPIC_TASK_PRIORITY = 0 ;
/* Install APIC timer ISR vector. */
prvSetInterruptGate ( ( uint8_t ) portAPIC_TIMER_INT_VECTOR , vPortTimerHandler , portIDT_FLAGS ) ;
/* Install API error handler. */
prvSetInterruptGate ( ( uint8_t ) portAPIC_LVT_ERROR_VECTOR , vPortAPICErrorHandlerWrapper , portIDT_FLAGS ) ;
/* Install Yield handler. */
prvSetInterruptGate ( ( uint8_t ) portAPIC_YIELD_INT_VECTOR , vPortYieldCall , portIDT_FLAGS ) ;
/* Install spurious interrupt vector. */
prvSetInterruptGate ( ( uint8_t ) portAPIC_SPURIOUS_INT_VECTOR , vPortAPICSpuriousHandler , portIDT_FLAGS ) ;
/* Enable the APIC, mapping the spurious interrupt at the same time. */
portAPIC_SPURIOUS_INT = portAPIC_SPURIOUS_INT_VECTOR | portAPIC_ENABLE_BIT ;
/* Set timer error vector. */
portAPIC_LVT_ERROR = portAPIC_LVT_ERROR_VECTOR ;
/* Set the interrupt frequency. */
portAPIC_TMRDIV = portAPIC_DIV_16 ;
portAPIC_TIMER_INITIAL_COUNT = ( ( configCPU_CLOCK_HZ > > 4UL ) / configTICK_RATE_HZ ) - 1UL ;
}
/*-----------------------------------------------------------*/
BaseType_t xPortStartScheduler ( void )
{
BaseType_t xWord ;
/* Some versions of GCC require the -mno-ms-bitfields command line option
for packing to work . */
configASSERT ( sizeof ( struct IDTEntry ) = = portEXPECTED_IDT_ENTRY_SIZE ) ;
/* Fill part of the system stack with a known value to help detect stack
overflow . A few zeros are left so GDB doesn ' t get confused unwinding
the stack . */
for ( xWord = 0 ; xWord < configISR_STACK_SIZE - 20 ; xWord + + )
{
ulSystemStack [ xWord ] = portSTACK_WORD ;
}
/* Initialise Interrupt Descriptor Table (IDT). */
vPortSetupIDT ( ) ;
/* Initialise LAPIC and install system handlers. */
prvSetupTimerInterrupt ( ) ;
/* Make sure the stack used by interrupts is aligned. */
ulTopOfSystemStack & = ~ portBYTE_ALIGNMENT_MASK ;
ulCriticalNesting = 0 ;
/* Enable LAPIC Counter.*/
portAPIC_LVT_TIMER = portAPIC_TIMER_PERIODIC | portAPIC_TIMER_INT_VECTOR ;
/* Sometimes needed. */
portAPIC_TMRDIV = portAPIC_DIV_16 ;
/* Should not return from the following function as the scheduler will then
be executing the tasks . */
vPortStartFirstTask ( ) ;
return 0 ;
}
/*-----------------------------------------------------------*/
void vPortEndScheduler ( void )
{
/* Not implemented in ports where there is nothing to return to.
Artificially force an assert . */
configASSERT ( ulCriticalNesting = = 1000UL ) ;
}
/*-----------------------------------------------------------*/
void vPortEnterCritical ( void )
{
if ( ulCriticalNesting = = 0 )
{
# if( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY )
{
__asm volatile ( " cli " ) ;
}
# else
{
portAPIC_TASK_PRIORITY = portMAX_API_CALL_PRIORITY ;
configASSERT ( portAPIC_TASK_PRIORITY = = portMAX_API_CALL_PRIORITY ) ;
}
# endif
}
/* Now interrupts are disabled ulCriticalNesting can be accessed
directly . Increment ulCriticalNesting to keep a count of how many times
portENTER_CRITICAL ( ) has been called . */
ulCriticalNesting + + ;
}
/*-----------------------------------------------------------*/
void vPortExitCritical ( void )
{
if ( ulCriticalNesting > portNO_CRITICAL_NESTING )
{
/* Decrement the nesting count as the critical section is being
exited . */
ulCriticalNesting - - ;
/* If the nesting level has reached zero then all interrupt
priorities must be re - enabled . */
if ( ulCriticalNesting = = portNO_CRITICAL_NESTING )
{
/* Critical nesting has reached zero so all interrupt priorities
should be unmasked . */
# if( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY )
{
__asm volatile ( " sti " ) ;
}
# else
{
portAPIC_TASK_PRIORITY = 0 ;
}
# endif
/* If a yield was pended from within the critical section then
perform the yield now . */
if ( ulPortYieldPending ! = pdFALSE )
{
ulPortYieldPending = pdFALSE ;
__asm volatile ( portYIELD_INTERRUPT ) ;
}
}
}
}
/*-----------------------------------------------------------*/
uint32_t ulPortSetInterruptMask ( void )
{
volatile uint32_t ulOriginalMask ;
/* Set mask to max syscall priority. */
# if( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY )
{
/* Return whether interrupts were already enabled or not. Pop adjusts
the stack first . */
__asm volatile ( " pushf \t \n "
" pop %0 \t \n "
" cli "
: " =rm " ( ulOriginalMask ) : : " memory " ) ;
ulOriginalMask & = portEFLAGS_IF ;
}
# else
{
/* Return original mask. */
ulOriginalMask = portAPIC_TASK_PRIORITY ;
portAPIC_TASK_PRIORITY = portMAX_API_CALL_PRIORITY ;
configASSERT ( portAPIC_TASK_PRIORITY = = portMAX_API_CALL_PRIORITY ) ;
}
# endif
return ulOriginalMask ;
}
/*-----------------------------------------------------------*/
void vPortClearInterruptMask ( uint32_t ulNewMaskValue )
{
# if( configMAX_API_CALL_INTERRUPT_PRIORITY == portMAX_PRIORITY )
{
if ( ulNewMaskValue ! = pdFALSE )
{
__asm volatile ( " sti " ) ;
}
}
# else
{
portAPIC_TASK_PRIORITY = ulNewMaskValue ;
configASSERT ( portAPIC_TASK_PRIORITY = = ulNewMaskValue ) ;
}
# endif
}
/*-----------------------------------------------------------*/
# if ( configSUPPORT_FPU == 1 )
void vPortTaskUsesFPU ( void )
{
/* A task is registering the fact that it needs an FPU context. Allocate a
buffer into which the context can be saved . */
pucPortTaskFPUContextBuffer = ( uint8_t * ) pvPortMalloc ( portFPU_CONTEXT_SIZE_BYTES ) ;
configASSERT ( pucPortTaskFPUContextBuffer ) ;
/* Initialise the floating point registers. */
__asm volatile ( " fninit " ) ;
}
# endif /* configSUPPORT_FPU */
/*-----------------------------------------------------------*/
void vPortAPICErrorHandler ( void )
{
/* Variable to hold the APIC error status for viewing in the debugger. */
volatile uint32_t ulErrorStatus = 0 ;
portAPIC_ERROR_STATUS = 0 ;
ulErrorStatus = portAPIC_ERROR_STATUS ;
( void ) ulErrorStatus ;
/* Force an assert. */
configASSERT ( ulCriticalNesting = = ~ 0UL ) ;
}
/*-----------------------------------------------------------*/
# if( configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 )
void vPortCentralInterruptHandler ( uint32_t ulVector )
{
if ( ulVector < portNUM_VECTORS )
{
if ( xInterruptHandlerTable [ ulVector ] ! = NULL )
{
( xInterruptHandlerTable [ ulVector ] ) ( ) ;
}
}
/* Check for a system stack overflow. */
configASSERT ( ulSystemStack [ 10 ] = = portSTACK_WORD ) ;
configASSERT ( ulSystemStack [ 12 ] = = portSTACK_WORD ) ;
configASSERT ( ulSystemStack [ 14 ] = = portSTACK_WORD ) ;
}
# endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
/*-----------------------------------------------------------*/
# if ( configUSE_COMMON_INTERRUPT_ENTRY_POINT == 1 )
BaseType_t xPortRegisterCInterruptHandler ( ISR_Handler_t pxHandler , uint32_t ulVectorNumber )
{
BaseType_t xReturn ;
xReturn = prvCheckValidityOfVectorNumber ( ulVectorNumber ) ;
if ( xReturn ! = pdFAIL )
{
/* Save the handler passed in by the application in the vector number
passed in . The addresses are then called from the central interrupt
handler . */
xInterruptHandlerTable [ ulVectorNumber ] = pxHandler ;
}
return xReturn ;
}
# endif /* configUSE_COMMON_INTERRUPT_ENTRY_POINT */
/*-----------------------------------------------------------*/
BaseType_t xPortInstallInterruptHandler ( ISR_Handler_t pxHandler , uint32_t ulVectorNumber )
{
BaseType_t xReturn ;
xReturn = prvCheckValidityOfVectorNumber ( ulVectorNumber ) ;
if ( xReturn ! = pdFAIL )
{
taskENTER_CRITICAL ( ) ;
{
/* Update the IDT to include the application defined handler. */
prvSetInterruptGate ( ( uint8_t ) ulVectorNumber , ( ISR_Handler_t ) pxHandler , portIDT_FLAGS ) ;
}
taskEXIT_CRITICAL ( ) ;
}
return xReturn ;
}
/*-----------------------------------------------------------*/
static BaseType_t prvCheckValidityOfVectorNumber ( uint32_t ulVectorNumber )
{
BaseType_t xReturn ;
/* Check validity of vector number. */
if ( ulVectorNumber > = portNUM_VECTORS )
{
/* Too high. */
xReturn = pdFAIL ;
}
else if ( ulVectorNumber < portAPIC_MIN_ALLOWABLE_VECTOR )
{
/* Too low. */
xReturn = pdFAIL ;
}
else if ( ulVectorNumber = = portAPIC_TIMER_INT_VECTOR )
{
/* In use by FreeRTOS. */
xReturn = pdFAIL ;
}
else if ( ulVectorNumber = = portAPIC_YIELD_INT_VECTOR )
{
/* In use by FreeRTOS. */
xReturn = pdFAIL ;
}
else if ( ulVectorNumber = = portAPIC_LVT_ERROR_VECTOR )
{
/* In use by FreeRTOS. */
xReturn = pdFAIL ;
}
else if ( ulVectorNumber = = portAPIC_SPURIOUS_INT_VECTOR )
{
/* In use by FreeRTOS. */
xReturn = pdFAIL ;
}
else if ( xInterruptHandlerTable [ ulVectorNumber ] ! = NULL )
{
/* Already in use by the application. */
xReturn = pdFAIL ;
}
else
{
xReturn = pdPASS ;
}
return xReturn ;
}
/*-----------------------------------------------------------*/
void vGenerateYieldInterrupt ( void )
{
__asm volatile ( portYIELD_INTERRUPT ) ;
}