apic_vector.s revision 129620
1/*-
2 * Copyright (c) 1989, 1990 William F. Jolitz.
3 * Copyright (c) 1990 The Regents of the University of California.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 4. Neither the name of the University nor the names of its contributors
15 *    may be used to endorse or promote products derived from this software
16 *    without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 *	from: vector.s, 386BSD 0.1 unknown origin
31 * $FreeBSD: head/sys/i386/i386/apic_vector.s 129620 2004-05-23 16:50:55Z bde $
32 */
33
34/*
35 * Interrupt entry points for external interrupts triggered by I/O APICs
36 * as well as IPI handlers.
37 */
38
39#include <machine/asmacros.h>
40#include <machine/apicreg.h>
41#include <machine/smptests.h>
42
43#include "assym.s"
44
45/*
46 * Macros to create and destroy a trap frame.
47 */
48#define PUSH_FRAME							\
49	pushl	$0 ;		/* dummy error code */			\
50	pushl	$0 ;		/* dummy trap type */			\
51	pushal ;		/* 8 ints */				\
52	pushl	%ds ;		/* save data and extra segments ... */	\
53	pushl	%es ;							\
54	pushl	%fs
55
56#define POP_FRAME							\
57	popl	%fs ;							\
58	popl	%es ;							\
59	popl	%ds ;							\
60	popal ;								\
61	addl	$4+4,%esp
62
63/*
64 * I/O Interrupt Entry Point.  Rather than having one entry point for
65 * each interrupt source, we use one entry point for each 32-bit word
66 * in the ISR.  The handler determines the highest bit set in the ISR,
67 * translates that into a vector, and passes the vector to the
68 * lapic_handle_intr() function.
69 */
70#define	ISR_VEC(index, vec_name)					\
71	.text ;								\
72	SUPERALIGN_TEXT ;						\
73IDTVEC(vec_name) ;							\
74	PUSH_FRAME ;							\
75	movl	$KDSEL, %eax ;	/* reload with kernel's data segment */	\
76	movl	%eax, %ds ;						\
77	movl	%eax, %es ;						\
78	movl	$KPSEL, %eax ;	/* reload with per-CPU data segment */	\
79	movl	%eax, %fs ;						\
80	FAKE_MCOUNT(TF_EIP(%esp)) ;					\
81	movl	lapic, %edx ;	/* pointer to local APIC */		\
82	movl	LA_ISR + 16 * (index)(%edx), %eax ;	/* load ISR */	\
83	bsrl	%eax, %eax ;	/* index of highset set bit in ISR */	\
84	jz	2f ;							\
85	addl	$(32 * index),%eax ;					\
861: ;									\
87	pushl	%eax ;		/* pass the IRQ */			\
88	call	lapic_handle_intr ;					\
89	addl	$4, %esp ;	/* discard parameter */			\
90	MEXITCOUNT ;							\
91	jmp	doreti ;						\
922:	movl	$-1, %eax ;	/* send a vector of -1 */		\
93	jmp	1b
94
95/*
96 * Handle "spurious INTerrupts".
97 * Notes:
98 *  This is different than the "spurious INTerrupt" generated by an
99 *   8259 PIC for missing INTs.  See the APIC documentation for details.
100 *  This routine should NOT do an 'EOI' cycle.
101 */
102	.text
103	SUPERALIGN_TEXT
104IDTVEC(spuriousint)
105
106	/* No EOI cycle used here */
107
108	iret
109
110MCOUNT_LABEL(bintr2)
111	ISR_VEC(1, apic_isr1)
112	ISR_VEC(2, apic_isr2)
113	ISR_VEC(3, apic_isr3)
114	ISR_VEC(4, apic_isr4)
115	ISR_VEC(5, apic_isr5)
116	ISR_VEC(6, apic_isr6)
117	ISR_VEC(7, apic_isr7)
118MCOUNT_LABEL(eintr2)
119
120#ifdef SMP
121/*
122 * Global address space TLB shootdown.
123 */
124	.text
125	SUPERALIGN_TEXT
126IDTVEC(invltlb)
127	pushl	%eax
128	pushl	%ds
129	movl	$KDSEL, %eax		/* Kernel data selector */
130	movl	%eax, %ds
131
132#ifdef COUNT_XINVLTLB_HITS
133	pushl	%fs
134	movl	$KPSEL, %eax		/* Private space selector */
135	movl	%eax, %fs
136	movl	PCPU(CPUID), %eax
137	popl	%fs
138	incl	xhits_gbl(,%eax,4)
139#endif /* COUNT_XINVLTLB_HITS */
140
141	movl	%cr3, %eax		/* invalidate the TLB */
142	movl	%eax, %cr3
143
144	movl	lapic, %eax
145	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
146
147	lock
148	incl	smp_tlb_wait
149
150	popl	%ds
151	popl	%eax
152	iret
153
154/*
155 * Single page TLB shootdown
156 */
157	.text
158	SUPERALIGN_TEXT
159IDTVEC(invlpg)
160	pushl	%eax
161	pushl	%ds
162	movl	$KDSEL, %eax		/* Kernel data selector */
163	movl	%eax, %ds
164
165#ifdef COUNT_XINVLTLB_HITS
166	pushl	%fs
167	movl	$KPSEL, %eax		/* Private space selector */
168	movl	%eax, %fs
169	movl	PCPU(CPUID), %eax
170	popl	%fs
171	incl	xhits_pg(,%eax,4)
172#endif /* COUNT_XINVLTLB_HITS */
173
174	movl	smp_tlb_addr1, %eax
175	invlpg	(%eax)			/* invalidate single page */
176
177	movl	lapic, %eax
178	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
179
180	lock
181	incl	smp_tlb_wait
182
183	popl	%ds
184	popl	%eax
185	iret
186
187/*
188 * Page range TLB shootdown.
189 */
190	.text
191	SUPERALIGN_TEXT
192IDTVEC(invlrng)
193	pushl	%eax
194	pushl	%edx
195	pushl	%ds
196	movl	$KDSEL, %eax		/* Kernel data selector */
197	movl	%eax, %ds
198
199#ifdef COUNT_XINVLTLB_HITS
200	pushl	%fs
201	movl	$KPSEL, %eax		/* Private space selector */
202	movl	%eax, %fs
203	movl	PCPU(CPUID), %eax
204	popl	%fs
205	incl	xhits_rng(,%eax,4)
206#endif /* COUNT_XINVLTLB_HITS */
207
208	movl	smp_tlb_addr1, %edx
209	movl	smp_tlb_addr2, %eax
2101:	invlpg	(%edx)			/* invalidate single page */
211	addl	$PAGE_SIZE, %edx
212	cmpl	%eax, %edx
213	jb	1b
214
215	movl	lapic, %eax
216	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
217
218	lock
219	incl	smp_tlb_wait
220
221	popl	%ds
222	popl	%edx
223	popl	%eax
224	iret
225
226/*
227 * Forward hardclock to another CPU.  Pushes a clockframe and calls
228 * forwarded_hardclock().
229 */
230	.text
231	SUPERALIGN_TEXT
232IDTVEC(hardclock)
233	PUSH_FRAME
234	movl	$KDSEL, %eax	/* reload with kernel's data segment */
235	movl	%eax, %ds
236	movl	%eax, %es
237	movl	$KPSEL, %eax
238	movl	%eax, %fs
239
240	movl	lapic, %edx
241	movl	$0, LA_EOI(%edx)	/* End Of Interrupt to APIC */
242
243	pushl	$0		/* XXX convert trapframe to clockframe */
244	call	forwarded_hardclock
245	addl	$4, %esp	/* XXX convert clockframe to trapframe */
246	MEXITCOUNT
247	jmp	doreti
248
249/*
250 * Forward statclock to another CPU.  Pushes a clockframe and calls
251 * forwarded_statclock().
252 */
253	.text
254	SUPERALIGN_TEXT
255IDTVEC(statclock)
256	PUSH_FRAME
257	movl	$KDSEL, %eax	/* reload with kernel's data segment */
258	movl	%eax, %ds
259	movl	%eax, %es
260	movl	$KPSEL, %eax
261	movl	%eax, %fs
262
263	movl	lapic, %edx
264	movl	$0, LA_EOI(%edx)	/* End Of Interrupt to APIC */
265
266	FAKE_MCOUNT(TF_EIP(%esp))
267
268	pushl	$0		/* XXX convert trapframe to clockframe */
269	call	forwarded_statclock
270	addl	$4, %esp	/* XXX convert clockframe to trapframe */
271	MEXITCOUNT
272	jmp	doreti
273
274/*
275 * Executed by a CPU when it receives an Xcpuast IPI from another CPU,
276 *
277 * The other CPU has already executed aston() or need_resched() on our
278 * current process, so we simply need to ack the interrupt and return
279 * via doreti to run ast().
280 */
281
282	.text
283	SUPERALIGN_TEXT
284IDTVEC(cpuast)
285	PUSH_FRAME
286	movl	$KDSEL, %eax
287	movl	%eax, %ds		/* use KERNEL data segment */
288	movl	%eax, %es
289	movl	$KPSEL, %eax
290	movl	%eax, %fs
291
292	movl	lapic, %edx
293	movl	$0, LA_EOI(%edx)	/* End Of Interrupt to APIC */
294
295	FAKE_MCOUNT(TF_EIP(%esp))
296
297	MEXITCOUNT
298	jmp	doreti
299
300/*
301 * Executed by a CPU when it receives an Xcpustop IPI from another CPU,
302 *
303 *  - Signals its receipt.
304 *  - Waits for permission to restart.
305 *  - Signals its restart.
306 */
307	.text
308	SUPERALIGN_TEXT
309IDTVEC(cpustop)
310	pushl	%ebp
311	movl	%esp, %ebp
312	pushl	%eax
313	pushl	%ecx
314	pushl	%edx
315	pushl	%ds			/* save current data segment */
316	pushl	%es
317	pushl	%fs
318
319	movl	$KDSEL, %eax
320	movl	%eax, %ds		/* use KERNEL data segment */
321	movl	%eax, %es
322	movl	$KPSEL, %eax
323	movl	%eax, %fs
324
325	movl	lapic, %eax
326	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
327
328	movl	PCPU(CPUID), %eax
329	imull	$PCB_SIZE, %eax
330	leal	CNAME(stoppcbs)(%eax), %eax
331	pushl	%eax
332	call	CNAME(savectx)		/* Save process context */
333	addl	$4, %esp
334
335	movl	PCPU(CPUID), %eax
336
337	lock
338	btsl	%eax, CNAME(stopped_cpus) /* stopped_cpus |= (1<<id) */
3391:
340	btl	%eax, CNAME(started_cpus) /* while (!(started_cpus & (1<<id))) */
341	jnc	1b
342
343	lock
344	btrl	%eax, CNAME(started_cpus) /* started_cpus &= ~(1<<id) */
345	lock
346	btrl	%eax, CNAME(stopped_cpus) /* stopped_cpus &= ~(1<<id) */
347
348	test	%eax, %eax
349	jnz	2f
350
351	movl	CNAME(cpustop_restartfunc), %eax
352	test	%eax, %eax
353	jz	2f
354	movl	$0, CNAME(cpustop_restartfunc)	/* One-shot */
355
356	call	*%eax
3572:
358	popl	%fs
359	popl	%es
360	popl	%ds			/* restore previous data segment */
361	popl	%edx
362	popl	%ecx
363	popl	%eax
364	movl	%ebp, %esp
365	popl	%ebp
366	iret
367
368/*
369 * Executed by a CPU when it receives a RENDEZVOUS IPI from another CPU.
370 *
371 * - Calls the generic rendezvous action function.
372 */
373	.text
374	SUPERALIGN_TEXT
375IDTVEC(rendezvous)
376	PUSH_FRAME
377	movl	$KDSEL, %eax
378	movl	%eax, %ds		/* use KERNEL data segment */
379	movl	%eax, %es
380	movl	$KPSEL, %eax
381	movl	%eax, %fs
382
383	call	smp_rendezvous_action
384
385	movl	lapic, %eax
386	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
387	POP_FRAME
388	iret
389
390/*
391 * Clean up when we lose out on the lazy context switch optimization.
392 * ie: when we are about to release a PTD but a cpu is still borrowing it.
393 */
394	SUPERALIGN_TEXT
395IDTVEC(lazypmap)
396	PUSH_FRAME
397	movl	$KDSEL, %eax
398	movl	%eax, %ds		/* use KERNEL data segment */
399	movl	%eax, %es
400	movl	$KPSEL, %eax
401	movl	%eax, %fs
402
403	call	pmap_lazyfix_action
404
405	movl	lapic, %eax
406	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
407	POP_FRAME
408	iret
409#endif /* SMP */
410