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