/* | |
* 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 ); | |
} | |