swtch.S revision 112924
1/*-
2 * Copyright (c) 2001 Jake Burkholder.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/sparc64/sparc64/swtch.S 112924 2003-04-01 04:58:50Z jake $
27 */
28
29#include <machine/asmacros.h>
30#include <machine/asi.h>
31#include <machine/ktr.h>
32#include <machine/tstate.h>
33
34	.register	%g2, #ignore
35	.register	%g3, #ignore
36
37#include "assym.s"
38
39ENTRY(cpu_throw)
40	save	%sp, -CCFSZ, %sp
41	call	choosethread
42	 ldx	[PCPU(CURTHREAD)], %l0
43	flushw
44	b,a	%xcc, .Lsw1
45	 nop
46END(cpu_throw)
47
48ENTRY(cpu_switch)
49	/*
50	 * Choose a new thread.  If its the same as the current one, do
51	 * nothing.
52	 */
53	save	%sp, -CCFSZ, %sp
54	call	choosethread
55	 ldx	[PCPU(CURTHREAD)], %l0
56	cmp	%l0, %o0
57	be,a,pn	%xcc, 4f
58	 nop
59	ldx	[%l0 + TD_PCB], %l1
60
61	/*
62	 * If the current thread was using floating point, save its context.
63	 */
64	ldx	[%l0 + TD_FRAME], %l2
65	ldx	[%l2 + TF_FPRS], %l3
66	andcc	%l3, FPRS_FEF, %g0
67	bz,a,pt	%xcc, 1f
68	 nop
69	wr	%g0, FPRS_FEF, %fprs
70	wr	%g0, ASI_BLK_S, %asi
71	stda	%f0, [%l1 + PCB_UFP + (0 * 64)] %asi
72	stda	%f16, [%l1 + PCB_UFP + (1 * 64)] %asi
73	stda	%f32, [%l1 + PCB_UFP + (2 * 64)] %asi
74	stda	%f48, [%l1 + PCB_UFP + (3 * 64)] %asi
75	membar	#Sync
76	wr	%g0, 0, %fprs
77	andn	%l3, FPRS_FEF, %l3
78	stx	%l3, [%l2 + TF_FPRS]
79	ldx	[%l1 + PCB_FLAGS], %l3
80	or	%l3, PCB_FEF, %l3
81	stx	%l3, [%l1 + PCB_FLAGS]
82
83	/*
84	 * Flush the windows out to the stack and save the current frame
85	 * pointer and program counter.
86	 */
871:	flushw
88	wrpr	%g0, 0, %cleanwin
89	stx	%fp, [%l1 + PCB_SP]
90	stx	%i7, [%l1 + PCB_PC]
91
92	/*
93	 * Load the new thread's frame pointer and program counter, and set
94	 * the current thread and pcb.
95	 */
96.Lsw1:
97#if KTR_COMPILE & KTR_PROC
98	CATR(KTR_PROC, "cpu_switch: new td=%p pc=%#lx fp=%#lx"
99	    , %g1, %g2, %g3, 7, 8, 9)
100	stx	%o0, [%g1 + KTR_PARM1]
101	ldx	[%o0 + TD_PCB], %g2
102	ldx	[%g2 + PCB_PC], %g3
103	stx	%g3, [%g1 + KTR_PARM2]
104	ldx	[%g2 + PCB_SP], %g3
105	stx	%g3, [%g1 + KTR_PARM3]
1069:
107#endif
108	ldx	[%o0 + TD_PCB], %o1
109	ldx	[%o1 + PCB_SP], %fp
110	ldx	[%o1 + PCB_PC], %i7
111	sub	%fp, CCFSZ, %sp
112	stx	%o0, [PCPU(CURTHREAD)]
113	stx	%o1, [PCPU(CURPCB)]
114
115	SET(sched_lock, %o3, %o2)
116	stx	%o0, [%o2 + MTX_LOCK]
117
118	wrpr	%g0, PSTATE_NORMAL, %pstate
119	mov	%o1, PCB_REG
120	wrpr	%g0, PSTATE_ALT, %pstate
121	mov	%o1, PCB_REG
122	wrpr	%g0, PSTATE_KERNEL, %pstate
123
124	/*
125	 * Point to the vmspaces of the new process, and of the last non-kernel
126	 * process to run.
127	 */
128	ldx	[%o0 + TD_PROC], %o2
129	ldx	[PCPU(VMSPACE)], %l2
130	ldx	[%o2 + P_VMSPACE], %o2
131
132#if KTR_COMPILE & KTR_PROC
133	CATR(KTR_PROC, "cpu_switch: new vm=%p old vm=%p"
134	    , %g1, %g2, %g3, 7, 8, 9)
135	stx	%o2, [%g1 + KTR_PARM1]
136	stx	%l2, [%g1 + KTR_PARM2]
1379:
138#endif
139
140	/*
141	 * If they are the same we are done.
142	 */
143	cmp	%l2, %o2
144	be,a,pn %xcc, 4f
145	 nop
146
147	/*
148	 * If the new process has nucleus context we are done.
149	 */
150	lduw	[PCPU(CPUID)], %o3
151	sllx	%o3, INT_SHIFT, %o3
152	add	%o2, VM_PMAP + PM_CONTEXT, %o4
153	lduw	[%o3 + %o4], %o5
154
155#if KTR_COMPILE & KTR_PROC
156	CATR(KTR_PROC, "cpu_switch: ctx=%#lx"
157	    , %g1, %g2, %g3, 7, 8, 9)
158	stx	%o5, [%g1 + KTR_PARM1]
1599:
160#endif
161
162	brz,a,pn %o5, 4f
163	 nop
164
165	/*
166	 * If there was no non-kernel vmspace, don't try to deactivate it.
167	 */
168	brz,a,pn %l2, 2f
169	 nop
170
171	/*
172	 * Mark the pmap of the last non-kernel vmspace to run as no longer
173	 * active on this cpu.
174	 */
175	lduw	[%l2 + VM_PMAP + PM_ACTIVE], %l3
176	lduw	[PCPU(CPUMASK)], %l4
177	andn	%l3, %l4, %l3
178	stw	%l3, [%l2 + VM_PMAP + PM_ACTIVE]
179
180	/*
181	 * Take away its context.
182	 */
183	lduw	[PCPU(CPUID)], %l3
184	sllx	%l3, INT_SHIFT, %l3
185	add	%l2, VM_PMAP + PM_CONTEXT, %l4
186	mov	-1, %l5
187	stw	%l5, [%l3 + %l4]
188
189	/*
190	 * Find the current free tlb context for this cpu and install it as
191	 * the new primary context.
192	 */
1932:	lduw	[PCPU(TLB_CTX)], %o5
194	stw	%o5, [%o3 + %o4]
195	mov	AA_DMMU_PCXR, %o4
196	stxa	%o5, [%o4] ASI_DMMU
197	membar	#Sync
198
199	/*
200	 * See if we have run out of free contexts.
201	 */
202	lduw	[PCPU(TLB_CTX_MAX)], %o3
203
204#if KTR_COMPILE & KTR_PROC
205	CATR(KTR_PROC, "cpu_switch: ctx=%#lx next=%#lx max=%#lx"
206	    , %g1, %g2, %g3, 7, 8, 9)
207	stx	%o5, [%g1 + KTR_PARM1]
208	add	%o5, 1, %g2
209	stx	%g2, [%g1 + KTR_PARM2]
210	stx	%o3, [%g1 + KTR_PARM3]
2119:
212#endif
213
214	add	%o5, 1, %o5
215	cmp	%o3, %o5
216	bne,a,pt %xcc, 3f
217	 stw	%o5, [PCPU(TLB_CTX)]
218
219#if KTR_COMPILE & KTR_PROC
220	CATR(KTR_PROC, "cpu_switch: context rollover"
221	    , %g1, %g2, %g3, 7, 8, 9)
2229:
223#endif
224
225	/*
226	 * We will start re-using contexts on the next switch.  Flush all
227	 * non-nucleus mappings from the tlb, and reset the next free context.
228	 */
229	call	pmap_context_rollover
230	 nop
231	ldx	[PCPU(CURTHREAD)], %o0
232	ldx	[%o0 + TD_PROC], %o2
233	ldx	[%o2 + P_VMSPACE], %o2
234
235	/*
236	 * Mark the pmap as active on this cpu.
237	 */
2383:	lduw	[%o2 + VM_PMAP + PM_ACTIVE], %o3
239	lduw	[PCPU(CPUMASK)], %o4
240	or	%o3, %o4, %o3
241	stw	%o3, [%o2 + VM_PMAP + PM_ACTIVE]
242
243	/*
244	 * Make note of the change in vmspace.
245	 */
246	stx	%o2, [PCPU(VMSPACE)]
247
248	/*
249	 * Load the tsb registers.
250	 */
251	ldx	[%o2 + VM_PMAP + PM_TSB], %o3
252	mov	AA_DMMU_TSB, %o4
253	stxa	%o3, [%o4] ASI_DMMU
254	mov	AA_IMMU_TSB, %o4
255	stxa	%o3, [%o4] ASI_IMMU
256	membar	#Sync
257
2584:
259#if KTR_COMPILE & KTR_PROC
260	CATR(KTR_PROC, "cpu_switch: return"
261	    , %g1, %g2, %g3, 7, 8, 9)
2629:
263#endif
264
265	/*
266	 * Done.  Return and load the new process's window from the stack.
267	 */
268	ret
269	 restore
270END(cpu_switch)
271
272ENTRY(savectx)
273	save	%sp, -CCFSZ, %sp
274	flushw
275	call	savefpctx
276	 mov	%i0, %o0
277	stx	%fp, [%i0 + PCB_SP]
278	stx	%i7, [%i0 + PCB_PC]
279	ret
280	 restore %g0, 0, %o0
281END(savectx)
282
283/*
284 * void savefpctx(uint32_t *);
285 */
286ENTRY(savefpctx)
287	wr	%g0, FPRS_FEF, %fprs
288	wr	%g0, ASI_BLK_S, %asi
289	stda	%f0, [%o0 + (0 * 64)] %asi
290	stda	%f16, [%o0 + (1 * 64)] %asi
291	stda	%f32, [%o0 + (2 * 64)] %asi
292	stda	%f48, [%o0 + (3 * 64)] %asi
293	membar	#Sync
294	retl
295	 wr	%g0, 0, %fprs
296END(savefpctx)
297