apic_vector.s revision 53425
1/*
2 *	from: vector.s, 386BSD 0.1 unknown origin
3 * $FreeBSD: head/sys/i386/i386/apic_vector.s 53425 1999-11-19 16:49:30Z dillon $
4 */
5
6
7#include <machine/apic.h>
8#include <machine/smp.h>
9
10#include "i386/isa/intr_machdep.h"
11
12
13#ifdef FAST_SIMPLELOCK
14
15#define GET_FAST_INTR_LOCK						\
16	pushl	$_fast_intr_lock ;		/* address of lock */	\
17	call	_s_lock ;			/* MP-safe */		\
18	addl	$4,%esp
19
20#define REL_FAST_INTR_LOCK						\
21	movl	$0, _fast_intr_lock
22
23#else /* FAST_SIMPLELOCK */
24
25#define GET_FAST_INTR_LOCK						\
26	call	_get_isrlock
27
28#define REL_FAST_INTR_LOCK						\
29	movl	$_mp_lock, %edx ; /* GIANT_LOCK */			\
30	call	_MPrellock_edx
31
32#endif /* FAST_SIMPLELOCK */
33
34/* convert an absolute IRQ# into a bitmask */
35#define IRQ_BIT(irq_num)	(1 << (irq_num))
36
37/* make an index into the IO APIC from the IRQ# */
38#define REDTBL_IDX(irq_num)	(0x10 + ((irq_num) * 2))
39
40
41/*
42 * Macros for interrupt interrupt entry, call to handler, and exit.
43 */
44
45#ifdef FAST_WITHOUTCPL
46
47/*
48 */
49#define	FAST_INTR(irq_num, vec_name)					\
50	.text ;								\
51	SUPERALIGN_TEXT ;						\
52IDTVEC(vec_name) ;							\
53	pushl	%eax ;		/* save only call-used registers */	\
54	pushl	%ecx ;							\
55	pushl	%edx ;							\
56	pushl	%ds ;							\
57	MAYBE_PUSHL_ES ;						\
58	pushl	%fs ;							\
59	movl	$KDSEL,%eax ;						\
60	movl	%ax,%ds ;						\
61	MAYBE_MOVW_AX_ES ;						\
62	movl	$KPSEL,%eax ;						\
63	movl	%ax,%fs ;						\
64	FAKE_MCOUNT((5+ACTUALLY_PUSHED)*4(%esp)) ;			\
65	pushl	_intr_unit + (irq_num) * 4 ;				\
66	GET_FAST_INTR_LOCK ;						\
67	call	*_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \
68	REL_FAST_INTR_LOCK ;						\
69	addl	$4, %esp ;						\
70	movl	$0, lapic_eoi ;						\
71	lock ; 								\
72	incl	_cnt+V_INTR ;	/* book-keeping can wait */		\
73	movl	_intr_countp + (irq_num) * 4, %eax ;			\
74	lock ; 								\
75	incl	(%eax) ;						\
76	MEXITCOUNT ;							\
77	popl	%fs ;							\
78	MAYBE_POPL_ES ;							\
79	popl	%ds ;							\
80	popl	%edx ;							\
81	popl	%ecx ;							\
82	popl	%eax ;							\
83	iret
84
85#else /* FAST_WITHOUTCPL */
86
87#define	FAST_INTR(irq_num, vec_name)					\
88	.text ;								\
89	SUPERALIGN_TEXT ;						\
90IDTVEC(vec_name) ;							\
91	pushl	%eax ;		/* save only call-used registers */	\
92	pushl	%ecx ;							\
93	pushl	%edx ;							\
94	pushl	%ds ;							\
95	MAYBE_PUSHL_ES ;						\
96	pushl	%fs ;							\
97	movl	$KDSEL, %eax ;						\
98	movl	%ax, %ds ;						\
99	MAYBE_MOVW_AX_ES ;						\
100	movl	$KPSEL, %eax ;						\
101	movl	%ax, %fs ;						\
102	FAKE_MCOUNT((5+ACTUALLY_PUSHED)*4(%esp)) ;			\
103	GET_FAST_INTR_LOCK ;						\
104	pushl	_intr_unit + (irq_num) * 4 ;				\
105	call	*_intr_handler + (irq_num) * 4 ; /* do the work ASAP */ \
106	addl	$4, %esp ;						\
107	movl	$0, lapic_eoi ;						\
108	lock ; 								\
109	incl	_cnt+V_INTR ;	/* book-keeping can wait */		\
110	movl	_intr_countp + (irq_num) * 4,%eax ;			\
111	lock ; 								\
112	incl	(%eax) ;						\
113	movl	_cpl, %eax ;	/* unmasking pending HWIs or SWIs? */	\
114	notl	%eax ;							\
115	andl	_ipending, %eax ;					\
116	jne	2f ; 		/* yes, maybe handle them */		\
1171: ;									\
118	MEXITCOUNT ;							\
119	REL_FAST_INTR_LOCK ;						\
120	popl	%fs ;							\
121	MAYBE_POPL_ES ;							\
122	popl	%ds ;							\
123	popl	%edx ;							\
124	popl	%ecx ;							\
125	popl	%eax ;							\
126	iret ;								\
127;									\
128	ALIGN_TEXT ;							\
1292: ;									\
130	cmpb	$3, _intr_nesting_level ;	/* enough stack? */	\
131	jae	1b ;		/* no, return */			\
132	movl	_cpl, %eax ;						\
133	/* XXX next line is probably unnecessary now. */		\
134	movl	$HWI_MASK|SWI_MASK, _cpl ;	/* limit nesting ... */	\
135	lock ; 								\
136	incb	_intr_nesting_level ;	/* ... really limit it ... */	\
137	sti ;			/* to do this as early as possible */	\
138	popl	%fs ;		/* discard most of thin frame ... */	\
139	MAYBE_POPL_ES ;		/* discard most of thin frame ... */	\
140	popl	%ecx ;		/* ... original %ds ... */		\
141	popl	%edx ;							\
142	xchgl	%eax, 4(%esp) ;	/* orig %eax; save cpl */		\
143	pushal ;		/* build fat frame (grrr) ... */	\
144	pushl	%ecx ;		/* ... actually %ds ... */		\
145	pushl	%es ;							\
146	pushl	%fs ;
147	movl	$KDSEL, %eax ;						\
148	movl	%ax, %es ;						\
149	movl	$KPSEL, %eax ;
150	movl	%ax, %fs ;
151	movl	(3+8+0)*4(%esp), %ecx ;	/* %ecx from thin frame ... */	\
152	movl	%ecx, (3+6)*4(%esp) ;	/* ... to fat frame ... */	\
153	movl	(3+8+1)*4(%esp), %eax ;	/* ... cpl from thin frame */	\
154	pushl	%eax ;							\
155	subl	$4, %esp ;	/* junk for unit number */		\
156	MEXITCOUNT ;							\
157	jmp	_doreti
158
159#endif /** FAST_WITHOUTCPL */
160
161
162/*
163 *
164 */
165#define PUSH_FRAME							\
166	pushl	$0 ;		/* dummy error code */			\
167	pushl	$0 ;		/* dummy trap type */			\
168	pushal ;							\
169	pushl	%ds ;		/* save data and extra segments ... */	\
170	pushl	%es ;							\
171	pushl	%fs
172
173#define POP_FRAME							\
174	popl	%fs ;							\
175	popl	%es ;							\
176	popl	%ds ;							\
177	popal ;								\
178	addl	$4+4,%esp
179
180#define IOAPICADDR(irq_num) CNAME(int_to_apicintpin) + 16 * (irq_num) + 8
181#define REDIRIDX(irq_num) CNAME(int_to_apicintpin) + 16 * (irq_num) + 12
182
183#define MASK_IRQ(irq_num)						\
184	IMASK_LOCK ;				/* into critical reg */	\
185	testl	$IRQ_BIT(irq_num), _apic_imen ;				\
186	jne	7f ;			/* masked, don't mask */	\
187	orl	$IRQ_BIT(irq_num), _apic_imen ;	/* set the mask bit */	\
188	movl	IOAPICADDR(irq_num), %ecx ;	/* ioapic addr */	\
189	movl	REDIRIDX(irq_num), %eax ;	/* get the index */	\
190	movl	%eax, (%ecx) ;			/* write the index */	\
191	movl	IOAPIC_WINDOW(%ecx), %eax ;	/* current value */	\
192	orl	$IOART_INTMASK, %eax ;		/* set the mask */	\
193	movl	%eax, IOAPIC_WINDOW(%ecx) ;	/* new value */		\
1947: ;						/* already masked */	\
195	IMASK_UNLOCK
196/*
197 * Test to see whether we are handling an edge or level triggered INT.
198 *  Level-triggered INTs must still be masked as we don't clear the source,
199 *  and the EOI cycle would cause redundant INTs to occur.
200 */
201#define MASK_LEVEL_IRQ(irq_num)						\
202	testl	$IRQ_BIT(irq_num), _apic_pin_trigger ;			\
203	jz	9f ;				/* edge, don't mask */	\
204	MASK_IRQ(irq_num) ;						\
2059:
206
207
208#ifdef APIC_INTR_REORDER
209#define EOI_IRQ(irq_num)						\
210	movl	_apic_isrbit_location + 8 * (irq_num), %eax ;		\
211	movl	(%eax), %eax ;						\
212	testl	_apic_isrbit_location + 4 + 8 * (irq_num), %eax ;	\
213	jz	9f ;				/* not active */	\
214	movl	$0, lapic_eoi ;						\
215	APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ;	\
2169:
217
218#else
219#define EOI_IRQ(irq_num)						\
220	testl	$IRQ_BIT(irq_num), lapic_isr1;				\
221	jz	9f	;			/* not active */	\
222	movl	$0, lapic_eoi;						\
223	APIC_ITRACE(apic_itrace_eoi, irq_num, APIC_ITRACE_EOI) ;	\
2249:
225#endif
226
227
228/*
229 * Test to see if the source is currntly masked, clear if so.
230 */
231#define UNMASK_IRQ(irq_num)					\
232	IMASK_LOCK ;				/* into critical reg */	\
233	testl	$IRQ_BIT(irq_num), _apic_imen ;				\
234	je	7f ;			/* bit clear, not masked */	\
235	andl	$~IRQ_BIT(irq_num), _apic_imen ;/* clear mask bit */	\
236	movl	IOAPICADDR(irq_num),%ecx ;	/* ioapic addr */	\
237	movl	REDIRIDX(irq_num), %eax ;	/* get the index */	\
238	movl	%eax,(%ecx) ;			/* write the index */	\
239	movl	IOAPIC_WINDOW(%ecx),%eax ;	/* current value */	\
240	andl	$~IOART_INTMASK,%eax ;		/* clear the mask */	\
241	movl	%eax,IOAPIC_WINDOW(%ecx) ;	/* new value */		\
2427: ;									\
243	IMASK_UNLOCK
244
245#ifdef INTR_SIMPLELOCK
246#define ENLOCK
247#define DELOCK
248#define LATELOCK call	_get_isrlock
249#else
250#define ENLOCK \
251	ISR_TRYLOCK ;		/* XXX this is going away... */		\
252	testl	%eax, %eax ;			/* did we get it? */	\
253	jz	3f
254#define DELOCK	ISR_RELLOCK
255#define LATELOCK
256#endif
257
258#ifdef APIC_INTR_DIAGNOSTIC
259#ifdef APIC_INTR_DIAGNOSTIC_IRQ
260log_intr_event:
261	pushf
262	cli
263	pushl	$CNAME(apic_itrace_debuglock)
264	call	CNAME(s_lock_np)
265	addl	$4, %esp
266	movl	CNAME(apic_itrace_debugbuffer_idx), %ecx
267	andl	$32767, %ecx
268	movl	_cpuid, %eax
269	shll	$8,	%eax
270	orl	8(%esp), %eax
271	movw	%ax,	CNAME(apic_itrace_debugbuffer)(,%ecx,2)
272	incl	%ecx
273	andl	$32767, %ecx
274	movl	%ecx,	CNAME(apic_itrace_debugbuffer_idx)
275	pushl	$CNAME(apic_itrace_debuglock)
276	call	CNAME(s_unlock_np)
277	addl	$4, %esp
278	popf
279	ret
280
281
282#define APIC_ITRACE(name, irq_num, id)					\
283	lock ;					/* MP-safe */		\
284	incl	CNAME(name) + (irq_num) * 4 ;				\
285	pushl	%eax ;							\
286	pushl	%ecx ;							\
287	pushl	%edx ;							\
288	movl	$(irq_num), %eax ;					\
289	cmpl	$APIC_INTR_DIAGNOSTIC_IRQ, %eax ;			\
290	jne	7f ;							\
291	pushl	$id ;							\
292	call	log_intr_event ;					\
293	addl	$4, %esp ;						\
2947: ;									\
295	popl	%edx ;							\
296	popl	%ecx ;							\
297	popl	%eax
298#else
299#define APIC_ITRACE(name, irq_num, id)					\
300	lock ;					/* MP-safe */		\
301	incl	CNAME(name) + (irq_num) * 4
302#endif
303
304#define APIC_ITRACE_ENTER 1
305#define APIC_ITRACE_EOI 2
306#define APIC_ITRACE_TRYISRLOCK 3
307#define APIC_ITRACE_GOTISRLOCK 4
308#define APIC_ITRACE_ENTER2 5
309#define APIC_ITRACE_LEAVE 6
310#define APIC_ITRACE_UNMASK 7
311#define APIC_ITRACE_ACTIVE 8
312#define APIC_ITRACE_MASKED 9
313#define APIC_ITRACE_NOISRLOCK 10
314#define APIC_ITRACE_MASKED2 11
315#define APIC_ITRACE_SPLZ 12
316#define APIC_ITRACE_DORETI 13
317
318#else
319#define APIC_ITRACE(name, irq_num, id)
320#endif
321
322#ifdef CPL_AND_CML
323
324#define	INTR(irq_num, vec_name, maybe_extra_ipending)			\
325	.text ;								\
326	SUPERALIGN_TEXT ;						\
327/* _XintrNN: entry point used by IDT/HWIs & splz_unpend via _vec[]. */	\
328IDTVEC(vec_name) ;							\
329	PUSH_FRAME ;							\
330	movl	$KDSEL, %eax ;	/* reload with kernel's data segment */	\
331	movl	%ax, %ds ;						\
332	movl	%ax, %es ;						\
333	movl	$KPSEL, %eax ;						\
334	movl	%ax, %fs ;						\
335;									\
336	maybe_extra_ipending ;						\
337;									\
338	APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ;	\
339	lock ;					/* MP-safe */		\
340	btsl	$(irq_num), iactive ;		/* lazy masking */	\
341	jc	1f ;				/* already active */	\
342;									\
343	MASK_LEVEL_IRQ(irq_num) ;					\
344	EOI_IRQ(irq_num) ;						\
3450: ;									\
346	APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\
347	ENLOCK ;							\
348;									\
349	APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\
350	AVCPL_LOCK ;				/* MP-safe */		\
351	testl	$IRQ_BIT(irq_num), _cpl ;				\
352	jne	2f ;				/* this INT masked */	\
353	testl	$IRQ_BIT(irq_num), _cml ;				\
354	jne	2f ;				/* this INT masked */	\
355	orl	$IRQ_BIT(irq_num), _cil ;				\
356	AVCPL_UNLOCK ;							\
357;									\
358	incb	_intr_nesting_level ;					\
359;	 								\
360  /* entry point used by doreti_unpend for HWIs. */			\
361__CONCAT(Xresume,irq_num): ;						\
362	FAKE_MCOUNT(13*4(%esp)) ;		/* XXX avoid dbl cnt */ \
363	lock ;	incl	_cnt+V_INTR ;		/* tally interrupts */	\
364	movl	_intr_countp + (irq_num) * 4, %eax ;			\
365	lock ;	incl	(%eax) ;					\
366;									\
367	AVCPL_LOCK ;				/* MP-safe */		\
368	movl	_cml, %eax ;						\
369	pushl	%eax ;							\
370	orl	_intr_mask + (irq_num) * 4, %eax ;			\
371	movl	%eax, _cml ;						\
372	AVCPL_UNLOCK ;							\
373;									\
374	pushl	_intr_unit + (irq_num) * 4 ;				\
375	incl	_inside_intr ;						\
376	APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ;	\
377	sti ;								\
378	call	*_intr_handler + (irq_num) * 4 ;			\
379	cli ;								\
380	APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ;	\
381	decl	_inside_intr ;						\
382;									\
383	lock ;	andl $~IRQ_BIT(irq_num), iactive ;			\
384	lock ;	andl $~IRQ_BIT(irq_num), _cil ;				\
385	UNMASK_IRQ(irq_num) ;						\
386	APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ;	\
387	sti ;				/* doreti repeats cli/sti */	\
388	MEXITCOUNT ;							\
389	LATELOCK ;							\
390	jmp	_doreti ;						\
391;									\
392	ALIGN_TEXT ;							\
3931: ;						/* active */		\
394	APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ;	\
395	MASK_IRQ(irq_num) ;						\
396	EOI_IRQ(irq_num) ;						\
397	AVCPL_LOCK ;				/* MP-safe */		\
398	lock ;								\
399	orl	$IRQ_BIT(irq_num), _ipending ;				\
400	AVCPL_UNLOCK ;							\
401	lock ;								\
402	btsl	$(irq_num), iactive ;		/* still active */	\
403	jnc	0b ;				/* retry */		\
404	POP_FRAME ;							\
405	iret ;								\
406;									\
407	ALIGN_TEXT ;							\
4082: ;						/* masked by cpl|cml */	\
409	APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ;	\
410	lock ;								\
411	orl	$IRQ_BIT(irq_num), _ipending ;				\
412	AVCPL_UNLOCK ;							\
413	DELOCK ;		/* XXX this is going away... */		\
414	POP_FRAME ;							\
415	iret ;								\
416	ALIGN_TEXT ;							\
4173: ; 			/* other cpu has isr lock */			\
418	APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\
419	AVCPL_LOCK ;				/* MP-safe */		\
420	lock ;								\
421	orl	$IRQ_BIT(irq_num), _ipending ;				\
422	testl	$IRQ_BIT(irq_num), _cpl ;				\
423	jne	4f ;				/* this INT masked */	\
424	testl	$IRQ_BIT(irq_num), _cml ;				\
425	jne	4f ;				/* this INT masked */	\
426	orl	$IRQ_BIT(irq_num), _cil ;				\
427	AVCPL_UNLOCK ;							\
428	call	forward_irq ;	/* forward irq to lock holder */	\
429	POP_FRAME ;	 			/* and return */	\
430	iret ;								\
431	ALIGN_TEXT ;							\
4324: ;	 					/* blocked */		\
433	APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\
434	AVCPL_UNLOCK ;							\
435	POP_FRAME ;	 			/* and return */	\
436	iret
437
438#else /* CPL_AND_CML */
439
440
441#define	INTR(irq_num, vec_name, maybe_extra_ipending)			\
442	.text ;								\
443	SUPERALIGN_TEXT ;						\
444/* _XintrNN: entry point used by IDT/HWIs & splz_unpend via _vec[]. */	\
445IDTVEC(vec_name) ;							\
446	PUSH_FRAME ;							\
447	movl	$KDSEL, %eax ;	/* reload with kernel's data segment */	\
448	movl	%ax, %ds ;						\
449	movl	%ax, %es ;						\
450	movl	$KPSEL, %eax ;						\
451	movl	%ax, %fs ;						\
452;									\
453	maybe_extra_ipending ;						\
454;									\
455	APIC_ITRACE(apic_itrace_enter, irq_num, APIC_ITRACE_ENTER) ;	\
456	lock ;					/* MP-safe */		\
457	btsl	$(irq_num), iactive ;		/* lazy masking */	\
458	jc	1f ;				/* already active */	\
459;									\
460	MASK_LEVEL_IRQ(irq_num) ;					\
461	EOI_IRQ(irq_num) ;						\
4620: ;									\
463	APIC_ITRACE(apic_itrace_tryisrlock, irq_num, APIC_ITRACE_TRYISRLOCK) ;\
464	ISR_TRYLOCK ;		/* XXX this is going away... */		\
465	testl	%eax, %eax ;			/* did we get it? */	\
466	jz	3f ;				/* no */		\
467;									\
468	APIC_ITRACE(apic_itrace_gotisrlock, irq_num, APIC_ITRACE_GOTISRLOCK) ;\
469	AVCPL_LOCK ;				/* MP-safe */		\
470	testl	$IRQ_BIT(irq_num), _cpl ;				\
471	jne	2f ;				/* this INT masked */	\
472	AVCPL_UNLOCK ;							\
473;									\
474	incb	_intr_nesting_level ;					\
475;	 								\
476  /* entry point used by doreti_unpend for HWIs. */			\
477__CONCAT(Xresume,irq_num): ;						\
478	FAKE_MCOUNT(13*4(%esp)) ;		/* XXX avoid dbl cnt */ \
479	lock ;	incl	_cnt+V_INTR ;		/* tally interrupts */	\
480	movl	_intr_countp + (irq_num) * 4, %eax ;			\
481	lock ;	incl	(%eax) ;					\
482;									\
483	AVCPL_LOCK ;				/* MP-safe */		\
484	movl	_cpl, %eax ;						\
485	pushl	%eax ;							\
486	orl	_intr_mask + (irq_num) * 4, %eax ;			\
487	movl	%eax, _cpl ;						\
488	lock ;								\
489	andl	$~IRQ_BIT(irq_num), _ipending ;				\
490	AVCPL_UNLOCK ;							\
491;									\
492	pushl	_intr_unit + (irq_num) * 4 ;				\
493	APIC_ITRACE(apic_itrace_enter2, irq_num, APIC_ITRACE_ENTER2) ;	\
494	sti ;								\
495	call	*_intr_handler + (irq_num) * 4 ;			\
496	cli ;								\
497	APIC_ITRACE(apic_itrace_leave, irq_num, APIC_ITRACE_LEAVE) ;	\
498;									\
499	lock ;	andl	$~IRQ_BIT(irq_num), iactive ;			\
500	UNMASK_IRQ(irq_num) ;						\
501	APIC_ITRACE(apic_itrace_unmask, irq_num, APIC_ITRACE_UNMASK) ;	\
502	sti ;				/* doreti repeats cli/sti */	\
503	MEXITCOUNT ;							\
504	jmp	_doreti ;						\
505;									\
506	ALIGN_TEXT ;							\
5071: ;						/* active  */		\
508	APIC_ITRACE(apic_itrace_active, irq_num, APIC_ITRACE_ACTIVE) ;	\
509	MASK_IRQ(irq_num) ;						\
510	EOI_IRQ(irq_num) ;						\
511	AVCPL_LOCK ;				/* MP-safe */		\
512	lock ;								\
513	orl	$IRQ_BIT(irq_num), _ipending ;				\
514	AVCPL_UNLOCK ;							\
515	lock ;								\
516	btsl	$(irq_num), iactive ;		/* still active */	\
517	jnc	0b ;				/* retry */		\
518	POP_FRAME ;							\
519	iret ;		/* XXX:	 iactive bit might be 0 now */		\
520	ALIGN_TEXT ;							\
5212: ;				/* masked by cpl, leave iactive set */	\
522	APIC_ITRACE(apic_itrace_masked, irq_num, APIC_ITRACE_MASKED) ;	\
523	lock ;								\
524	orl	$IRQ_BIT(irq_num), _ipending ;				\
525	AVCPL_UNLOCK ;							\
526	ISR_RELLOCK ;		/* XXX this is going away... */		\
527	POP_FRAME ;							\
528	iret ;								\
529	ALIGN_TEXT ;							\
5303: ; 			/* other cpu has isr lock */			\
531	APIC_ITRACE(apic_itrace_noisrlock, irq_num, APIC_ITRACE_NOISRLOCK) ;\
532	AVCPL_LOCK ;				/* MP-safe */		\
533	lock ;								\
534	orl	$IRQ_BIT(irq_num), _ipending ;				\
535	testl	$IRQ_BIT(irq_num), _cpl ;				\
536	jne	4f ;				/* this INT masked */	\
537	AVCPL_UNLOCK ;							\
538	call	forward_irq ;	 /* forward irq to lock holder */	\
539	POP_FRAME ;	 			/* and return */	\
540	iret ;								\
541	ALIGN_TEXT ;							\
5424: ;	 					/* blocked */		\
543	APIC_ITRACE(apic_itrace_masked2, irq_num, APIC_ITRACE_MASKED2) ;\
544	AVCPL_UNLOCK ;							\
545	POP_FRAME ;	 			/* and return */	\
546	iret
547
548#endif /* CPL_AND_CML */
549
550
551/*
552 * Handle "spurious INTerrupts".
553 * Notes:
554 *  This is different than the "spurious INTerrupt" generated by an
555 *   8259 PIC for missing INTs.  See the APIC documentation for details.
556 *  This routine should NOT do an 'EOI' cycle.
557 */
558	.text
559	SUPERALIGN_TEXT
560	.globl _Xspuriousint
561_Xspuriousint:
562
563	/* No EOI cycle used here */
564
565	iret
566
567
568/*
569 * Handle TLB shootdowns.
570 */
571	.text
572	SUPERALIGN_TEXT
573	.globl	_Xinvltlb
574_Xinvltlb:
575	pushl	%eax
576
577#ifdef COUNT_XINVLTLB_HITS
578	pushl	%fs
579	movl	$KPSEL, %eax
580	movl	%ax, %fs
581	movl	_cpuid, %eax
582	popl	%fs
583	ss
584	incl	_xhits(,%eax,4)
585#endif /* COUNT_XINVLTLB_HITS */
586
587	movl	%cr3, %eax		/* invalidate the TLB */
588	movl	%eax, %cr3
589
590	ss				/* stack segment, avoid %ds load */
591	movl	$0, lapic_eoi		/* End Of Interrupt to APIC */
592
593	popl	%eax
594	iret
595
596
597#ifdef BETTER_CLOCK
598
599/*
600 * Executed by a CPU when it receives an Xcpucheckstate IPI from another CPU,
601 *
602 *  - Stores current cpu state in checkstate_cpustate[cpuid]
603 *      0 == user, 1 == sys, 2 == intr
604 *  - Stores current process in checkstate_curproc[cpuid]
605 *
606 *  - Signals its receipt by setting bit cpuid in checkstate_probed_cpus.
607 *
608 * stack: 0->ds, 4->fs, 8->ebx, 12->eax, 16->eip, 20->cs, 24->eflags
609 */
610
611	.text
612	SUPERALIGN_TEXT
613	.globl _Xcpucheckstate
614	.globl _checkstate_cpustate
615	.globl _checkstate_curproc
616	.globl _checkstate_pc
617_Xcpucheckstate:
618	pushl	%eax
619	pushl	%ebx
620	pushl	%ds			/* save current data segment */
621	pushl	%fs
622
623	movl	$KDSEL, %eax
624	movl	%ax, %ds		/* use KERNEL data segment */
625	movl	$KPSEL, %eax
626	movl	%ax, %fs
627
628	movl	$0, lapic_eoi		/* End Of Interrupt to APIC */
629
630	movl	$0, %ebx
631	movl	20(%esp), %eax
632	andl	$3, %eax
633	cmpl	$3, %eax
634	je	1f
635	testl	$PSL_VM, 24(%esp)
636	jne	1f
637	incl	%ebx			/* system or interrupt */
638#ifdef CPL_AND_CML
639	cmpl	$0, _inside_intr
640	je	1f
641	incl	%ebx			/* interrupt */
642#endif
6431:
644	movl	_cpuid, %eax
645	movl	%ebx, _checkstate_cpustate(,%eax,4)
646	movl	_curproc, %ebx
647	movl	%ebx, _checkstate_curproc(,%eax,4)
648	movl	16(%esp), %ebx
649	movl	%ebx, _checkstate_pc(,%eax,4)
650
651	lock				/* checkstate_probed_cpus |= (1<<id) */
652	btsl	%eax, _checkstate_probed_cpus
653
654	popl	%fs
655	popl	%ds			/* restore previous data segment */
656	popl	%ebx
657	popl	%eax
658	iret
659
660#endif /* BETTER_CLOCK */
661
662/*
663 * Executed by a CPU when it receives an Xcpuast IPI from another CPU,
664 *
665 *  - Signals its receipt by clearing bit cpuid in checkstate_need_ast.
666 *
667 *  - We need a better method of triggering asts on other cpus.
668 */
669
670	.text
671	SUPERALIGN_TEXT
672	.globl _Xcpuast
673_Xcpuast:
674	PUSH_FRAME
675	movl	$KDSEL, %eax
676	movl	%ax, %ds		/* use KERNEL data segment */
677	movl	%ax, %es
678	movl	$KPSEL, %eax
679	movl	%ax, %fs
680
681	movl	_cpuid, %eax
682	lock				/* checkstate_need_ast &= ~(1<<id) */
683	btrl	%eax, _checkstate_need_ast
684	movl	$0, lapic_eoi		/* End Of Interrupt to APIC */
685
686	lock
687	btsl	%eax, _checkstate_pending_ast
688	jc	1f
689
690	FAKE_MCOUNT(13*4(%esp))
691
692	/*
693	 * Giant locks do not come cheap.
694	 * A lot of cycles are going to be wasted here.
695	 */
696	call	_get_isrlock
697
698	AVCPL_LOCK
699#ifdef CPL_AND_CML
700	movl	_cml, %eax
701#else
702	movl	_cpl, %eax
703#endif
704	pushl	%eax
705	movl	$1, _astpending		/* XXX */
706	AVCPL_UNLOCK
707	lock
708	incb	_intr_nesting_level
709	sti
710
711	pushl	$0
712
713	movl	_cpuid, %eax
714	lock
715	btrl	%eax, _checkstate_pending_ast
716	lock
717	btrl	%eax, CNAME(resched_cpus)
718	jnc	2f
719	movl	$1, CNAME(want_resched)
720	lock
721	incl	CNAME(want_resched_cnt)
7222:
723	lock
724	incl	CNAME(cpuast_cnt)
725	MEXITCOUNT
726	jmp	_doreti
7271:
728	/* We are already in the process of delivering an ast for this CPU */
729	POP_FRAME
730	iret
731
732
733/*
734 *	 Executed by a CPU when it receives an XFORWARD_IRQ IPI.
735 */
736
737	.text
738	SUPERALIGN_TEXT
739	.globl _Xforward_irq
740_Xforward_irq:
741	PUSH_FRAME
742	movl	$KDSEL, %eax
743	movl	%ax, %ds		/* use KERNEL data segment */
744	movl	%ax, %es
745	movl	$KPSEL, %eax
746	movl	%ax, %fs
747
748	movl	$0, lapic_eoi		/* End Of Interrupt to APIC */
749
750	FAKE_MCOUNT(13*4(%esp))
751
752	ISR_TRYLOCK
753	testl	%eax,%eax		/* Did we get the lock ? */
754	jz  1f				/* No */
755
756	lock
757	incl	CNAME(forward_irq_hitcnt)
758	cmpb	$4, _intr_nesting_level
759	jae	2f
760
761	AVCPL_LOCK
762#ifdef CPL_AND_CML
763	movl	_cml, %eax
764#else
765	movl	_cpl, %eax
766#endif
767	pushl	%eax
768	AVCPL_UNLOCK
769	lock
770	incb	_intr_nesting_level
771	sti
772
773	pushl	$0
774
775	MEXITCOUNT
776	jmp	_doreti			/* Handle forwarded interrupt */
7771:
778	lock
779	incl	CNAME(forward_irq_misscnt)
780	call	forward_irq	/* Oops, we've lost the isr lock */
781	MEXITCOUNT
782	POP_FRAME
783	iret
7842:
785	lock
786	incl	CNAME(forward_irq_toodeepcnt)
7873:
788	ISR_RELLOCK
789	MEXITCOUNT
790	POP_FRAME
791	iret
792
793/*
794 *
795 */
796forward_irq:
797	MCOUNT
798	cmpl	$0,_invltlb_ok
799	jz	4f
800
801	cmpl	$0, CNAME(forward_irq_enabled)
802	jz	4f
803
804	movl	_mp_lock,%eax
805	cmpl	$FREE_LOCK,%eax
806	jne	1f
807	movl	$0, %eax		/* Pick CPU #0 if noone has lock */
8081:
809	shrl	$24,%eax
810	movl	_cpu_num_to_apic_id(,%eax,4),%ecx
811	shll	$24,%ecx
812	movl	lapic_icr_hi, %eax
813	andl	$~APIC_ID_MASK, %eax
814	orl	%ecx, %eax
815	movl	%eax, lapic_icr_hi
816
8172:
818	movl	lapic_icr_lo, %eax
819	andl	$APIC_DELSTAT_MASK,%eax
820	jnz	2b
821	movl	lapic_icr_lo, %eax
822	andl	$APIC_RESV2_MASK, %eax
823	orl	$(APIC_DEST_DESTFLD|APIC_DELMODE_FIXED|XFORWARD_IRQ_OFFSET), %eax
824	movl	%eax, lapic_icr_lo
8253:
826	movl	lapic_icr_lo, %eax
827	andl	$APIC_DELSTAT_MASK,%eax
828	jnz	3b
8294:
830	ret
831
832/*
833 * Executed by a CPU when it receives an Xcpustop IPI from another CPU,
834 *
835 *  - Signals its receipt.
836 *  - Waits for permission to restart.
837 *  - Signals its restart.
838 */
839
840	.text
841	SUPERALIGN_TEXT
842	.globl _Xcpustop
843_Xcpustop:
844	pushl	%ebp
845	movl	%esp, %ebp
846	pushl	%eax
847	pushl	%ecx
848	pushl	%edx
849	pushl	%ds			/* save current data segment */
850	pushl	%fs
851
852	movl	$KDSEL, %eax
853	movl	%ax, %ds		/* use KERNEL data segment */
854	movl	$KPSEL, %eax
855	movl	%ax, %fs
856
857	movl	$0, lapic_eoi		/* End Of Interrupt to APIC */
858
859	movl	_cpuid, %eax
860	imull	$PCB_SIZE, %eax
861	leal	CNAME(stoppcbs)(%eax), %eax
862	pushl	%eax
863	call	CNAME(savectx)		/* Save process context */
864	addl	$4, %esp
865
866
867	movl	_cpuid, %eax
868
869	lock
870	btsl	%eax, _stopped_cpus	/* stopped_cpus |= (1<<id) */
8711:
872	btl	%eax, _started_cpus	/* while (!(started_cpus & (1<<id))) */
873	jnc	1b
874
875	lock
876	btrl	%eax, _started_cpus	/* started_cpus &= ~(1<<id) */
877	lock
878	btrl	%eax, _stopped_cpus	/* stopped_cpus &= ~(1<<id) */
879
880	test	%eax, %eax
881	jnz	2f
882
883	movl	CNAME(cpustop_restartfunc), %eax
884	test	%eax, %eax
885	jz	2f
886	movl	$0, CNAME(cpustop_restartfunc)	/* One-shot */
887
888	call	%eax
8892:
890	popl	%fs
891	popl	%ds			/* restore previous data segment */
892	popl	%edx
893	popl	%ecx
894	popl	%eax
895	movl	%ebp, %esp
896	popl	%ebp
897	iret
898
899
900MCOUNT_LABEL(bintr)
901	FAST_INTR(0,fastintr0)
902	FAST_INTR(1,fastintr1)
903	FAST_INTR(2,fastintr2)
904	FAST_INTR(3,fastintr3)
905	FAST_INTR(4,fastintr4)
906	FAST_INTR(5,fastintr5)
907	FAST_INTR(6,fastintr6)
908	FAST_INTR(7,fastintr7)
909	FAST_INTR(8,fastintr8)
910	FAST_INTR(9,fastintr9)
911	FAST_INTR(10,fastintr10)
912	FAST_INTR(11,fastintr11)
913	FAST_INTR(12,fastintr12)
914	FAST_INTR(13,fastintr13)
915	FAST_INTR(14,fastintr14)
916	FAST_INTR(15,fastintr15)
917	FAST_INTR(16,fastintr16)
918	FAST_INTR(17,fastintr17)
919	FAST_INTR(18,fastintr18)
920	FAST_INTR(19,fastintr19)
921	FAST_INTR(20,fastintr20)
922	FAST_INTR(21,fastintr21)
923	FAST_INTR(22,fastintr22)
924	FAST_INTR(23,fastintr23)
925#define	CLKINTR_PENDING	movl $1,CNAME(clkintr_pending)
926	INTR(0,intr0, CLKINTR_PENDING)
927	INTR(1,intr1,)
928	INTR(2,intr2,)
929	INTR(3,intr3,)
930	INTR(4,intr4,)
931	INTR(5,intr5,)
932	INTR(6,intr6,)
933	INTR(7,intr7,)
934	INTR(8,intr8,)
935	INTR(9,intr9,)
936	INTR(10,intr10,)
937	INTR(11,intr11,)
938	INTR(12,intr12,)
939	INTR(13,intr13,)
940	INTR(14,intr14,)
941	INTR(15,intr15,)
942	INTR(16,intr16,)
943	INTR(17,intr17,)
944	INTR(18,intr18,)
945	INTR(19,intr19,)
946	INTR(20,intr20,)
947	INTR(21,intr21,)
948	INTR(22,intr22,)
949	INTR(23,intr23,)
950MCOUNT_LABEL(eintr)
951
952/*
953 * Executed by a CPU when it receives a RENDEZVOUS IPI from another CPU.
954 *
955 * - Calls the generic rendezvous action function.
956 */
957	.text
958	SUPERALIGN_TEXT
959	.globl	_Xrendezvous
960_Xrendezvous:
961	PUSH_FRAME
962	movl	$KDSEL, %eax
963	movl	%ax, %ds		/* use KERNEL data segment */
964	movl	%ax, %es
965	movl	$KPSEL, %eax
966	movl	%ax, %fs
967
968	call	_smp_rendezvous_action
969
970	movl	$0, lapic_eoi		/* End Of Interrupt to APIC */
971	POP_FRAME
972	iret
973
974
975	.data
976/*
977 * Addresses of interrupt handlers.
978 *  XresumeNN: Resumption addresses for HWIs.
979 */
980	.globl _ihandlers
981_ihandlers:
982/*
983 * used by:
984 *  ipl.s:	doreti_unpend
985 */
986	.long	Xresume0,  Xresume1,  Xresume2,  Xresume3
987	.long	Xresume4,  Xresume5,  Xresume6,  Xresume7
988	.long	Xresume8,  Xresume9,  Xresume10, Xresume11
989	.long	Xresume12, Xresume13, Xresume14, Xresume15
990	.long	Xresume16, Xresume17, Xresume18, Xresume19
991	.long	Xresume20, Xresume21, Xresume22, Xresume23
992/*
993 * used by:
994 *  ipl.s:	doreti_unpend
995 *  apic_ipl.s:	splz_unpend
996 */
997	.long	_swi_null, swi_net, _swi_null, _swi_null
998	.long	_swi_vm, _swi_null, _softclock, _swi_null
999
1000imasks:				/* masks for interrupt handlers */
1001	.space	NHWI*4		/* padding; HWI masks are elsewhere */
1002
1003	.long	SWI_TTY_MASK, SWI_NET_MASK, SWI_CAMNET_MASK, SWI_CAMBIO_MASK
1004	.long	SWI_VM_MASK, 0, SWI_CLOCK_MASK, 0
1005
1006/* active flag for lazy masking */
1007iactive:
1008	.long	0
1009
1010#ifdef COUNT_XINVLTLB_HITS
1011	.globl	_xhits
1012_xhits:
1013	.space	(NCPU * 4), 0
1014#endif /* COUNT_XINVLTLB_HITS */
1015
1016/* variables used by stop_cpus()/restart_cpus()/Xcpustop */
1017	.globl _stopped_cpus, _started_cpus
1018_stopped_cpus:
1019	.long	0
1020_started_cpus:
1021	.long	0
1022
1023#ifdef BETTER_CLOCK
1024	.globl _checkstate_probed_cpus
1025_checkstate_probed_cpus:
1026	.long	0
1027#endif /* BETTER_CLOCK */
1028	.globl _checkstate_need_ast
1029_checkstate_need_ast:
1030	.long	0
1031_checkstate_pending_ast:
1032	.long	0
1033	.globl CNAME(forward_irq_misscnt)
1034	.globl CNAME(forward_irq_toodeepcnt)
1035	.globl CNAME(forward_irq_hitcnt)
1036	.globl CNAME(resched_cpus)
1037	.globl CNAME(want_resched_cnt)
1038	.globl CNAME(cpuast_cnt)
1039	.globl CNAME(cpustop_restartfunc)
1040CNAME(forward_irq_misscnt):
1041	.long 0
1042CNAME(forward_irq_hitcnt):
1043	.long 0
1044CNAME(forward_irq_toodeepcnt):
1045	.long 0
1046CNAME(resched_cpus):
1047	.long 0
1048CNAME(want_resched_cnt):
1049	.long 0
1050CNAME(cpuast_cnt):
1051	.long 0
1052CNAME(cpustop_restartfunc):
1053	.long 0
1054
1055
1056
1057	.globl	_apic_pin_trigger
1058_apic_pin_trigger:
1059	.long	0
1060
1061	.text
1062