Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:41

0001 /*
0002  *  This file contains the implementation of the function described in irq.h
0003  */
0004 
0005 /*
0006  *  Copyright (C) 1998 valette@crf.canon.fr
0007  *
0008  *  COPYRIGHT (c) 1989-2011.
0009  *  On-Line Applications Research Corporation (OAR).
0010  *
0011  *  The license and distribution terms for this file may be
0012  *  found in found in the file LICENSE in this distribution or at
0013  *  http://www.rtems.org/license/LICENSE.
0014  */
0015 
0016 #include <rtems/asm.h>
0017 #include <bspopts.h>
0018 #include <rtems/score/cpu.h>
0019 #include <rtems/score/percpu.h>
0020 
0021 #include <bsp.h> /* to establish dependency on prototype */
0022 
0023 #ifndef CPU_STACK_ALIGNMENT
0024 #error "Missing header? CPU_STACK_ALIGNMENT is not defined here"
0025 #endif
0026 
0027 /* Stack frame we use for intermediate storage               */
0028 #define ARG_OFF  0
0029 #define EBX_OFF  4        /* ebx                              */
0030 #define EBP_OFF  8       /* code restoring ebp/esp relies on */
0031 #define ESP_OFF 12       /* esp being on top of ebp!         */
0032 #ifdef __SSE__
0033 #ifdef RTEMS_SMP
0034 #error SMP with SSE support has not been tested. Use at your own risk.
0035 #endif
0036 /* need to be on 16 byte boundary for SSE, add 12 to do that */
0037 #define FRM_SIZ (20+12+512)
0038 #define SSE_OFF 32
0039 #else
0040 #define FRM_SIZ 16
0041 #endif
0042 
0043     BEGIN_CODE
0044 
0045 SYM (_ISR_Handler):
0046     /*
0047      *  Before this was point is reached the vectors unique
0048      *  entry point did the following:
0049      *
0050      *     1. saved scratch registers registers eax edx ecx"
0051      *     2. put the vector number in ecx.
0052      *
0053      * BEGINNING OF ESTABLISH SEGMENTS
0054      *
0055      *  WARNING: If an interrupt can occur when the segments are
0056      *           not correct, then this is where we should establish
0057      *           the segments.  In addition to establishing the
0058      *           segments, it may be necessary to establish a stack
0059      *           in the current data area on the outermost interrupt.
0060      *
0061      *  NOTE:  If the previous values of the segment registers are
0062      *         pushed, do not forget to adjust SAVED_REGS.
0063      *
0064      *  NOTE:  Make sure the Lthread_dispatch_done code restores these
0065      *         when this type of code is needed.
0066      */
0067 
0068     /***** ESTABLISH SEGMENTS CODE GOES HERE  ******/
0069 
0070     /*
0071      * END OF ESTABLISH SEGMENTS
0072      */
0073 
0074     /*
0075      * Establish an aligned stack frame
0076      *   original sp
0077      *   saved ebp
0078      *   saved ebx
0079      *   vector arg to BSP_dispatch_isr   <- aligned SP
0080      */
0081     movl      esp, eax
0082     subl      $FRM_SIZ, esp
0083     movl      eax, ESP_OFF(esp)
0084     movl      ebp, EBP_OFF(esp)
0085     movl      ebx, EBX_OFF(esp)
0086 
0087     /*
0088      * GCC versions starting with 4.3 no longer place the cld
0089      * instruction before string operations.  We  need to ensure
0090      * it is set correctly for ISR handlers.
0091      */
0092     cld
0093 
0094 #ifdef __SSE__
0095     /* NOTE: SSE only is supported if the BSP enables fxsave/fxrstor
0096      * to save/restore SSE context! This is so far only implemented
0097      * for pc386!.
0098      */
0099 
0100     /* We save SSE here (on the task stack) because we possibly
0101      * call other C-code (besides the ISR, namely _Thread_Dispatch())
0102      */
0103     /*  don't wait here; a possible exception condition will eventually be
0104      *  detected when the task resumes control and executes a FP instruction
0105     fwait
0106      */
0107     fxsave SSE_OFF(esp)
0108     fninit                          /* clean-slate FPU                */
0109     movl   $0x1f80, ARG_OFF(esp)    /* use ARG_OFF as scratch space   */
0110     ldmxcsr ARG_OFF(esp)            /* clean-slate MXCSR              */
0111 #endif
0112 
0113     /*
0114      *  Now switch stacks if necessary
0115      */
0116 
0117 PUBLIC (ISR_STOP)
0118 ISR_STOP:
0119 .check_stack_switch:
0120     movl      esp, ebp                  /* ebp = previous stack pointer */
0121     andl      $ - CPU_STACK_ALIGNMENT, esp  /* Make sure esp is 16 byte aligned */
0122 
0123     GET_SELF_CPU_CONTROL ebx
0124 
0125     /* is this the outermost interrupt? */
0126     cmpl      $0, PER_CPU_ISR_NEST_LEVEL(ebx)
0127     jne       nested                    /* No, then continue */
0128     movl      PER_CPU_INTERRUPT_STACK_HIGH(ebx), esp
0129 
0130     /*
0131      *  We want to insure that the old stack pointer is in ebp
0132      *  By saving it on every interrupt, all we have to do is
0133      *  movl ebp->esp near the end of every interrupt.
0134      */
0135 
0136 nested:
0137     incl      PER_CPU_ISR_NEST_LEVEL(ebx)  /* one nest level deeper */
0138     incl      PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx) /* disable
0139                                                             multitasking */
0140     /*
0141      *  ECX is preloaded with the vector number; store as arg
0142      *  on top of stack. Note that _CPU_Interrupt_stack_high
0143      *  was adjusted in _CPU_Interrupt_stack_setup() (score/rtems/cpu.h)
0144      *  to make sure there is space.
0145      */
0146 
0147     movl      ecx, ARG_OFF(esp)  /* store vector arg in stack */
0148     call      BSP_dispatch_isr
0149 
0150     movl      ARG_OFF(esp), ecx     /* grab vector arg from stack */
0151 
0152     /*
0153      * Restore stack. This moves back to the task stack
0154      * when all interrupts are unnested.
0155      */
0156     movl      ebp, esp
0157 
0158     /*
0159      * Thread dispatching is necessary and allowed if and only if
0160      *   dispatch_necessary == 1 and
0161      *   isr_dispatch_disable == 0 and
0162      *   thread_dispatch_disable_level == 0.
0163      *
0164      * Otherwise, continue with .Lthread_dispatch_done
0165      */
0166     movl      PER_CPU_DISPATCH_NEEDED(ebx), eax
0167     xorl      PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx), eax
0168     decl      PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx)
0169     orl       PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx), eax
0170     orl       PER_CPU_ISR_DISPATCH_DISABLE(ebx), eax
0171     decl      PER_CPU_ISR_NEST_LEVEL(ebx)  /* one less ISR nest level */
0172 
0173     cmpl      $0, eax
0174     jne       .Lthread_dispatch_done    /* Is task switch necessary? */
0175 
0176 .Ldo_thread_dispatch:
0177       /* Set ISR dispatch disable and thread dispatch disable level to one */
0178       movl    $1, PER_CPU_ISR_DISPATCH_DISABLE(ebx)
0179       movl    $1, PER_CPU_THREAD_DISPATCH_DISABLE_LEVEL(ebx)
0180       /* Call Thread_Do_dispatch(), this function will enable interrupts */
0181       push    $EFLAGS_INTR_ENABLE      /* Set interrupt flag manually */
0182       push    ebx
0183       call    _Thread_Do_dispatch
0184 
0185       /* Disable interrupts */
0186       cli
0187       addl    $8, esp
0188       /* Sometimes after returning from _Thread_Do_dispatch current CPU and ebx ptr are different */
0189       GET_SELF_CPU_CONTROL ebx
0190       cmpb    $0, PER_CPU_DISPATCH_NEEDED(ebx)
0191       jne     .Ldo_thread_dispatch
0192 
0193       /* We are done with thread dispatching */
0194       movl    $0, PER_CPU_ISR_DISPATCH_DISABLE(ebx)
0195      /*
0196       * fall through Lthread_dispatch_done to restore complete contex (scratch registers
0197       * eip, CS, Flags).
0198       */
0199 .Lthread_dispatch_done:
0200 
0201 #ifdef __SSE__
0202     fwait
0203     fxrstor   SSE_OFF(esp)
0204 #endif
0205 
0206     /* restore ebx, ebp and original esp */
0207     addl      $EBX_OFF, esp
0208     popl      ebx
0209     popl      ebp
0210     popl      esp
0211 
0212     /*
0213      * BEGINNING OF DE-ESTABLISH SEGMENTS
0214      *
0215      *  NOTE:  Make sure there is code here if code is added to
0216      *         load the segment registers.
0217      *
0218      */
0219 
0220     /******* DE-ESTABLISH SEGMENTS CODE GOES HERE ********/
0221 
0222     /*
0223      * END OF DE-ESTABLISH SEGMENTS
0224      */
0225     popl      edx
0226     popl      ecx
0227     popl      eax
0228     iret
0229 
0230 #define DISTINCT_INTERRUPT_ENTRY(_vector) \
0231     .p2align 4                         ; \
0232     PUBLIC (rtems_irq_prologue_ ## _vector ) ; \
0233 SYM (rtems_irq_prologue_ ## _vector ):             \
0234     pushl     eax                ; \
0235     pushl     ecx                ; \
0236     pushl     edx                ; \
0237     movl      $ _vector, ecx     ; \
0238     jmp       SYM (_ISR_Handler) ;
0239 
0240 DISTINCT_INTERRUPT_ENTRY(0)
0241 DISTINCT_INTERRUPT_ENTRY(1)
0242 DISTINCT_INTERRUPT_ENTRY(2)
0243 DISTINCT_INTERRUPT_ENTRY(3)
0244 DISTINCT_INTERRUPT_ENTRY(4)
0245 DISTINCT_INTERRUPT_ENTRY(5)
0246 DISTINCT_INTERRUPT_ENTRY(6)
0247 DISTINCT_INTERRUPT_ENTRY(7)
0248 DISTINCT_INTERRUPT_ENTRY(8)
0249 DISTINCT_INTERRUPT_ENTRY(9)
0250 DISTINCT_INTERRUPT_ENTRY(10)
0251 DISTINCT_INTERRUPT_ENTRY(11)
0252 DISTINCT_INTERRUPT_ENTRY(12)
0253 DISTINCT_INTERRUPT_ENTRY(13)
0254 DISTINCT_INTERRUPT_ENTRY(14)
0255 DISTINCT_INTERRUPT_ENTRY(15)
0256 DISTINCT_INTERRUPT_ENTRY(16)
0257 
0258     /*
0259      * routine used to initialize the IDT by default
0260      */
0261 
0262 PUBLIC (default_raw_idt_handler)
0263 PUBLIC (raw_idt_notify)
0264 
0265 SYM (default_raw_idt_handler):
0266     pusha
0267     cld
0268     mov       esp, ebp
0269     andl     $ - CPU_STACK_ALIGNMENT, esp
0270     call      raw_idt_notify
0271     mov       ebp, esp
0272     popa
0273     iret
0274 
0275 END_CODE
0276 
0277 END