123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687 |
- /*
- * FreeRTOS Kernel V10.4.6
- * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * SPDX-License-Identifier: MIT
- *
- * 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.
- *
- * https://www.FreeRTOS.org
- * https://github.com/FreeRTOS
- *
- */
- /* 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 );
- }
|