Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:24

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  *  @file
0005  *
0006  *  This file contains all assembly code for the Intel i386 implementation
0007  *  of RTEMS.
0008  */
0009 
0010 /*
0011  *  COPYRIGHT (c) 1989-1999.
0012  *  On-Line Applications Research Corporation (OAR).
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #ifdef HAVE_CONFIG_H
0037 #include "config.h"
0038 #endif
0039 
0040 #include <rtems/asm.h>
0041 #include <rtems/score/cpu.h>
0042 
0043 #ifndef CPU_STACK_ALIGNMENT
0044 #error "Missing header? CPU_STACK_ALIGNMENT not defined"
0045 #endif
0046 
0047 /*
0048  * Format of i386 Register structure
0049  */
0050 
0051 .set REG_EFLAGS,  I386_CONTEXT_CONTROL_EFLAGS_OFFSET
0052 .set REG_ESP,     I386_CONTEXT_CONTROL_ESP_OFFSET
0053 .set REG_EBP,     I386_CONTEXT_CONTROL_EBP_OFFSET
0054 .set REG_EBX,     I386_CONTEXT_CONTROL_EBX_OFFSET
0055 .set REG_ESI,     I386_CONTEXT_CONTROL_ESI_OFFSET
0056 .set REG_EDI,     I386_CONTEXT_CONTROL_EDI_OFFSET
0057 .set REG_GS_0,    I386_CONTEXT_CONTROL_GS_0_OFFSET
0058 .set REG_GS_1,    I386_CONTEXT_CONTROL_GS_1_OFFSET
0059 
0060         BEGIN_CODE
0061 
0062 /*
0063  *  void _CPU_Context_switch( run_context, heir_context )
0064  *
0065  *  This routine performs a normal non-FP context.
0066  */
0067 
0068         .p2align  1
0069         PUBLIC (_CPU_Context_switch)
0070         PUBLIC (_CPU_Context_switch_no_return)
0071 
0072 .set RUNCONTEXT_ARG,   4                   /* save context argument */
0073 .set HEIRCONTEXT_ARG,  8                   /* restore context argument */
0074 
0075 SYM (_CPU_Context_switch):
0076 SYM (_CPU_Context_switch_no_return):
0077         movl      RUNCONTEXT_ARG(esp),eax  /* eax = running threads context */
0078         GET_SELF_CPU_CONTROL edx           /* edx has address for per_CPU information */
0079         movl      PER_CPU_ISR_DISPATCH_DISABLE(edx),ecx
0080         pushf                              /* push eflags */
0081         popl      REG_EFLAGS(eax)          /* save eflags */
0082         movl      esp,REG_ESP(eax)         /* save stack pointer */
0083         movl      ebp,REG_EBP(eax)         /* save base pointer */
0084         movl      ebx,REG_EBX(eax)         /* save ebx */
0085         movl      esi,REG_ESI(eax)         /* save source register */
0086         movl      edi,REG_EDI(eax)         /* save destination register */
0087         movl      ecx, I386_CONTEXT_CONTROL_ISR_DISPATCH_DISABLE(eax)
0088 
0089         movl      eax,ecx                  /* ecx = running threads context */
0090         movl      HEIRCONTEXT_ARG(esp),eax /* eax = heir threads context */
0091 
0092 #ifdef RTEMS_SMP
0093       /*
0094        * The executing thread no longer executes on this processor.  Switch
0095        * the stack to the temporary interrupt stack of this processor.  Mark
0096        * the context of the executing thread as not executing.
0097        */
0098         leal      PER_CPU_INTERRUPT_FRAME_AREA + CPU_INTERRUPT_FRAME_SIZE(edx),esp
0099         movb      $0, I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET(ecx)
0100 
0101 .L_check_is_executing:
0102         lock bts  $0,I386_CONTEXT_CONTROL_IS_EXECUTING_OFFSET(eax)  /* Indicator in carry flag */
0103         jc        .L_get_potential_new_heir
0104 #endif
0105 
0106 /* Start restoring context */
0107 .L_restore:
0108         movl      I386_CONTEXT_CONTROL_ISR_DISPATCH_DISABLE(eax),ecx
0109         movl      ecx,PER_CPU_ISR_DISPATCH_DISABLE(edx)
0110         movl      REG_ESP(eax),esp         /* restore stack pointer */
0111         pushl     REG_EFLAGS(eax)          /* push eflags */
0112         popf                               /* restore eflags */
0113         movl      REG_EBP(eax),ebp         /* restore base pointer */
0114         movl      REG_EBX(eax),ebx         /* restore ebx */
0115         movl      REG_ESI(eax),esi         /* restore source register */
0116         movl      REG_EDI(eax),edi         /* restore destination register */
0117         GET_CPU_ID ecx
0118         movl      REG_GS_0(eax), edx       /* restore gs segment */
0119         movl      edx, _Global_descriptor_table+24(,ecx,8)
0120         movl      REG_GS_1(eax), edx
0121         movl      edx, _Global_descriptor_table+28(,ecx,8)
0122         leal      24(,ecx,8), edx
0123         movl      edx, gs
0124         ret
0125 
0126 /*
0127  *  NOTE: May be unnecessary to reload some registers.
0128  */
0129 
0130 /*
0131  *  void _CPU_Context_restore( new_context )
0132  *
0133  *  This routine performs a normal non-FP context.
0134  */
0135 
0136         PUBLIC (_CPU_Context_restore)
0137 
0138 .set NEWCONTEXT_ARG,   4                   /* context to restore argument */
0139 
0140 SYM (_CPU_Context_restore):
0141         movl      NEWCONTEXT_ARG(esp),eax  /* eax = running threads context */
0142         GET_SELF_CPU_CONTROL edx           /* edx has address for per_CPU information */
0143         jmp       .L_restore
0144 
0145 #ifdef RTEMS_SMP
0146 
0147 .L_get_potential_new_heir:
0148 
0149         /* We may have a new heir */
0150 
0151         /* Read the executing and heir */
0152         movl    PER_CPU_OFFSET_EXECUTING(edx),ebx
0153         movl    PER_CPU_OFFSET_HEIR(edx),esi
0154 
0155         /*
0156          * Update the executing only if necessary to avoid cache line
0157          * monopolization.
0158          */
0159         cmp     esi,ebx
0160         je      .L_check_is_executing
0161 
0162         /* Calculate the heir context pointer */
0163         addl    esi,eax
0164         subl    ebx,eax
0165 
0166         /* Update the executing */
0167         movl    esi,PER_CPU_OFFSET_EXECUTING(edx)
0168 
0169         jmp     .L_check_is_executing
0170 #endif
0171 
0172 /*void _CPU_Context_save_fp_context( &fp_context_ptr )
0173  *  void _CPU_Context_restore_fp_context( &fp_context_ptr )
0174  *
0175  *  This section is used to context switch an i80287, i80387,
0176  *  the built-in coprocessor or the i80486 or compatible.
0177  */
0178 
0179 .set FPCONTEXT_ARG,   4                    /* FP context argument */
0180 
0181 #ifndef __SSE__
0182         .p2align  1
0183         PUBLIC (_CPU_Context_save_fp)
0184 SYM (_CPU_Context_save_fp):
0185         movl      FPCONTEXT_ARG(esp),eax   /* eax = &ptr to FP context area */
0186         movl      (eax),eax                /* eax = FP context area */
0187         fsave     (eax)                    /* save FP context */
0188         ret
0189 
0190         .p2align  1
0191         PUBLIC (_CPU_Context_restore_fp)
0192 SYM (_CPU_Context_restore_fp):
0193         movl      FPCONTEXT_ARG(esp),eax   /* eax = &ptr to FP context area */
0194         movl      (eax),eax                /* eax = FP context area */
0195         frstor    (eax)                    /* restore FP context */
0196         ret
0197 #endif
0198 
0199 #ifdef __SSE__
0200 #define SSE_OFF  16
0201 #endif
0202 
0203         PUBLIC (_Exception_Handler)
0204 SYM (_Exception_Handler):
0205     pusha                  /* Push general purpose registers    */
0206     pushl   $0             /* Null pointer to SSE area          */
0207     movl    esp,  ebp      /* Save original SP                  */
0208 #ifndef __SSE__
0209     subl    $4,   esp      /* Reserve space for argument        */
0210                            /* Align stack (courtesy for C/gcc)  */
0211     andl    $ - CPU_STACK_ALIGNMENT, esp
0212 #else
0213     subl    $512, esp      /* Space for SSE area                */
0214                            /* Align stack (courtesy for C/gcc)  */
0215     andl    $ - CPU_STACK_ALIGNMENT, esp
0216 /* Doing fwait here will re-throw an already pending FP exception!
0217     fwait
0218  */
0219     fxsave  0(esp)
0220     fninit                 /* Clean-slate FPU                   */
0221     movl    $0x1f80, 0(ebp)
0222     ldmxcsr 0(ebp)         /* Clean-slate MXCSR                 */
0223     movl    esp, 0(ebp)    /* Store pointer to SSE area         */
0224     subl    $SSE_OFF, esp  /* Aligned space for argument        */
0225 #endif
0226     movl    ebp, (esp)     /* Store argument                    */
0227     movl    _currentExcHandler, eax    /* Call function stored in _currentExcHandler */
0228     call    * eax
0229 #ifdef __SSE__
0230     fwait
0231     fxrstor 16(esp)
0232 #endif
0233     movl    ebp,  esp      /* Restore original SP               */
0234     addl    $4,   esp      /* Skill pointer to SSE area         */
0235     popa                   /* Restore general purpose registers */
0236     addl    $8, esp        /* Skill vector number and faultCode */
0237     iret
0238 
0239 #define DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY(_vector) \
0240         .p2align 4                         ; \
0241         PUBLIC (rtems_exception_prologue_ ## _vector ) ; \
0242 SYM (rtems_exception_prologue_ ## _vector ):             \
0243     pushl   $ _vector   ; \
0244         jmp   SYM (_Exception_Handler) ;
0245 
0246 #define DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY(_vector) \
0247         .p2align 4                         ; \
0248         PUBLIC (rtems_exception_prologue_ ## _vector ) ; \
0249 SYM (rtems_exception_prologue_ ## _vector ):             \
0250     pushl   $ 0     ; \
0251     pushl   $ _vector   ; \
0252         jmp   SYM (_Exception_Handler) ;
0253 
0254 /*
0255  * Divide Error
0256  */
0257 DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (0)
0258 /*
0259  * Debug Exception
0260  */
0261 DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (1)
0262 /*
0263  * NMI
0264  */
0265 DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (2)
0266 /*
0267  * Breakpoint
0268  */
0269 DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (3)
0270 /*
0271  * Overflow
0272  */
0273 DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (4)
0274 /*
0275  * Bound Range Exceeded
0276  */
0277 DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (5)
0278 /*
0279  * Invalid Opcode
0280  */
0281 DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (6)
0282 /*
0283  * No Math Coproc
0284  */
0285 DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (7)
0286 /*
0287  * Double Fault
0288  */
0289 DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (8)
0290 /*
0291  * Coprocessor segment overrun
0292  */
0293 DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (9)
0294 /*
0295  * Invalid TSS
0296  */
0297 DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (10)
0298 /*
0299  * Segment Not Present
0300  */
0301 DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (11)
0302 /*
0303  * Stack segment Fault
0304  */
0305 DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (12)
0306 /*
0307  * General Protection Fault
0308  */
0309 DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (13)
0310 /*
0311  * Page Fault
0312  */
0313 DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (14)
0314 /*
0315  * Floating point error (NB 15 is reserved it is therefor skipped)
0316  */
0317 DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (16)
0318 /*
0319  * Aligment Check
0320  */
0321 DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (17)
0322 /*
0323  * Machine Check
0324  */
0325 DISTINCT_EXCEPTION_WITH_FAULTCODE_ENTRY (18)
0326 
0327 #ifdef __SSE__
0328 /*
0329  * SIMD FP Exception
0330  */
0331 DISTINCT_EXCEPTION_WITHOUT_FAULTCODE_ENTRY (19)
0332 #endif
0333 
0334 
0335 /*
0336  *  void *i386_Logical_to_physical(
0337  *     uint16_t    segment,
0338  *     void             *address
0339  *  );
0340  *
0341  *  Returns thirty-two bit physical address for segment:address.
0342  */
0343 
0344 .set SEGMENT_ARG, 4
0345 .set ADDRESS_ARG, 8
0346 
0347              PUBLIC (i386_Logical_to_physical)
0348 
0349 SYM (i386_Logical_to_physical):
0350 
0351         xorl    eax,eax                /* clear eax */
0352         movzwl  SEGMENT_ARG(esp),ecx   /* ecx = segment value */
0353         movl    $ SYM (_Global_descriptor_table),edx
0354                                        /* edx = address of our GDT */
0355         addl    ecx,edx                /* edx = address of desired entry */
0356         movb    7(edx),ah              /* ah = base 31:24 */
0357         movb    4(edx),al              /* al = base 23:16 */
0358         shll    $16,eax                /* move ax into correct bits */
0359         movw    2(edx),ax              /* ax = base 0:15 */
0360         movl    ADDRESS_ARG(esp),ecx   /* ecx = address to convert */
0361         addl    eax,ecx                /* ecx = physical address equivalent */
0362         movl    ecx,eax                /* eax = ecx */
0363         ret
0364 
0365 /*
0366  *  void *i386_Physical_to_logical(
0367  *     uint16_t    segment,
0368  *     void             *address
0369  *  );
0370  *
0371  *  Returns thirty-two bit physical address for segment:address.
0372  */
0373 
0374 /*
0375  *.set SEGMENT_ARG, 4
0376  *.set ADDRESS_ARG, 8   -- use sets from above
0377  */
0378 
0379        PUBLIC (i386_Physical_to_logical)
0380 
0381 SYM (i386_Physical_to_logical):
0382         xorl    eax,eax                /* clear eax */
0383         movzwl  SEGMENT_ARG(esp),ecx   /* ecx = segment value */
0384         movl    $ SYM (_Global_descriptor_table),edx
0385                                        /* edx = address of our GDT */
0386         addl    ecx,edx                /* edx = address of desired entry */
0387         movb    7(edx),ah              /* ah = base 31:24 */
0388         movb    4(edx),al              /* al = base 23:16 */
0389         shll    $16,eax                /* move ax into correct bits */
0390         movw    2(edx),ax              /* ax = base 0:15 */
0391         movl    ADDRESS_ARG(esp),ecx   /* ecx = address to convert */
0392         subl    eax,ecx                /* ecx = logical address equivalent */
0393         movl    ecx,eax                /* eax = ecx */
0394         ret
0395 
0396 /*
0397  *  int i386_Physical_to_real(
0398  *     void     *address,
0399  *     uint16_t *segment,
0400  *     uint16_t *offset
0401  *  );
0402  *
0403  *  Fills segment:offest real mode pointer counted from thirty-two bit physical
0404  *  address.
0405  *  Returns 0 if inconvertible, 1 if successfuly converted.
0406  */
0407 
0408 .set PHYS_PTR_ARG,   4
0409 .set RM_PTR_SEG_ARG, 8
0410 .set RM_PTR_OFF_ARG, 12
0411 
0412        PUBLIC (i386_Physical_to_real)
0413 
0414 SYM (i386_Physical_to_real):
0415         movl    PHYS_PTR_ARG(esp),eax
0416         cmpl    $0x10FFF0, eax
0417         js      1f
0418         movl    $0, eax
0419         ret
0420 1:      cmpl    $0x100000, eax
0421         js      2f
0422         subl    $0xFFFF0, eax
0423         movl    RM_PTR_OFF_ARG(esp), ecx
0424         movw    ax, (ecx)
0425         movl    RM_PTR_SEG_ARG(esp), ecx
0426         movw    $0xFFFF, (ecx)
0427         movl    $1, eax
0428         ret
0429 2:  movl    eax, edx
0430         and     $0xF, ax
0431         movl    RM_PTR_OFF_ARG(esp), ecx
0432         movw    ax, (ecx)
0433         shrl    $4, edx
0434         movl    RM_PTR_SEG_ARG(esp), ecx
0435         movw    dx, (ecx)
0436         movl    $1, eax
0437         ret
0438 
0439 END_CODE
0440 
0441 END