NetBSD-5.0.2/sys/arch/m68k/m68k/switch_subr.s

Compare this file to the similar file:
Show the results in this format:

/*	$NetBSD: switch_subr.s,v 1.21.36.1 2009/06/05 18:36:05 snj Exp $	*/

/*
 * Copyright (c) 2001 The NetBSD Foundation.
 * Copyright (c) 1980, 1990, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * Split from: Utah $Hdr: locore.s 1.66 92/12/22$
 */

/*
 * Copyright (c) 1988 University of Utah.
 *
 * This code is derived from software contributed to Berkeley by
 * the Systems Programming Group of the University of Utah Computer
 * Science Department.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * Split from: Utah $Hdr: locore.s 1.66 92/12/22$
 */

#include "opt_fpu_emulate.h"
#include "opt_lockdebug.h"
#include "opt_pmap_debug.h"

/*
 * NOTICE: This is not a standalone file.  To use it, #include it in
 * your port's locore.s, like so:
 *
 *	#include <m68k/m68k/switch_subr.s>
 *
 * If your port uses one or more non-motorola FPU devices, you must use:
 *
 *      #define _M68K_CUSTOM_FPU_CTX 1
 *
 * before including this file. In this case, you must also provide
 * two assembly sub-routines for saving and restoring FPU context:
 *
 *      ASENTRY(m68k_fpuctx_save)
 *        %a1 -> The PCB of the outgoing thread where fpu state should be saved
 *
 *        %a0 and %a1 must be preserved across the call, but all other
 *        registers are available for use.
 *
 *	ASENTRY(m68k_fpuctx_restore)
 *        %a1 -> The PCB of the incoming thread where fpu state is saved
 *
 *	  All registers except %d0, %d1 and %a0 must be preserved across
 *        the call.
 */

	.data
GLOBAL(curpcb)
GLOBAL(masterpaddr)		| XXXcompatibility (debuggers)
	.long	0

/*
 * When no processes are on the runq, Swtch branches to Idle
 * to wait for something to come ready.
 */
ASENTRY_NOPROFILE(cpu_idle)
	stop	#PSL_LOWIPL
GLOBAL(_Idle)				/* For sun2/sun3's clock.c ... */
	rts

/*
 * struct lwp *cpu_switchto(struct lwp *oldlwp, struct lwp *newlwp)
 *
 * Switch to the specific next LWP.
 */
ENTRY(cpu_switchto)
	movl	%sp@(4),%a1		| fetch `current' lwp
#ifdef M68010
	movl	%a1,%d0
	tstl	%d0
#else
	tstl	%a1			| Old LWP exited?
#endif
	jeq	Lcpu_switch_noctxsave	| Yup. Don't bother saving context

	/*
	 * Save state of previous process in its pcb.
	 */
	movl	%a1@(L_ADDR),%a1
	moveml	%d2-%d7/%a2-%a7,%a1@(PCB_REGS)	| save non-scratch registers
	movl	%usp,%a2		| grab USP (a2 has been saved)
	movl	%a2,%a1@(PCB_USP)	| and save it

#ifdef _M68K_CUSTOM_FPU_CTX
	jbsr	_ASM_LABEL(m68k_fpuctx_save)
#else
#ifdef FPCOPROC
#ifdef FPU_EMULATE
	tstl	_C_LABEL(fputype)	| Do we have an FPU?
	jeq	Lcpu_switch_nofpsave	| No  Then don't attempt save.
#endif
	lea	%a1@(PCB_FPCTX),%a2	| pointer to FP save area
	fsave	%a2@			| save FP state
#if defined(M68020) || defined(M68030) || defined(M68040)
#if defined(M68060)
	cmpl	#FPU_68060,_C_LABEL(fputype)
	jeq	Lcpu_switch_savfp60                
#endif  
	tstb	%a2@			| null state frame?
	jeq	Lcpu_switch_nofpsave	| yes, all done
	fmovem	%fp0-%fp7,%a2@(FPF_REGS) | save FP general registers
	fmovem	%fpcr/%fpsr/%fpi,%a2@(FPF_FPCR) | save FP control registers
#if defined(M68060)
	jra	Lcpu_switch_nofpsave 
#endif  
#endif  
#if defined(M68060)
Lcpu_switch_savfp60:
	tstb	%a2@(2)			| null state frame?
	jeq	Lcpu_switch_nofpsave	| yes, all done 
	fmovem	%fp0-%fp7,%a2@(FPF_REGS) | save FP general registers 
	fmovem	%fpcr,%a2@(FPF_FPCR)	| save FP control registers
	fmovem	%fpsr,%a2@(FPF_FPSR)
	fmovem	%fpi,%a2@(FPF_FPI)
#endif
Lcpu_switch_nofpsave:
#endif	/* FPCOPROC */
#endif	/* !_M68K_CUSTOM_FPU_CTX */

Lcpu_switch_noctxsave:
	movl	%sp@(8),%a0		| get newlwp
	movl	%a0,_C_LABEL(curlwp)
	movl	%a0@(L_ADDR),%a1	| get l_addr
	movl	%a1,_C_LABEL(curpcb)

#if defined(sun2) || defined(sun3)
	movl	%a0@(L_PROC),%a2
	movl	%a2@(P_VMSPACE),%a2	| vm = p->p_vmspace
#if defined(DIAGNOSTIC) && !defined(sun2)
	tstl	%a2			| vm == VM_MAP_NULL?
	jeq	Lcpu_switch_badsw	| panic
#endif
#if !defined(_SUN3X_) || defined(PMAP_DEBUG)
	movl	%a2@(VM_PMAP),%sp@-	| push vm->vm_map.pmap
	jbsr	_C_LABEL(_pmap_switch)	| _pmap_switch(pmap)
	addql	#4,%sp
	movl	_C_LABEL(curpcb),%a1	| restore p_addr
| Note: _pmap_switch() will clear the cache if needed.
#else
	/* Use this inline version on sun3x when not debugging the pmap. */
	lea	_C_LABEL(kernel_crp),%a3 | our CPU Root Ptr. (CRP)
	movl	%a2@(VM_PMAP),%a2 	| pmap = vm->vm_map.pmap
	movl	%a2@(PM_A_PHYS),%d0	| phys = pmap->pm_a_phys
	cmpl	%a3@(4),%d0		|  == kernel_crp.rp_addr ?
	jeq	Lsame_mmuctx		| skip loadcrp/flush
	/* OK, it is a new MMU context.  Load it up. */
	movl	%d0,%a3@(4)
	movl	#CACHE_CLR,%d0
	movc	%d0,%cacr		| invalidate cache(s)
	pflusha				| flush entire TLB
	pmove	%a3@,%crp		| load new user root pointer
Lsame_mmuctx:
#endif	/* !defined(_SUN3X_) || defined(PMAP_DEBUG) */
#else	/* !defined(sun2) && !defined(sun3) */
	/*
	 * Activate process's address space.
	 * XXX Should remember the last USTP value loaded, and call this
	 * XXX only of it has changed.
	 */
	pea	%a0@			| push newlwp
	jbsr	_C_LABEL(pmap_activate)	| pmap_activate(newlwp)
	/*
	 *  Check for restartable atomic sequences (RAS)
	 */
	movl	_C_LABEL(curlwp),%a0
	movl	%a0@(L_PROC),%a2
	tstl	%a2@(P_RASLIST)
	jeq	1f
	movl	%a0@(L_MD_REGS),%a1
	movl	%a1@(TF_PC),%sp@-
	movl	%a2,%sp@-
	jbsr	_C_LABEL(ras_lookup)
	addql	#8,%sp
	movql	#-1,%d0
	cmpl	%a0,%d0
	jeq	1f
	movl	_C_LABEL(curlwp),%a1
	movl	%a1@(L_MD_REGS),%a1
	movel	%a0,%a1@(TF_PC)
1:
	movl	%sp@+,%d0		| restore newlwp
	movl	_C_LABEL(curpcb),%a1	| restore l_addr
#endif

	movl	%sp@(4),%d1		| restore oldlwp for a return value
	lea     _ASM_LABEL(tmpstk),%sp	| now goto a tmp stack for NMI

	moveml	%a1@(PCB_REGS),%d2-%d7/%a2-%a7	| and registers
	movl	%a1@(PCB_USP),%a0
	movl	%a0,%usp		| and USP

#ifdef _M68K_CUSTOM_FPU_CTX
	moveml	%d0/%d1,%sp@-
	jbsr	_ASM_LABEL(m68k_fpuctx_restore)
	moveml	%sp@+,%d0/%d1
#else
#ifdef FPCOPROC
#ifdef FPU_EMULATE
	tstl	_C_LABEL(fputype)	| Do we have an FPU?
	jeq	Lcpu_switch_nofprest	| No  Then don't attempt restore.
#endif
	lea	%a1@(PCB_FPCTX),%a0	| pointer to FP save area
#if defined(M68020) || defined(M68030) || defined(M68040)
#if defined(M68060)
	cmpl	#FPU_68060,_C_LABEL(fputype)
	jeq	Lcpu_switch_resfp60rest1
#endif  
	tstb	%a0@			| null state frame?
	jeq	Lcpu_switch_resfprest	| yes, easy
	fmovem	%a0@(FPF_FPCR),%fpcr/%fpsr/%fpi | restore FP control registers
	fmovem	%a0@(FPF_REGS),%fp0-%fp7	| restore FP general registers
#if defined(M68060)
	jra	Lcpu_switch_resfprest
#endif
#endif

#if defined(M68060)
Lcpu_switch_resfp60rest1:
	tstb	%a0@(2)			| null state frame?
	jeq	Lcpu_switch_resfprest	| yes, easy
	fmovem	%a0@(FPF_FPCR),%fpcr	| restore FP control registers
	fmovem	%a0@(FPF_FPSR),%fpsr
	fmovem	%a0@(FPF_FPI),%fpi
	fmovem	%a0@(FPF_REGS),%fp0-%fp7 | restore FP general registers
#endif
Lcpu_switch_resfprest:
	frestore %a0@			| restore state
#endif /* FPCOPROC */
#endif /* !_M68K_CUSTOM_FPU_CTX */

Lcpu_switch_nofprest:
	movl	%d1,%d0
	movl	%d0,%a0
	rts

Lcpu_switch_badsw:
	PANIC("switch")
	/*NOTREACHED*/

/*
 * savectx(pcb)
 * Update pcb, saving current processor state.
 */
ENTRY(savectx)
	movl	%sp@(4),%a1
	movw	%sr,%a1@(PCB_PS)
	movl	%usp,%a0		| grab USP
	movl	%a0,%a1@(PCB_USP)	| and save it
	moveml	%d2-%d7/%a2-%a7,%a1@(PCB_REGS)	| save non-scratch registers

#ifdef _M68K_CUSTOM_FPU_CTX
	jbsr	_ASM_LABEL(m68k_fpuctx_save)
#else
#ifdef FPCOPROC
#ifdef FPU_EMULATE
	tstl	_C_LABEL(fputype)	| Do we have FPU?
	jeq	Lsavectx_nofpsave	| No?  Then don't save state.
#endif
	lea	%a1@(PCB_FPCTX),%a0	| pointer to FP save area
	fsave	%a0@			| save FP state
#if defined(M68020) || defined(M68030) || defined(M68040)
#if defined(M68060)
	cmpl	#FPU_68060,_C_LABEL(fputype)
	jeq	Lsavectx_savfp60
#endif  
	tstb	%a0@			| null state frame?
	jeq	Lsavectx_nofpsave	| yes, all done
	fmovem	%fp0-%fp7,%a0@(FPF_REGS)	| save FP general registers
	fmovem	%fpcr/%fpsr/%fpi,%a0@(FPF_FPCR) | save FP control registers
#if defined(M68060)
	jra	Lsavectx_nofpsave
#endif
#endif  
#if defined(M68060)
Lsavectx_savfp60:
	tstb	%a0@(2)			| null state frame?
	jeq	Lsavectx_nofpsave	| yes, all done
	fmovem	%fp0-%fp7,%a0@(FPF_REGS) | save FP general registers
	fmovem	%fpcr,%a0@(FPF_FPCR)	| save FP control registers
	fmovem	%fpsr,%a0@(FPF_FPSR)
	fmovem	%fpi,%a0@(FPF_FPI)
#endif  
Lsavectx_nofpsave:
#endif /* FPCOPROC */
#endif /* !_M68K_CUSTOM_FPU_CTX */
	moveq	#0,%d0			| return 0
	rts

#if !defined(M68010)
/*
 * void m68k_make_fpu_idle_frame(void)
 *
 * On machines with an FPU, generate an "idle" state frame to be
 * used by cpu_setmcontext().
 *
 * Before calling, make sure the machine actually has an FPU ...
 */
ENTRY(m68k_make_fpu_idle_frame)
	clrl	%sp@-
	fnop

	frestore %sp@		| Effectively `resets' the FPU
	fnop

	/* Loading '0.0' will change FPU to "idle". */
	fmove.d #0,%fp0
	fnop

	/* Save the resulting idle frame into the buffer */
	lea	_C_LABEL(m68k_cached_fpu_idle_frame),%a0
	fsave	%a0@
	fnop

	/* Reset the FPU again */
	frestore %sp@
	fnop
	addql	#4,%sp
	rts
#endif

/*
 * lwp_trampoline: call function in register %a2 with %a3 as an arg
 * and then rei.
 * %a0 will have old lwp from cpu_switchto(), and %a4 is new lwp
 */
ENTRY_NOPROFILE(lwp_trampoline)
	movl	%a4,%sp@-		| new lwp
	movl	%a0,%sp@-		| old lpw
	jbsr	_C_LABEL(lwp_startup)
	addql	#8,%sp
	movl	%a3,%sp@-		| push function arg
	jbsr	%a2@			| call function
	addql	#4,%sp			| pop arg
	movl	%sp@(FR_SP),%a0		| grab and load
	movl	%a0,%usp		|   user SP
	moveml	%sp@+,#0x7FFF		| restore most user regs
	addql	#8,%sp			| toss SP and stack adjust
	jra	_ASM_LABEL(rei)		| and return

/*
 * Very similar to lwp_trampoline, but do not call lwp_startup
 */
ENTRY_NOPROFILE(setfunc_trampoline)
	movl	%a3,%sp@-		| push function arg
	jbsr	%a2@			| call function
	addql	#4,%sp			| pop arg
	movl	%sp@(FR_SP),%a0		| grab and load
	movl	%a0,%usp		|   user SP
	moveml	%sp@+,#0x7FFF		| restore most user regs
	addql	#8,%sp			| toss SP and stack adjust
	jra	_ASM_LABEL(rei)		| and return