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
|