root/arch/i386/i386/vector.s

/* [<][>][^][v][top][bottom][index][help] */
    1 /*      $OpenBSD: vector.s,v 1.10 2007/04/12 20:22:58 art Exp $ */
    2 /*      $NetBSD: vector.s,v 1.32 1996/01/07 21:29:47 mycroft Exp $      */
    3 
    4 /*
    5  * Copyright (c) 1993, 1994, 1995 Charles M. Hannum.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *      notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *      notice, this list of conditions and the following disclaimer in the
   14  *      documentation and/or other materials provided with the distribution.
   15  * 3. All advertising materials mentioning features or use of this software
   16  *      must display the following acknowledgement:
   17  *      This product includes software developed by Charles M. Hannum.
   18  * 4. The name of the author may not be used to endorse or promote products
   19  *      derived from this software without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   31  */
   32 
   33 #include <machine/i8259.h>
   34 #include <dev/isa/isareg.h>
   35 
   36 #define MY_COUNT _C_LABEL(uvmexp)
   37 
   38 /*
   39  * Macros for interrupt entry, call to handler, and exit.
   40  *
   41  * XXX
   42  * The interrupt frame is set up to look like a trap frame.  This may be a
   43  * waste.  The only handler which needs a frame is the clock handler, and it
   44  * only needs a few bits.  Xdoreti() needs a trap frame for handling ASTs, but
   45  * it could easily convert the frame on demand.
   46  *
   47  * The direct costs of setting up a trap frame are two pushl's (error code and
   48  * trap number), an addl to get rid of these, and pushing and popping the
   49  * callee-saved registers %esi, %edi, %ebx, and %ebp twice.
   50  *
   51  * If the interrupt frame is made more flexible,  INTR can push %eax first and
   52  * decide the ipending case with less overhead, e.g., by avoiding loading the
   53  * segment registers.
   54  *
   55  * XXX
   56  * Should we do a cld on every system entry to avoid the requirement for
   57  * scattered cld's?
   58  */
   59 
   60         .globl  _C_LABEL(isa_strayintr)
   61 
   62 #ifdef MULTIPROCESSOR
   63 #define LOCK_KERNEL(ipl)        pushl ipl; call _C_LABEL(i386_intlock); addl $4,%esp
   64 #define UNLOCK_KERNEL(ipl)      pushl ipl; call _C_LABEL(i386_intunlock); addl $4,%esp
   65 #else
   66 #define LOCK_KERNEL(ipl)
   67 #define UNLOCK_KERNEL(ipl)
   68 #endif
   69 
   70 #define voidop(num)
   71 
   72 /*
   73  * Normal vectors.
   74  *
   75  * We cdr down the intrhand chain, calling each handler with its appropriate
   76  * argument (0 meaning a pointer to the frame, for clock interrupts).
   77  *
   78  * The handler returns one of three values:
   79  *   0 - This interrupt wasn't for me.
   80  *   1 - This interrupt was for me.
   81  *  -1 - This interrupt might have been for me, but I don't know.
   82  * If there are no handlers, or they all return 0, we flag it as a `stray'
   83  * interrupt.  On a system with level-triggered interrupts, we could terminate
   84  * immediately when one of them returns 1; but this is a PC.
   85  *
   86  * On exit, we jump to Xdoreti(), to process soft interrupts and ASTs.
   87  */
   88 #define INTRSTUB(name, num, early_ack, late_ack, mask, unmask, level_mask) \
   89 IDTVEC(resume_/**/name/**/num)                                          ;\
   90         push    %ebx                                                    ;\
   91         cli                                                             ;\
   92         jmp     1f                                                      ;\
   93 IDTVEC(recurse_/**/name/**/num)                                         ;\
   94         pushfl                                                          ;\
   95         pushl   %cs                                                     ;\
   96         pushl   %esi                                                    ;\
   97         pushl   $0                      /* dummy error code */          ;\
   98         pushl   $T_ASTFLT               /* trap # for doing ASTs */     ;\
   99         movl    %ebx,%esi                                               ;\
  100         INTRENTRY                                                       ;\
  101         MAKE_FRAME                                                      ;\
  102         push    %esi                                                    ;\
  103         cli                                                             ;\
  104         jmp     1f                                                      ;\
  105 _C_LABEL(Xintr_/**/name/**/num):                                        ;\
  106         pushl   $0                      /* dummy error code */          ;\
  107         pushl   $T_ASTFLT               /* trap # for doing ASTs */     ;\
  108         INTRENTRY                                                       ;\
  109         MAKE_FRAME                                                      ;\
  110         mask(num)                       /* mask it in hardware */       ;\
  111         early_ack(num)                  /* and allow other intrs */     ;\
  112         incl    MY_COUNT+V_INTR         /* statistical info */          ;\
  113         movl    _C_LABEL(iminlevel) + (num) * 4, %eax                   ;\
  114         movl    CPL,%ebx                                                ;\
  115         cmpl    %eax,%ebx                                               ;\
  116         jae     _C_LABEL(Xhold_/**/name/**/num)/* currently masked; hold it */;\
  117         pushl   %ebx                    /* cpl to restore on exit */    ;\
  118 1:                                                                      ;\
  119         movl    _C_LABEL(imaxlevel) + (num) * 4,%eax                    ;\
  120         movl    %eax,CPL                /* block enough for this irq */ ;\
  121         sti                             /* safe to take intrs now */    ;\
  122         movl    _C_LABEL(intrhand) + (num) * 4,%ebx     /* head of chain */ ;\
  123         testl   %ebx,%ebx                                               ;\
  124         jz      _C_LABEL(Xstray_/**/name/**/num)        /* no handlers; we're stray */  ;\
  125         STRAY_INITIALIZE                /* nobody claimed it yet */     ;\
  126         LOCK_KERNEL(IF_PPL(%esp))                                       ;\
  127 7:      movl    IH_ARG(%ebx),%eax       /* get handler arg */           ;\
  128         testl   %eax,%eax                                               ;\
  129         jnz     4f                                                      ;\
  130         movl    %esp,%eax               /* 0 means frame pointer */     ;\
  131 4:      pushl   %eax                                                    ;\
  132         call    *IH_FUN(%ebx)           /* call it */                   ;\
  133         addl    $4,%esp                 /* toss the arg */              ;\
  134         STRAY_INTEGRATE                 /* maybe he claimed it */       ;\
  135         orl     %eax,%eax               /* should it be counted? */     ;\
  136         jz      5f                      /* no, skip it */               ;\
  137         addl    $1,IH_COUNT(%ebx)       /* count the intrs */           ;\
  138         adcl    $0,IH_COUNT+4(%ebx)                                     ;\
  139 5:      movl    IH_NEXT(%ebx),%ebx      /* next handler in chain */     ;\
  140         testl   %ebx,%ebx                                               ;\
  141         jnz     7b                                                      ;\
  142         UNLOCK_KERNEL(IF_PPL(%esp))                                     ;\
  143         STRAY_TEST(name,num)            /* see if it's a stray */       ;\
  144 6:      unmask(num)                     /* unmask it in hardware */     ;\
  145         late_ack(num)                                                   ;\
  146         jmp     _C_LABEL(Xdoreti)       /* lower spl and do ASTs */     ;\
  147 IDTVEC(stray_/**/name/**/num)                                           ;\
  148         pushl   $num                                                    ;\
  149         call    _C_LABEL(isa_strayintr)                                 ;\
  150         addl    $4,%esp                                                 ;\
  151         jmp     6b                                                      ;\
  152 IDTVEC(hold_/**/name/**/num)                                            ;\
  153         orb     $IRQ_BIT(num),_C_LABEL(ipending) + IRQ_BYTE(num)        ;\
  154         INTRFASTEXIT
  155 
  156 #if defined(DEBUG)
  157 #define STRAY_INITIALIZE \
  158         xorl    %esi,%esi
  159 #define STRAY_INTEGRATE \
  160         orl     %eax,%esi
  161 #define STRAY_TEST(name,num) \
  162         testl   %esi,%esi                                               ;\
  163         jz      _C_LABEL(Xstray_/**/name/**/num)
  164 #else /* !DEBUG */
  165 #define STRAY_INITIALIZE
  166 #define STRAY_INTEGRATE
  167 #define STRAY_TEST(name,num)
  168 #endif /* DEBUG */
  169 
  170 #ifdef DDB
  171 #define MAKE_FRAME \
  172         leal    -8(%esp),%ebp
  173 #else /* !DDB */
  174 #define MAKE_FRAME
  175 #endif /* DDB */
  176 
  177 #define ICUADDR IO_ICU1
  178 
  179 INTRSTUB(legacy,0, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
  180     voidop)
  181 INTRSTUB(legacy,1, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
  182     voidop)
  183 INTRSTUB(legacy,2, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
  184     voidop)
  185 INTRSTUB(legacy,3, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
  186     voidop)
  187 INTRSTUB(legacy,4, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
  188     voidop)
  189 INTRSTUB(legacy,5, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
  190     voidop)
  191 INTRSTUB(legacy,6, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
  192     voidop)
  193 INTRSTUB(legacy,7, i8259_asm_ack1, voidop, i8259_asm_mask, i8259_asm_unmask,
  194     voidop)
  195 
  196 #undef ICUADDR
  197 #define ICUADDR IO_ICU2
  198 
  199 INTRSTUB(legacy,8, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
  200     voidop)
  201 INTRSTUB(legacy,9, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
  202     voidop)
  203 INTRSTUB(legacy,10, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
  204     voidop)
  205 INTRSTUB(legacy,11, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
  206     voidop)
  207 INTRSTUB(legacy,12, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
  208     voidop)
  209 INTRSTUB(legacy,13, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
  210     voidop)
  211 INTRSTUB(legacy,14, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
  212     voidop)
  213 INTRSTUB(legacy,15, i8259_asm_ack2, voidop, i8259_asm_mask, i8259_asm_unmask,
  214     voidop)
  215 
  216 /*
  217  * These tables are used by the ISA configuration code.
  218  */
  219 /* interrupt service routine entry points */
  220 IDTVEC(intr)
  221         .long   _C_LABEL(Xintr_legacy0), _C_LABEL(Xintr_legacy1)
  222         .long   _C_LABEL(Xintr_legacy2), _C_LABEL(Xintr_legacy3)
  223         .long   _C_LABEL(Xintr_legacy4), _C_LABEL(Xintr_legacy5)
  224         .long   _C_LABEL(Xintr_legacy6), _C_LABEL(Xintr_legacy7)
  225         .long   _C_LABEL(Xintr_legacy8), _C_LABEL(Xintr_legacy9)
  226         .long   _C_LABEL(Xintr_legacy10), _C_LABEL(Xintr_legacy11)
  227         .long   _C_LABEL(Xintr_legacy12), _C_LABEL(Xintr_legacy13)
  228         .long   _C_LABEL(Xintr_legacy14), _C_LABEL(Xintr_legacy15)
  229 
  230 /*
  231  * These tables are used by Xdoreti() and Xspllower().
  232  */
  233 /* resume points for suspended interrupts */
  234 IDTVEC(resume)
  235         .long   _C_LABEL(Xresume_legacy0), _C_LABEL(Xresume_legacy1)
  236         .long   _C_LABEL(Xresume_legacy2), _C_LABEL(Xresume_legacy3)
  237         .long   _C_LABEL(Xresume_legacy4), _C_LABEL(Xresume_legacy5)
  238         .long   _C_LABEL(Xresume_legacy6), _C_LABEL(Xresume_legacy7)
  239         .long   _C_LABEL(Xresume_legacy8), _C_LABEL(Xresume_legacy9)
  240         .long   _C_LABEL(Xresume_legacy10), _C_LABEL(Xresume_legacy11)
  241         .long   _C_LABEL(Xresume_legacy12), _C_LABEL(Xresume_legacy13)
  242         .long   _C_LABEL(Xresume_legacy14), _C_LABEL(Xresume_legacy15)
  243         /* for soft interrupts */
  244         .long   0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  245         .long   _C_LABEL(Xsoftast), _C_LABEL(Xsofttty) 
  246         .long   _C_LABEL(Xsoftnet), _C_LABEL(Xsoftclock)
  247         .long   0, 0
  248 /* fake interrupts to resume from splx() */
  249 IDTVEC(recurse)
  250         .long   _C_LABEL(Xrecurse_legacy0), _C_LABEL(Xrecurse_legacy1)
  251         .long   _C_LABEL(Xrecurse_legacy2), _C_LABEL(Xrecurse_legacy3)
  252         .long   _C_LABEL(Xrecurse_legacy4), _C_LABEL(Xrecurse_legacy5)
  253         .long   _C_LABEL(Xrecurse_legacy6), _C_LABEL(Xrecurse_legacy7)
  254         .long   _C_LABEL(Xrecurse_legacy8), _C_LABEL(Xrecurse_legacy9)
  255         .long   _C_LABEL(Xrecurse_legacy10), _C_LABEL(Xrecurse_legacy11)
  256         .long   _C_LABEL(Xrecurse_legacy12), _C_LABEL(Xrecurse_legacy13)
  257         .long   _C_LABEL(Xrecurse_legacy14), _C_LABEL(Xrecurse_legacy15)
  258         /* for soft interrupts */
  259         .long   0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  260         .long   _C_LABEL(Xsoftast), _C_LABEL(Xsofttty) 
  261         .long   _C_LABEL(Xsoftnet), _C_LABEL(Xsoftclock)
  262         .long   0, 0

/* [<][>][^][v][top][bottom][index][help] */