swtch.S revision 210096
1/*	$OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $	*/
2/*-
3 * Copyright (c) 1992, 1993
4 *	The Regents of the University of California.  All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * Digital Equipment Corporation and Ralph Campbell.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * Copyright (C) 1989 Digital Equipment Corporation.
34 * Permission to use, copy, modify, and distribute this software and
35 * its documentation for any purpose and without fee is hereby granted,
36 * provided that the above copyright notice appears in all copies.
37 * Digital Equipment Corporation makes no representations about the
38 * suitability of this software for any purpose.  It is provided "as is"
39 * without express or implied warranty.
40 *
41 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s,
42 *	v 1.1 89/07/11 17:55:04 nelson Exp  SPRITE (DECWRL)
43 * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s,
44 *	v 9.2 90/01/29 18:00:39 shirriff Exp  SPRITE (DECWRL)
45 * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s,
46 *	v 1.1 89/07/10 14:27:41 nelson Exp  SPRITE (DECWRL)
47 *
48 *	from: @(#)locore.s	8.5 (Berkeley) 1/4/94
49 *	JNPR: swtch.S,v 1.6.2.1 2007/09/10 10:36:50 girish
50 * $FreeBSD: head/sys/mips/mips/swtch.S 210096 2010-07-15 01:47:47Z imp $
51 */
52
53/*
54 *	Contains code that is the first executed at boot time plus
55 *	assembly language support routines.
56 */
57
58#include "opt_cputype.h"
59#include <sys/syscall.h>
60#include <machine/asm.h>
61#include <machine/cpu.h>
62#include <machine/cpuregs.h>
63#include <machine/regnum.h>
64#include <machine/pte.h>
65
66#include "assym.s"
67
68	.set	noreorder			# Noreorder is default style!
69
70/*
71 * FREEBSD_DEVELOPERS_FIXME
72 * Some MIPS CPU may need delays using nops between executing CP0 Instructions
73 */
74
75#if 1
76#define	HAZARD_DELAY			nop ; nop ; nop ; nop
77#else
78#define	HAZARD_DELAY
79#endif
80
81#define	SAVE_U_PCB_REG(reg, offs, base) \
82	REG_S	reg, U_PCB_REGS + (SZREG * offs) (base)
83
84#define	RESTORE_U_PCB_REG(reg, offs, base) \
85	REG_L	reg, U_PCB_REGS + (SZREG * offs) (base)
86
87#define	SAVE_U_PCB_FPREG(reg, offs, base) \
88	FP_S	reg, U_PCB_FPREGS + (SZFPREG * offs) (base)
89
90#define	RESTORE_U_PCB_FPREG(reg, offs, base) \
91	FP_L	reg, U_PCB_FPREGS + (SZFPREG * offs) (base)
92
93#define	SAVE_U_PCB_FPSR(reg, offs, base) \
94	REG_S	reg, U_PCB_FPREGS + (SZFPREG * offs) (base)
95
96#define	RESTORE_U_PCB_FPSR(reg, offs, base) \
97	REG_L	reg, U_PCB_FPREGS + (SZFPREG * offs) (base)
98
99#define	SAVE_U_PCB_CONTEXT(reg, offs, base) \
100	REG_S	reg, U_PCB_CONTEXT + (SZREG * offs) (base)
101
102#define	RESTORE_U_PCB_CONTEXT(reg, offs, base) \
103	REG_L	reg, U_PCB_CONTEXT + (SZREG * offs) (base)
104
105#define	ITLBNOPFIX	nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
106
107/*
108 * Setup for and return to user.
109 */
110LEAF(fork_trampoline)
111	move	a0,s0
112	move	a1,s1
113	jal	_C_LABEL(fork_exit)
114	move	a2,s2			  #BDSlot
115
116	DO_AST
117
118	mfc0	v0, MIPS_COP_0_STATUS
119	and     v0, ~(MIPS_SR_INT_IE)
120	mtc0	v0, MIPS_COP_0_STATUS	# disable interrupts
121	COP0_SYNC
122/*
123 * The use of k1 for storing the PCB pointer must be done only
124 * after interrupts are disabled.  Otherwise it will get overwritten
125 * by the interrupt code.
126 */
127	.set	noat
128	GET_CPU_PCPU(k1)
129	PTR_L	k1, PC_CURPCB(k1)
130
131	RESTORE_U_PCB_REG(t0, MULLO, k1)
132	RESTORE_U_PCB_REG(t1, MULHI, k1)
133	mtlo	t0
134	mthi	t1
135	RESTORE_U_PCB_REG(a0, PC, k1)
136	RESTORE_U_PCB_REG(AT, AST, k1)
137	RESTORE_U_PCB_REG(v0, V0, k1)
138	MTC0	a0, MIPS_COP_0_EXC_PC	# set return address
139
140	RESTORE_U_PCB_REG(v1, V1, k1)
141	RESTORE_U_PCB_REG(a0, A0, k1)
142	RESTORE_U_PCB_REG(a1, A1, k1)
143	RESTORE_U_PCB_REG(a2, A2, k1)
144	RESTORE_U_PCB_REG(a3, A3, k1)
145	RESTORE_U_PCB_REG(t0, T0, k1)
146	RESTORE_U_PCB_REG(t1, T1, k1)
147	RESTORE_U_PCB_REG(t2, T2, k1)
148	RESTORE_U_PCB_REG(t3, T3, k1)
149	RESTORE_U_PCB_REG(ta0, TA0, k1)
150	RESTORE_U_PCB_REG(ta1, TA1, k1)
151	RESTORE_U_PCB_REG(ta2, TA2, k1)
152	RESTORE_U_PCB_REG(ta3, TA3, k1)
153	RESTORE_U_PCB_REG(s0, S0, k1)
154	RESTORE_U_PCB_REG(s1, S1, k1)
155	RESTORE_U_PCB_REG(s2, S2, k1)
156	RESTORE_U_PCB_REG(s3, S3, k1)
157	RESTORE_U_PCB_REG(s4, S4, k1)
158	RESTORE_U_PCB_REG(s5, S5, k1)
159	RESTORE_U_PCB_REG(s6, S6, k1)
160	RESTORE_U_PCB_REG(s7, S7, k1)
161	RESTORE_U_PCB_REG(t8, T8, k1)
162	RESTORE_U_PCB_REG(t9, T9, k1)
163	RESTORE_U_PCB_REG(k0, SR, k1)
164	RESTORE_U_PCB_REG(gp, GP, k1)
165	RESTORE_U_PCB_REG(s8, S8, k1)
166	RESTORE_U_PCB_REG(ra, RA, k1)
167	RESTORE_U_PCB_REG(sp, SP, k1)
168	li	k1, ~MIPS_SR_INT_MASK
169	and	k0, k0, k1
170	mfc0	k1, MIPS_COP_0_STATUS
171	and	k1, k1, MIPS_SR_INT_MASK
172	or	k0, k0, k1
173	mtc0	k0, MIPS_COP_0_STATUS	# switch to user mode (when eret...)
174	HAZARD_DELAY
175	sync
176	eret
177	.set	at
178END(fork_trampoline)
179
180/*
181 * Update pcb, saving current processor state.
182 * Note: this only works if pcbp != curproc's pcb since
183 * cpu_switch() will copy over pcb_context.
184 *
185 *	savectx(struct pcb *pcbp);
186 */
187LEAF(savectx)
188	SAVE_U_PCB_CONTEXT(s0, PREG_S0, a0)
189	SAVE_U_PCB_CONTEXT(s1, PREG_S1, a0)
190	SAVE_U_PCB_CONTEXT(s2, PREG_S2, a0)
191	SAVE_U_PCB_CONTEXT(s3, PREG_S3, a0)
192	mfc0	v0, MIPS_COP_0_STATUS
193	SAVE_U_PCB_CONTEXT(s4, PREG_S4, a0)
194	SAVE_U_PCB_CONTEXT(s5, PREG_S5, a0)
195	SAVE_U_PCB_CONTEXT(s6, PREG_S6, a0)
196	SAVE_U_PCB_CONTEXT(s7, PREG_S7, a0)
197	SAVE_U_PCB_CONTEXT(sp, PREG_SP, a0)
198	SAVE_U_PCB_CONTEXT(s8, PREG_S8, a0)
199	SAVE_U_PCB_CONTEXT(ra, PREG_RA, a0)
200	SAVE_U_PCB_CONTEXT(v0, PREG_SR, a0)
201	SAVE_U_PCB_CONTEXT(gp, PREG_GP, a0)
202
203	move	v0, ra			/* save 'ra' before we trash it */
204	jal	1f
205	nop
2061:
207	SAVE_U_PCB_CONTEXT(ra, PREG_PC, a0)
208	move	ra, v0			/* restore 'ra' before returning */
209
210	/*
211	 * FREEBSD_DEVELOPERS_FIXME:
212	 * In case there are CPU-specific registers that need
213	 * to be saved with the other registers do so here.
214	 */
215	j	ra
216	move	v0, zero
217END(savectx)
218
219NON_LEAF(cpu_throw, CALLFRAME_SIZ, ra)
220	mfc0	t0, MIPS_COP_0_STATUS		# t0 = saved status register
221	nop
222	nop
223	and     a3, t0, ~(MIPS_SR_INT_IE)
224	mtc0	a3, MIPS_COP_0_STATUS		# Disable all interrupts
225	ITLBNOPFIX
226	j	mips_sw1			# We're not interested in old
227						# thread's context, so jump
228						# right to action
229	nop					# BDSLOT
230END(cpu_throw)
231
232/*
233 * cpu_switch(struct thread *old, struct thread *new, struct mutex *mtx);
234 *	a0 - old
235 *	a1 - new
236 *	a2 - mtx
237 * Find the highest priority process and resume it.
238 */
239NON_LEAF(cpu_switch, CALLFRAME_SIZ, ra)
240	mfc0	t0, MIPS_COP_0_STATUS		# t0 = saved status register
241	nop
242	nop
243	and     a3, t0, ~(MIPS_SR_INT_IE)
244	mtc0	a3, MIPS_COP_0_STATUS		# Disable all interrupts
245	ITLBNOPFIX
246	beqz	a0, mips_sw1
247	move	a3, a0
248	PTR_L	a0, TD_PCB(a0)		# load PCB addr of curproc
249	SAVE_U_PCB_CONTEXT(sp, PREG_SP, a0)		# save old sp
250	PTR_SUBU	sp, sp, CALLFRAME_SIZ
251	REG_S	ra, CALLFRAME_RA(sp)
252	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
253	SAVE_U_PCB_CONTEXT(s0, PREG_S0, a0)		# do a 'savectx()'
254	SAVE_U_PCB_CONTEXT(s1, PREG_S1, a0)
255	SAVE_U_PCB_CONTEXT(s2, PREG_S2, a0)
256	SAVE_U_PCB_CONTEXT(s3, PREG_S3, a0)
257	SAVE_U_PCB_CONTEXT(s4, PREG_S4, a0)
258	SAVE_U_PCB_CONTEXT(s5, PREG_S5, a0)
259	SAVE_U_PCB_CONTEXT(s6, PREG_S6, a0)
260	SAVE_U_PCB_CONTEXT(s7, PREG_S7, a0)
261	SAVE_U_PCB_CONTEXT(s8, PREG_S8, a0)
262	SAVE_U_PCB_CONTEXT(ra, PREG_RA, a0)		# save return address
263	SAVE_U_PCB_CONTEXT(t0, PREG_SR, a0)		# save status register
264	SAVE_U_PCB_CONTEXT(gp, PREG_GP, a0)
265	jal	getpc
266	nop
267getpc:
268	SAVE_U_PCB_CONTEXT(ra, PREG_PC, a0)		# save return address
269	/*
270	 * FREEBSD_DEVELOPERS_FIXME:
271	 * In case there are CPU-specific registers that need
272	 * to be saved with the other registers do so here.
273	 */
274
275	PTR_S	a2, TD_LOCK(a3)			# Switchout td_lock
276
277mips_sw1:
278#if defined(SMP) && defined(SCHED_ULE)
279	PTR_LA	t0, _C_LABEL(blocked_lock)
280blocked_loop:
281	PTR_L	t1, TD_LOCK(a1)
282	beq	t0, t1, blocked_loop
283	nop
284#endif
285	move	s7, a1	# Store newthread
286/*
287 * Switch to new context.
288 */
289	GET_CPU_PCPU(a3)
290	PTR_S	a1, PC_CURTHREAD(a3)
291	PTR_L	a2, TD_PCB(a1)
292	PTR_S	a2, PC_CURPCB(a3)
293	PTR_L	v0, TD_KSTACK(a1)
294#if !defined(__mips_n64)
295	PTR_LI	s0, MIPS_KSEG2_START		# If Uarea addr is below kseg2,
296	bltu	v0, s0, sw2			# no need to insert in TLB.
297#endif
298	lw	a1, TD_UPTE + 0(s7)		# a1 = u. pte #0
299	lw	a2, TD_UPTE + 4(s7)		# a2 = u. pte #1
300/*
301 * Wiredown the USPACE of newproc in TLB entry#0.  Check whether target
302 * USPACE is already in another place of TLB before that, and if so
303 * invalidate that TLB entry.
304 * NOTE: This is hard coded to UPAGES == 2.
305 * Also, there should be no TLB faults at this point.
306 */
307	MTC0	v0, MIPS_COP_0_TLB_HI		# VPN = va
308	HAZARD_DELAY
309	tlbp					# probe VPN
310	HAZARD_DELAY
311	mfc0	s0, MIPS_COP_0_TLB_INDEX
312	HAZARD_DELAY
313
314	PTR_LI	t1, MIPS_KSEG0_START		# invalidate tlb entry
315	bltz	s0, entry0set
316	nop
317	sll	s0, PAGE_SHIFT + 1
318	addu	t1, s0
319	MTC0	t1, MIPS_COP_0_TLB_HI
320	mtc0	zero, MIPS_COP_0_TLB_LO0
321	mtc0	zero, MIPS_COP_0_TLB_LO1
322	HAZARD_DELAY
323	tlbwi
324	HAZARD_DELAY
325	MTC0	v0, MIPS_COP_0_TLB_HI		# set VPN again
326
327entry0set:
328/* SMP!! - Works only for  unshared TLB case - i.e. no v-cpus */
329	mtc0	zero, MIPS_COP_0_TLB_INDEX		# TLB entry #0
330	HAZARD_DELAY
331	mtc0	a1, MIPS_COP_0_TLB_LO0		# upte[0]
332	HAZARD_DELAY
333	mtc0	a2, MIPS_COP_0_TLB_LO1		# upte[1]
334	HAZARD_DELAY
335	tlbwi					# set TLB entry #0
336	HAZARD_DELAY
337/*
338 * Now running on new u struct.
339 */
340sw2:
341	PTR_LA	t1, _C_LABEL(pmap_activate)	# s7 = new proc pointer
342	jalr	t1				# s7 = new proc pointer
343	move	a0, s7				# BDSLOT
344/*
345 * Restore registers and return.
346 */
347	PTR_L	a0, TD_PCB(s7)
348	RESTORE_U_PCB_CONTEXT(gp, PREG_GP, a0)
349	RESTORE_U_PCB_CONTEXT(v0, PREG_SR, a0)	# restore kernel context
350	RESTORE_U_PCB_CONTEXT(ra, PREG_RA, a0)
351	RESTORE_U_PCB_CONTEXT(s0, PREG_S0, a0)
352	RESTORE_U_PCB_CONTEXT(s1, PREG_S1, a0)
353	RESTORE_U_PCB_CONTEXT(s2, PREG_S2, a0)
354	RESTORE_U_PCB_CONTEXT(s3, PREG_S3, a0)
355	RESTORE_U_PCB_CONTEXT(s4, PREG_S4, a0)
356	RESTORE_U_PCB_CONTEXT(s5, PREG_S5, a0)
357	RESTORE_U_PCB_CONTEXT(s6, PREG_S6, a0)
358	RESTORE_U_PCB_CONTEXT(s7, PREG_S7, a0)
359	RESTORE_U_PCB_CONTEXT(sp, PREG_SP, a0)
360	RESTORE_U_PCB_CONTEXT(s8, PREG_S8, a0)
361	/*
362	 * FREEBSD_DEVELOPERS_FIXME:
363	 * In case there are CPU-specific registers that need
364	 * to be restored with the other registers do so here.
365	 */
366	mfc0	t0, MIPS_COP_0_STATUS
367	and	t0, t0, MIPS_SR_INT_MASK
368	and	v0, v0, ~MIPS_SR_INT_MASK
369	or	v0, v0, t0
370	mtc0	v0, MIPS_COP_0_STATUS
371	ITLBNOPFIX
372
373	j	ra
374	nop
375END(cpu_switch)
376
377/*----------------------------------------------------------------------------
378 *
379 * MipsSwitchFPState --
380 *
381 *	Save the current state into 'from' and restore it from 'to'.
382 *
383 *	MipsSwitchFPState(from, to)
384 *		struct thread *from;
385 *		struct trapframe *to;
386 *
387 * Results:
388 *	None.
389 *
390 * Side effects:
391 *	None.
392 *
393 *----------------------------------------------------------------------------
394 */
395LEAF(MipsSwitchFPState)
396	mfc0	t1, MIPS_COP_0_STATUS	# Save old SR
397	li	t0, MIPS_SR_COP_1_BIT	# enable the coprocessor
398	mtc0	t0, MIPS_COP_0_STATUS
399	ITLBNOPFIX
400
401	beq	a0, zero, 1f		# skip save if NULL pointer
402	nop
403/*
404 * First read out the status register to make sure that all FP operations
405 * have completed.
406 */
407	PTR_L	a0, TD_PCB(a0)			# get pointer to pcb for proc
408	cfc1	t0, MIPS_FPU_CSR		# stall til FP done
409	cfc1	t0, MIPS_FPU_CSR		# now get status
410	li	t3, ~MIPS_SR_COP_1_BIT
411	RESTORE_U_PCB_REG(t2, PS, a0)		# get CPU status register
412	SAVE_U_PCB_FPSR(t0, FSR_NUM, a0)	# save FP status
413	and	t2, t2, t3			# clear COP_1 enable bit
414	SAVE_U_PCB_REG(t2, PS, a0)		# save new status register
415/*
416 * Save the floating point registers.
417 */
418	SAVE_U_PCB_FPREG($f0, F0_NUM, a0)
419	SAVE_U_PCB_FPREG($f1, F1_NUM, a0)
420	SAVE_U_PCB_FPREG($f2, F2_NUM, a0)
421	SAVE_U_PCB_FPREG($f3, F3_NUM, a0)
422	SAVE_U_PCB_FPREG($f4, F4_NUM, a0)
423	SAVE_U_PCB_FPREG($f5, F5_NUM, a0)
424	SAVE_U_PCB_FPREG($f6, F6_NUM, a0)
425	SAVE_U_PCB_FPREG($f7, F7_NUM, a0)
426	SAVE_U_PCB_FPREG($f8, F8_NUM, a0)
427	SAVE_U_PCB_FPREG($f9, F9_NUM, a0)
428	SAVE_U_PCB_FPREG($f10, F10_NUM, a0)
429	SAVE_U_PCB_FPREG($f11, F11_NUM, a0)
430	SAVE_U_PCB_FPREG($f12, F12_NUM, a0)
431	SAVE_U_PCB_FPREG($f13, F13_NUM, a0)
432	SAVE_U_PCB_FPREG($f14, F14_NUM, a0)
433	SAVE_U_PCB_FPREG($f15, F15_NUM, a0)
434	SAVE_U_PCB_FPREG($f16, F16_NUM, a0)
435	SAVE_U_PCB_FPREG($f17, F17_NUM, a0)
436	SAVE_U_PCB_FPREG($f18, F18_NUM, a0)
437	SAVE_U_PCB_FPREG($f19, F19_NUM, a0)
438	SAVE_U_PCB_FPREG($f20, F20_NUM, a0)
439	SAVE_U_PCB_FPREG($f21, F21_NUM, a0)
440	SAVE_U_PCB_FPREG($f22, F22_NUM, a0)
441	SAVE_U_PCB_FPREG($f23, F23_NUM, a0)
442	SAVE_U_PCB_FPREG($f24, F24_NUM, a0)
443	SAVE_U_PCB_FPREG($f25, F25_NUM, a0)
444	SAVE_U_PCB_FPREG($f26, F26_NUM, a0)
445	SAVE_U_PCB_FPREG($f27, F27_NUM, a0)
446	SAVE_U_PCB_FPREG($f28, F28_NUM, a0)
447	SAVE_U_PCB_FPREG($f29, F29_NUM, a0)
448	SAVE_U_PCB_FPREG($f30, F30_NUM, a0)
449	SAVE_U_PCB_FPREG($f31, F31_NUM, a0)
450
4511:
452/*
453 *  Restore the floating point registers.
454 */
455	RESTORE_U_PCB_FPSR(t0, FSR_NUM, a1)	# get status register
456	RESTORE_U_PCB_FPREG($f0, F0_NUM, a1)
457	RESTORE_U_PCB_FPREG($f1, F1_NUM, a1)
458	RESTORE_U_PCB_FPREG($f2, F2_NUM, a1)
459	RESTORE_U_PCB_FPREG($f3, F3_NUM, a1)
460	RESTORE_U_PCB_FPREG($f4, F4_NUM, a1)
461	RESTORE_U_PCB_FPREG($f5, F5_NUM, a1)
462	RESTORE_U_PCB_FPREG($f6, F6_NUM, a1)
463	RESTORE_U_PCB_FPREG($f7, F7_NUM, a1)
464	RESTORE_U_PCB_FPREG($f8, F8_NUM, a1)
465	RESTORE_U_PCB_FPREG($f9, F9_NUM, a1)
466	RESTORE_U_PCB_FPREG($f10, F10_NUM, a1)
467	RESTORE_U_PCB_FPREG($f11, F11_NUM, a1)
468	RESTORE_U_PCB_FPREG($f12, F12_NUM, a1)
469	RESTORE_U_PCB_FPREG($f13, F13_NUM, a1)
470	RESTORE_U_PCB_FPREG($f14, F14_NUM, a1)
471	RESTORE_U_PCB_FPREG($f15, F15_NUM, a1)
472	RESTORE_U_PCB_FPREG($f16, F16_NUM, a1)
473	RESTORE_U_PCB_FPREG($f17, F17_NUM, a1)
474	RESTORE_U_PCB_FPREG($f18, F18_NUM, a1)
475	RESTORE_U_PCB_FPREG($f19, F19_NUM, a1)
476	RESTORE_U_PCB_FPREG($f20, F20_NUM, a1)
477	RESTORE_U_PCB_FPREG($f21, F21_NUM, a1)
478	RESTORE_U_PCB_FPREG($f22, F22_NUM, a1)
479	RESTORE_U_PCB_FPREG($f23, F23_NUM, a1)
480	RESTORE_U_PCB_FPREG($f24, F24_NUM, a1)
481	RESTORE_U_PCB_FPREG($f25, F25_NUM, a1)
482	RESTORE_U_PCB_FPREG($f26, F26_NUM, a1)
483	RESTORE_U_PCB_FPREG($f27, F27_NUM, a1)
484	RESTORE_U_PCB_FPREG($f28, F28_NUM, a1)
485	RESTORE_U_PCB_FPREG($f29, F29_NUM, a1)
486	RESTORE_U_PCB_FPREG($f30, F30_NUM, a1)
487	RESTORE_U_PCB_FPREG($f31, F31_NUM, a1)
488
489	and	t0, t0, ~MIPS_FPU_EXCEPTION_BITS
490	ctc1	t0, MIPS_FPU_CSR
491	nop
492
493	mtc0	t1, MIPS_COP_0_STATUS		# Restore the status register.
494	ITLBNOPFIX
495	j	ra
496	nop
497END(MipsSwitchFPState)
498
499/*----------------------------------------------------------------------------
500 *
501 * MipsSaveCurFPState --
502 *
503 *	Save the current floating point coprocessor state.
504 *
505 *	MipsSaveCurFPState(td)
506 *		struct thread *td;
507 *
508 * Results:
509 *	None.
510 *
511 * Side effects:
512 *	machFPCurProcPtr is cleared.
513 *
514 *----------------------------------------------------------------------------
515 */
516LEAF(MipsSaveCurFPState)
517	PTR_L	a0, TD_PCB(a0)			# get pointer to pcb for thread
518	mfc0	t1, MIPS_COP_0_STATUS		# Disable interrupts and
519	li	t0, MIPS_SR_COP_1_BIT		#  enable the coprocessor
520	mtc0	t0, MIPS_COP_0_STATUS
521	ITLBNOPFIX
522	GET_CPU_PCPU(a1)
523	PTR_S	zero, PC_FPCURTHREAD(a1)	# indicate state has been saved
524/*
525 * First read out the status register to make sure that all FP operations
526 * have completed.
527 */
528	RESTORE_U_PCB_REG(t2, PS, a0)		# get CPU status register
529	li	t3, ~MIPS_SR_COP_1_BIT
530	and	t2, t2, t3			# clear COP_1 enable bit
531	cfc1	t0, MIPS_FPU_CSR		# stall til FP done
532	cfc1	t0, MIPS_FPU_CSR		# now get status
533	SAVE_U_PCB_REG(t2, PS, a0)		# save new status register
534	SAVE_U_PCB_FPSR(t0, FSR_NUM, a0)	# save FP status
535/*
536 * Save the floating point registers.
537 */
538	SAVE_U_PCB_FPREG($f0, F0_NUM, a0)
539	SAVE_U_PCB_FPREG($f1, F1_NUM, a0)
540	SAVE_U_PCB_FPREG($f2, F2_NUM, a0)
541	SAVE_U_PCB_FPREG($f3, F3_NUM, a0)
542	SAVE_U_PCB_FPREG($f4, F4_NUM, a0)
543	SAVE_U_PCB_FPREG($f5, F5_NUM, a0)
544	SAVE_U_PCB_FPREG($f6, F6_NUM, a0)
545	SAVE_U_PCB_FPREG($f7, F7_NUM, a0)
546	SAVE_U_PCB_FPREG($f8, F8_NUM, a0)
547	SAVE_U_PCB_FPREG($f9, F9_NUM, a0)
548	SAVE_U_PCB_FPREG($f10, F10_NUM, a0)
549	SAVE_U_PCB_FPREG($f11, F11_NUM, a0)
550	SAVE_U_PCB_FPREG($f12, F12_NUM, a0)
551	SAVE_U_PCB_FPREG($f13, F13_NUM, a0)
552	SAVE_U_PCB_FPREG($f14, F14_NUM, a0)
553	SAVE_U_PCB_FPREG($f15, F15_NUM, a0)
554	SAVE_U_PCB_FPREG($f16, F16_NUM, a0)
555	SAVE_U_PCB_FPREG($f17, F17_NUM, a0)
556	SAVE_U_PCB_FPREG($f18, F18_NUM, a0)
557	SAVE_U_PCB_FPREG($f19, F19_NUM, a0)
558	SAVE_U_PCB_FPREG($f20, F20_NUM, a0)
559	SAVE_U_PCB_FPREG($f21, F21_NUM, a0)
560	SAVE_U_PCB_FPREG($f22, F22_NUM, a0)
561	SAVE_U_PCB_FPREG($f23, F23_NUM, a0)
562	SAVE_U_PCB_FPREG($f24, F24_NUM, a0)
563	SAVE_U_PCB_FPREG($f25, F25_NUM, a0)
564	SAVE_U_PCB_FPREG($f26, F26_NUM, a0)
565	SAVE_U_PCB_FPREG($f27, F27_NUM, a0)
566	SAVE_U_PCB_FPREG($f28, F28_NUM, a0)
567	SAVE_U_PCB_FPREG($f29, F29_NUM, a0)
568	SAVE_U_PCB_FPREG($f30, F30_NUM, a0)
569	SAVE_U_PCB_FPREG($f31, F31_NUM, a0)
570
571	mtc0	t1, MIPS_COP_0_STATUS		# Restore the status register.
572	ITLBNOPFIX
573	j	ra
574	nop
575END(MipsSaveCurFPState)
576
577/*
578 * When starting init, call this to configure the process for user
579 * mode.  This will be inherited by other processes.
580 */
581LEAF_NOPROFILE(prepare_usermode)
582	j	ra
583	nop
584END(prepare_usermode)
585
586
587/*
588 * This code is copied the user's stack for returning from signal handlers
589 * (see sendsig() and sigreturn()). We have to compute the address
590 * of the sigcontext struct for the sigreturn call.
591 */
592	.globl	_C_LABEL(sigcode)
593_C_LABEL(sigcode):
594	addu	a0, sp, SIGF_UC			# address of ucontext
595	li	v0, SYS_sigreturn
596# sigreturn (ucp)
597	syscall
598	break	0				# just in case sigreturn fails
599	.globl	_C_LABEL(esigcode)
600_C_LABEL(esigcode):
601
602	.data
603	.globl	szsigcode
604szsigcode:
605	.long	esigcode-sigcode
606	.text
607