xref: /netbsd/sys/arch/m68k/m68k/switch_subr.s (revision 2dc232a0)
1/*	$NetBSD: switch_subr.s,v 1.34 2020/01/08 20:59:18 skrll 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 `current' 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)
137	movl	L_PCB(%a0),%a1		| get its pcb
138	movl	%a1,_C_LABEL(curpcb)
139
140#if defined(sun2) || defined(sun3)
141	movl	L_PROC(%a0),%a2
142	movl	P_VMSPACE(%a2),%a2	| vm = p->p_vmspace
143#if defined(DIAGNOSTIC) && !defined(sun2)
144	tstl	%a2			| vm == VM_MAP_NULL?
145	jeq	.Lcpu_switch_badsw	| panic
146#endif
147	pea	(%a0)			| save newlwp
148#if !defined(_SUN3X_) || defined(PMAP_DEBUG)
149	movl	VM_PMAP(%a2),-(%sp)	| push vm->vm_map.pmap
150	jbsr	_C_LABEL(_pmap_switch)	| _pmap_switch(pmap)
151	addql	#4,%sp
152	movl	_C_LABEL(curpcb),%a1	| restore curpcb
153| Note: _pmap_switch() will clear the cache if needed.
154#else
155	/* Use this inline version on sun3x when not debugging the pmap. */
156	lea	_C_LABEL(kernel_crp),%a3 | our CPU Root Ptr. (CRP)
157	movl	VM_PMAP(%a2),%a2 	| pmap = vm->vm_map.pmap
158	movl	PM_A_PHYS(%a2),%d0	| phys = pmap->pm_a_phys
159	cmpl	4(%a3),%d0		|  == kernel_crp.rp_addr ?
160	jeq	.Lsame_mmuctx		| skip loadcrp/flush
161	/* OK, it is a new MMU context.  Load it up. */
162	movl	%d0,4(%a3)
163	movl	#CACHE_CLR,%d0
164	movc	%d0,%cacr		| invalidate cache(s)
165	pflusha				| flush entire TLB
166	pmove	(%a3),%crp		| load new user root pointer
167.Lsame_mmuctx:
168#endif	/* !defined(_SUN3X_) || defined(PMAP_DEBUG) */
169#else	/* !defined(sun2) && !defined(sun3) */
170	/*
171	 * Activate process's address space.
172	 * XXX Should remember the last USTP value loaded, and call this
173	 * XXX only of it has changed.
174	 */
175	pea	(%a0)			| push newlwp
176	jbsr	_C_LABEL(pmap_activate)	| pmap_activate(newlwp)
177	/* Note that newlwp will be popped off the stack later. */
178#endif
179
180	/*
181	 *  Check for restartable atomic sequences (RAS)
182	 */
183	movl	_C_LABEL(curlwp),%a0
184	movl	L_PROC(%a0),%a2
185	tstl	P_RASLIST(%a2)
186	jeq	1f
187	movl	L_MD_REGS(%a0),%a1
188	movl	TF_PC(%a1),-(%sp)
189	movl	%a2,-(%sp)
190	jbsr	_C_LABEL(ras_lookup)
191	addql	#8,%sp
192	movql	#-1,%d0
193	cmpl	%a0,%d0
194	jeq	1f
195	movl	_C_LABEL(curlwp),%a1
196	movl	L_MD_REGS(%a1),%a1
197	movl	%a0,TF_PC(%a1)
1981:
199	movl	(%sp)+,%d0		| restore newlwp
200	movl	_C_LABEL(curpcb),%a1	| restore pcb
201
202	movl	4(%sp),%d1		| restore oldlwp for a return value
203	lea     _ASM_LABEL(tmpstk),%sp	| now goto a tmp stack for NMI
204
205	moveml	PCB_REGS(%a1),%d2-%d7/%a2-%a7	| and registers
206	movl	PCB_USP(%a1),%a0
207	movl	%a0,%usp		| and USP
208
209#ifdef _M68K_CUSTOM_FPU_CTX
210	moveml	%d0/%d1,-(%sp)
211	jbsr	_ASM_LABEL(m68k_fpuctx_restore)
212	moveml	(%sp)+,%d0/%d1
213#else
214#ifdef FPCOPROC
215	tstl	_C_LABEL(fputype)	| Do we have an FPU?
216	jeq	.Lcpu_switch_nofprest	| No  Then don't attempt restore.
217
218	lea	PCB_FPCTX(%a1),%a0	| pointer to FP save area
219#if defined(M68020) || defined(M68030) || defined(M68040)
220#if defined(M68060)
221	cmpl	#FPU_68060,_C_LABEL(fputype)
222	jeq	.Lcpu_switch_resfp60rest1
223#endif
224	tstb	(%a0)			| null state frame?
225	jeq	.Lcpu_switch_resfprest	| yes, easy
226	fmovem	FPF_FPCR(%a0),%fpcr/%fpsr/%fpi | restore FP control registers
227	fmovem	FPF_REGS(%a0),%fp0-%fp7	| restore FP general registers
228#if defined(M68060)
229	jra	.Lcpu_switch_resfprest
230#endif
231#endif
232
233#if defined(M68060)
234.Lcpu_switch_resfp60rest1:
235	tstb	2(%a0)			| null state frame?
236	jeq	.Lcpu_switch_resfprest	| yes, easy
237	fmovem	FPF_FPCR(%a0),%fpcr	| restore FP control registers
238	fmovem	FPF_FPSR(%a0),%fpsr
239	fmovem	FPF_FPI(%a0),%fpi
240	fmovem	FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers
241#endif
242.Lcpu_switch_resfprest:
243	frestore (%a0)			| restore state
244#endif /* FPCOPROC */
245#endif /* !_M68K_CUSTOM_FPU_CTX */
246
247.Lcpu_switch_nofprest:
248	movl	%d1,%d0
249	movl	%d0,%a0
250	rts
251
252.Lcpu_switch_badsw:
253	PANIC("switch")
254	/*NOTREACHED*/
255
256/*
257 * savectx(pcb)
258 * Update pcb, saving current processor state.
259 */
260ENTRY(savectx)
261	movl	4(%sp),%a1
262	movw	%sr,PCB_PS(%a1)
263	movl	%usp,%a0		| grab USP
264	movl	%a0,PCB_USP(%a1)	| and save it
265	moveml	%d2-%d7/%a2-%a7,PCB_REGS(%a1)	| save non-scratch registers
266
267#ifdef _M68K_CUSTOM_FPU_CTX
268	jbsr	_ASM_LABEL(m68k_fpuctx_save)
269#else
270#ifdef FPCOPROC
271	tstl	_C_LABEL(fputype)	| Do we have FPU?
272	jeq	.Lsavectx_nofpsave	| No?  Then don't save state.
273
274	lea	PCB_FPCTX(%a1),%a0	| pointer to FP save area
275	fsave	(%a0)			| save FP state
276#if defined(M68020) || defined(M68030) || defined(M68040)
277#if defined(M68060)
278	cmpl	#FPU_68060,_C_LABEL(fputype)
279	jeq	.Lsavectx_savfp60
280#endif
281	tstb	(%a0)			| null state frame?
282	jeq	.Lsavectx_nofpsave	| yes, all done
283	fmovem	%fp0-%fp7,FPF_REGS(%a0)	| save FP general registers
284	fmovem	%fpcr/%fpsr/%fpi,FPF_FPCR(%a0) | save FP control registers
285#if defined(M68060)
286	jra	.Lsavectx_nofpsave
287#endif
288#endif
289#if defined(M68060)
290.Lsavectx_savfp60:
291	tstb	2(%a0)			| null state frame?
292	jeq	.Lsavectx_nofpsave	| yes, all done
293	fmovem	%fp0-%fp7,FPF_REGS(%a0) | save FP general registers
294	fmovem	%fpcr,FPF_FPCR(%a0)	| save FP control registers
295	fmovem	%fpsr,FPF_FPSR(%a0)
296	fmovem	%fpi,FPF_FPI(%a0)
297#endif
298.Lsavectx_nofpsave:
299#endif /* FPCOPROC */
300#endif /* !_M68K_CUSTOM_FPU_CTX */
301	moveq	#0,%d0			| return 0
302	rts
303
304#if !defined(M68010)
305/*
306 * void m68k_make_fpu_idle_frame(void)
307 *
308 * On machines with an FPU, generate an "idle" state frame to be
309 * used by cpu_setmcontext().
310 *
311 * Before calling, make sure the machine actually has an FPU ...
312 */
313ENTRY(m68k_make_fpu_idle_frame)
314	clrl	-(%sp)
315	fnop
316
317	frestore (%sp)		| Effectively `resets' the FPU
318	fnop
319
320	/* Loading '0.0' will change FPU to "idle". */
321	fmove.d #0,%fp0
322	fnop
323
324	/* Save the resulting idle frame into the buffer */
325	lea	_C_LABEL(m68k_cached_fpu_idle_frame),%a0
326	fsave	(%a0)
327	fnop
328
329	/* Reset the FPU again */
330	frestore (%sp)
331	fnop
332	addql	#4,%sp
333	rts
334#endif
335
336/*
337 * Save and restore 68881 state.
338 */
339#ifdef FPCOPROC
340ENTRY(m68881_save)
341	movl	4(%sp),%a0		| save area pointer
342	fsave	(%a0)			| save state
343#if defined(M68020) || defined(M68030) || defined(M68040)
344#if defined(M68060)
345	cmpl	#FPU_68060,_C_LABEL(fputype)
346	jeq	.Lm68060fpsave
347#endif
348.Lm68881fpsave:
349	tstb	(%a0)			| null state frame?
350	jeq	.Lm68881sdone		| yes, all done
351	fmovem	%fp0-%fp7,FPF_REGS(%a0)	| save FP general registers
352	fmovem	%fpcr/%fpsr/%fpi,FPF_FPCR(%a0) | save FP control registers
353.Lm68881sdone:
354	rts
355#endif
356#if defined(M68060)
357.Lm68060fpsave:
358	tstb	2(%a0)			| null state frame?
359	jeq	.Lm68060sdone		| yes, all done
360	fmovem	%fp0-%fp7,FPF_REGS(%a0)	| save FP general registers
361	fmovem	%fpcr,FPF_FPCR(%a0)	| save FP control registers
362	fmovem	%fpsr,FPF_FPSR(%a0)
363	fmovem	%fpi,FPF_FPI(%a0)
364.Lm68060sdone:
365        rts
366#endif
367
368ENTRY(m68881_restore)
369	movl	4(%sp),%a0		| save area pointer
370#if defined(M68020) || defined(M68030) || defined(M68040)
371#if defined(M68060)
372	cmpl	#FPU_68060,_C_LABEL(fputype)
373	jeq	.Lm68060fprestore
374#endif
375.Lm68881fprestore:
376	tstb	(%a0)			| null state frame?
377	jeq	.Lm68881rdone		| yes, easy
378	fmovem	FPF_FPCR(%a0),%fpcr/%fpsr/%fpi | restore FP control registers
379	fmovem	FPF_REGS(%a0),%fp0-%fp7	| restore FP general registers
380.Lm68881rdone:
381	frestore (%a0)			| restore state
382	rts
383#endif
384#if defined(M68060)
385.Lm68060fprestore:
386	tstb	2(%a0)			| null state frame?
387	jeq	.Lm68060fprdone		| yes, easy
388	fmovem	FPF_FPCR(%a0),%fpcr	| restore FP control registers
389	fmovem	FPF_FPSR(%a0),%fpsr
390	fmovem	FPF_FPI(%a0),%fpi
391	fmovem	FPF_REGS(%a0),%fp0-%fp7 | restore FP general registers
392.Lm68060fprdone:
393	frestore (%a0)			| restore state
394	rts
395#endif
396#endif
397
398/*
399 * lwp_trampoline: call function in register %a2 with %a3 as an arg
400 * and then rei.
401 * %a0 will have old lwp from cpu_switchto(), and %a4 is new lwp
402 */
403ENTRY_NOPROFILE(lwp_trampoline)
404	movl	%a4,-(%sp)		| new lwp
405	movl	%a0,-(%sp)		| old lpw
406	jbsr	_C_LABEL(lwp_startup)
407	addql	#8,%sp
408	movl	%a3,-(%sp)		| push function arg
409	jbsr	(%a2)			| call function
410	addql	#4,%sp			| pop arg
411	movl	FR_SP(%sp),%a0		| grab and load
412	movl	%a0,%usp		|   user SP
413	moveml	(%sp)+,#0x7FFF		| restore most user regs
414	addql	#8,%sp			| toss SP and stack adjust
415	jra	_ASM_LABEL(rei)		| and return
416