Home | History | Annotate | Line # | Download | only in m68k
      1 /*	$NetBSD: switch_subr.s,v 1.42 2025/04/03 13:44:06 nat Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2001 The NetBSD Foundation.
      5  * Copyright (c) 1988 University of Utah.
      6  * Copyright (c) 1980, 1990, 1993
      7  *	The Regents of the University of California.  All rights reserved.
      8  *
      9  * This code is derived from software contributed to Berkeley by
     10  * the Systems Programming Group of the University of Utah Computer
     11  * Science Department.
     12  *
     13  * Redistribution and use in source and binary forms, with or without
     14  * modification, are permitted provided that the following conditions
     15  * are met:
     16  * 1. Redistributions of source code must retain the above copyright
     17  *    notice, this list of conditions and the following disclaimer.
     18  * 2. Redistributions in binary form must reproduce the above copyright
     19  *    notice, this list of conditions and the following disclaimer in the
     20  *    documentation and/or other materials provided with the distribution.
     21  * 3. Neither the name of the University nor the names of its contributors
     22  *    may be used to endorse or promote products derived from this software
     23  *    without specific prior written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     35  * SUCH DAMAGE.
     36  *
     37  * Split from: Utah $Hdr: locore.s 1.66 92/12/22$
     38  */
     39 
     40 #include "opt_fpu_emulate.h"
     41 #include "opt_lockdebug.h"
     42 #include "opt_pmap_debug.h"
     43 #include "opt_m68k_arch.h"
     44 
     45 /*
     46  * NOTICE: This is not a standalone file.  To use it, #include it in
     47  * your port's locore.s, like so:
     48  *
     49  *	#include <m68k/m68k/switch_subr.s>
     50  *
     51  * If your port uses one or more non-motorola FPU devices, you must use:
     52  *
     53  *      #define _M68K_CUSTOM_FPU_CTX 1
     54  *
     55  * before including this file. In this case, you must also provide
     56  * two assembly sub-routines for saving and restoring FPU context:
     57  *
     58  *      ASENTRY(m68k_fpuctx_save)
     59  *        %a1 -> The PCB of the outgoing thread where fpu state should be saved
     60  *
     61  *        %a0 and %a1 must be preserved across the call, but all other
     62  *        registers are available for use.
     63  *
     64  *	ASENTRY(m68k_fpuctx_restore)
     65  *        %a1 -> The PCB of the incoming thread where fpu state is saved
     66  *
     67  *	  All registers except %d0, %d1 and %a0 must be preserved across
     68  *        the call.
     69  */
     70 
     71 	.data
     72 GLOBAL(curpcb)
     73 GLOBAL(masterpaddr)		| XXXcompatibility (debuggers)
     74 	.long	0
     75 
     76 /*
     77  * When no processes are on the runq, Swtch branches to Idle
     78  * to wait for something to come ready.
     79  */
     80 ASENTRY_NOPROFILE(cpu_idle)
     81 	stop	#PSL_LOWIPL
     82 GLOBAL(_Idle)				/* For sun2/sun3's clock.c ... */
     83 	rts
     84 
     85 /*
     86  * struct lwp *cpu_switchto(struct lwp *oldlwp, struct lwp *newlwp)
     87  *
     88  * Switch to the specific next LWP.
     89  */
     90 ENTRY(cpu_switchto)
     91 	movl	4(%sp),%a1		| fetch outgoing lwp
     92 	/*
     93 	 * Save state of previous process in its pcb.
     94 	 */
     95 	movl	L_PCB(%a1),%a1
     96 	moveml	%d2-%d7/%a2-%a7,PCB_REGS(%a1)	| save non-scratch registers
     97 	movl	%usp,%a2		| grab USP (a2 has been saved)
     98 	movl	%a2,PCB_USP(%a1)	| and save it
     99 
    100 #ifdef _M68K_CUSTOM_FPU_CTX
    101 	jbsr	_ASM_LABEL(m68k_fpuctx_save)
    102 #else
    103 #ifdef FPCOPROC
    104 	tstl	_C_LABEL(fputype)	| Do we have an FPU?
    105 	jeq	.Lcpu_switch_nofpsave	| No  Then don't attempt save.
    106 
    107 	lea	PCB_FPCTX(%a1),%a2	| pointer to FP save area
    108 	fsave	(%a2)			| save FP state
    109 #if defined(M68020) || defined(M68030) || defined(M68040)
    110 #if defined(M68060)
    111 	cmpl	#FPU_68060,_C_LABEL(fputype)
    112 	jeq	.Lcpu_switch_savfp60
    113 #endif
    114 	tstb	(%a2)			| null state frame?
    115 	jeq	.Lcpu_switch_nofpsave	| yes, all done
    116 	fmovem	%fp0-%fp7,FPF_REGS(%a2) | save FP general registers
    117 	fmovem	%fpcr/%fpsr/%fpi,FPF_FPCR(%a2) | save FP control registers
    118 #if defined(M68060)
    119 	jra	.Lcpu_switch_nofpsave
    120 #endif
    121 #endif
    122 #if defined(M68060)
    123 .Lcpu_switch_savfp60:
    124 	tstb	2(%a2)			| null state frame?
    125 	jeq	.Lcpu_switch_nofpsave	| yes, all done
    126 	fmovem	%fp0-%fp7,FPF_REGS(%a2) | save FP general registers
    127 	fmovem	%fpcr,FPF_FPCR(%a2)	| save FP control registers
    128 	fmovem	%fpsr,FPF_FPSR(%a2)
    129 	fmovem	%fpi,FPF_FPI(%a2)
    130 #endif
    131 .Lcpu_switch_nofpsave:
    132 #endif	/* FPCOPROC */
    133 #endif	/* !_M68K_CUSTOM_FPU_CTX */
    134 
    135 	movl	8(%sp),%a0		| get newlwp
    136 	movl	%a0,_C_LABEL(curlwp)	| curlwp = new lwp
    137 	movl	L_PCB(%a0),%a1		| get its pcb
    138 	movl	%a1,_C_LABEL(curpcb)	| curpcb = new pcb
    139 
    140 	/*
    141 	 * Check for restartable atomic sequences (RAS)
    142 	 */
    143 	movl	L_PROC(%a0),%a2
    144 	tstl	P_RASLIST(%a2)		| p->p_raslist == NULL?
    145 	jeq	2f			| yes, skip it.
    146 	movl	L_MD_REGS(%a0),%a1
    147 	movl	TF_PC(%a1),-(%sp)	| push return PC
    148 	movl	%a2,-(%sp)		| push proc
    149 	jbsr	_C_LABEL(ras_lookup)	| a0 = ras_lookup(p, pc)
    150 	addql	#8,%sp
    151 	movql	#-1,%d0
    152 	cmpl	%a0,%d0			| a0 == -1?
    153 	jeq	1f			| yes, skip it.
    154 	movl	_C_LABEL(curlwp),%a1
    155 	movl	L_MD_REGS(%a1),%a1
    156 	movl	%a0,TF_PC(%a1)		| fixup return PC
    157 1:
    158 	movl	_C_LABEL(curlwp),%a0	| recover new lwp
    159 	movl	_C_LABEL(curpcb),%a1	| recover new pcb
    160 2:
    161 	movl	%a0,%d0			| free up %a0
    162 	movl	4(%sp),%d1		| get oldlwp for return value
    163 	lea	_ASM_LABEL(tmpstk),%sp	| switch to tmp stack in case of NMI
    164 
    165 	moveml	PCB_REGS(%a1),%d2-%d7/%a2-%a7 | restore registers
    166 	movl	PCB_USP(%a1),%a0
    167 	movl	%a0,%usp		      | and USP
    168 
    169 #ifdef _M68K_CUSTOM_FPU_CTX
    170 	moveml	%d0/%d1,-(%sp)
    171 	jbsr	_ASM_LABEL(m68k_fpuctx_restore)
    172 	moveml	(%sp)+,%d0/%d1
    173 #else
    174 #ifdef FPCOPROC
    175 	tstl	_C_LABEL(fputype)	| Do we have an FPU?
    176 	jeq	.Lcpu_switch_nofprest	| No  Then don't attempt restore.
    177 
    178 	lea	PCB_FPCTX(%a1),%a0	| pointer to FP save area
    179 #if defined(M68020) || defined(M68030) || defined(M68040)
    180 #if defined(M68060)
    181 	cmpl	#FPU_68060,_C_LABEL(fputype)
    182 	jeq	.Lcpu_switch_resfp60rest1
    183 #endif
    184 	tstb	(%a0)			| null state frame?
    185 	jeq	.Lcpu_switch_resfprest	| yes, easy
    186 	fmovem	FPF_FPCR(%a0),%fpcr/%fpsr/%fpi | restore FP control registers
    187 	fmovem	FPF_REGS(%a0),%fp0-%fp7	| restore FP general registers
    188 #if defined(M68060)
    189 	jra	.Lcpu_switch_resfprest
    190 #endif
    191 #endif
    192 
    193 #if defined(M68060)
    194 .Lcpu_switch_resfp60rest1:
    195 	tstb	2(%a0)			| null state frame?
    196 	jeq	.Lcpu_switch_resfprest	| yes, easy
    197 	fmovem	FPF_FPCR(%a0),%fpcr	| restore FP control registers
    198 	fmovem	FPF_FPSR(%a0),%fpsr
    199 	fmovem	FPF_FPI(%a0),%fpi
    200 	fmovem	FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers
    201 #endif
    202 .Lcpu_switch_resfprest:
    203 	frestore (%a0)			| restore state
    204 #endif /* FPCOPROC */
    205 #endif /* !_M68K_CUSTOM_FPU_CTX */
    206 
    207 .Lcpu_switch_nofprest:
    208 	movl	%d1,%d0			| return outgoing lwp
    209 	movl	%d0,%a0			| (in a0, too)
    210 	rts
    211 
    212 /*
    213  * savectx(pcb)
    214  * Update pcb, saving current processor state.
    215  */
    216 ENTRY(savectx)
    217 	movl	4(%sp),%a1
    218 	movw	%sr,PCB_PS(%a1)
    219 	movl	%usp,%a0		| grab USP
    220 	movl	%a0,PCB_USP(%a1)	| and save it
    221 	moveml	%d2-%d7/%a2-%a7,PCB_REGS(%a1)	| save non-scratch registers
    222 
    223 #ifdef _M68K_CUSTOM_FPU_CTX
    224 	jbsr	_ASM_LABEL(m68k_fpuctx_save)
    225 #else
    226 #ifdef FPCOPROC
    227 	tstl	_C_LABEL(fputype)	| Do we have FPU?
    228 	jeq	.Lsavectx_nofpsave	| No?  Then don't save state.
    229 
    230 	lea	PCB_FPCTX(%a1),%a0	| pointer to FP save area
    231 	fsave	(%a0)			| save FP state
    232 #if defined(M68020) || defined(M68030) || defined(M68040)
    233 #if defined(M68060)
    234 	cmpl	#FPU_68060,_C_LABEL(fputype)
    235 	jeq	.Lsavectx_savfp60
    236 #endif
    237 	tstb	(%a0)			| null state frame?
    238 	jeq	.Lsavectx_nofpsave	| yes, all done
    239 	fmovem	%fp0-%fp7,FPF_REGS(%a0)	| save FP general registers
    240 	fmovem	%fpcr/%fpsr/%fpi,FPF_FPCR(%a0) | save FP control registers
    241 #if defined(M68060)
    242 	jra	.Lsavectx_nofpsave
    243 #endif
    244 #endif
    245 #if defined(M68060)
    246 .Lsavectx_savfp60:
    247 	tstb	2(%a0)			| null state frame?
    248 	jeq	.Lsavectx_nofpsave	| yes, all done
    249 	fmovem	%fp0-%fp7,FPF_REGS(%a0) | save FP general registers
    250 	fmovem	%fpcr,FPF_FPCR(%a0)	| save FP control registers
    251 	fmovem	%fpsr,FPF_FPSR(%a0)
    252 	fmovem	%fpi,FPF_FPI(%a0)
    253 #endif
    254 .Lsavectx_nofpsave:
    255 #endif /* FPCOPROC */
    256 #endif /* !_M68K_CUSTOM_FPU_CTX */
    257 	moveq	#0,%d0			| return 0
    258 	rts
    259 
    260 #if !defined(M68010)
    261 /*
    262  * void m68k_make_fpu_idle_frame(void)
    263  *
    264  * On machines with an FPU, generate an "idle" state frame to be
    265  * used by cpu_setmcontext().
    266  *
    267  * Before calling, make sure the machine actually has an FPU ...
    268  */
    269 ENTRY(m68k_make_fpu_idle_frame)
    270 	clrl	-(%sp)
    271 	fnop
    272 
    273 	frestore (%sp)			| Effectively `resets' the FPU
    274 	fnop
    275 
    276 	/* Loading '0.0' will change FPU to "idle". */
    277 	fmove.d #0,%fp0
    278 	fnop
    279 
    280 	/* Save the resulting idle frame into the buffer */
    281 	lea	_C_LABEL(m68k_cached_fpu_idle_frame),%a0
    282 	fsave	(%a0)
    283 	fnop
    284 
    285 	/* Reset the FPU again */
    286 	frestore (%sp)
    287 	fnop
    288 	addql	#4,%sp
    289 	rts
    290 #endif
    291 
    292 /*
    293  * Save and restore 68881 state.
    294  */
    295 #ifdef FPCOPROC
    296 ENTRY(m68881_save)
    297 	movl	4(%sp),%a0		| save area pointer
    298 	fsave	(%a0)			| save state
    299 #if defined(M68020) || defined(M68030) || defined(M68040)
    300 #if defined(M68060)
    301 	cmpl	#FPU_68060,_C_LABEL(fputype)
    302 	jeq	.Lm68060fpsave
    303 #endif
    304 .Lm68881fpsave:
    305 	tstb	(%a0)			| null state frame?
    306 	jeq	.Lm68881sdone		| yes, all done
    307 	fmovem	%fp0-%fp7,FPF_REGS(%a0)	| save FP general registers
    308 	fmovem	%fpcr/%fpsr/%fpi,FPF_FPCR(%a0) | save FP control registers
    309 .Lm68881sdone:
    310 	rts
    311 #endif
    312 #if defined(M68060)
    313 .Lm68060fpsave:
    314 	tstb	2(%a0)			| null state frame?
    315 	jeq	.Lm68060sdone		| yes, all done
    316 	fmovem	%fp0-%fp7,FPF_REGS(%a0)	| save FP general registers
    317 	fmovem	%fpcr,FPF_FPCR(%a0)	| save FP control registers
    318 	fmovem	%fpsr,FPF_FPSR(%a0)
    319 	fmovem	%fpi,FPF_FPI(%a0)
    320 .Lm68060sdone:
    321         rts
    322 #endif
    323 
    324 ENTRY(m68881_restore)
    325 	movl	4(%sp),%a0		| save area pointer
    326 #if defined(M68020) || defined(M68030) || defined(M68040)
    327 #if defined(M68060)
    328 	cmpl	#FPU_68060,_C_LABEL(fputype)
    329 	jeq	.Lm68060fprestore
    330 #endif
    331 .Lm68881fprestore:
    332 	tstb	(%a0)			| null state frame?
    333 	jeq	.Lm68881rdone		| yes, easy
    334 	fmovem	FPF_FPCR(%a0),%fpcr/%fpsr/%fpi | restore FP control registers
    335 	fmovem	FPF_REGS(%a0),%fp0-%fp7	| restore FP general registers
    336 .Lm68881rdone:
    337 	frestore (%a0)			| restore state
    338 	rts
    339 #endif
    340 #if defined(M68060)
    341 .Lm68060fprestore:
    342 	tstb	2(%a0)			| null state frame?
    343 	jeq	.Lm68060fprdone		| yes, easy
    344 	fmovem	FPF_FPCR(%a0),%fpcr	| restore FP control registers
    345 	fmovem	FPF_FPSR(%a0),%fpsr
    346 	fmovem	FPF_FPI(%a0),%fpi
    347 	fmovem	FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers
    348 .Lm68060fprdone:
    349 	frestore (%a0)			| restore state
    350 	rts
    351 #endif
    352 #endif
    353 
    354 /*
    355  * lwp_trampoline: call function in register %a2 with %a3 as an arg
    356  * and then rei.
    357  * %a0 will have old lwp from cpu_switchto(), and %a4 is new lwp
    358  */
    359 ENTRY_NOPROFILE(lwp_trampoline)
    360 	movl	%a4,-(%sp)		| new lwp
    361 	movl	%a0,-(%sp)		| old lpw
    362 	jbsr	_C_LABEL(lwp_startup)
    363 	addql	#8,%sp
    364 	movl	%a3,-(%sp)		| push function arg
    365 	jbsr	(%a2)			| call function
    366 	addql	#4,%sp			| pop arg
    367 	movl	FR_SP(%sp),%a0		| grab and load
    368 	movl	%a0,%usp		|   user SP
    369 	moveml	(%sp)+,#0x7FFF		| restore most user regs
    370 	addql	#8,%sp			| toss SP and stack adjust
    371 	jra	_ASM_LABEL(rei)		| and return
    372