apic_vector.s revision 122620
1275970Scy/*-
2275970Scy * Copyright (c) 1989, 1990 William F. Jolitz.
3275970Scy * Copyright (c) 1990 The Regents of the University of California.
4275970Scy * All rights reserved.
5275970Scy *
6275970Scy * Redistribution and use in source and binary forms, with or without
7275970Scy * modification, are permitted provided that the following conditions
8275970Scy * are met:
9275970Scy * 1. Redistributions of source code must retain the above copyright
10275970Scy *    notice, this list of conditions and the following disclaimer.
11275970Scy * 2. Redistributions in binary form must reproduce the above copyright
12275970Scy *    notice, this list of conditions and the following disclaimer in the
13275970Scy *    documentation and/or other materials provided with the distribution.
14275970Scy * 3. All advertising materials mentioning features or use of this software
15275970Scy *    must display the following acknowledgement:
16275970Scy *	This product includes software developed by the University of
17275970Scy *	California, Berkeley and its contributors.
18275970Scy * 4. Neither the name of the University nor the names of its contributors
19275970Scy *    may be used to endorse or promote products derived from this software
20275970Scy *    without specific prior written permission.
21275970Scy *
22275970Scy * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23275970Scy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24275970Scy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25275970Scy * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26275970Scy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27275970Scy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28275970Scy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29275970Scy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30275970Scy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31275970Scy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32275970Scy * SUCH DAMAGE.
33275970Scy *
34275970Scy *	from: vector.s, 386BSD 0.1 unknown origin
35275970Scy * $FreeBSD: head/sys/i386/i386/apic_vector.s 122620 2003-11-13 18:16:37Z jhb $
36275970Scy */
37275970Scy
38275970Scy/*
39275970Scy * Interrupt entry points for external interrupts triggered by I/O APICs
40275970Scy * as well as IPI handlers.
41275970Scy */
42275970Scy
43275970Scy#include <machine/asmacros.h>
44275970Scy#include <machine/apicreg.h>
45275970Scy#include <machine/smptests.h>
46275970Scy
47275970Scy#include "assym.s"
48275970Scy
49275970Scy/*
50275970Scy * Macros to create and destroy a trap frame.
51275970Scy */
52275970Scy#define PUSH_FRAME							\
53275970Scy	pushl	$0 ;		/* dummy error code */			\
54275970Scy	pushl	$0 ;		/* dummy trap type */			\
55275970Scy	pushal ;		/* 8 ints */				\
56275970Scy	pushl	%ds ;		/* save data and extra segments ... */	\
57275970Scy	pushl	%es ;							\
58275970Scy	pushl	%fs
59275970Scy
60275970Scy#define POP_FRAME							\
61275970Scy	popl	%fs ;							\
62275970Scy	popl	%es ;							\
63275970Scy	popl	%ds ;							\
64275970Scy	popal ;								\
65275970Scy	addl	$4+4,%esp
66275970Scy
67275970Scy/*
68275970Scy * I/O Interrupt Entry Point.  Rather than having one entry point for
69275970Scy * each interrupt source, we use one entry point for each 32-bit word
70275970Scy * in the ISR.  The handler determines the highest bit set in the ISR,
71275970Scy * translates that into a vector, and passes the vector to the
72275970Scy * lapic_handle_intr() function.
73275970Scy */
74275970Scy#define	ISR_VEC(index, vec_name)					\
75275970Scy	.text ;								\
76275970Scy	SUPERALIGN_TEXT ;						\
77275970ScyIDTVEC(vec_name) ;							\
78275970Scy	PUSH_FRAME ;							\
79275970Scy	movl	$KDSEL, %eax ;	/* reload with kernel's data segment */	\
80275970Scy	mov	%ax, %ds ;						\
81275970Scy	mov	%ax, %es ;						\
82275970Scy	movl	$KPSEL, %eax ;	/* reload with per-CPU data segment */	\
83275970Scy	mov	%ax, %fs ;						\
84275970Scy	movl	lapic, %edx ;	/* pointer to local APIC */		\
85275970Scy	movl	LA_ISR + 16 * (index)(%edx), %eax ;	/* load ISR */	\
86275970Scy	bsrl	%eax, %eax ;	/* index of highset set bit in ISR */	\
87275970Scy	jz	2f ;							\
88275970Scy	addl	$(32 * index),%eax ;					\
89275970Scy1: ;									\
90275970Scy	FAKE_MCOUNT(13*4(%esp)) ;	/* XXX avoid double count */	\
91275970Scy	pushl	%eax ;		/* pass the IRQ */			\
92275970Scy	call	lapic_handle_intr ;					\
93275970Scy	addl	$4, %esp ;	/* discard parameter */			\
94275970Scy	MEXITCOUNT ;							\
95275970Scy	jmp	doreti ;						\
96275970Scy2:	movl	$-1, %eax ;	/* send a vector of -1 */		\
97275970Scy	jmp	1b
98275970Scy
99275970Scy/*
100275970Scy * Handle "spurious INTerrupts".
101275970Scy * Notes:
102275970Scy *  This is different than the "spurious INTerrupt" generated by an
103275970Scy *   8259 PIC for missing INTs.  See the APIC documentation for details.
104275970Scy *  This routine should NOT do an 'EOI' cycle.
105275970Scy */
106275970Scy	.text
107275970Scy	SUPERALIGN_TEXT
108275970ScyIDTVEC(spuriousint)
109275970Scy
110275970Scy	/* No EOI cycle used here */
111275970Scy
112275970Scy	iret
113275970Scy
114275970ScyMCOUNT_LABEL(bintr2)
115275970Scy	ISR_VEC(1, apic_isr1)
116275970Scy	ISR_VEC(2, apic_isr2)
117275970Scy	ISR_VEC(3, apic_isr3)
118275970Scy	ISR_VEC(4, apic_isr4)
119275970Scy	ISR_VEC(5, apic_isr5)
120275970ScyMCOUNT_LABEL(eintr2)
121275970Scy
122275970Scy#ifdef SMP
123275970Scy/*
124275970Scy * Global address space TLB shootdown.
125275970Scy */
126275970Scy	.text
127275970Scy	SUPERALIGN_TEXT
128275970ScyIDTVEC(invltlb)
129275970Scy	pushl	%eax
130275970Scy	pushl	%ds
131275970Scy	movl	$KDSEL, %eax		/* Kernel data selector */
132275970Scy	mov	%ax, %ds
133275970Scy
134275970Scy#ifdef COUNT_XINVLTLB_HITS
135275970Scy	pushl	%fs
136275970Scy	movl	$KPSEL, %eax		/* Private space selector */
137275970Scy	mov	%ax, %fs
138275970Scy	movl	PCPU(CPUID), %eax
139275970Scy	popl	%fs
140275970Scy	incl	xhits_gbl(,%eax,4)
141275970Scy#endif /* COUNT_XINVLTLB_HITS */
142275970Scy
143275970Scy	movl	%cr3, %eax		/* invalidate the TLB */
144275970Scy	movl	%eax, %cr3
145275970Scy
146275970Scy	movl	lapic, %eax
147275970Scy	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
148275970Scy
149275970Scy	lock
150275970Scy	incl	smp_tlb_wait
151275970Scy
152275970Scy	popl	%ds
153275970Scy	popl	%eax
154275970Scy	iret
155275970Scy
156275970Scy/*
157275970Scy * Single page TLB shootdown
158275970Scy */
159275970Scy	.text
160275970Scy	SUPERALIGN_TEXT
161275970ScyIDTVEC(invlpg)
162275970Scy	pushl	%eax
163275970Scy	pushl	%ds
164275970Scy	movl	$KDSEL, %eax		/* Kernel data selector */
165275970Scy	mov	%ax, %ds
166275970Scy
167275970Scy#ifdef COUNT_XINVLTLB_HITS
168275970Scy	pushl	%fs
169275970Scy	movl	$KPSEL, %eax		/* Private space selector */
170275970Scy	mov	%ax, %fs
171275970Scy	movl	PCPU(CPUID), %eax
172275970Scy	popl	%fs
173275970Scy	incl	xhits_pg(,%eax,4)
174275970Scy#endif /* COUNT_XINVLTLB_HITS */
175275970Scy
176275970Scy	movl	smp_tlb_addr1, %eax
177275970Scy	invlpg	(%eax)			/* invalidate single page */
178275970Scy
179275970Scy	movl	lapic, %eax
180275970Scy	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
181275970Scy
182275970Scy	lock
183275970Scy	incl	smp_tlb_wait
184275970Scy
185275970Scy	popl	%ds
186275970Scy	popl	%eax
187275970Scy	iret
188275970Scy
189275970Scy/*
190275970Scy * Page range TLB shootdown.
191275970Scy */
192275970Scy	.text
193275970Scy	SUPERALIGN_TEXT
194275970ScyIDTVEC(invlrng)
195275970Scy	pushl	%eax
196275970Scy	pushl	%edx
197275970Scy	pushl	%ds
198275970Scy	movl	$KDSEL, %eax		/* Kernel data selector */
199275970Scy	mov	%ax, %ds
200275970Scy
201275970Scy#ifdef COUNT_XINVLTLB_HITS
202275970Scy	pushl	%fs
203275970Scy	movl	$KPSEL, %eax		/* Private space selector */
204275970Scy	mov	%ax, %fs
205275970Scy	movl	PCPU(CPUID), %eax
206275970Scy	popl	%fs
207275970Scy	incl	xhits_rng(,%eax,4)
208275970Scy#endif /* COUNT_XINVLTLB_HITS */
209275970Scy
210275970Scy	movl	smp_tlb_addr1, %edx
211275970Scy	movl	smp_tlb_addr2, %eax
212275970Scy1:	invlpg	(%edx)			/* invalidate single page */
213275970Scy	addl	$PAGE_SIZE, %edx
214275970Scy	cmpl	%eax, %edx
215275970Scy	jb	1b
216275970Scy
217275970Scy	movl	lapic, %eax
218275970Scy	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
219275970Scy
220275970Scy	lock
221275970Scy	incl	smp_tlb_wait
222275970Scy
223275970Scy	popl	%ds
224275970Scy	popl	%edx
225275970Scy	popl	%eax
226275970Scy	iret
227275970Scy
228275970Scy/*
229275970Scy * Forward hardclock to another CPU.  Pushes a clockframe and calls
230275970Scy * forwarded_hardclock().
231275970Scy */
232275970Scy	.text
233275970Scy	SUPERALIGN_TEXT
234275970ScyIDTVEC(hardclock)
235275970Scy	PUSH_FRAME
236275970Scy	movl	$KDSEL, %eax	/* reload with kernel's data segment */
237275970Scy	mov	%ax, %ds
238275970Scy	mov	%ax, %es
239275970Scy	movl	$KPSEL, %eax
240275970Scy	mov	%ax, %fs
241275970Scy
242275970Scy	movl	lapic, %edx
243275970Scy	movl	$0, LA_EOI(%edx)	/* End Of Interrupt to APIC */
244275970Scy
245275970Scy	pushl	$0		/* XXX convert trapframe to clockframe */
246275970Scy	call	forwarded_hardclock
247275970Scy	addl	$4, %esp	/* XXX convert clockframe to trapframe */
248275970Scy	MEXITCOUNT
249275970Scy	jmp	doreti
250275970Scy
251275970Scy/*
252275970Scy * Forward statclock to another CPU.  Pushes a clockframe and calls
253275970Scy * forwarded_statclock().
254275970Scy */
255275970Scy	.text
256275970Scy	SUPERALIGN_TEXT
257275970ScyIDTVEC(statclock)
258275970Scy	PUSH_FRAME
259275970Scy	movl	$KDSEL, %eax	/* reload with kernel's data segment */
260275970Scy	mov	%ax, %ds
261275970Scy	mov	%ax, %es
262275970Scy	movl	$KPSEL, %eax
263275970Scy	mov	%ax, %fs
264275970Scy
265275970Scy	movl	lapic, %edx
266275970Scy	movl	$0, LA_EOI(%edx)	/* End Of Interrupt to APIC */
267275970Scy
268275970Scy	FAKE_MCOUNT(13*4(%esp))
269275970Scy
270275970Scy	pushl	$0		/* XXX convert trapframe to clockframe */
271275970Scy	call	forwarded_statclock
272275970Scy	addl	$4, %esp	/* XXX convert clockframe to trapframe */
273275970Scy	MEXITCOUNT
274275970Scy	jmp	doreti
275275970Scy
276275970Scy/*
277275970Scy * Executed by a CPU when it receives an Xcpuast IPI from another CPU,
278275970Scy *
279275970Scy * The other CPU has already executed aston() or need_resched() on our
280275970Scy * current process, so we simply need to ack the interrupt and return
281275970Scy * via doreti to run ast().
282275970Scy */
283275970Scy
284275970Scy	.text
285275970Scy	SUPERALIGN_TEXT
286275970ScyIDTVEC(cpuast)
287275970Scy	PUSH_FRAME
288275970Scy	movl	$KDSEL, %eax
289275970Scy	mov	%ax, %ds		/* use KERNEL data segment */
290275970Scy	mov	%ax, %es
291275970Scy	movl	$KPSEL, %eax
292275970Scy	mov	%ax, %fs
293275970Scy
294275970Scy	movl	lapic, %edx
295275970Scy	movl	$0, LA_EOI(%edx)	/* End Of Interrupt to APIC */
296275970Scy
297275970Scy	FAKE_MCOUNT(13*4(%esp))
298275970Scy
299275970Scy	MEXITCOUNT
300275970Scy	jmp	doreti
301275970Scy
302275970Scy/*
303275970Scy * Executed by a CPU when it receives an Xcpustop IPI from another CPU,
304275970Scy *
305275970Scy *  - Signals its receipt.
306275970Scy *  - Waits for permission to restart.
307275970Scy *  - Signals its restart.
308275970Scy */
309275970Scy	.text
310275970Scy	SUPERALIGN_TEXT
311275970ScyIDTVEC(cpustop)
312275970Scy	pushl	%ebp
313275970Scy	movl	%esp, %ebp
314275970Scy	pushl	%eax
315275970Scy	pushl	%ecx
316275970Scy	pushl	%edx
317275970Scy	pushl	%ds			/* save current data segment */
318275970Scy	pushl	%es
319275970Scy	pushl	%fs
320275970Scy
321275970Scy	movl	$KDSEL, %eax
322275970Scy	mov	%ax, %ds		/* use KERNEL data segment */
323275970Scy	mov	%ax, %es
324275970Scy	movl	$KPSEL, %eax
325275970Scy	mov	%ax, %fs
326275970Scy
327275970Scy	movl	lapic, %eax
328275970Scy	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
329275970Scy
330275970Scy	movl	PCPU(CPUID), %eax
331275970Scy	imull	$PCB_SIZE, %eax
332275970Scy	leal	CNAME(stoppcbs)(%eax), %eax
333275970Scy	pushl	%eax
334275970Scy	call	CNAME(savectx)		/* Save process context */
335275970Scy	addl	$4, %esp
336275970Scy
337275970Scy	movl	PCPU(CPUID), %eax
338275970Scy
339275970Scy	lock
340275970Scy	btsl	%eax, CNAME(stopped_cpus) /* stopped_cpus |= (1<<id) */
341275970Scy1:
342275970Scy	btl	%eax, CNAME(started_cpus) /* while (!(started_cpus & (1<<id))) */
343275970Scy	jnc	1b
344275970Scy
345275970Scy	lock
346275970Scy	btrl	%eax, CNAME(started_cpus) /* started_cpus &= ~(1<<id) */
347275970Scy	lock
348275970Scy	btrl	%eax, CNAME(stopped_cpus) /* stopped_cpus &= ~(1<<id) */
349275970Scy
350275970Scy	test	%eax, %eax
351275970Scy	jnz	2f
352275970Scy
353	movl	CNAME(cpustop_restartfunc), %eax
354	test	%eax, %eax
355	jz	2f
356	movl	$0, CNAME(cpustop_restartfunc)	/* One-shot */
357
358	call	*%eax
3592:
360	popl	%fs
361	popl	%es
362	popl	%ds			/* restore previous data segment */
363	popl	%edx
364	popl	%ecx
365	popl	%eax
366	movl	%ebp, %esp
367	popl	%ebp
368	iret
369
370/*
371 * Executed by a CPU when it receives a RENDEZVOUS IPI from another CPU.
372 *
373 * - Calls the generic rendezvous action function.
374 */
375	.text
376	SUPERALIGN_TEXT
377IDTVEC(rendezvous)
378	PUSH_FRAME
379	movl	$KDSEL, %eax
380	mov	%ax, %ds		/* use KERNEL data segment */
381	mov	%ax, %es
382	movl	$KPSEL, %eax
383	mov	%ax, %fs
384
385	call	smp_rendezvous_action
386
387	movl	lapic, %eax
388	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
389	POP_FRAME
390	iret
391
392/*
393 * Clean up when we lose out on the lazy context switch optimization.
394 * ie: when we are about to release a PTD but a cpu is still borrowing it.
395 */
396	SUPERALIGN_TEXT
397IDTVEC(lazypmap)
398	PUSH_FRAME
399	movl	$KDSEL, %eax
400	mov	%ax, %ds		/* use KERNEL data segment */
401	mov	%ax, %es
402	movl	$KPSEL, %eax
403	mov	%ax, %fs
404
405	call	pmap_lazyfix_action
406
407	movl	lapic, %eax
408	movl	$0, LA_EOI(%eax)	/* End Of Interrupt to APIC */
409	POP_FRAME
410	iret
411#endif /* SMP */
412