swtch.S revision 89043
180709Sjake/*-
280709Sjake * Copyright (c) 2001 Jake Burkholder.
380709Sjake * All rights reserved.
480709Sjake *
580709Sjake * Redistribution and use in source and binary forms, with or without
680709Sjake * modification, are permitted provided that the following conditions
780709Sjake * are met:
880709Sjake * 1. Redistributions of source code must retain the above copyright
980709Sjake *    notice, this list of conditions and the following disclaimer.
1080709Sjake * 2. Redistributions in binary form must reproduce the above copyright
1180709Sjake *    notice, this list of conditions and the following disclaimer in the
1280709Sjake *    documentation and/or other materials provided with the distribution.
1380709Sjake *
1481337Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1580709Sjake * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1680709Sjake * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1781337Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1880709Sjake * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1980709Sjake * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2080709Sjake * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2180709Sjake * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2280709Sjake * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2380709Sjake * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2480709Sjake * SUCH DAMAGE.
2580709Sjake *
2680709Sjake * $FreeBSD: head/sys/sparc64/sparc64/swtch.S 89043 2002-01-08 05:10:07Z jake $
2780709Sjake */
2880709Sjake
2980709Sjake#include <machine/asmacros.h>
3081184Sjake#include <machine/asi.h>
3182909Sjake#include <machine/ktr.h>
3282909Sjake#include <machine/tstate.h>
3380709Sjake
3480709Sjake#include "assym.s"
3580709Sjake
3682013SjakeENTRY(cpu_throw)
3782013Sjake	save	%sp, -CCFSZ, %sp
3883366Sjulian	call	choosethread
3983366Sjulian	 ldx	[PCPU(CURTHREAD)], %l0
4082013Sjake	flushw
4188645Sjake	b,a	%xcc, .Lsw1
4288645Sjake	 nop
4382013SjakeEND(cpu_throw)
4482013Sjake
4580709SjakeENTRY(cpu_switch)
4681184Sjake	/*
4788645Sjake	 * Choose a new thread.  If its the same as the current one, do
4881184Sjake	 * nothing.
4981184Sjake	 */
5080709Sjake	save	%sp, -CCFSZ, %sp
5183366Sjulian	call	choosethread
5283366Sjulian	 ldx	[PCPU(CURTHREAD)], %l0
5380709Sjake	cmp	%l0, %o0
5488645Sjake	be,a,pn	%xcc, 6f
5588645Sjake	 nop
5688645Sjake	ldx	[%l0 + TD_PCB], %l1
5781184Sjake
5881184Sjake	/*
5988645Sjake	 * If the current thread was using floating point, save its context.
6081184Sjake	 */
6188645Sjake	ldx	[%l0 + TD_FRAME], %l2
6288645Sjake	ldub	[%l2 + TF_FPRS], %l3
6388645Sjake	andcc	%l3, FPRS_FEF, %g0
6488645Sjake	bz,a,pt	%xcc, 1f
6582013Sjake	 nop
6688645Sjake	wr	%g0, FPRS_FEF, %fprs
6788645Sjake	wr	%g0, ASI_BLK_S, %asi
6888645Sjake	stda	%f0, [%l1 + PCB_FPSTATE + FP_FB0] %asi
6988645Sjake	stda	%f16, [%l1 + PCB_FPSTATE + FP_FB1] %asi
7088645Sjake	stda	%f32, [%l1 + PCB_FPSTATE + FP_FB2] %asi
7188645Sjake	stda	%f48, [%l1 + PCB_FPSTATE + FP_FB3] %asi
7288645Sjake	membar	#Sync
7388645Sjake	wr	%g0, 0, %fprs
7488645Sjake	andn	%l3, FPRS_FEF, %l3
7588645Sjake	stb	%l3, [%l2 + TF_FPRS]
7681184Sjake
7781184Sjake	/*
7881184Sjake	 * Flush the windows out to the stack and save the current frame
7981184Sjake	 * pointer and program counter.
8081184Sjake	 */
8180709Sjake1:	flushw
8280709Sjake	wrpr	%g0, 0, %cleanwin
8388645Sjake	stx	%fp, [%l1 + PCB_FP]
8488645Sjake	stx	%i7, [%l1 + PCB_PC]
8581184Sjake
8681184Sjake	/*
8788645Sjake	 * Load the new thread's frame pointer and program counter, and set
8888645Sjake	 * the current thread and pcb.
8981184Sjake	 */
9088645Sjake.Lsw1:
9185239Sjake#if KTR_COMPILE & KTR_PROC
9288645Sjake	CATR(KTR_PROC, "cpu_switch: td=%d (%s) pc=%#lx fp=%#lx"
9388645Sjake	    , %l3, %l4, %l5, 7, 8, 9)
9488645Sjake	ldx	[%o0 + TD_PROC], %l4
9588645Sjake	lduw	[%l4 + P_PID], %l5
9688645Sjake	stx	%l5, [%l3 + KTR_PARM1]
9788645Sjake	add	%l4, P_COMM, %l5
9888645Sjake	stx	%l5, [%l3 + KTR_PARM2]
9988645Sjake	ldx	[%o0 + TD_PCB], %l4
10088645Sjake	ldx	[%l4 + PCB_PC], %l5
10188645Sjake	stx	%l5, [%l3 + KTR_PARM3]
10288645Sjake	ldx	[%l4 + PCB_FP], %l5
10388645Sjake	stx	%l5, [%l3 + KTR_PARM4]
10482909Sjake9:
10582909Sjake#endif
10683366Sjulian	ldx	[%o0 + TD_PCB], %o1
10783366Sjulian	ldx	[%o1 + PCB_FP], %fp
10883366Sjulian	ldx	[%o1 + PCB_PC], %i7
10981184Sjake	sub	%fp, CCFSZ, %sp
11083366Sjulian	stx	%o0, [PCPU(CURTHREAD)]
11181184Sjake	stx	%o1, [PCPU(CURPCB)]
11281184Sjake
11389043Sjake	wrpr	%g0, PSTATE_NORMAL, %pstate
11489043Sjake	mov	%o1, PCB_REG
11588645Sjake	wrpr	%g0, PSTATE_ALT, %pstate
11688645Sjake	mov	%o1, PCB_REG
11788645Sjake	wrpr	%g0, PSTATE_KERNEL, %pstate
11888645Sjake
11981184Sjake	/*
12088645Sjake	 * Point to the vmspaces of the new and old processes.
12181184Sjake	 */
12288645Sjake2:	ldx	[%l0 + TD_PROC], %l2
12383366Sjulian	ldx	[%o0 + TD_PROC], %o2
12488645Sjake	ldx	[%l2 + P_VMSPACE], %l2
12583366Sjulian	ldx	[%o2 + P_VMSPACE], %o2
12681184Sjake
12781184Sjake	/*
12888645Sjake	 * If they're the same we are done.
12981184Sjake	 */
13088645Sjake	cmp	%l2, %o2
13188645Sjake	be,a,pn %xcc, 6f
13281184Sjake	 nop
13381184Sjake
13488645Sjake	/*
13588645Sjake	 * If the old process has nucleus context we can skip demapping the
13688645Sjake	 * tsb.
13788645Sjake	 */
13888645Sjake	lduw	[%l2 + VM_PMAP + PM_CONTEXT], %l3
13988645Sjake	brz,a,pn %l3, 3f
14088645Sjake	 nop
14182013Sjake
14281184Sjake	/*
14388645Sjake	 * Demap the old process's tsb.
14481184Sjake	 */
14588645Sjake	ldx	[%l2 + VM_PMAP + PM_TSB], %l3
14688645Sjake	or	%l3, TLB_DEMAP_NUCLEUS | TLB_DEMAP_PAGE, %l3
14788645Sjake	stxa	%g0, [%l3] ASI_DMMU_DEMAP
14888645Sjake	membar	#Sync
14981184Sjake
15081184Sjake	/*
15188645Sjake	 * Mark the pmap no longer active on this cpu.
15288645Sjake	 */
15388645Sjake	lduw	[%l2 + VM_PMAP + PM_ACTIVE], %l3
15488645Sjake	mov	1, %l4
15588645Sjake	lduw	[PCPU(CPUID)], %l5
15688645Sjake	sllx	%l4, %l5, %l4
15788645Sjake	andn	%l3, %l4, %l3
15888645Sjake	stw	%l3, [%l2 + VM_PMAP + PM_ACTIVE]
15988645Sjake
16088645Sjake	/*
16188645Sjake	 * If the new process has nucleus context we are done.
16288645Sjake	 */
16388645Sjake3:	lduw	[%o2 + VM_PMAP + PM_CONTEXT], %o3
16488645Sjake	brz,a,pn %o3, 6f
16588645Sjake	 nop
16688645Sjake
16788645Sjake	/*
16888645Sjake	 * If the new process has had its context stolen, get one.
16988645Sjake	 */
17088645Sjake	cmp	%o3, -1
17188645Sjake	bne,a,pt %xcc, 4f
17288645Sjake	 nop
17388645Sjake	PANIC("cpu_switch: steal context", %o4)
17488645Sjake
17588645Sjake	/*
17681184Sjake	 * Install the new primary context.
17781184Sjake	 */
17888645Sjake4:	mov	AA_DMMU_PCXR, %o4
17988645Sjake	stxa	%o3, [%o4] ASI_DMMU
18081184Sjake	flush	%o0
18181184Sjake
18281184Sjake	/*
18388645Sjake	 * Mark the pmap as active on this cpu.
18481184Sjake	 */
18588645Sjake	lduw	[%o2 + VM_PMAP + PM_ACTIVE], %o3
18688645Sjake	mov	1, %o4
18788645Sjake	lduw	[PCPU(CPUID)], %o5
18888645Sjake	sllx	%o4, %o5, %o4
18988645Sjake	or	%o3, %o4, %o3
19088645Sjake	stw	%o3, [%o2 + VM_PMAP + PM_ACTIVE]
19181184Sjake
19281184Sjake	/*
19388645Sjake	 * Load the address of the user tsb and the tte data that maps it into
19488645Sjake	 * kernel space and set the lock bit.
19581184Sjake	 */
19688645Sjake	ldx	[%o2 + VM_PMAP + PM_TSB], %o3
19788645Sjake	ldx	[%o2 + VM_PMAP + PM_TSB_TTE], %o4
19888645Sjake	ldx	[%o4 + TTE_DATA], %o4
19988645Sjake	or	%o4, TD_L, %o4
20081184Sjake
20181184Sjake	/*
20288645Sjake	 * Switch to mmu globals, install the preloaded tsb pointer and map
20388645Sjake	 * the new tsb.  We also disable interrupts so that this is as atomic
20488645Sjake	 * as can be.
20588645Sjake	 */
20688645Sjake	wrpr	%g0, PSTATE_MMU, %pstate
20788645Sjake	mov	%o3, TSB_REG
20888645Sjake	or	%o3, TLB_DEMAP_NUCLEUS | TLB_DEMAP_PAGE, %o5
20988645Sjake	stxa	%g0, [%o5] ASI_DMMU_DEMAP
21088645Sjake	mov	AA_DMMU_TAR, %o5
21188645Sjake	stxa	%o3, [%o5] ASI_DMMU
21288645Sjake	stxa	%o4, [%g0] ASI_DTLB_DATA_IN_REG
21388645Sjake	membar	#Sync
21488645Sjake	wrpr	%g0, PSTATE_KERNEL, %pstate
21588645Sjake
21688645Sjake	/*
21781184Sjake	 * Done.  Return and load the new process's window from the stack.
21881184Sjake	 */
21988645Sjake6:	ret
22080709Sjake	 restore
22180709SjakeEND(cpu_switch)
22280709Sjake
22380709SjakeENTRY(savectx)
22480709Sjake	save	%sp, -CCFSZ, %sp
22580709Sjake	flushw
22681135Stmm	call	savefpctx
22788645Sjake	 mov	%i0, %o0
22888645Sjake	stx	%fp, [%i0 + PCB_FP]
22988645Sjake	stx	%i7, [%i0 + PCB_PC]
23080709Sjake	ret
23180709Sjake	 restore %g0, 0, %o0
23280709SjakeEND(savectx)
23381135Stmm
23481135StmmENTRY(savefpctx)
23588645Sjake	wr	%g0, FPRS_FEF, %fprs
23688645Sjake	wr	%g0, ASI_BLK_S, %asi
23788645Sjake	stda	%f0, [%o0 + PCB_FPSTATE + FP_FB0] %asi
23888645Sjake	stda	%f16, [%o0 + PCB_FPSTATE + FP_FB1] %asi
23988645Sjake	stda	%f32, [%o0 + PCB_FPSTATE + FP_FB2] %asi
24088645Sjake	stda	%f48, [%o0 + PCB_FPSTATE + FP_FB3] %asi
24188645Sjake	membar	#Sync
24281135Stmm	retl
24388645Sjake	 wr	%g0, 0, %fprs
24481135StmmEND(savefpctx)
24581135Stmm
24681135StmmENTRY(restorefpctx)
24788645Sjake	wr	%g0, FPRS_FEF, %fprs
24888645Sjake	wr	%g0, ASI_BLK_S, %asi
24988645Sjake	ldda	[%o0 + PCB_FPSTATE + FP_FB0] %asi, %f0
25088645Sjake	ldda	[%o0 + PCB_FPSTATE + FP_FB1] %asi, %f16
25188645Sjake	ldda	[%o0 + PCB_FPSTATE + FP_FB2] %asi, %f32
25288645Sjake	ldda	[%o0 + PCB_FPSTATE + FP_FB3] %asi, %f48
25388645Sjake	membar	#Sync
25481135Stmm	retl
25588645Sjake	 wr	%g0, 0, %fprs
25681135StmmEND(restorefpctx)
257