The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/apic_ipl.s

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1997, by Steve Passe
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. The name of the developer may NOT be used to endorse or promote products
   11  *    derived from this software without specific prior written permission.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  *
   25  * $FreeBSD$
   26  */
   27 
   28 
   29         .data
   30         ALIGN_DATA
   31 
   32 /* current INTerrupt level */
   33         .globl  _cil
   34 _cil:   .long   0
   35 
   36 /* current INTerrupt level mask */
   37         .globl  _cml
   38 _cml:   .long   0
   39 
   40 
   41 /*
   42  * Routines used by splz_unpend to build an interrupt frame from a
   43  * trap frame.  The _vec[] routines build the proper frame on the stack,
   44  * then call one of _Xintr0 thru _XintrNN.
   45  *
   46  * used by:
   47  *   i386/isa/apic_ipl.s (this file):   splz_unpend JUMPs to HWIs.
   48  *   i386/isa/clock.c:                  setup _vec[clock] to point at _vec8254.
   49  */
   50         .globl _vec
   51 _vec:
   52         .long    vec0,  vec1,  vec2,  vec3,  vec4,  vec5,  vec6,  vec7
   53         .long    vec8,  vec9, vec10, vec11, vec12, vec13, vec14, vec15
   54         .long   vec16, vec17, vec18, vec19, vec20, vec21, vec22, vec23
   55 
   56 /*
   57  * Note:
   58  *      This is the UP equivilant of _imen.
   59  *      It is OPAQUE, and must NOT be accessed directly.
   60  *      It MUST be accessed along with the IO APIC as a 'critical region'.
   61  *      Accessed by:
   62  *              INTREN()
   63  *              INTRDIS()
   64  *              MAYBE_MASK_IRQ
   65  *              MAYBE_UNMASK_IRQ
   66  *              imen_dump()
   67  */
   68         .align 2                                /* MUST be 32bit aligned */
   69         .globl _apic_imen
   70 _apic_imen:
   71         .long   HWI_MASK
   72 
   73 
   74 /*
   75  * 
   76  */
   77         .text
   78         SUPERALIGN_TEXT
   79 
   80 /*
   81  * Interrupt priority mechanism
   82  *      -- soft splXX masks with group mechanism (cpl)
   83  *      -- h/w masks for currently active or unused interrupts (imen)
   84  *      -- ipending = active interrupts currently masked by cpl
   85  */
   86 
   87 ENTRY(splz)
   88         /*
   89          * The caller has restored cpl and checked that (ipending & ~cpl)
   90          * is nonzero.  We have to repeat the check since if there is an
   91          * interrupt while we're looking, _doreti processing for the
   92          * interrupt will handle all the unmasked pending interrupts
   93          * because we restored early.  We're repeating the calculation
   94          * of (ipending & ~cpl) anyway so that the caller doesn't have
   95          * to pass it, so this only costs one "jne".  "bsfl %ecx,%ecx"
   96          * is undefined when %ecx is 0 so we can't rely on the secondary
   97          * btrl tests.
   98          */
   99         AICPL_LOCK
  100         movl    _cpl,%eax
  101 #ifdef CPL_AND_CML
  102         orl     _cml, %eax              /* add cml to cpl */
  103 #endif
  104 splz_next:
  105         /*
  106          * We don't need any locking here.  (ipending & ~cpl) cannot grow 
  107          * while we're looking at it - any interrupt will shrink it to 0.
  108          */
  109         movl    %eax,%ecx
  110         notl    %ecx                    /* set bit = unmasked level */
  111         andl    _ipending,%ecx          /* set bit = unmasked pending INT */
  112         jne     splz_unpend
  113         AICPL_UNLOCK
  114         ret
  115 
  116         ALIGN_TEXT
  117 splz_unpend:
  118         bsfl    %ecx,%ecx
  119         btrl    %ecx,_ipending
  120         jnc     splz_next
  121         cmpl    $NHWI,%ecx
  122         jae     splz_swi
  123         /*
  124          * We would prefer to call the intr handler directly here but that
  125          * doesn't work for badly behaved handlers that want the interrupt
  126          * frame.  Also, there's a problem determining the unit number.
  127          * We should change the interface so that the unit number is not
  128          * determined at config time.
  129          *
  130          * The vec[] routines build the proper frame on the stack,
  131          * then call one of _Xintr0 thru _XintrNN.
  132          */
  133         pushl   %ecx
  134         AICPL_UNLOCK
  135         popl    %ecx
  136         jmp     *_vec(,%ecx,4)
  137 
  138         ALIGN_TEXT
  139 splz_swi:
  140         cmpl    $SWI_AST,%ecx
  141         je      splz_next               /* "can't happen" */
  142         pushl   %eax
  143         orl     imasks(,%ecx,4),%eax
  144         movl    %eax,_cpl
  145         pushl   %ecx
  146         AICPL_UNLOCK
  147         popl    %ecx
  148         call    *_ihandlers(,%ecx,4)
  149         AICPL_LOCK
  150         popl    %eax
  151         movl    %eax,_cpl
  152         jmp     splz_next
  153 
  154 /*
  155  * Fake clock interrupt(s) so that they appear to come from our caller instead
  156  * of from here, so that system profiling works.
  157  * XXX do this more generally (for all vectors; look up the C entry point).
  158  * XXX frame bogusness stops us from just jumping to the C entry point.
  159  * We have to clear iactive since this is an unpend call, and it will be
  160  * set from the time of the original INT.
  161  */
  162 
  163 /*
  164  * The 'generic' vector stubs.
  165  */
  166 
  167 #define BUILD_VEC(irq_num)                                              \
  168         ALIGN_TEXT ;                                                    \
  169 __CONCAT(vec,irq_num): ;                                                \
  170         popl    %eax ;                                                  \
  171         pushfl ;                                                        \
  172         pushl   $KCSEL ;                                                \
  173         pushl   %eax ;                                                  \
  174         cli ;                                                           \
  175         lock ;                                  /* MP-safe */           \
  176         andl    $~IRQ_BIT(irq_num), iactive ;   /* lazy masking */      \
  177         MEXITCOUNT ;                                                    \
  178         APIC_ITRACE(apic_itrace_splz, irq_num, APIC_ITRACE_SPLZ) ;      \
  179         jmp     __CONCAT(_Xintr,irq_num)
  180 
  181 
  182         BUILD_VEC(0)
  183         BUILD_VEC(1)
  184         BUILD_VEC(2)
  185         BUILD_VEC(3)
  186         BUILD_VEC(4)
  187         BUILD_VEC(5)
  188         BUILD_VEC(6)
  189         BUILD_VEC(7)
  190         BUILD_VEC(8)
  191         BUILD_VEC(9)
  192         BUILD_VEC(10)
  193         BUILD_VEC(11)
  194         BUILD_VEC(12)
  195         BUILD_VEC(13)
  196         BUILD_VEC(14)
  197         BUILD_VEC(15)
  198         BUILD_VEC(16)                   /* 8 additional INTs in IO APIC */
  199         BUILD_VEC(17)
  200         BUILD_VEC(18)
  201         BUILD_VEC(19)
  202         BUILD_VEC(20)
  203         BUILD_VEC(21)
  204         BUILD_VEC(22)
  205         BUILD_VEC(23)
  206 
  207 
  208 /******************************************************************************
  209  * XXX FIXME: figure out where these belong.
  210  */
  211 
  212 /* this nonsense is to verify that masks ALWAYS have 1 and only 1 bit set */
  213 #define QUALIFY_MASKS_NOT
  214 
  215 #ifdef QUALIFY_MASKS
  216 #define QUALIFY_MASK            \
  217         btrl    %ecx, %eax ;    \
  218         andl    %eax, %eax ;    \
  219         jz      1f ;            \
  220         pushl   $bad_mask ;     \
  221         call    _panic ;        \
  222 1:
  223 
  224 bad_mask:       .asciz  "bad mask"
  225 #else
  226 #define QUALIFY_MASK
  227 #endif
  228 
  229 /*
  230  * (soon to be) MP-safe function to clear ONE INT mask bit.
  231  * The passed arg is a 32bit u_int MASK.
  232  * It sets the associated bit in _apic_imen.
  233  * It sets the mask bit of the associated IO APIC register.
  234  */
  235 ENTRY(INTREN)
  236         pushfl                          /* save state of EI flag */
  237         cli                             /* prevent recursion */
  238         IMASK_LOCK                      /* enter critical reg */
  239 
  240         movl    8(%esp), %eax           /* mask into %eax */
  241         bsfl    %eax, %ecx              /* get pin index */
  242         btrl    %ecx, _apic_imen        /* update _apic_imen */
  243 
  244         QUALIFY_MASK
  245 
  246         shll    $4, %ecx
  247         movl    CNAME(int_to_apicintpin) + 8(%ecx), %edx
  248         movl    CNAME(int_to_apicintpin) + 12(%ecx), %ecx
  249 
  250         movl    %ecx, (%edx)            /* write the target register index */
  251         movl    16(%edx), %eax          /* read the target register data */
  252         andl    $~IOART_INTMASK, %eax   /* clear mask bit */
  253         movl    %eax, 16(%edx)          /* write the APIC register data */
  254 
  255         IMASK_UNLOCK                    /* exit critical reg */
  256         popfl                           /* restore old state of EI flag */
  257         ret
  258 
  259 /*
  260  * (soon to be) MP-safe function to set ONE INT mask bit.
  261  * The passed arg is a 32bit u_int MASK.
  262  * It clears the associated bit in _apic_imen.
  263  * It clears the mask bit of the associated IO APIC register.
  264  */
  265 ENTRY(INTRDIS)
  266         pushfl                          /* save state of EI flag */
  267         cli                             /* prevent recursion */
  268         IMASK_LOCK                      /* enter critical reg */
  269 
  270         movl    8(%esp), %eax           /* mask into %eax */
  271         bsfl    %eax, %ecx              /* get pin index */
  272         btsl    %ecx, _apic_imen        /* update _apic_imen */
  273 
  274         QUALIFY_MASK
  275 
  276         shll    $4, %ecx
  277         movl    CNAME(int_to_apicintpin) + 8(%ecx), %edx
  278         movl    CNAME(int_to_apicintpin) + 12(%ecx), %ecx
  279 
  280         movl    %ecx, (%edx)            /* write the target register index */
  281         movl    16(%edx), %eax          /* read the target register data */
  282         orl     $IOART_INTMASK, %eax    /* set mask bit */
  283         movl    %eax, 16(%edx)          /* write the APIC register data */
  284 
  285         IMASK_UNLOCK                    /* exit critical reg */
  286         popfl                           /* restore old state of EI flag */
  287         ret
  288 
  289 
  290 /******************************************************************************
  291  *
  292  */
  293 
  294 
  295 /*
  296  * void write_ioapic_mask(int apic, u_int mask); 
  297  */
  298 
  299 #define _INT_MASK       0x00010000
  300 #define _PIN_MASK       0x00ffffff
  301 
  302 #define _OLD_ESI          0(%esp)
  303 #define _OLD_EBX          4(%esp)
  304 #define _RETADDR          8(%esp)
  305 #define _APIC            12(%esp)
  306 #define _MASK            16(%esp)
  307 
  308         .align 2
  309 write_ioapic_mask:
  310         pushl %ebx                      /* scratch */
  311         pushl %esi                      /* scratch */
  312 
  313         movl    _apic_imen, %ebx
  314         xorl    _MASK, %ebx             /* %ebx = _apic_imen ^ mask */
  315         andl    $_PIN_MASK, %ebx        /* %ebx = _apic_imen & 0x00ffffff */
  316         jz      all_done                /* no change, return */
  317 
  318         movl    _APIC, %esi             /* APIC # */
  319         movl    _ioapic(,%esi,4), %esi  /* %esi holds APIC base address */
  320 
  321 next_loop:                              /* %ebx = diffs, %esi = APIC base */
  322         bsfl    %ebx, %ecx              /* %ecx = index if 1st/next set bit */
  323         jz      all_done
  324 
  325         btrl    %ecx, %ebx              /* clear this bit in diffs */
  326         leal    16(,%ecx,2), %edx       /* calculate register index */
  327 
  328         movl    %edx, (%esi)            /* write the target register index */
  329         movl    16(%esi), %eax          /* read the target register data */
  330 
  331         btl     %ecx, _MASK             /* test for mask or unmask */
  332         jnc     clear                   /* bit is clear */
  333         orl     $_INT_MASK, %eax        /* set mask bit */
  334         jmp     write
  335 clear:  andl    $~_INT_MASK, %eax       /* clear mask bit */
  336 
  337 write:  movl    %eax, 16(%esi)          /* write the APIC register data */
  338 
  339         jmp     next_loop               /* try another pass */
  340 
  341 all_done:
  342         popl    %esi
  343         popl    %ebx
  344         ret
  345 
  346 #undef _OLD_ESI
  347 #undef _OLD_EBX
  348 #undef _RETADDR
  349 #undef _APIC
  350 #undef _MASK
  351 
  352 #undef _PIN_MASK
  353 #undef _INT_MASK
  354 
  355 #ifdef oldcode
  356 
  357 _INTREN:
  358         movl _apic_imen, %eax
  359         notl %eax                       /* mask = ~mask */
  360         andl _apic_imen, %eax           /* %eax = _apic_imen & ~mask */
  361 
  362         pushl %eax                      /* new (future) _apic_imen value */
  363         pushl $0                        /* APIC# arg */
  364         call write_ioapic_mask          /* modify the APIC registers */
  365 
  366         addl $4, %esp                   /* remove APIC# arg from stack */
  367         popl _apic_imen                 /* _apic_imen |= mask */
  368         ret
  369 
  370 _INTRDIS:
  371         movl _apic_imen, %eax
  372         orl 4(%esp), %eax               /* %eax = _apic_imen | mask */
  373 
  374         pushl %eax                      /* new (future) _apic_imen value */
  375         pushl $0                        /* APIC# arg */
  376         call write_ioapic_mask          /* modify the APIC registers */
  377 
  378         addl $4, %esp                   /* remove APIC# arg from stack */
  379         popl _apic_imen                 /* _apic_imen |= mask */
  380         ret
  381 
  382 #endif /* oldcode */
  383 
  384 
  385 #ifdef ready
  386 
  387 /*
  388  * u_int read_io_apic_mask(int apic); 
  389  */
  390         ALIGN_TEXT
  391 read_io_apic_mask:
  392         ret
  393 
  394 /*
  395  * Set INT mask bit for each bit set in 'mask'.
  396  * Ignore INT mask bit for all others.
  397  *
  398  * void set_io_apic_mask(apic, u_int32_t bits); 
  399  */
  400         ALIGN_TEXT
  401 set_io_apic_mask:
  402         ret
  403 
  404 /*
  405  * void set_ioapic_maskbit(int apic, int bit); 
  406  */
  407         ALIGN_TEXT
  408 set_ioapic_maskbit:
  409         ret
  410 
  411 /*
  412  * Clear INT mask bit for each bit set in 'mask'.
  413  * Ignore INT mask bit for all others.
  414  *
  415  * void clr_io_apic_mask(int apic, u_int32_t bits); 
  416  */
  417         ALIGN_TEXT
  418 clr_io_apic_mask:
  419         ret
  420 
  421 /*
  422  * void clr_ioapic_maskbit(int apic, int bit); 
  423  */
  424         ALIGN_TEXT
  425 clr_ioapic_maskbit:
  426         ret
  427 
  428 #endif /** ready */
  429 
  430 /******************************************************************************
  431  * 
  432  */
  433 
  434 /*
  435  * u_int io_apic_write(int apic, int select);
  436  */
  437 ENTRY(io_apic_read)
  438         movl    4(%esp), %ecx           /* APIC # */
  439         movl    _ioapic(,%ecx,4), %edx  /* APIC base register address */
  440         movl    8(%esp), %eax           /* target register index */
  441         movl    %eax, (%edx)            /* write the target register index */
  442         movl    16(%edx), %eax          /* read the APIC register data */
  443         ret                             /* %eax = register value */
  444 
  445 /*
  446  * void io_apic_write(int apic, int select, int value);
  447  */
  448 ENTRY(io_apic_write)
  449         movl    4(%esp), %ecx           /* APIC # */
  450         movl    _ioapic(,%ecx,4), %edx  /* APIC base register address */
  451         movl    8(%esp), %eax           /* target register index */
  452         movl    %eax, (%edx)            /* write the target register index */
  453         movl    12(%esp), %eax          /* target register value */
  454         movl    %eax, 16(%edx)          /* write the APIC register data */
  455         ret                             /* %eax = void */
  456 
  457 /*
  458  * Send an EOI to the local APIC.
  459  */
  460 ENTRY(apic_eoi)
  461         movl    $0, _lapic+0xb0
  462         ret

Cache object: a87d43057758836c7cd5c1723772f62f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.