Back to home page

LXR

 
 

    


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

0001 /**
0002  *  @file
0003  *
0004  *  @brief Intel i386 Dependent Source
0005  */
0006 
0007 /*
0008  *  COPYRIGHT (c) 1989-1999.
0009  *  On-Line Applications Research Corporation (OAR).
0010  *
0011  * Redistribution and use in source and binary forms, with or without
0012  * modification, are permitted provided that the following conditions
0013  * are met:
0014  * 1. Redistributions of source code must retain the above copyright
0015  *    notice, this list of conditions and the following disclaimer.
0016  * 2. Redistributions in binary form must reproduce the above copyright
0017  *    notice, this list of conditions and the following disclaimer in the
0018  *    documentation and/or other materials provided with the distribution.
0019  *
0020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0021  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0022  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0023  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0024  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0025  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0026  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0027  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0028  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0029  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0030  * POSSIBILITY OF SUCH DAMAGE.
0031  */
0032 
0033 #ifdef HAVE_CONFIG_H
0034 #include "config.h"
0035 #endif
0036 
0037 #include <inttypes.h>
0038 
0039 #include <rtems.h>
0040 #include <rtems/score/isr.h>
0041 #include <rtems/score/idtr.h>
0042 #include <rtems/score/tls.h>
0043 
0044 #include <rtems/bspIo.h>
0045 #include <rtems/score/percpu.h>
0046 #include <rtems/score/thread.h>
0047 
0048 #define I386_ASSERT_OFFSET(field, off) \
0049   RTEMS_STATIC_ASSERT( \
0050     offsetof(Context_Control, field) \
0051       == I386_CONTEXT_CONTROL_ ## off ## _OFFSET, \
0052     Context_Control_ ## field \
0053   )
0054 
0055 I386_ASSERT_OFFSET(eflags, EFLAGS);
0056 I386_ASSERT_OFFSET(esp, ESP);
0057 I386_ASSERT_OFFSET(ebp, EBP);
0058 I386_ASSERT_OFFSET(ebx, EBX);
0059 I386_ASSERT_OFFSET(esi, ESI);
0060 I386_ASSERT_OFFSET(edi, EDI);
0061 
0062 RTEMS_STATIC_ASSERT(
0063   offsetof(Context_Control, gs)
0064     == I386_CONTEXT_CONTROL_GS_0_OFFSET,
0065   Context_Control_gs_0
0066 );
0067 
0068 #ifdef RTEMS_SMP
0069   I386_ASSERT_OFFSET(is_executing, IS_EXECUTING);
0070 #endif
0071 
0072 #if CPU_HARDWARE_FP
0073 Context_Control_fp _CPU_Null_fp_context;
0074 #endif
0075 
0076 void _CPU_Initialize(void)
0077 {
0078 #if CPU_HARDWARE_FP
0079   register uint16_t     fp_status __asm__ ("ax");
0080   register Context_Control_fp  *fp_context;
0081 #endif
0082 
0083   /*
0084    *  The following code saves a NULL i387 context which is given
0085    *  to each task at start and restart time.  The following code
0086    *  is based upon that provided in the i386 Programmer's
0087    *  Manual and should work on any coprocessor greater than
0088    *  the i80287.
0089    *
0090    *  NOTE: The NO WAIT form of the coprocessor instructions
0091    *        MUST be used in case there is not a coprocessor
0092    *        to wait for.
0093    */
0094 
0095 #if CPU_HARDWARE_FP
0096   fp_status = 0xa5a5;
0097   __asm__ volatile( "fninit" );
0098   __asm__ volatile( "fnstsw %0" : "=a" (fp_status) : "0" (fp_status) );
0099 
0100   if ( fp_status ==  0 ) {
0101 
0102     fp_context = &_CPU_Null_fp_context;
0103 
0104 #ifdef __SSE__
0105     asm volatile( "fstcw %0":"=m"(fp_context->fpucw) );
0106 #else
0107     __asm__ volatile( "fsave (%0)" : "=r" (fp_context)
0108                                : "0"  (fp_context)
0109                 );
0110 #endif
0111   }
0112 #endif
0113 
0114 #ifdef __SSE__
0115 
0116   __asm__ volatile("stmxcsr %0":"=m"(fp_context->mxcsr));
0117 
0118   /* The BSP must enable the SSE extensions (early).
0119    * If any SSE instruction was already attempted
0120    * then that crashed the system.
0121    * As a courtesy, we double-check here but it
0122    * may be too late (which is also why we don't
0123    * enable SSE here).
0124    */
0125   {
0126   uint32_t cr4;
0127     __asm__ __volatile__("mov %%cr4, %0":"=r"(cr4));
0128     if ( 0x600 != (cr4 & 0x600) ) {
0129       printk("PANIC: RTEMS was compiled for SSE but BSP did not enable it"
0130              "(CR4: 0%" PRIu32 ")\n", cr4);
0131       while ( 1 ) {
0132         __asm__ __volatile__("hlt");
0133       }
0134     }
0135   }
0136 #endif
0137 }
0138 
0139 /*
0140  * Stack alignment note:
0141  *
0142  * We want the stack to look to the '_entry_point' routine
0143  * like an ordinary stack frame as if '_entry_point' was
0144  * called from C-code.
0145  * Note that '_entry_point' is jumped-to by the 'ret'
0146  * instruction returning from _CPU_Context_switch() or
0147  * _CPU_Context_restore() thus popping the _entry_point
0148  * from the stack.
0149  * However, _entry_point expects a frame to look like this:
0150  *
0151  *      args        [_Thread_Handler expects no args, however]
0152  *      ------      (alignment boundary)
0153  * SP-> return_addr return here when _entry_point returns which (never happens)
0154  *
0155  *
0156  * Hence we must initialize the stack as follows
0157  *
0158  *         [arg1          ]:  n/a
0159  *         [arg0 (aligned)]:  n/a
0160  *         [ret. addr     ]:  NULL
0161  * SP->    [jump-target   ]:  _entry_point
0162  *
0163  * When Context_switch returns it pops the _entry_point from
0164  * the stack which then finds a standard layout.
0165  */
0166 
0167 void _CPU_Context_Initialize(
0168   Context_Control *the_context,
0169   void *_stack_base,
0170   size_t _size,
0171   uint32_t _isr,
0172   void (*_entry_point)( void ),
0173   bool is_fp,
0174   void *tls_area
0175 )
0176 {
0177   uint32_t _stack;
0178   uint32_t tcb;
0179 
0180   (void) is_fp; /* avoid warning for being unused */
0181 
0182   if ( _isr ) {
0183     the_context->eflags = CPU_EFLAGS_INTERRUPTS_OFF;
0184   } else {
0185     the_context->eflags = CPU_EFLAGS_INTERRUPTS_ON;
0186   }
0187 
0188   _stack  = ((uint32_t)(_stack_base)) + (_size);
0189   _stack &= ~ (CPU_STACK_ALIGNMENT - 1);
0190   _stack -= 2*sizeof(void *); /* see above for why we need to do this */
0191   *((void (**)(void))(_stack)) = (_entry_point);
0192   the_context->ebp     = (void *) 0;
0193   the_context->esp     = (void *) _stack;
0194 
0195   if ( tls_area != NULL ) {
0196     tcb = (uint32_t) _TLS_Initialize_area( tls_area );
0197   } else {
0198     tcb = 0;
0199   }
0200 
0201   the_context->gs.limit_15_0 = 0xffff;
0202   the_context->gs.base_address_15_0 = (tcb >> 0) & 0xffff;
0203   the_context->gs.type = 0x2;
0204   the_context->gs.descriptor_type = 0x1;
0205   the_context->gs.limit_19_16 = 0xf;
0206   the_context->gs.present = 0x1;
0207   the_context->gs.operation_size = 0x1;
0208   the_context->gs.granularity = 0x1;
0209   the_context->gs.base_address_23_16 = (tcb >> 16) & 0xff;
0210   the_context->gs.base_address_31_24 = (tcb >> 24) & 0xff;
0211 }
0212 
0213 uint32_t   _CPU_ISR_Get_level( void )
0214 {
0215   uint32_t   level;
0216 
0217 #if !defined(I386_DISABLE_INLINE_ISR_DISABLE_ENABLE)
0218   i386_get_interrupt_level( level );
0219 #else
0220   level = i386_get_interrupt_level();
0221 #endif
0222 
0223   return level;
0224 }
0225 
0226 struct Frame_ {
0227     struct Frame_  *up;
0228     uintptr_t       pc;
0229 };
0230 
0231 void _CPU_Exception_frame_print (const CPU_Exception_frame *ctx)
0232 {
0233   unsigned int faultAddr = 0;
0234   printk("----------------------------------------------------------\n");
0235   printk("Exception %" PRIu32 " caught at PC %" PRIx32 " by thread %" PRIx32 "\n",
0236      ctx->idtIndex,
0237      ctx->eip,
0238      _Thread_Executing->Object.id);
0239   printk("----------------------------------------------------------\n");
0240   printk("Processor execution context at time of the fault was  :\n");
0241   printk("----------------------------------------------------------\n");
0242   printk(" EAX =  0x%08" PRIx32 "   EBX =  0x%08" PRIx32 "  ECX =  0x%08" PRIx32 "  EDX =  0x%08" PRIx32 "\n",
0243      ctx->eax, ctx->ebx, ctx->ecx, ctx->edx);
0244   printk(" ESI = 0x%08" PRIx32 "    EDI =  0x%08" PRIx32 "  EBP =  0x%08" PRIx32 "  ESP =  0x%08" PRIx32 "\n",
0245      ctx->esi, ctx->edi, ctx->ebp, ctx->esp0);
0246   printk("----------------------------------------------------------\n");
0247   printk("Error code pushed by processor itself (if not 0) = %" PRIx32 "\n",
0248      ctx->faultCode);
0249   printk("----------------------------------------------------------\n");
0250   if (ctx->idtIndex == I386_EXCEPTION_PAGE_FAULT){
0251     faultAddr = i386_get_cr2();
0252     printk("Page fault linear address (CR2) = %x\n", faultAddr);
0253     printk("----------------------------------------------------------\n\n");
0254   }
0255  if (_ISR_Nest_level > 0) {
0256     /*
0257      * In this case we shall not delete the task interrupted as
0258      * it has nothing to do with the fault. We cannot return either
0259      * because the eip points to the faulty instruction so...
0260      */
0261     printk("Exception while executing ISR!!!. System locked\n");
0262   }
0263   else {
0264     struct Frame_ *fp = (struct Frame_*)ctx->ebp;
0265     int           i;
0266 
0267     printk("Call Stack Trace of EIP:\n");
0268     if ( fp ) {
0269         for ( i=1; fp->up; fp=fp->up, i++ ) {
0270             printk("0x%08" PRIxPTR " ",fp->pc);
0271             if ( ! (i&3) )
0272                 printk("\n");
0273         }
0274     }
0275     printk("\n");
0276     /*
0277      * OK I could probably use a simplified version but at least this
0278      * should work.
0279      */
0280 #if 0
0281     printk(" ************ FAULTY THREAD WILL BE SUSPENDED **************\n");
0282     rtems_task_suspend(_Thread_Executing->Object.id);
0283 #endif
0284   }
0285 }
0286 
0287 static void _defaultExcHandler (CPU_Exception_frame *ctx)
0288 {
0289   rtems_fatal(
0290     RTEMS_FATAL_SOURCE_EXCEPTION,
0291     (rtems_fatal_code) ctx
0292   );
0293 }
0294 
0295 cpuExcHandlerType _currentExcHandler = _defaultExcHandler;
0296 
0297 extern void rtems_exception_prologue_0(void);
0298 extern void rtems_exception_prologue_1(void);
0299 extern void rtems_exception_prologue_2(void);
0300 extern void rtems_exception_prologue_3(void);
0301 extern void rtems_exception_prologue_4(void);
0302 extern void rtems_exception_prologue_5(void);
0303 extern void rtems_exception_prologue_6(void);
0304 extern void rtems_exception_prologue_7(void);
0305 extern void rtems_exception_prologue_8(void);
0306 extern void rtems_exception_prologue_9(void);
0307 extern void rtems_exception_prologue_10(void);
0308 extern void rtems_exception_prologue_11(void);
0309 extern void rtems_exception_prologue_12(void);
0310 extern void rtems_exception_prologue_13(void);
0311 extern void rtems_exception_prologue_14(void);
0312 extern void rtems_exception_prologue_16(void);
0313 extern void rtems_exception_prologue_17(void);
0314 extern void rtems_exception_prologue_18(void);
0315 #ifdef __SSE__
0316 extern void rtems_exception_prologue_19(void);
0317 #endif
0318 
0319 static rtems_raw_irq_hdl tbl[] = {
0320      rtems_exception_prologue_0,
0321      rtems_exception_prologue_1,
0322      rtems_exception_prologue_2,
0323      rtems_exception_prologue_3,
0324      rtems_exception_prologue_4,
0325      rtems_exception_prologue_5,
0326      rtems_exception_prologue_6,
0327      rtems_exception_prologue_7,
0328      rtems_exception_prologue_8,
0329      rtems_exception_prologue_9,
0330      rtems_exception_prologue_10,
0331      rtems_exception_prologue_11,
0332      rtems_exception_prologue_12,
0333      rtems_exception_prologue_13,
0334      rtems_exception_prologue_14,
0335      0,
0336      rtems_exception_prologue_16,
0337      rtems_exception_prologue_17,
0338      rtems_exception_prologue_18,
0339 #ifdef __SSE__
0340      rtems_exception_prologue_19,
0341 #endif
0342 };
0343 
0344 void rtems_exception_init_mngt(void)
0345 {
0346       size_t                     i,j;
0347       interrupt_gate_descriptor  *currentIdtEntry;
0348       unsigned           limit;
0349       unsigned           level;
0350 
0351       i = sizeof(tbl) / sizeof (rtems_raw_irq_hdl);
0352 
0353       i386_get_info_from_IDTR (&currentIdtEntry, &limit);
0354 
0355       _CPU_ISR_Disable(level);
0356       for (j = 0; j < i; j++) {
0357     create_interrupt_gate_descriptor (&currentIdtEntry[j], tbl[j]);
0358       }
0359       _CPU_ISR_Enable(level);
0360 }