source: rtems/cpukit/score/cpu/i386/cpu_asm.S @ 7c39cab

5
Last change on this file since 7c39cab was 7b0c74ff, checked in by Sebastian Huber <sebastian.huber@…>, on 06/09/17 at 13:42:36

i386: Support thread-local storage (TLS)

Update #2468.

  • Property mode set to 100644
File size: 11.2 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.set REG_GS_0,    I386_CONTEXT_CONTROL_GS_0_OFFSET
36.set REG_GS_1,    I386_CONTEXT_CONTROL_GS_1_OFFSET
37
38        BEGIN_CODE
39
40/*
41 *  void _CPU_Context_switch( run_context, heir_context )
42 *
43 *  This routine performs a normal non-FP context.
44 */
45
46        .p2align  1
47        PUBLIC (_CPU_Context_switch)
48
49.set RUNCONTEXT_ARG,   4                   /* save context argument */
50.set HEIRCONTEXT_ARG,  8                   /* restore context argument */
51
52SYM (_CPU_Context_switch):
53        movl      RUNCONTEXT_ARG(esp),eax  /* eax = running threads context */
54        pushf                              /* push eflags */
55        popl      REG_EFLAGS(eax)          /* save eflags */
56        movl      esp,REG_ESP(eax)         /* save stack pointer */
57        movl      ebp,REG_EBP(eax)         /* save base pointer */
58        movl      ebx,REG_EBX(eax)         /* save ebx */
59        movl      esi,REG_ESI(eax)         /* save source register */
60        movl      edi,REG_EDI(eax)         /* save destination register */
61
62#ifdef RTEMS_SMP
63        /* The executing context no longer executes on this processor */
64        movb      $0, I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET(eax)
65#endif
66
67        movl      HEIRCONTEXT_ARG(esp),eax /* eax = heir threads context */
68
69#ifdef RTEMS_SMP
70        /* Wait for heir context to stop execution */
711:
72        movb      I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET(eax), bl
73        testb     bl, bl
74        jne       1b
75
76        /* The heir context executes now on this processor */
77        movb      $1, I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET(eax)
78#endif
79
80restore:
81        pushl     REG_EFLAGS(eax)          /* push eflags */
82        popf                               /* restore eflags */
83        movl      REG_ESP(eax),esp         /* restore stack pointer */
84        movl      REG_EBP(eax),ebp         /* restore base pointer */
85        movl      REG_EBX(eax),ebx         /* restore ebx */
86        movl      REG_ESI(eax),esi         /* restore source register */
87        movl      REG_EDI(eax),edi         /* restore destination register */
88        movl      REG_GS_0(eax), ecx       /* restore gs segment */
89        movl      REG_GS_1(eax), edx
90        movl      ecx, _Global_descriptor_table + 24
91        movl      edx, _Global_descriptor_table + 28
92        movl      $24, ecx
93        mov       ecx, gs
94        ret
95
96/*
97 *  NOTE: May be unnecessary to reload some registers.
98 */
99
100/*
101 *  void _CPU_Context_restore( new_context )
102 *
103 *  This routine performs a normal non-FP context.
104 */
105
106        PUBLIC (_CPU_Context_restore)
107
108.set NEWCONTEXT_ARG,   4                   /* context to restore argument */
109
110SYM (_CPU_Context_restore):
111        movl      NEWCONTEXT_ARG(esp),eax  /* eax = running threads context */
112        jmp       restore
113
114/*void _CPU_Context_save_fp_context( &fp_context_ptr )
115 *  void _CPU_Context_restore_fp_context( &fp_context_ptr )
116 *
117 *  This section is used to context switch an i80287, i80387,
118 *  the built-in coprocessor or the i80486 or compatible.
119 */
120
121.set FPCONTEXT_ARG,   4                    /* FP context argument */
122
123#ifndef __SSE__
124        .p2align  1
125        PUBLIC (_CPU_Context_save_fp)
126SYM (_CPU_Context_save_fp):
127        movl      FPCONTEXT_ARG(esp),eax   /* eax = &ptr to FP context area */
128        movl      (eax),eax                /* eax = FP context area */
129        fsave     (eax)                    /* save FP context */
130        ret
131
132        .p2align  1
133        PUBLIC (_CPU_Context_restore_fp)
134SYM (_CPU_Context_restore_fp):
135        movl      FPCONTEXT_ARG(esp),eax   /* eax = &ptr to FP context area */
136        movl      (eax),eax                /* eax = FP context area */
137        frstor    (eax)                    /* restore FP context */
138        ret
139#endif
140
141#ifdef __SSE__
142#define SSE_OFF  16
143#endif
144
145        PUBLIC (_Exception_Handler)
146SYM (_Exception_Handler):
147        pusha                  /* Push general purpose registers    */
148        pushl   $0             /* Null pointer to SSE area          */
149        movl    esp,  ebp      /* Save original SP                  */
150#ifndef __SSE__
151        subl    $4,   esp      /* Reserve space for argument        */
152                           /* Align stack (courtesy for C/gcc)  */
153        andl    $ - CPU_STACK_ALIGNMENT, esp
154#else
155        subl    $512, esp      /* Space for SSE area                */
156                           /* Align stack (courtesy for C/gcc)  */
157        andl    $ - CPU_STACK_ALIGNMENT, esp
158/* Doing fwait here will re-throw an already pending FP exception!
159        fwait
160 */
161        fxsave  0(esp)
162        fninit                 /* Clean-slate FPU                   */
163        movl    $0x1f80, 0(ebp)
164        ldmxcsr 0(ebp)         /* Clean-slate MXCSR                 */
165        movl    esp, 0(ebp)    /* Store pointer to SSE area         */
166        subl    $SSE_OFF, esp  /* Aligned space for argument        */
167#endif
168        movl    ebp, (esp)     /* Store argument                    */
169        movl    _currentExcHandler, eax    /* Call function stored in _currentExcHandler */
170        call    * eax
171#ifdef __SSE__
172        fwait
173        fxrstor 16(esp)
174#endif
175        movl    ebp,  esp      /* Restore original SP               */
176        addl    $4,   esp      /* Skill pointer to SSE area         */
177        popa                   /* Restore general purpose registers */
178        addl    $8, esp        /* Skill vector number and faultCode */
179        iret
180
181#define DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY(_vector) \
182        .p2align 4                         ; \
183        PUBLIC (rtems_exception_prologue_ ## _vector ) ; \
184SYM (rtems_exception_prologue_ ## _vector ):             \
185        pushl   $ _vector       ; \
186        jmp   SYM (_Exception_Handler) ;
187
188#define DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY(_vector) \
189        .p2align 4                         ; \
190        PUBLIC (rtems_exception_prologue_ ## _vector ) ; \
191SYM (rtems_exception_prologue_ ## _vector ):             \
192        pushl   $ 0             ; \
193        pushl   $ _vector       ; \
194        jmp   SYM (_Exception_Handler) ;
195
196/*
197 * Divide Error
198 */
199DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (0)
200/*
201 * Debug Exception
202 */
203DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (1)
204/*
205 * NMI
206 */
207DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (2)
208/*
209 * Breakpoint
210 */
211DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (3)
212/*
213 * Overflow
214 */
215DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (4)
216/*
217 * Bound Range Exceeded
218 */
219DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (5)
220/*
221 * Invalid Opcode
222 */
223DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (6)
224/*
225 * No Math Coproc
226 */
227DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (7)
228/*
229 * Double Fault
230 */
231DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (8)
232/*
233 * Coprocessor segment overrun
234 */
235DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (9)
236/*
237 * Invalid TSS
238 */
239DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (10)
240/*
241 * Segment Not Present
242 */
243DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (11)
244/*
245 * Stack segment Fault
246 */
247DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (12)
248/*
249 * General Protection Fault
250 */
251DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (13)
252/*
253 * Page Fault
254 */
255DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (14)
256/*
257 * Floating point error (NB 15 is reserved it is therefor skipped)
258 */
259DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (16)
260/*
261 * Aligment Check
262 */
263DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (17)
264/*
265 * Machine Check
266 */
267DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (18)
268
269#ifdef __SSE__
270/*
271 * SIMD FP Exception
272 */
273DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (19)
274#endif
275
276
277/*
278 *  void *i386_Logical_to_physical(
279 *     uint16_t    segment,
280 *     void             *address
281 *  );
282 *
283 *  Returns thirty-two bit physical address for segment:address.
284 */
285
286.set SEGMENT_ARG, 4
287.set ADDRESS_ARG, 8
288
289             PUBLIC (i386_Logical_to_physical)
290
291SYM (i386_Logical_to_physical):
292
293        xorl    eax,eax                /* clear eax */
294        movzwl  SEGMENT_ARG(esp),ecx   /* ecx = segment value */
295        movl    $ SYM (_Global_descriptor_table),edx
296                                       /* edx = address of our GDT */
297        addl    ecx,edx                /* edx = address of desired entry */
298        movb    7(edx),ah              /* ah = base 31:24 */
299        movb    4(edx),al              /* al = base 23:16 */
300        shll    $16,eax                /* move ax into correct bits */
301        movw    2(edx),ax              /* ax = base 0:15 */
302        movl    ADDRESS_ARG(esp),ecx   /* ecx = address to convert */
303        addl    eax,ecx                /* ecx = physical address equivalent */
304        movl    ecx,eax                /* eax = ecx */
305        ret
306
307/*
308 *  void *i386_Physical_to_logical(
309 *     uint16_t    segment,
310 *     void             *address
311 *  );
312 *
313 *  Returns thirty-two bit physical address for segment:address.
314 */
315
316/*
317 *.set SEGMENT_ARG, 4
318 *.set ADDRESS_ARG, 8   -- use sets from above
319 */
320
321       PUBLIC (i386_Physical_to_logical)
322
323SYM (i386_Physical_to_logical):
324        xorl    eax,eax                /* clear eax */
325        movzwl  SEGMENT_ARG(esp),ecx   /* ecx = segment value */
326        movl    $ SYM (_Global_descriptor_table),edx
327                                       /* edx = address of our GDT */
328        addl    ecx,edx                /* edx = address of desired entry */
329        movb    7(edx),ah              /* ah = base 31:24 */
330        movb    4(edx),al              /* al = base 23:16 */
331        shll    $16,eax                /* move ax into correct bits */
332        movw    2(edx),ax              /* ax = base 0:15 */
333        movl    ADDRESS_ARG(esp),ecx   /* ecx = address to convert */
334        subl    eax,ecx                /* ecx = logical address equivalent */
335        movl    ecx,eax                /* eax = ecx */
336        ret
337
338/*
339 *  int i386_Physical_to_real(
340 *     void     *address,
341 *     uint16_t *segment,
342 *     uint16_t *offset
343 *  );
344 *
345 *  Fills segment:offest real mode pointer counted from thirty-two bit physical
346 *  address.
347 *  Returns 0 if inconvertible, 1 if successfuly converted.
348 */
349
350.set PHYS_PTR_ARG,   4
351.set RM_PTR_SEG_ARG, 8
352.set RM_PTR_OFF_ARG, 12
353
354       PUBLIC (i386_Physical_to_real)
355
356SYM (i386_Physical_to_real):
357        movl    PHYS_PTR_ARG(esp),eax
358        cmpl    $0x10FFF0, eax
359        js      1f
360        movl    $0, eax
361        ret
3621:      cmpl    $0x100000, eax
363        js      2f
364        subl    $0xFFFF0, eax
365        movl    RM_PTR_OFF_ARG(esp), ecx
366        movw    ax, (ecx)
367        movl    RM_PTR_SEG_ARG(esp), ecx
368        movw    $0xFFFF, (ecx)
369        movl    $1, eax
370        ret
3712:      movl    eax, edx
372        and     $0xF, ax
373        movl    RM_PTR_OFF_ARG(esp), ecx
374        movw    ax, (ecx)
375        shrl    $4, edx
376        movl    RM_PTR_SEG_ARG(esp), ecx
377        movw    dx, (ecx)
378        movl    $1, eax
379        ret
380
381END_CODE
382
383END
Note: See TracBrowser for help on using the repository browser.