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