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