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