2 * Copyright (c) 1997, by Steve Passe
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
32 /* current INTerrupt level */
36 /* current INTerrupt level mask */
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.
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.
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
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'.
68 .p2align 2 /* MUST be 32bit aligned */
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
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
102 orl _cml, %eax /* add cml to cpl */
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.
110 notl %ecx /* set bit = unmasked level */
111 andl _ipending,%ecx /* set bit = unmasked pending INT */
125 * We would prefer to call the intr handler directly here but that
126 * doesn't work for badly behaved handlers that want the interrupt
127 * frame. Also, there's a problem determining the unit number.
128 * We should change the interface so that the unit number is not
129 * determined at config time.
131 * The vec[] routines build the proper frame on the stack,
132 * then call one of _Xintr0 thru _XintrNN.
142 orl imasks(,%ecx,4),%eax
147 call *_ihandlers(,%ecx,4)
154 * Fake clock interrupt(s) so that they appear to come from our caller instead
155 * of from here, so that system profiling works.
156 * XXX do this more generally (for all vectors; look up the C entry point).
157 * XXX frame bogusness stops us from just jumping to the C entry point.
158 * We have to clear iactive since this is an unpend call, and it will be
159 * set from the time of the original INT.
163 * The 'generic' vector stubs.
166 #define BUILD_VEC(irq_num) \
168 __CONCAT(vec,irq_num): ; \
174 lock ; /* MP-safe */ \
175 andl $~IRQ_BIT(irq_num), iactive ; /* lazy masking */ \
177 APIC_ITRACE(apic_itrace_splz, irq_num, APIC_ITRACE_SPLZ) ; \
178 jmp __CONCAT(_Xintr,irq_num)
197 BUILD_VEC(16) /* 8 additional INTs in IO APIC */
207 /******************************************************************************
208 * XXX FIXME: figure out where these belong.
211 /* this nonsense is to verify that masks ALWAYS have 1 and only 1 bit set */
212 #define QUALIFY_MASKS_NOT
215 #define QUALIFY_MASK \
223 bad_mask: .asciz "bad mask"
229 * (soon to be) MP-safe function to clear ONE INT mask bit.
230 * The passed arg is a 32bit u_int MASK.
231 * It sets the associated bit in _apic_imen.
232 * It sets the mask bit of the associated IO APIC register.
235 pushfl /* save state of EI flag */
236 cli /* prevent recursion */
237 IMASK_LOCK /* enter critical reg */
239 movl 8(%esp), %eax /* mask into %eax */
240 bsfl %eax, %ecx /* get pin index */
241 btrl %ecx, _apic_imen /* update _apic_imen */
246 movl CNAME(int_to_apicintpin) + 8(%ecx), %edx
247 movl CNAME(int_to_apicintpin) + 12(%ecx), %ecx
251 movl %ecx, (%edx) /* write the target register index */
252 movl 16(%edx), %eax /* read the target register data */
253 andl $~IOART_INTMASK, %eax /* clear mask bit */
254 movl %eax, 16(%edx) /* write the APIC register data */
256 IMASK_UNLOCK /* exit critical reg */
257 popfl /* restore old state of EI flag */
261 * (soon to be) MP-safe function to set ONE INT mask bit.
262 * The passed arg is a 32bit u_int MASK.
263 * It clears the associated bit in _apic_imen.
264 * It clears the mask bit of the associated IO APIC register.
267 pushfl /* save state of EI flag */
268 cli /* prevent recursion */
269 IMASK_LOCK /* enter critical reg */
271 movl 8(%esp), %eax /* mask into %eax */
272 bsfl %eax, %ecx /* get pin index */
273 btsl %ecx, _apic_imen /* update _apic_imen */
278 movl CNAME(int_to_apicintpin) + 8(%ecx), %edx
279 movl CNAME(int_to_apicintpin) + 12(%ecx), %ecx
283 movl %ecx, (%edx) /* write the target register index */
284 movl 16(%edx), %eax /* read the target register data */
285 orl $IOART_INTMASK, %eax /* set mask bit */
286 movl %eax, 16(%edx) /* write the APIC register data */
288 IMASK_UNLOCK /* exit critical reg */
289 popfl /* restore old state of EI flag */
293 /******************************************************************************
299 * void write_ioapic_mask(int apic, u_int mask);
302 #define _INT_MASK 0x00010000
303 #define _PIN_MASK 0x00ffffff
305 #define _OLD_ESI 0(%esp)
306 #define _OLD_EBX 4(%esp)
307 #define _RETADDR 8(%esp)
308 #define _APIC 12(%esp)
309 #define _MASK 16(%esp)
313 pushl %ebx /* scratch */
314 pushl %esi /* scratch */
316 movl _apic_imen, %ebx
317 xorl _MASK, %ebx /* %ebx = _apic_imen ^ mask */
318 andl $_PIN_MASK, %ebx /* %ebx = _apic_imen & 0x00ffffff */
319 jz all_done /* no change, return */
321 movl _APIC, %esi /* APIC # */
322 movl _ioapic(,%esi,4), %esi /* %esi holds APIC base address */
324 next_loop: /* %ebx = diffs, %esi = APIC base */
325 bsfl %ebx, %ecx /* %ecx = index if 1st/next set bit */
328 btrl %ecx, %ebx /* clear this bit in diffs */
329 leal 16(,%ecx,2), %edx /* calculate register index */
331 movl %edx, (%esi) /* write the target register index */
332 movl 16(%esi), %eax /* read the target register data */
334 btl %ecx, _MASK /* test for mask or unmask */
335 jnc clear /* bit is clear */
336 orl $_INT_MASK, %eax /* set mask bit */
338 clear: andl $~_INT_MASK, %eax /* clear mask bit */
340 write: movl %eax, 16(%esi) /* write the APIC register data */
342 jmp next_loop /* try another pass */
361 movl _apic_imen, %eax
362 notl %eax /* mask = ~mask */
363 andl _apic_imen, %eax /* %eax = _apic_imen & ~mask */
365 pushl %eax /* new (future) _apic_imen value */
366 pushl $0 /* APIC# arg */
367 call write_ioapic_mask /* modify the APIC registers */
369 addl $4, %esp /* remove APIC# arg from stack */
370 popl _apic_imen /* _apic_imen |= mask */
374 movl _apic_imen, %eax
375 orl 4(%esp), %eax /* %eax = _apic_imen | mask */
377 pushl %eax /* new (future) _apic_imen value */
378 pushl $0 /* APIC# arg */
379 call write_ioapic_mask /* modify the APIC registers */
381 addl $4, %esp /* remove APIC# arg from stack */
382 popl _apic_imen /* _apic_imen |= mask */
391 * u_int read_io_apic_mask(int apic);
398 * Set INT mask bit for each bit set in 'mask'.
399 * Ignore INT mask bit for all others.
401 * void set_io_apic_mask(apic, u_int32_t bits);
408 * void set_ioapic_maskbit(int apic, int bit);
415 * Clear INT mask bit for each bit set in 'mask'.
416 * Ignore INT mask bit for all others.
418 * void clr_io_apic_mask(int apic, u_int32_t bits);
425 * void clr_ioapic_maskbit(int apic, int bit);
433 /******************************************************************************
438 * u_int io_apic_write(int apic, int select);
441 movl 4(%esp), %ecx /* APIC # */
442 movl _ioapic(,%ecx,4), %edx /* APIC base register address */
443 movl 8(%esp), %eax /* target register index */
444 movl %eax, (%edx) /* write the target register index */
445 movl 16(%edx), %eax /* read the APIC register data */
446 ret /* %eax = register value */
449 * void io_apic_write(int apic, int select, int value);
452 movl 4(%esp), %ecx /* APIC # */
453 movl _ioapic(,%ecx,4), %edx /* APIC base register address */
454 movl 8(%esp), %eax /* target register index */
455 movl %eax, (%edx) /* write the target register index */
456 movl 12(%esp), %eax /* target register value */
457 movl %eax, 16(%edx) /* write the APIC register data */
458 ret /* %eax = void */
461 * Send an EOI to the local APIC.