source: rtems/cpukit/score/cpu/i386/cpu_asm.S @ 38b59a6

4.115
Last change on this file since 38b59a6 was 38b59a6, checked in by Sebastian Huber <sebastian.huber@…>, on 05/02/14 at 08:31:09

score: Implement forced thread migration

The current implementation of task migration in RTEMS has some
implications with respect to the interrupt latency. It is crucial to
preserve the system invariant that a task can execute on at most one
processor in the system at a time. This is accomplished with a boolean
indicator in the task context. The processor architecture specific
low-level task context switch code will mark that a task context is no
longer executing and waits that the heir context stopped execution
before it restores the heir context and resumes execution of the heir
task. So there is one point in time in which a processor is without a
task. This is essential to avoid cyclic dependencies in case multiple
tasks migrate at once. Otherwise some supervising entity is necessary to
prevent life-locks. Such a global supervisor would lead to scalability
problems so this approach is not used. Currently the thread dispatch is
performed with interrupts disabled. So in case the heir task is
currently executing on another processor then this prolongs the time of
disabled interrupts since one processor has to wait for another
processor to make progress.

It is difficult to avoid this issue with the interrupt latency since
interrupts normally store the context of the interrupted task on its
stack. In case a task is marked as not executing we must not use its
task stack to store such an interrupt context. We cannot use the heir
stack before it stopped execution on another processor. So if we enable
interrupts during this transition we have to provide an alternative task
independent stack for this time frame. This issue needs further
investigation.

  • Property mode set to 100644
File size: 9.8 KB
Line 
1/*  cpu_asm.s
2 *
3 *  This file contains all assembly code for the Intel i386 implementation
4 *  of RTEMS.
5 *
6 *  COPYRIGHT (c) 1989-1999.
7 *  On-Line Applications Research Corporation (OAR).
8 *
9 *  The license and distribution terms for this file may be
10 *  found in the file LICENSE in this distribution or at
11 *  http://www.rtems.org/license/LICENSE.
12 */
13
14#ifdef HAVE_CONFIG_H
15#include "config.h"
16#endif
17
18#include <rtems/asm.h>
19#include <rtems/score/cpu.h>
20
21#ifndef CPU_STACK_ALIGNMENT
22#error "Missing header? CPU_STACK_ALIGNMENT not defined"
23#endif
24
25/*
26 * Format of i386 Register structure
27 */
28
29.set REG_EFLAGS,  I386_CONTEXT_CONTROL_EFLAGS_OFFSET
30.set REG_ESP,     I386_CONTEXT_CONTROL_ESP_OFFSET
31.set REG_EBP,     I386_CONTEXT_CONTROL_EBP_OFFSET
32.set REG_EBX,     I386_CONTEXT_CONTROL_EBX_OFFSET
33.set REG_ESI,     I386_CONTEXT_CONTROL_ESI_OFFSET
34.set REG_EDI,     I386_CONTEXT_CONTROL_EDI_OFFSET
35
36        BEGIN_CODE
37
38/*
39 *  void _CPU_Context_switch( run_context, heir_context )
40 *
41 *  This routine performs a normal non-FP context.
42 */
43
44        .p2align  1
45        PUBLIC (_CPU_Context_switch)
46
47.set RUNCONTEXT_ARG,   4                   /* save context argument */
48.set HEIRCONTEXT_ARG,  8                   /* restore context argument */
49
50SYM (_CPU_Context_switch):
51        movl      RUNCONTEXT_ARG(esp),eax  /* eax = running threads context */
52        pushf                              /* push eflags */
53        popl      REG_EFLAGS(eax)          /* save eflags */
54        movl      esp,REG_ESP(eax)         /* save stack pointer */
55        movl      ebp,REG_EBP(eax)         /* save base pointer */
56        movl      ebx,REG_EBX(eax)         /* save ebx */
57        movl      esi,REG_ESI(eax)         /* save source register */
58        movl      edi,REG_EDI(eax)         /* save destination register */
59
60#ifdef RTEMS_SMP
61        /* Indicate that this context is no longer executing */
62        movb      $0, I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET(eax)
63#endif
64
65        movl      HEIRCONTEXT_ARG(esp),eax /* eax = heir threads context */
66
67restore:
68#ifdef RTEMS_SMP
69        /* Wait for context to stop execution if necessary */
701:
71        movb      I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET(eax), bl
72        testb     bl, bl
73        jne       1b
74
75        /* Indicate that this context is executing */
76        movb      $1, I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET(eax)
77#endif
78
79        pushl     REG_EFLAGS(eax)          /* push eflags */
80        popf                               /* restore eflags */
81        movl      REG_ESP(eax),esp         /* restore stack pointer */
82        movl      REG_EBP(eax),ebp         /* restore base pointer */
83        movl      REG_EBX(eax),ebx         /* restore ebx */
84        movl      REG_ESI(eax),esi         /* restore source register */
85        movl      REG_EDI(eax),edi         /* restore destination register */
86        ret
87
88/*
89 *  NOTE: May be unnecessary to reload some registers.
90 */
91
92/*
93 *  void _CPU_Context_restore( new_context )
94 *
95 *  This routine performs a normal non-FP context.
96 */
97
98        PUBLIC (_CPU_Context_restore)
99
100.set NEWCONTEXT_ARG,   4                   /* context to restore argument */
101
102SYM (_CPU_Context_restore):
103        movl      NEWCONTEXT_ARG(esp),eax  /* eax = running threads context */
104        jmp       restore
105
106/*void _CPU_Context_save_fp_context( &fp_context_ptr )
107 *  void _CPU_Context_restore_fp_context( &fp_context_ptr )
108 *
109 *  This section is used to context switch an i80287, i80387,
110 *  the built-in coprocessor or the i80486 or compatible.
111 */
112
113.set FPCONTEXT_ARG,   4                    /* FP context argument */
114
115#ifndef __SSE__
116        .p2align  1
117        PUBLIC (_CPU_Context_save_fp)
118SYM (_CPU_Context_save_fp):
119        movl      FPCONTEXT_ARG(esp),eax   /* eax = &ptr to FP context area */
120        movl      (eax),eax                /* eax = FP context area */
121        fsave     (eax)                    /* save FP context */
122        ret
123
124        .p2align  1
125        PUBLIC (_CPU_Context_restore_fp)
126SYM (_CPU_Context_restore_fp):
127        movl      FPCONTEXT_ARG(esp),eax   /* eax = &ptr to FP context area */
128        movl      (eax),eax                /* eax = FP context area */
129        frstor    (eax)                    /* restore FP context */
130        ret
131#endif
132
133#ifdef __SSE__
134#define SSE_OFF  16
135#endif
136
137        PUBLIC (_Exception_Handler)
138SYM (_Exception_Handler):
139        pusha                  /* Push general purpose registers    */
140        pushl   $0             /* Null pointer to SSE area          */
141        movl    esp,  ebp      /* Save original SP                  */
142#ifndef __SSE__
143        subl    $4,   esp      /* Reserve space for argument        */
144                           /* Align stack (courtesy for C/gcc)  */
145        andl    $ - CPU_STACK_ALIGNMENT, esp
146#else
147        subl    $512, esp      /* Space for SSE area                */
148                           /* Align stack (courtesy for C/gcc)  */
149        andl    $ - CPU_STACK_ALIGNMENT, esp
150/* Doing fwait here will re-throw an already pending FP exception!
151        fwait
152 */
153        fxsave  0(esp)
154        fninit                 /* Clean-slate FPU                   */
155        movl    $0x1f80, 0(ebp)
156        ldmxcsr 0(ebp)         /* Clean-slate MXCSR                 */
157        movl    esp, 0(ebp)    /* Store pointer to SSE area         */
158        subl    $SSE_OFF, esp  /* Aligned space for argument        */
159#endif
160        movl    ebp, (esp)     /* Store argument                    */
161        movl    _currentExcHandler, eax    /* Call function stored in _currentExcHandler */
162        call    * eax
163#ifdef __SSE__
164        fwait
165        fxrstor 16(esp)
166#endif
167        movl    ebp,  esp      /* Restore original SP               */
168        addl    $4,   esp      /* Skill pointer to SSE area         */
169        popa                   /* Restore general purpose registers */
170        addl    $8, esp        /* Skill vector number and faultCode */
171        iret
172
173#define DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY(_vector) \
174        .p2align 4                         ; \
175        PUBLIC (rtems_exception_prologue_ ## _vector ) ; \
176SYM (rtems_exception_prologue_ ## _vector ):             \
177        pushl   $ _vector       ; \
178        jmp   SYM (_Exception_Handler) ;
179
180#define DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY(_vector) \
181        .p2align 4                         ; \
182        PUBLIC (rtems_exception_prologue_ ## _vector ) ; \
183SYM (rtems_exception_prologue_ ## _vector ):             \
184        pushl   $ 0             ; \
185        pushl   $ _vector       ; \
186        jmp   SYM (_Exception_Handler) ;
187
188/*
189 * Divide Error
190 */
191DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (0)
192/*
193 * Debug Exception
194 */
195DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (1)
196/*
197 * NMI
198 */
199DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (2)
200/*
201 * Breakpoint
202 */
203DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (3)
204/*
205 * Overflow
206 */
207DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (4)
208/*
209 * Bound Range Exceeded
210 */
211DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (5)
212/*
213 * Invalid Opcode
214 */
215DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (6)
216/*
217 * No Math Coproc
218 */
219DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (7)
220/*
221 * Double Fault
222 */
223DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (8)
224/*
225 * Coprocessor segment overrun
226 */
227DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (9)
228/*
229 * Invalid TSS
230 */
231DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (10)
232/*
233 * Segment Not Present
234 */
235DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (11)
236/*
237 * Stack segment Fault
238 */
239DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (12)
240/*
241 * General Protection Fault
242 */
243DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (13)
244/*
245 * Page Fault
246 */
247DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (14)
248/*
249 * Floating point error (NB 15 is reserved it is therefor skipped)
250 */
251DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (16)
252/*
253 * Aligment Check
254 */
255DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (17)
256/*
257 * Machine Check
258 */
259DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (18)
260
261#ifdef __SSE__
262/*
263 * SIMD FP Exception
264 */
265DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (19)
266#endif
267
268
269/*
270 *  void *i386_Logical_to_physical(
271 *     uint16_t    segment,
272 *     void             *address
273 *  );
274 *
275 *  Returns thirty-two bit physical address for segment:address.
276 */
277
278.set SEGMENT_ARG, 4
279.set ADDRESS_ARG, 8
280
281             PUBLIC (i386_Logical_to_physical)
282
283SYM (i386_Logical_to_physical):
284
285        xorl    eax,eax                /* clear eax */
286        movzwl  SEGMENT_ARG(esp),ecx   /* ecx = segment value */
287        movl    $ SYM (_Global_descriptor_table),edx
288                                       /* edx = address of our GDT */
289        addl    ecx,edx                /* edx = address of desired entry */
290        movb    7(edx),ah              /* ah = base 31:24 */
291        movb    4(edx),al              /* al = base 23:16 */
292        shll    $16,eax                /* move ax into correct bits */
293        movw    2(edx),ax              /* ax = base 0:15 */
294        movl    ADDRESS_ARG(esp),ecx   /* ecx = address to convert */
295        addl    eax,ecx                /* ecx = physical address equivalent */
296        movl    ecx,eax                /* eax = ecx */
297        ret
298
299/*
300 *  void *i386_Physical_to_logical(
301 *     uint16_t    segment,
302 *     void             *address
303 *  );
304 *
305 *  Returns thirty-two bit physical address for segment:address.
306 */
307
308/*
309 *.set SEGMENT_ARG, 4
310 *.set ADDRESS_ARG, 8   -- use sets from above
311 */
312
313       PUBLIC (i386_Physical_to_logical)
314
315SYM (i386_Physical_to_logical):
316        xorl    eax,eax                /* clear eax */
317        movzwl  SEGMENT_ARG(esp),ecx   /* ecx = segment value */
318        movl    $ SYM (_Global_descriptor_table),edx
319                                       /* edx = address of our GDT */
320        addl    ecx,edx                /* edx = address of desired entry */
321        movb    7(edx),ah              /* ah = base 31:24 */
322        movb    4(edx),al              /* al = base 23:16 */
323        shll    $16,eax                /* move ax into correct bits */
324        movw    2(edx),ax              /* ax = base 0:15 */
325        movl    ADDRESS_ARG(esp),ecx   /* ecx = address to convert */
326        subl    eax,ecx                /* ecx = logical address equivalent */
327        movl    ecx,eax                /* eax = ecx */
328        ret
329
330END_CODE
331
332END
Note: See TracBrowser for help on using the repository browser.