Home | History | Annotate | Line # | Download | only in m68k
      1 /*	$NetBSD: switch_subr.s,v 1.46 2026/03/29 13:41:37 thorpej 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 #include <machine/asm.h>
     46 
     47 #include "assym.h"
     48 
     49 	.file	"switch_subr.s"
     50 	.text
     51 
     52 	.data
     53 GLOBAL(curpcb)
     54 GLOBAL(masterpaddr)		| XXXcompatibility (debuggers)
     55 	.long	0
     56 
     57 /*
     58  * When no processes are on the runq, Swtch branches to Idle
     59  * to wait for something to come ready.
     60  */
     61 ASENTRY_NOPROFILE(cpu_idle)
     62 	stop	#PSL_LOWIPL
     63 GLOBAL(_Idle)				/* For sun2/sun3's clock.c ... */
     64 	rts
     65 
     66 /*
     67  * struct lwp *cpu_switchto(struct lwp *oldlwp, struct lwp *newlwp)
     68  *
     69  * Switch to the specific next LWP.
     70  */
     71 ENTRY(cpu_switchto)
     72 	movl	4(%sp),%a1		| fetch outgoing lwp
     73 	/*
     74 	 * Save state of previous process in its pcb.
     75 	 */
     76 	movl	L_PCB(%a1),%a1
     77 	moveml	%d2-%d7/%a2-%a7,PCB_REGS(%a1)	| save non-scratch registers
     78 	movl	%usp,%a2		| grab USP (a2 has been saved)
     79 	movl	%a2,PCB_USP(%a1)	| and save it
     80 
     81 #ifdef M68K_FPCOPROC
     82 	tstl	_C_LABEL(fputype)	| Do we have an FPU?
     83 	jeq	.Lcpu_switch_nofpsave	| No  Then don't attempt save.
     84 
     85 	lea	PCB_FPCTX(%a1),%a2	| pointer to FP save area
     86 	fsave	(%a2)			| save FP state
     87 #if defined(M68020) || defined(M68030) || defined(M68040)
     88 #if defined(M68060)
     89 	cmpl	#FPU_68060,_C_LABEL(fputype)
     90 	jeq	.Lcpu_switch_savfp60
     91 #endif
     92 	tstb	(%a2)			| null state frame?
     93 	jeq	.Lcpu_switch_nofpsave	| yes, all done
     94 	fmovem	%fp0-%fp7,FPF_REGS(%a2) | save FP general registers
     95 	fmovem	%fpcr/%fpsr/%fpi,FPF_FPCR(%a2) | save FP control registers
     96 #if defined(M68060)
     97 	jra	.Lcpu_switch_nofpsave
     98 #endif
     99 #endif
    100 #if defined(M68060)
    101 .Lcpu_switch_savfp60:
    102 	tstb	2(%a2)			| null state frame?
    103 	jeq	.Lcpu_switch_nofpsave	| yes, all done
    104 	fmovem	%fp0-%fp7,FPF_REGS(%a2) | save FP general registers
    105 	fmovem	%fpcr,FPF_FPCR(%a2)	| save FP control registers
    106 	fmovem	%fpsr,FPF_FPSR(%a2)
    107 	fmovem	%fpi,FPF_FPI(%a2)
    108 #endif
    109 .Lcpu_switch_nofpsave:
    110 #endif	/* M68K_FPCOPROC */
    111 
    112 	movl	8(%sp),%a0		| get newlwp
    113 	movl	%a0,_C_LABEL(curlwp)	| curlwp = new lwp
    114 	movl	L_PCB(%a0),%a1		| get its pcb
    115 	movl	%a1,_C_LABEL(curpcb)	| curpcb = new pcb
    116 
    117 	/*
    118 	 * Check for restartable atomic sequences (RAS)
    119 	 */
    120 	movl	L_PROC(%a0),%a2
    121 	tstl	P_RASLIST(%a2)		| p->p_raslist == NULL?
    122 	jeq	2f			| yes, skip it.
    123 	movl	L_MD_REGS(%a0),%a1
    124 	movl	TF_PC(%a1),-(%sp)	| push return PC
    125 	movl	%a2,-(%sp)		| push proc
    126 	jbsr	_C_LABEL(ras_lookup)	| a0 = ras_lookup(p, pc)
    127 	addql	#8,%sp
    128 	movql	#-1,%d0
    129 	cmpl	%a0,%d0			| a0 == -1?
    130 	jeq	1f			| yes, skip it.
    131 	movl	_C_LABEL(curlwp),%a1
    132 	movl	L_MD_REGS(%a1),%a1
    133 	movl	%a0,TF_PC(%a1)		| fixup return PC
    134 1:
    135 	movl	_C_LABEL(curlwp),%a0	| recover new lwp
    136 	movl	_C_LABEL(curpcb),%a1	| recover new pcb
    137 2:
    138 	movl	%a0,%d0			| free up %a0
    139 	movl	4(%sp),%d1		| get oldlwp for return value
    140 	lea	_ASM_LABEL(tmpstk),%sp	| switch to tmp stack in case of NMI
    141 
    142 	moveml	PCB_REGS(%a1),%d2-%d7/%a2-%a7 | restore registers
    143 	movl	PCB_USP(%a1),%a0
    144 	movl	%a0,%usp		      | and USP
    145 
    146 #ifdef M68K_FPCOPROC
    147 	tstl	_C_LABEL(fputype)	| Do we have an FPU?
    148 	jeq	.Lcpu_switch_nofprest	| No  Then don't attempt restore.
    149 
    150 	lea	PCB_FPCTX(%a1),%a0	| pointer to FP save area
    151 #if defined(M68020) || defined(M68030) || defined(M68040)
    152 #if defined(M68060)
    153 	cmpl	#FPU_68060,_C_LABEL(fputype)
    154 	jeq	.Lcpu_switch_resfp60rest1
    155 #endif
    156 	tstb	(%a0)			| null state frame?
    157 	jeq	.Lcpu_switch_resfprest	| yes, easy
    158 	fmovem	FPF_FPCR(%a0),%fpcr/%fpsr/%fpi | restore FP control registers
    159 	fmovem	FPF_REGS(%a0),%fp0-%fp7	| restore FP general registers
    160 #if defined(M68060)
    161 	jra	.Lcpu_switch_resfprest
    162 #endif
    163 #endif
    164 
    165 #if defined(M68060)
    166 .Lcpu_switch_resfp60rest1:
    167 	tstb	2(%a0)			| null state frame?
    168 	jeq	.Lcpu_switch_resfprest	| yes, easy
    169 	fmovem	FPF_FPCR(%a0),%fpcr	| restore FP control registers
    170 	fmovem	FPF_FPSR(%a0),%fpsr
    171 	fmovem	FPF_FPI(%a0),%fpi
    172 	fmovem	FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers
    173 #endif
    174 .Lcpu_switch_resfprest:
    175 	frestore (%a0)			| restore state
    176 #endif /* M68K_FPCOPROC */
    177 
    178 .Lcpu_switch_nofprest:
    179 	movl	%d1,%d0			| return outgoing lwp
    180 	movl	%d0,%a0			| (in a0, too)
    181 	rts
    182 
    183 /*
    184  * savectx(pcb)
    185  * Update pcb, saving current processor state.
    186  */
    187 ENTRY(savectx)
    188 	movl	4(%sp),%a1
    189 	movw	%sr,PCB_PS(%a1)
    190 	movl	%usp,%a0		| grab USP
    191 	movl	%a0,PCB_USP(%a1)	| and save it
    192 	moveml	%d2-%d7/%a2-%a7,PCB_REGS(%a1)	| save non-scratch registers
    193 
    194 #ifdef M68K_FPCOPROC
    195 	tstl	_C_LABEL(fputype)	| Do we have FPU?
    196 	jeq	.Lsavectx_nofpsave	| No?  Then don't save state.
    197 
    198 	lea	PCB_FPCTX(%a1),%a0	| pointer to FP save area
    199 	fsave	(%a0)			| save FP state
    200 #if defined(M68020) || defined(M68030) || defined(M68040)
    201 #if defined(M68060)
    202 	cmpl	#FPU_68060,_C_LABEL(fputype)
    203 	jeq	.Lsavectx_savfp60
    204 #endif
    205 	tstb	(%a0)			| null state frame?
    206 	jeq	.Lsavectx_nofpsave	| yes, all done
    207 	fmovem	%fp0-%fp7,FPF_REGS(%a0)	| save FP general registers
    208 	fmovem	%fpcr/%fpsr/%fpi,FPF_FPCR(%a0) | save FP control registers
    209 #if defined(M68060)
    210 	jra	.Lsavectx_nofpsave
    211 #endif
    212 #endif
    213 #if defined(M68060)
    214 .Lsavectx_savfp60:
    215 	tstb	2(%a0)			| null state frame?
    216 	jeq	.Lsavectx_nofpsave	| yes, all done
    217 	fmovem	%fp0-%fp7,FPF_REGS(%a0) | save FP general registers
    218 	fmovem	%fpcr,FPF_FPCR(%a0)	| save FP control registers
    219 	fmovem	%fpsr,FPF_FPSR(%a0)
    220 	fmovem	%fpi,FPF_FPI(%a0)
    221 #endif
    222 .Lsavectx_nofpsave:
    223 #endif /* M68K_FPCOPROC */
    224 	moveq	#0,%d0			| return 0
    225 	rts
    226 
    227 #ifdef M68K_FPCOPROC
    228 /*
    229  * void m68k_make_fpu_idle_frame(void)
    230  *
    231  * On machines with an FPU, generate an "idle" state frame to be
    232  * used by cpu_setmcontext().
    233  *
    234  * Before calling, make sure the machine actually has an FPU ...
    235  */
    236 ENTRY(m68k_make_fpu_idle_frame)
    237 	clrl	-(%sp)
    238 	fnop
    239 
    240 	frestore (%sp)			| Effectively `resets' the FPU
    241 	fnop
    242 
    243 	/* Loading '0.0' will change FPU to "idle". */
    244 	fmove.d #0,%fp0
    245 	fnop
    246 
    247 	/* Save the resulting idle frame into the buffer */
    248 	lea	_C_LABEL(m68k_cached_fpu_idle_frame),%a0
    249 	fsave	(%a0)
    250 	fnop
    251 
    252 	/* Reset the FPU again */
    253 	frestore (%sp)
    254 	fnop
    255 	addql	#4,%sp
    256 	rts
    257 
    258 /*
    259  * Save and restore 68881 state.
    260  */
    261 ENTRY(m68881_save)
    262 	movl	4(%sp),%a0		| save area pointer
    263 	fsave	(%a0)			| save state
    264 #if defined(M68020) || defined(M68030) || defined(M68040)
    265 #if defined(M68060)
    266 	cmpl	#FPU_68060,_C_LABEL(fputype)
    267 	jeq	.Lm68060fpsave
    268 #endif
    269 .Lm68881fpsave:
    270 	tstb	(%a0)			| null state frame?
    271 	jeq	.Lm68881sdone		| yes, all done
    272 	fmovem	%fp0-%fp7,FPF_REGS(%a0)	| save FP general registers
    273 	fmovem	%fpcr/%fpsr/%fpi,FPF_FPCR(%a0) | save FP control registers
    274 .Lm68881sdone:
    275 	rts
    276 #endif
    277 #if defined(M68060)
    278 .Lm68060fpsave:
    279 	tstb	2(%a0)			| null state frame?
    280 	jeq	.Lm68060sdone		| yes, all done
    281 	fmovem	%fp0-%fp7,FPF_REGS(%a0)	| save FP general registers
    282 	fmovem	%fpcr,FPF_FPCR(%a0)	| save FP control registers
    283 	fmovem	%fpsr,FPF_FPSR(%a0)
    284 	fmovem	%fpi,FPF_FPI(%a0)
    285 .Lm68060sdone:
    286         rts
    287 #endif
    288 
    289 ENTRY(m68881_restore)
    290 	movl	4(%sp),%a0		| save area pointer
    291 #if defined(M68020) || defined(M68030) || defined(M68040)
    292 #if defined(M68060)
    293 	cmpl	#FPU_68060,_C_LABEL(fputype)
    294 	jeq	.Lm68060fprestore
    295 #endif
    296 .Lm68881fprestore:
    297 	tstb	(%a0)			| null state frame?
    298 	jeq	.Lm68881rdone		| yes, easy
    299 	fmovem	FPF_FPCR(%a0),%fpcr/%fpsr/%fpi | restore FP control registers
    300 	fmovem	FPF_REGS(%a0),%fp0-%fp7	| restore FP general registers
    301 .Lm68881rdone:
    302 	frestore (%a0)			| restore state
    303 	rts
    304 #endif
    305 #if defined(M68060)
    306 .Lm68060fprestore:
    307 	tstb	2(%a0)			| null state frame?
    308 	jeq	.Lm68060fprdone		| yes, easy
    309 	fmovem	FPF_FPCR(%a0),%fpcr	| restore FP control registers
    310 	fmovem	FPF_FPSR(%a0),%fpsr
    311 	fmovem	FPF_FPI(%a0),%fpi
    312 	fmovem	FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers
    313 .Lm68060fprdone:
    314 	frestore (%a0)			| restore state
    315 	rts
    316 #endif
    317 
    318 #else /* ! M68K_FPCOPROC */
    319 
    320 #ifdef DIAGNOSTIC
    321 .L68881panic:
    322 	.asciz	"m68881 save/restore"
    323 	.even
    324 #endif
    325 
    326 ENTRY_NOPROFILE(m68881_save)
    327 GLOBAL(m68881_restore)
    328 #ifdef  DIAGNOSTIC
    329 	pea	.L68881panic
    330 	jbsr	_C_LABEL(panic)
    331 	/*NOTREACHED*/
    332 #endif
    333 	rts
    334 
    335 #endif /* M68K_FPCOPROC */
    336 
    337 /*
    338  * lwp_trampoline: call function in register %a2 with %a3 as an arg
    339  * and then rei.
    340  * %a0 will have old lwp from cpu_switchto(), and %a4 is new lwp
    341  */
    342 ENTRY_NOPROFILE(lwp_trampoline)
    343 	movl	%a4,-(%sp)		| new lwp
    344 	movl	%a0,-(%sp)		| old lpw
    345 	jbsr	_C_LABEL(lwp_startup)
    346 	addql	#8,%sp
    347 	movl	%a3,-(%sp)		| push function arg
    348 	jbsr	(%a2)			| call function
    349 	addql	#4,%sp			| pop arg
    350 	movl	FR_SP(%sp),%a0		| grab and load
    351 	movl	%a0,%usp		|   user SP
    352 	moveml	(%sp)+,#0x7FFF		| restore most user regs
    353 	addql	#8,%sp			| toss SP and stack adjust
    354 	jra	_ASM_LABEL(rei)		| and return
    355