xref: /netbsd-src/sys/arch/m68k/m68k/switch_subr.s (revision fd37012490804ae3a97ba29c97ce78f5d787def9)
1/*	$NetBSD: switch_subr.s,v 1.38 2024/10/31 07:30:28 isaki 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
72GLOBAL(curpcb)
73GLOBAL(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 */
80ASENTRY_NOPROFILE(cpu_idle)
81	stop	#PSL_LOWIPL
82GLOBAL(_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 */
90ENTRY(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
1571:
158	movl	_C_LABEL(curlwp),%a0	| recover new lwp
159	movl	_C_LABEL(curpcb),%a1	| recover new pcb
1602:
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 */
216ENTRY(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 */
269ENTRY(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
296ENTRY(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
324ENTRY(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 */
359ENTRY_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