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