|
|
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.