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