Annotation of Net2/arch/i386/isa/vector.s, revision 1.1.1.1

1.1       root        1: /* vector.s */
                      2: 
                      3: #include "i386/isa/icu.h"
                      4: #include "i386/isa/isa.h"
                      5: #include "vector.h"
                      6: 
                      7: #define        ICU_EOI                 0x20    /* XXX - define elsewhere */
                      8: 
                      9: #define        IRQ_BIT(irq_num)        (1 << ((irq_num) % 8))
                     10: #define        IRQ_BYTE(irq_num)       ((irq_num) / 8)
                     11: 
                     12: #ifndef AUTO_EOI_1
                     13: #define        ENABLE_ICU1 \
                     14:        movb    $ICU_EOI,%al ;  /* as soon as possible send EOI ... */ \
                     15:        FASTER_NOP ;            /* ... ASAP ... */ \
                     16:        outb    %al,$IO_ICU1    /* ... to clear in service bit */
                     17: #else /* AUTO_EOI_1 */
                     18: #define        ENABLE_ICU1             /* we now use auto-EOI to reduce i/o */
                     19: #endif
                     20: 
                     21: #ifndef AUTO_EOI_2
                     22: #define        ENABLE_ICU1_AND_2 \
                     23:        movb    $ICU_EOI,%al ;  /* as above */ \
                     24:        FASTER_NOP ; \
                     25:        outb    %al,$IO_ICU2 ;  /* but do second icu first */ \
                     26:        FASTER_NOP ; \
                     27:        outb    %al,$IO_ICU1    /* then first icu */
                     28: #else /* AUTO_EOI_2 */
                     29: #define        ENABLE_ICU1_AND_2       /* data sheet says no auto-EOI on slave ... */
                     30:                                /* ... but it sometimes works */
                     31: #endif
                     32: 
                     33: /*
                     34:  * Macros for interrupt interrupt entry, call to handler, and exit.
                     35:  *
                     36:  * XXX - the interrupt frame is set up to look like a trap frame.  This is
                     37:  * usually a waste of time.  The only interrupt handlers that want a frame
                     38:  * are the clock handler (it wants a clock frame), the npx handler (it's
                     39:  * easier to do right all in assembler).  The interrupt return routine
                     40:  * needs a trap frame for rare AST's (it could easily convert the frame).
                     41:  * The direct costs of setting up a trap frame are two pushl's (error
                     42:  * code and trap number), an addl to get rid of these, and pushing and
                     43:  * popping the call-saved regs %esi, %edi and %ebp twice,  The indirect
                     44:  * costs are making the driver interface nonuniform so unpending of
                     45:  * interrupts is more complicated and slower (call_driver(unit) would
                     46:  * be easier than ensuring an interrupt frame for all handlers.  Finally,
                     47:  * there are some struct copies in the npx handler and maybe in the clock
                     48:  * handler that could be avoided by working more with pointers to frames
                     49:  * instead of frames.
                     50:  *
                     51:  * XXX - should we do a cld on every system entry to avoid the requirement
                     52:  * for scattered cld's?
                     53:  *
                     54:  * Coding notes for *.s:
                     55:  *
                     56:  * If possible, avoid operations that involve an operand size override.
                     57:  * Word-sized operations might be smaller, but the operand size override
                     58:  * makes them slower on on 486's and no faster on 386's unless perhaps
                     59:  * the instruction pipeline is depleted.  E.g.,
                     60:  *
                     61:  *     Use movl to seg regs instead of the equivalent but more descriptive
                     62:  *     movw - gas generates an irelevant (slower) operand size override.
                     63:  *
                     64:  *     Use movl to ordinary regs in preference to movw and especially
                     65:  *     in preference to movz[bw]l.  Use unsigned (long) variables with the
                     66:  *     top bits clear instead of unsigned short variables to provide more
                     67:  *     opportunities for movl.
                     68:  *
                     69:  * If possible, use byte-sized operations.  They are smaller and no slower.
                     70:  *
                     71:  * Use (%reg) instead of 0(%reg) - gas generates larger code for the latter.
                     72:  *
                     73:  * If the interrupt frame is made more flexible,  INTR can push %eax first
                     74:  * and decide the ipending case with less overhead, e.g., by avoiding
                     75:  * loading segregs.
                     76:  */
                     77: 
                     78: #define        FAST_INTR(unit, irq_num, id_num, handler, enable_icus) \
                     79:        pushl   %eax ;          /* save only call-used registers */ \
                     80:        pushl   %ecx ; \
                     81:        pushl   %edx ; \
                     82:        pushl   %ds ; \
                     83:        pushl   %es ; \
                     84:        movl    $KDSEL,%eax ; \
                     85:        movl    %ax,%ds ; \
                     86:        movl    %ax,%es ; \
                     87:        SHOW_CLI ;              /* although it interferes with "ASAP" */ \
                     88:        pushl   $unit ; \
                     89:        call    handler ;       /* do the work ASAP */ \
                     90:        enable_icus ;           /* (re)enable ASAP (helps edge trigger?) */ \
                     91:        addl    $4,%esp ; \
                     92:        incl    _cnt+V_INTR ;   /* book-keeping can wait */ \
                     93:        COUNT_INTR(_intrcnt_actv, id_num) ; \
                     94:        SHOW_STI ; \
                     95:        popl    %es ; \
                     96:        popl    %ds ; \
                     97:        popl    %edx; \
                     98:        popl    %ecx; \
                     99:        popl    %eax; \
                    100:        iret
                    101: 
                    102: #define        INTR(unit, irq_num, id_num, mask, handler, icu, enable_icus, reg, stray) \
                    103:        pushl   $0 ;            /* dummy error code */ \
                    104:        pushl   $T_ASTFLT ; \
                    105:        pushal ; \
                    106:        pushl   %ds ;           /* save our data and extra segments ... */ \
                    107:        pushl   %es ; \
                    108:        movl    $KDSEL,%eax ;   /* ... and reload with kernel's own ... */ \
                    109:        movl    %ax,%ds ;       /* ... early in case SHOW_A_LOT is on */ \
                    110:        movl    %ax,%es ; \
                    111:        SHOW_CLI ;              /* interrupt did an implicit cli */ \
                    112:        movb    _imen + IRQ_BYTE(irq_num),%al ; \
                    113:        orb     $IRQ_BIT(irq_num),%al ; \
                    114:        movb    %al,_imen + IRQ_BYTE(irq_num) ; \
                    115:        SHOW_IMEN ; \
                    116:        FASTER_NOP ; \
                    117:        outb    %al,$icu+1 ; \
                    118:        enable_icus ; \
                    119:        incl    _cnt+V_INTR ;   /* tally interrupts */ \
                    120:        movl    _cpl,%eax ; \
                    121:        testb   $IRQ_BIT(irq_num),%reg ; \
                    122:        jne     2f ; \
                    123: 1: ; \
                    124:        COUNT_INTR(_intrcnt_actv, id_num) ; \
                    125:        movl    _cpl,%eax ; \
                    126:        pushl   %eax ; \
                    127:        pushl   $unit ; \
                    128:        orl     mask,%eax ; \
                    129:        movl    %eax,_cpl ; \
                    130:        SHOW_CPL ; \
                    131:        SHOW_STI ; \
                    132:        sti ; \
                    133:        call    handler ; \
                    134:        movb    _imen + IRQ_BYTE(irq_num),%al ; \
                    135:        andb    $~IRQ_BIT(irq_num),%al ; \
                    136:        movb    %al,_imen + IRQ_BYTE(irq_num) ; \
                    137:        SHOW_IMEN ; \
                    138:        FASTER_NOP ; \
                    139:        outb    %al,$icu+1 ; \
                    140:        jmp     doreti ; \
                    141: ; \
                    142:        ALIGN_TEXT ; \
                    143: 2: ; \
                    144:        COUNT_EVENT(_intrcnt_pend, id_num) ; \
                    145:        movl    $1b,%eax ;      /* register resume address */ \
                    146:                                /* XXX - someday do it at attach time */ \
                    147:        movl    %eax,Vresume + (irq_num) * 4 ;  \
                    148:        orb     $IRQ_BIT(irq_num),_ipending + IRQ_BYTE(irq_num) ; \
                    149:        SHOW_IPENDING ; \
                    150:        popl    %es ; \
                    151:        popl    %ds ; \
                    152:        popal ; \
                    153:        addl    $4+4,%esp ; \
                    154:        iret
                    155: 
                    156: /*
                    157:  * vector.h has defined a macro 'BUILD_VECTORS' containing a big list of info
                    158:  * about vectors, including a submacro 'BUILD_VECTOR' that operates on the
                    159:  * info about each vector.  We redefine 'BUILD_VECTOR' to expand the info
                    160:  * in different ways.  Here we expand it to a list of interrupt handlers.
                    161:  * This order is of course unimportant.  Elsewhere we expand it to inline
                    162:  * linear search code for which the order is a little more important and
                    163:  * concatenating the code with no holes is very important.
                    164:  *
                    165:  * XXX - now there is BUILD_FAST_VECTOR as well as BUILD_VECTOR.
                    166:  *
                    167:  * The info consists of the following items for each vector:
                    168:  *
                    169:  *     name (identifier):      name of the vector; used to build labels
                    170:  *     unit (expression):      unit number to call the device driver with
                    171:  *     irq_num (number):       number of the IRQ to handled (0-15)
                    172:  *     id_num (number):        uniq numeric id for handler (assigned by config)
                    173:  *     mask (blank-ident):     priority mask used
                    174:  *     handler (blank-ident):  interrupt handler to call
                    175:  *     icu_num (number):       (1 + irq_num / 8) converted for label building
                    176:  *     icu_enables (number):   1 for icu_num == 1, 1_AND_2 for icu_num == 2
                    177:  *     reg (blank-ident):      al for icu_num == 1, ah for icu_num == 2
                    178:  *
                    179:  * 'irq_num' is converted in several ways at config time to get around
                    180:  * limitations in cpp.  The macros have blanks after commas iff they would
                    181:  * not mess up identifiers and numbers.
                    182:  */
                    183: 
                    184: #undef BUILD_FAST_VECTOR
                    185: #define        BUILD_FAST_VECTOR(name, unit, irq_num, id_num, mask, handler, \
                    186:                          icu_num, icu_enables, reg) \
                    187:        .globl  handler ; \
                    188:        .text ; \
                    189:        .globl  _X/**/name ; \
                    190:        SUPERALIGN_TEXT ; \
                    191: _X/**/name: ; \
                    192:        FAST_INTR(unit, irq_num, id_num, handler, ENABLE_ICU/**/icu_enables)
                    193: 
                    194: #undef BUILD_VECTOR
                    195: #define        BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
                    196:                     icu_num, icu_enables, reg) \
                    197:        .globl  handler ; \
                    198:        .text ; \
                    199:        .globl  _X/**/name ; \
                    200:        SUPERALIGN_TEXT ; \
                    201: _X/**/name: ; \
                    202:        INTR(unit,irq_num,id_num, mask, handler, IO_ICU/**/icu_num, \
                    203:             ENABLE_ICU/**/icu_enables, reg,)
                    204: 
                    205:        BUILD_VECTORS
                    206: 
                    207:        /* hardware interrupt catcher (IDT 32 - 47) */
                    208:        .globl  _isa_strayintr
                    209: 
                    210: #define        STRAYINTR(irq_num, icu_num, icu_enables, reg) \
                    211: IDTVEC(intr/**/irq_num) ; \
                    212:        INTR(irq_num,irq_num,irq_num, _highmask,  _isa_strayintr, \
                    213:                  IO_ICU/**/icu_num, ENABLE_ICU/**/icu_enables, reg,stray)
                    214: 
                    215: /*
                    216:  * XXX - the mask (1 << 2) == IRQ_SLAVE will be generated for IRQ 2, instead
                    217:  * of the mask IRQ2 (defined as IRQ9 == (1 << 9)).  But IRQ 2 "can't happen".
                    218:  * In fact, all stray interrupts "can't happen" except for bugs.  The
                    219:  * "stray" IRQ 7 is documented behaviour of the 8259.  It happens when there
                    220:  * is a glitch on any of its interrupt inputs.  Does it really interrupt when
                    221:  * IRQ 7 is masked?
                    222:  *
                    223:  * XXX - unpend doesn't work for these, it sends them to the real handler.
                    224:  *
                    225:  * XXX - the race bug during initialization may be because I changed the
                    226:  * order of switching from the stray to the real interrupt handler to before
                    227:  * enabling interrupts.  The old order looked unsafe but maybe it is OK with
                    228:  * the stray interrupt handler installed.  But these handlers only reduce
                    229:  * the window of vulnerability - it is still open at the end of
                    230:  * isa_configure().
                    231:  *
                    232:  * XXX - many comments are stale.
                    233:  */
                    234: 
                    235:        STRAYINTR(0,1,1, al)
                    236:        STRAYINTR(1,1,1, al)
                    237:        STRAYINTR(2,1,1, al)
                    238:        STRAYINTR(3,1,1, al)
                    239:        STRAYINTR(4,1,1, al)
                    240:        STRAYINTR(5,1,1, al)
                    241:        STRAYINTR(6,1,1, al)
                    242:        STRAYINTR(8,2,1_AND_2, ah)
                    243:        STRAYINTR(9,2,1_AND_2, ah)
                    244:        STRAYINTR(10,2,1_AND_2, ah)
                    245:        STRAYINTR(11,2,1_AND_2, ah)
                    246:        STRAYINTR(12,2,1_AND_2, ah)
                    247:        STRAYINTR(13,2,1_AND_2, ah)
                    248:        STRAYINTR(14,2,1_AND_2, ah)
                    249:        STRAYINTR(15,2,1_AND_2, ah)
                    250: IDTVEC(intrdefault)
                    251:        STRAYINTR(7,1,1, al)    /* XXX */
                    252: #if 0
                    253:        INTRSTRAY(255, _highmask, 255) ; call   _isa_strayintr ; INTREXIT2
                    254: #endif
                    255: /*
                    256:  * These are the interrupt counters, I moved them here from icu.s so that
                    257:  * they are with the name table.  rgrimes
                    258:  *
                    259:  * There are now lots of counters, this has been redone to work with
                    260:  * Bruce Evans intr-0.1 code, which I modified some more to make it all
                    261:  * work with vmstat.
                    262:  */
                    263:        .data
                    264: Vresume:       .space  16 * 4  /* where to resume intr handler after unpend */
                    265:        .globl  _intrcnt
                    266: _intrcnt:                      /* used by vmstat to calc size of table */
                    267:        .globl  _intrcnt_bad7
                    268: _intrcnt_bad7: .space  4       /* glitches on irq 7 */
                    269:        .globl  _intrcnt_bad15
                    270: _intrcnt_bad15:        .space  4       /* glitches on irq 15 */
                    271:        .globl  _intrcnt_stray
                    272: _intrcnt_stray:        .space  4       /* total count of stray interrupts */
                    273:        .globl  _intrcnt_actv
                    274: _intrcnt_actv: .space  NR_REAL_INT_HANDLERS * 4        /* active interrupts */
                    275: 
                    276: #ifdef INTR_DEBUG
                    277:        .globl  _intrcnt_pend
                    278: _intrcnt_pend: .space  NR_REAL_INT_HANDLERS * 4        /* pending interrupts */
                    279:        .globl  _intrcnt_spl
                    280: _intrcnt_spl:  .space  32 * 4  /* XXX 32 should not be hard coded ? */
                    281:        .globl  _intrcnt_show
                    282: _intrcnt_show: .space  8 * 4   /* XXX 16 should not be hard coded ? */
                    283: #endif /* INTR_DEBUG */
                    284: 
                    285:        .globl  _eintrcnt
                    286: _eintrcnt:                     /* used by vmstat to calc size of table */
                    287: 
                    288: /*
                    289:  * Build the interrupt name table for vmstat
                    290:  */
                    291: 
                    292: #undef BUILD_FAST_VECTOR
                    293: #define BUILD_FAST_VECTOR      BUILD_VECTOR
                    294: 
                    295: #undef BUILD_VECTOR
                    296: #define        BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
                    297:                     icu_num, icu_enables, reg) \
                    298:        .ascii  "name irq" ; \
                    299:        .asciz  "irq_num"
                    300: /*
                    301:  * XXX - use the STRING and CONCAT macros from <sys/cdefs.h> to stringize
                    302:  * and concatenate names above and elsewhere.
                    303:  */
                    304: 
                    305:        .text
                    306:        .globl  _intrnames, _eintrnames
                    307: _intrnames:
                    308:        BUILD_VECTOR(bad,,7,,,,,,)
                    309:        BUILD_VECTOR(bad,,15,,,,,,)
                    310:        BUILD_VECTOR(stray,,,,,,,,)
                    311:        BUILD_VECTORS
                    312: 
                    313: #ifdef INTR_DEBUG
                    314: 
                    315: #undef BUILD_FAST_VECTOR
                    316: #define BUILD_FAST_VECTOR      BUILD_VECTOR
                    317: 
                    318: #undef BUILD_VECTOR
                    319: #define        BUILD_VECTOR(name, unit, irq_num, id_num, mask, handler, \
                    320:                     icu_num, icu_enables, reg) \
                    321:        .asciz  "name pend"
                    322: 
                    323:        BUILD_VECTORS
                    324: 
                    325: /*
                    326:  * now the spl names
                    327:  */
                    328:        .asciz  "unpend_v"
                    329:        .asciz  "doreti"
                    330:        .asciz  "p0!ni"
                    331:        .asciz  "!p0!ni"
                    332:        .asciz  "p0ni"
                    333:        .asciz  "netisr_raw"
                    334:        .asciz  "netisr_ip"
                    335:        .asciz  "netisr_imp"
                    336:        .asciz  "netisr_ns"
                    337:        .asciz  "softclock"
                    338:        .asciz  "trap"
                    339:        .asciz  "doreti_exit2"
                    340:        .asciz  "splbio"
                    341:        .asciz  "splclock"
                    342:        .asciz  "splhigh"
                    343:        .asciz  "splimp"
                    344:        .asciz  "splnet"
                    345:        .asciz  "splsoftclock"
                    346:        .asciz  "spltty"
                    347:        .asciz  "spl0"
                    348:        .asciz  "netisr_raw2"
                    349:        .asciz  "netisr_ip2"
                    350:        .asciz  "splx"
                    351:        .asciz  "splx!0"
                    352:        .asciz  "unpend_V"
                    353:        .asciz  "netisr_iso"
                    354:        .asciz  "netisr_imp2"
                    355:        .asciz  "netisr_ns2"
                    356:        .asciz  "netisr_iso2"
                    357:        .asciz  "spl29"         /* spl29-spl31 are spares */
                    358:        .asciz  "spl30"
                    359:        .asciz  "spl31"
                    360: /*
                    361:  * now the mask names
                    362:  */
                    363:        .asciz  "cli"
                    364:        .asciz  "cpl"
                    365:        .asciz  "imen"
                    366:        .asciz  "ipending"
                    367:        .asciz  "sti"
                    368:        .asciz  "mask5"         /* mask5-mask7 are spares */
                    369:        .asciz  "mask6"
                    370:        .asciz  "mask7"
                    371: #endif /* INTR_DEBUG */
                    372:        
                    373: _eintrnames:

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.