180709Sjake/*-
280709Sjake * Copyright (c) 2001 Jake Burkholder.
3226054Smarius * Copyright (c) 2011 Marius Strobl <marius@FreeBSD.org>
480709Sjake * All rights reserved.
580709Sjake *
680709Sjake * Redistribution and use in source and binary forms, with or without
780709Sjake * modification, are permitted provided that the following conditions
880709Sjake * are met:
980709Sjake * 1. Redistributions of source code must retain the above copyright
1080709Sjake *    notice, this list of conditions and the following disclaimer.
1180709Sjake * 2. Redistributions in binary form must reproduce the above copyright
1280709Sjake *    notice, this list of conditions and the following disclaimer in the
1380709Sjake *    documentation and/or other materials provided with the distribution.
1480709Sjake *
1581337Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1680709Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1780709Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1881337Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1980709Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2080709Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2180709Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2280709Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2380709Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2480709Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2580709Sjake * SUCH DAMAGE.
2680709Sjake */
2780709Sjake
28114188Sjake#include <machine/asm.h>
29114188Sjake__FBSDID("$FreeBSD$");
30114188Sjake
3180709Sjake#include <machine/asmacros.h>
3281184Sjake#include <machine/asi.h>
33166105Smarius#include <machine/fsr.h>
3482909Sjake#include <machine/ktr.h>
35166105Smarius#include <machine/pcb.h>
3682909Sjake#include <machine/tstate.h>
3780709Sjake
38114188Sjake#include "assym.s"
39226054Smarius#include "opt_sched.h"
40114188Sjake
4191613Sjake	.register	%g2, #ignore
4291613Sjake	.register	%g3, #ignore
4391613Sjake
44112993Speter/*
45112993Speter * void cpu_throw(struct thread *old, struct thread *new)
46112993Speter */
4782013SjakeENTRY(cpu_throw)
4882013Sjake	save	%sp, -CCFSZ, %sp
4982013Sjake	flushw
50112993Speter	ba	%xcc, .Lsw1
51203185Smarius	 mov	%g0, %i2
5282013SjakeEND(cpu_throw)
5382013Sjake
54112993Speter/*
55203185Smarius * void cpu_switch(struct thread *old, struct thread *new, struct mtx *mtx)
56112993Speter */
5780709SjakeENTRY(cpu_switch)
5880709Sjake	save	%sp, -CCFSZ, %sp
5981184Sjake
6081184Sjake	/*
61113024Sjake	 * If the current thread was using floating point in the kernel, save
62113024Sjake	 * its context.  The userland floating point context has already been
63113453Sjake	 * saved in that case.
64113024Sjake	 */
65113024Sjake	rd	%fprs, %l2
66113024Sjake	andcc	%l2, FPRS_FEF, %g0
67203185Smarius	bz,a,pt	%xcc, 1f
68113024Sjake	 nop
69113024Sjake	call	savefpctx
70113024Sjake	 add	PCB_REG, PCB_KFP, %o0
71226054Smarius	ba,a,pt	%xcc, 2f
72113024Sjake	 nop
73113024Sjake
74113024Sjake	/*
75113021Sjake	 * If the current thread was using floating point in userland, save
76113021Sjake	 * its context.
7781184Sjake	 */
78113021Sjake1:	sub	PCB_REG, TF_SIZEOF, %l2
79105733Sjake	ldx	[%l2 + TF_FPRS], %l3
8088645Sjake	andcc	%l3, FPRS_FEF, %g0
81113021Sjake	bz,a,pt	%xcc, 2f
8282013Sjake	 nop
83113021Sjake	call	savefpctx
84113021Sjake	 add	PCB_REG, PCB_UFP, %o0
8588645Sjake	andn	%l3, FPRS_FEF, %l3
86105733Sjake	stx	%l3, [%l2 + TF_FPRS]
87113021Sjake
88113021Sjake	ldx	[PCB_REG + PCB_FLAGS], %l3
89112924Sjake	or	%l3, PCB_FEF, %l3
90113021Sjake	stx	%l3, [PCB_REG + PCB_FLAGS]
9181184Sjake
9281184Sjake	/*
9381184Sjake	 * Flush the windows out to the stack and save the current frame
9481184Sjake	 * pointer and program counter.
9581184Sjake	 */
96113021Sjake2:	flushw
9780709Sjake	wrpr	%g0, 0, %cleanwin
98113021Sjake	stx	%fp, [PCB_REG + PCB_SP]
99113021Sjake	stx	%i7, [PCB_REG + PCB_PC]
10081184Sjake
10181184Sjake	/*
10288645Sjake	 * Load the new thread's frame pointer and program counter, and set
10388645Sjake	 * the current thread and pcb.
10481184Sjake	 */
10588645Sjake.Lsw1:
10685239Sjake#if KTR_COMPILE & KTR_PROC
10791613Sjake	CATR(KTR_PROC, "cpu_switch: new td=%p pc=%#lx fp=%#lx"
108203185Smarius	    , %g1, %g2, %g3, 8, 9, 10)
109203185Smarius	stx	%i1, [%g1 + KTR_PARM1]
110203185Smarius	ldx	[%i1 + TD_PCB], %g2
11191613Sjake	ldx	[%g2 + PCB_PC], %g3
11291613Sjake	stx	%g3, [%g1 + KTR_PARM2]
113112917Sjake	ldx	[%g2 + PCB_SP], %g3
11491613Sjake	stx	%g3, [%g1 + KTR_PARM3]
115203185Smarius10:
11682909Sjake#endif
117203185Smarius	ldx	[%i1 + TD_PCB], %l0
11881184Sjake
119203185Smarius	stx	%i1, [PCPU(CURTHREAD)]
120203185Smarius	stx	%l0, [PCPU(CURPCB)]
12191613Sjake
12289043Sjake	wrpr	%g0, PSTATE_NORMAL, %pstate
123203185Smarius	mov	%l0, PCB_REG
12488645Sjake	wrpr	%g0, PSTATE_ALT, %pstate
125203185Smarius	mov	%l0, PCB_REG
12688645Sjake	wrpr	%g0, PSTATE_KERNEL, %pstate
12788645Sjake
128113021Sjake	ldx	[PCB_REG + PCB_SP], %fp
129113021Sjake	ldx	[PCB_REG + PCB_PC], %i7
130113021Sjake	sub	%fp, CCFSZ, %sp
131113021Sjake
13281184Sjake	/*
133129749Stmm	 * Point to the pmaps of the new process, and of the last non-kernel
13491781Sjake	 * process to run.
13581184Sjake	 */
136203185Smarius	ldx	[%i1 + TD_PROC], %l1
137129749Stmm	ldx	[PCPU(PMAP)], %l2
138203185Smarius	ldx	[%l1 + P_VMSPACE], %i5
139203185Smarius	add	%i5, VM_PMAP, %l1
14081184Sjake
14191613Sjake#if KTR_COMPILE & KTR_PROC
142129749Stmm	CATR(KTR_PROC, "cpu_switch: new pmap=%p old pmap=%p"
143203185Smarius	    , %g1, %g2, %g3, 8, 9, 10)
144203185Smarius	stx	%l1, [%g1 + KTR_PARM1]
14591613Sjake	stx	%l2, [%g1 + KTR_PARM2]
146203185Smarius10:
14791613Sjake#endif
14891613Sjake
14981184Sjake	/*
15091613Sjake	 * If they are the same we are done.
15181184Sjake	 */
152203185Smarius	cmp	%l2, %l1
153226054Smarius	be,a,pn	%xcc, 8f
15481184Sjake	 nop
15581184Sjake
15691781Sjake	/*
157113453Sjake	 * If the new process is a kernel thread we can just leave the old
158113453Sjake	 * context active and avoid recycling its context number.
15991781Sjake	 */
160113453Sjake	SET(vmspace0, %i4, %i3)
161129749Stmm	cmp	%i5, %i3
162226054Smarius	be,a,pn	%xcc, 8f
16391781Sjake	 nop
16491781Sjake
16581184Sjake	/*
166129749Stmm	 * If there was no non-kernel pmap, don't try to deactivate it.
16781184Sjake	 */
168203185Smarius	brz,pn	%l2, 3f
169222813Sattilio	 lduw	[PCPU(CPUID)], %l3
17081184Sjake
17181184Sjake	/*
17291781Sjake	 * Mark the pmap of the last non-kernel vmspace to run as no longer
173181701Smarius	 * active on this CPU.
17488645Sjake	 */
175222813Sattilio	mov	_NCPUBITS, %l5
176292943Smarius	udivx	%l3, %l5, %l6
177222813Sattilio	srl	%l6, 0, %l4
178222813Sattilio	sllx	%l4, PTR_SHIFT, %l4
179222813Sattilio	add	%l4, PM_ACTIVE, %l4
180222813Sattilio	smul	%l6, %l5, %l5
181222813Sattilio	sub	%l3, %l5, %l5
182222813Sattilio	mov	1, %l6
183222813Sattilio	sllx	%l6, %l5, %l5
184226054Smarius#ifdef SMP
185226054Smarius	add	%l2, %l4, %l4
186226054Smarius	membar	#LoadStore | #StoreStore
187226054Smarius	ATOMIC_CLEAR_LONG(%l4, %l6, %l7, %l5)
188226054Smarius#else
189222813Sattilio	ldx	[%l2 + %l4], %l6
190222813Sattilio	andn	%l6, %l5, %l6
191222813Sattilio	stx	%l6, [%l2 + %l4]
192226054Smarius#endif
19388645Sjake
19488645Sjake	/*
195113453Sjake	 * Take away its context number.
19691613Sjake	 */
19791613Sjake	sllx	%l3, INT_SHIFT, %l3
198129749Stmm	add	%l2, PM_CONTEXT, %l4
19991613Sjake	mov	-1, %l5
20091613Sjake	stw	%l5, [%l3 + %l4]
20191613Sjake
202203185Smarius3:	cmp	%i2, %g0
203203185Smarius	be,pn	%xcc, 4f
204226054Smarius	 add	%i0, TD_LOCK, %l4
205226054Smarius#if defined(SCHED_ULE) && defined(SMP)
206226054Smarius	membar	#LoadStore | #StoreStore
207226054Smarius	ATOMIC_STORE_LONG(%l4, %l6, %l7, %i2)
208226054Smarius#else
209226054Smarius	stx	%i2, [%l4]
210226054Smarius#endif
211203185Smarius
21291613Sjake	/*
213181701Smarius	 * Find a new TLB context.  If we've run out we have to flush all
214181701Smarius	 * user mappings from the TLB and reset the context numbers.
21581184Sjake	 */
216203185Smarius4:	lduw	[PCPU(TLB_CTX)], %i3
217226054Smarius	lduw	[PCPU(TLB_CTX_MAX)], %i4
218113453Sjake	cmp	%i3, %i4
219203185Smarius	bne,a,pt %xcc, 5f
220113453Sjake	 nop
221113453Sjake	SET(tlb_flush_user, %i5, %i4)
222113453Sjake	ldx	[%i4], %i5
223113453Sjake	call	%i5
224203185Smarius	 lduw	[PCPU(TLB_CTX_MIN)], %i3
22581184Sjake
22681184Sjake	/*
227113453Sjake	 * Advance next free context.
22891613Sjake	 */
229203185Smarius5:	add	%i3, 1, %i4
230113453Sjake	stw	%i4, [PCPU(TLB_CTX)]
23191613Sjake
23291613Sjake	/*
233113453Sjake	 * Set the new context number in the pmap.
23491613Sjake	 */
235222813Sattilio	lduw	[PCPU(CPUID)], %l3
236222813Sattilio	sllx	%l3, INT_SHIFT, %i4
237203185Smarius	add	%l1, PM_CONTEXT, %i5
238113453Sjake	stw	%i3, [%i4 + %i5]
23991613Sjake
24091613Sjake	/*
241181701Smarius	 * Mark the pmap as active on this CPU.
24281184Sjake	 */
243222813Sattilio	mov	_NCPUBITS, %l5
244292943Smarius	udivx	%l3, %l5, %l6
245222813Sattilio	srl	%l6, 0, %l4
246222813Sattilio	sllx	%l4, PTR_SHIFT, %l4
247222813Sattilio	add	%l4, PM_ACTIVE, %l4
248222813Sattilio	smul	%l6, %l5, %l5
249222813Sattilio	sub	%l3, %l5, %l5
250222813Sattilio	mov	1, %l6
251222813Sattilio	sllx	%l6, %l5, %l5
252226054Smarius#ifdef SMP
253226054Smarius	add	%l1, %l4, %l4
254226054Smarius	ATOMIC_SET_LONG(%l4, %l6, %l7, %l5)
255226054Smarius#else
256222813Sattilio	ldx	[%l1 + %l4], %l6
257222813Sattilio	or	%l6, %l5, %l6
258222813Sattilio	stx	%l6, [%l1 + %l4]
259226054Smarius#endif
26081184Sjake
26181184Sjake	/*
262129749Stmm	 * Make note of the change in pmap.
26391781Sjake	 */
264226054Smarius#ifdef SMP
265226054Smarius	PCPU_ADDR(PMAP, %l4)
266226054Smarius	ATOMIC_STORE_LONG(%l4, %l5, %l6, %l1)
267226054Smarius#else
268203185Smarius	stx	%l1, [PCPU(PMAP)]
269226054Smarius#endif
27091781Sjake
27191781Sjake	/*
272181701Smarius	 * Fiddle the hardware bits.  Set the TSB registers and install the
273181701Smarius	 * new context number in the CPU.
27481184Sjake	 */
275203185Smarius	ldx	[%l1 + PM_TSB], %i4
276113453Sjake	mov	AA_DMMU_TSB, %i5
277113453Sjake	stxa	%i4, [%i5] ASI_DMMU
278113453Sjake	mov	AA_IMMU_TSB, %i5
279113453Sjake	stxa	%i4, [%i5] ASI_IMMU
280205258Smarius	setx	TLB_CXR_PGSZ_MASK, %i5, %i4
281113453Sjake	mov	AA_DMMU_PCXR, %i5
282203185Smarius	ldxa	[%i5] ASI_DMMU, %l1
283203185Smarius	and	%l1, %i4, %l1
284203185Smarius	or	%i3, %l1, %i3
285182877Smarius	sethi	%hi(KERNBASE), %i4
286113453Sjake	stxa	%i3, [%i5] ASI_DMMU
287182877Smarius	flush	%i4
28888645Sjake
289226054Smarius6:
290226054Smarius#if defined(SCHED_ULE) && defined(SMP)
291226054Smarius	SET(blocked_lock, %l2, %l1)
292226054Smarius	add	%i1, TD_LOCK, %l2
293226054Smarius7:
294226054Smarius	ATOMIC_LOAD_LONG(%l2, %l3)
295226054Smarius	cmp	%l1, %l3
296226054Smarius	be,a,pn	%xcc, 7b
297226054Smarius	 nop
298226054Smarius#endif
299226054Smarius
30088645Sjake	/*
301181701Smarius	 * Done, return and load the new process's window from the stack.
30281184Sjake	 */
303226054Smarius	ret
30480709Sjake	 restore
305203185Smarius
306226054Smarius8:	cmp	%i2, %g0
307226054Smarius	be,pn	%xcc, 6b
308226054Smarius	 add	%i0, TD_LOCK, %l4
309226054Smarius#if defined(SCHED_ULE) && defined(SMP)
310226054Smarius	membar	#LoadStore | #StoreStore
311226054Smarius	ATOMIC_STORE_LONG(%l4, %l6, %l7, %i2)
312226054Smarius	ba,pt	%xcc, 6b
313203185Smarius	 nop
314226054Smarius#else
315226054Smarius	ba,pt	%xcc, 6b
316226054Smarius	 stx	%i2, [%l4]
317226054Smarius#endif
31880709SjakeEND(cpu_switch)
31980709Sjake
32080709SjakeENTRY(savectx)
32180709Sjake	save	%sp, -CCFSZ, %sp
32280709Sjake	flushw
32381135Stmm	call	savefpctx
324113019Sjake	 add	%i0, PCB_UFP, %o0
325112917Sjake	stx	%fp, [%i0 + PCB_SP]
32688645Sjake	stx	%i7, [%i0 + PCB_PC]
32780709Sjake	ret
32880709Sjake	 restore %g0, 0, %o0
32980709SjakeEND(savectx)
33081135Stmm
33191613Sjake/*
332112920Sjake * void savefpctx(uint32_t *);
33391613Sjake */
33481135StmmENTRY(savefpctx)
33588645Sjake	wr	%g0, FPRS_FEF, %fprs
33688645Sjake	wr	%g0, ASI_BLK_S, %asi
337112920Sjake	stda	%f0, [%o0 + (0 * 64)] %asi
338112920Sjake	stda	%f16, [%o0 + (1 * 64)] %asi
339112920Sjake	stda	%f32, [%o0 + (2 * 64)] %asi
340112920Sjake	stda	%f48, [%o0 + (3 * 64)] %asi
34188645Sjake	membar	#Sync
34281135Stmm	retl
34388645Sjake	 wr	%g0, 0, %fprs
34481135StmmEND(savefpctx)
345