apic_vector.s revision 152701
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 152701 2005-11-22 22:54:42Z jhb $
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 "opt_smp.h"
40
41#include <machine/asmacros.h>
42#include <machine/apicreg.h>
43
44#include "assym.s"
45
46/*
47 * Macros to create and destroy a trap frame.
48 */
49#define PUSH_FRAME							\
50	pushl	$0 ;		/* dummy error code */			\
51	pushl	$0 ;		/* dummy trap type */			\
52	pushal ;		/* 8 ints */				\
53	pushl	%ds ;		/* save data and extra segments ... */	\
54	pushl	%es ;							\
55	pushl	%fs
56
57#define POP_FRAME							\
58	popl	%fs ;							\
59	popl	%es ;							\
60	popl	%ds ;							\
61	popal ;								\
62	addl	$4+4,%esp
63
64/*
65 * I/O Interrupt Entry Point.  Rather than having one entry point for
66 * each interrupt source, we use one entry point for each 32-bit word
67 * in the ISR.  The handler determines the highest bit set in the ISR,
68 * translates that into a vector, and passes the vector to the
69 * lapic_handle_intr() function.
70 */
71#define	ISR_VEC(index, vec_name)					\
72	.text ;								\
73	SUPERALIGN_TEXT ;						\
74IDTVEC(vec_name) ;							\
75	PUSH_FRAME ;							\
76	movl	$KDSEL, %eax ;	/* reload with kernel's data segment */	\
77	movl	%eax, %ds ;						\
78	movl	%eax, %es ;						\
79	movl	$KPSEL, %eax ;	/* reload with per-CPU data segment */	\
80	movl	%eax, %fs ;						\
81	FAKE_MCOUNT(TF_EIP(%esp)) ;					\
82	movl	lapic, %edx ;	/* pointer to local APIC */		\
83	movl	LA_ISR + 16 * (index)(%edx), %eax ;	/* load ISR */	\
84	bsrl	%eax, %eax ;	/* index of highset set bit in ISR */	\
85	jz	2f ;							\
86	addl	$(32 * index),%eax ;					\
871: ;									\
88	pushl	%eax ;		/* pass the IRQ */			\
89	call	lapic_handle_intr ;					\
90	addl	$4, %esp ;	/* discard parameter */			\
91	MEXITCOUNT ;							\
92	jmp	doreti ;						\
932:	movl	$-1, %eax ;	/* send a vector of -1 */		\
94	jmp	1b
95
96/*
97 * Handle "spurious INTerrupts".
98 * Notes:
99 *  This is different than the "spurious INTerrupt" generated by an
100 *   8259 PIC for missing INTs.  See the APIC documentation for details.
101 *  This routine should NOT do an 'EOI' cycle.
102 */
103	.text
104	SUPERALIGN_TEXT
105IDTVEC(spuriousint)
106
107	/* No EOI cycle used here */
108
109	iret
110
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)
118
119/*
120 * Local APIC periodic timer handler.
121 */
122	.text
123	SUPERALIGN_TEXT
124IDTVEC(timerint)
125	PUSH_FRAME
126	movl	$KDSEL, %eax	/* reload with kernel's data segment */
127	movl	%eax, %ds
128	movl	%eax, %es
129	movl	$KPSEL, %eax
130	movl	%eax, %fs
131
132	movl	lapic, %edx
133	movl	$0, LA_EOI(%edx)	/* End Of Interrupt to APIC */
134
135	FAKE_MCOUNT(TF_EIP(%esp))
136
137	pushl	$0		/* XXX convert trapframe to clockframe */
138	call	lapic_handle_timer
139	addl	$4, %esp	/* XXX convert clockframe to trapframe */
140	MEXITCOUNT
141	jmp	doreti
142
143#ifdef SMP
144/*
145 * Global address space TLB shootdown.
146 */
147	.text
148	SUPERALIGN_TEXT
149IDTVEC(invltlb)
150	pushl	%eax
151	pushl	%ds
152	movl	$KDSEL, %eax		/* Kernel data selector */
153	movl	%eax, %ds
154
155#if defined(COUNT_XINVLTLB_HITS) || defined(COUNT_IPIS)
156	pushl	%fs
157	movl	$KPSEL, %eax		/* Private space selector */
158	movl	%eax, %fs
159	movl	PCPU(CPUID), %eax
160	popl	%fs
161#ifdef COUNT_XINVLTLB_HITS
162	incl	xhits_gbl(,%eax,4)
163#endif
164#ifdef COUNT_IPIS
165	movl	ipi_invltlb_counts(,%eax,4),%eax
166	incl	(%eax)
167#endif
168#endif
169
170	movl	%cr3, %eax		/* invalidate the TLB */
171	movl	%eax, %cr3
172
173	movl	lapic, %eax
174	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
175
176	lock
177	incl	smp_tlb_wait
178
179	popl	%ds
180	popl	%eax
181	iret
182
183/*
184 * Single page TLB shootdown
185 */
186	.text
187	SUPERALIGN_TEXT
188IDTVEC(invlpg)
189	pushl	%eax
190	pushl	%ds
191	movl	$KDSEL, %eax		/* Kernel data selector */
192	movl	%eax, %ds
193
194#if defined(COUNT_XINVLTLB_HITS) || defined(COUNT_IPIS)
195	pushl	%fs
196	movl	$KPSEL, %eax		/* Private space selector */
197	movl	%eax, %fs
198	movl	PCPU(CPUID), %eax
199	popl	%fs
200#ifdef COUNT_XINVLTLB_HITS
201	incl	xhits_pg(,%eax,4)
202#endif
203#ifdef COUNT_IPIS
204	movl	ipi_invlpg_counts(,%eax,4),%eax
205	incl	(%eax)
206#endif
207#endif
208
209	movl	smp_tlb_addr1, %eax
210	invlpg	(%eax)			/* invalidate single page */
211
212	movl	lapic, %eax
213	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
214
215	lock
216	incl	smp_tlb_wait
217
218	popl	%ds
219	popl	%eax
220	iret
221
222/*
223 * Page range TLB shootdown.
224 */
225	.text
226	SUPERALIGN_TEXT
227IDTVEC(invlrng)
228	pushl	%eax
229	pushl	%edx
230	pushl	%ds
231	movl	$KDSEL, %eax		/* Kernel data selector */
232	movl	%eax, %ds
233
234#if defined(COUNT_XINVLTLB_HITS) || defined(COUNT_IPIS)
235	pushl	%fs
236	movl	$KPSEL, %eax		/* Private space selector */
237	movl	%eax, %fs
238	movl	PCPU(CPUID), %eax
239	popl	%fs
240#ifdef COUNT_XINVLTLB_HITS
241	incl	xhits_rng(,%eax,4)
242#endif
243#ifdef COUNT_IPIS
244	movl	ipi_invlrng_counts(,%eax,4),%eax
245	incl	(%eax)
246#endif
247#endif
248
249	movl	smp_tlb_addr1, %edx
250	movl	smp_tlb_addr2, %eax
2511:	invlpg	(%edx)			/* invalidate single page */
252	addl	$PAGE_SIZE, %edx
253	cmpl	%eax, %edx
254	jb	1b
255
256	movl	lapic, %eax
257	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
258
259	lock
260	incl	smp_tlb_wait
261
262	popl	%ds
263	popl	%edx
264	popl	%eax
265	iret
266
267/*
268 * Forward hardclock to another CPU.  Pushes a clockframe and calls
269 * forwarded_hardclock().
270 */
271	.text
272	SUPERALIGN_TEXT
273IDTVEC(ipi_intr_bitmap_handler)
274
275	PUSH_FRAME
276	movl	$KDSEL, %eax	/* reload with kernel's data segment */
277	movl	%eax, %ds
278	movl	%eax, %es
279	movl	$KPSEL, %eax
280	movl	%eax, %fs
281
282	movl	lapic, %edx
283	movl	$0, LA_EOI(%edx)	/* End Of Interrupt to APIC */
284
285	FAKE_MCOUNT(TF_EIP(%esp))
286
287	pushl	$0		/* XXX convert trapframe to clockframe */
288	call	ipi_bitmap_handler
289	addl	$4, %esp	/* XXX convert clockframe to trapframe */
290	MEXITCOUNT
291	jmp	doreti
292
293/*
294 * Executed by a CPU when it receives an Xcpustop IPI from another CPU,
295 *
296 *  - Signals its receipt.
297 *  - Waits for permission to restart.
298 *  - Signals its restart.
299 */
300	.text
301	SUPERALIGN_TEXT
302IDTVEC(cpustop)
303	pushl	%ebp
304	movl	%esp, %ebp
305	pushl	%eax
306	pushl	%ecx
307	pushl	%edx
308	pushl	%ds			/* save current data segment */
309	pushl	%es
310	pushl	%fs
311
312	movl	$KDSEL, %eax
313	movl	%eax, %ds		/* use KERNEL data segment */
314	movl	%eax, %es
315	movl	$KPSEL, %eax
316	movl	%eax, %fs
317
318	movl	lapic, %eax
319	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
320
321	movl	PCPU(CPUID), %eax
322	imull	$PCB_SIZE, %eax
323	leal	CNAME(stoppcbs)(%eax), %eax
324	pushl	%eax
325	call	CNAME(savectx)		/* Save process context */
326	addl	$4, %esp
327
328	movl	PCPU(CPUID), %eax
329
330	lock
331	btsl	%eax, CNAME(stopped_cpus) /* stopped_cpus |= (1<<id) */
3321:
333	btl	%eax, CNAME(started_cpus) /* while (!(started_cpus & (1<<id))) */
334	jnc	1b
335
336	lock
337	btrl	%eax, CNAME(started_cpus) /* started_cpus &= ~(1<<id) */
338	lock
339	btrl	%eax, CNAME(stopped_cpus) /* stopped_cpus &= ~(1<<id) */
340
341	test	%eax, %eax
342	jnz	2f
343
344	movl	CNAME(cpustop_restartfunc), %eax
345	test	%eax, %eax
346	jz	2f
347	movl	$0, CNAME(cpustop_restartfunc)	/* One-shot */
348
349	call	*%eax
3502:
351	popl	%fs
352	popl	%es
353	popl	%ds			/* restore previous data segment */
354	popl	%edx
355	popl	%ecx
356	popl	%eax
357	movl	%ebp, %esp
358	popl	%ebp
359	iret
360
361/*
362 * Executed by a CPU when it receives a RENDEZVOUS IPI from another CPU.
363 *
364 * - Calls the generic rendezvous action function.
365 */
366	.text
367	SUPERALIGN_TEXT
368IDTVEC(rendezvous)
369	PUSH_FRAME
370	movl	$KDSEL, %eax
371	movl	%eax, %ds		/* use KERNEL data segment */
372	movl	%eax, %es
373	movl	$KPSEL, %eax
374	movl	%eax, %fs
375
376#ifdef COUNT_IPIS
377	movl	PCPU(CPUID), %eax
378	movl	ipi_rendezvous_counts(,%eax,4), %eax
379	incl	(%eax)
380#endif
381	call	smp_rendezvous_action
382
383	movl	lapic, %eax
384	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
385	POP_FRAME
386	iret
387
388/*
389 * Clean up when we lose out on the lazy context switch optimization.
390 * ie: when we are about to release a PTD but a cpu is still borrowing it.
391 */
392	SUPERALIGN_TEXT
393IDTVEC(lazypmap)
394	PUSH_FRAME
395	movl	$KDSEL, %eax
396	movl	%eax, %ds		/* use KERNEL data segment */
397	movl	%eax, %es
398	movl	$KPSEL, %eax
399	movl	%eax, %fs
400
401#ifdef COUNT_IPIS
402	movl	PCPU(CPUID), %eax
403	movl	ipi_lazypmap_counts(,%eax,4), %eax
404	incl	(%eax)
405#endif
406	call	pmap_lazyfix_action
407
408	movl	lapic, %eax
409	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
410	POP_FRAME
411	iret
412#endif /* SMP */
413