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