source: rtems/cpukit/score/cpu/i386/cpu_asm.S @ 85d6a760

5
Last change on this file since 85d6a760 was 85d6a760, checked in by Jan Sommer <jan.sommer@…>, on 05/31/20 at 14:22:53

bsp/pc386: Update GDT to work for SMP

Create a GS segment in the GDT for each processor for storing TLS.
This makes the GDT in startAP.S obsolete as all processors now share the
same GDT, which is passed to each AP at startup.

The correct segment for each processor is calculated in cpu_asm.S.

Update #3335

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