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