|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.