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