swtch.S revision 210699
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 210699 2010-07-31 19:13:08Z jchandra $
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#define	SAVE_U_PCB_REG(reg, offs, base) \
71	REG_S	reg, U_PCB_REGS + (SZREG * offs) (base)
72
73#define	RESTORE_U_PCB_REG(reg, offs, base) \
74	REG_L	reg, U_PCB_REGS + (SZREG * offs) (base)
75
76#define	SAVE_U_PCB_FPREG(reg, offs, base) \
77	FP_S	reg, U_PCB_FPREGS + (SZFPREG * offs) (base)
78
79#define	RESTORE_U_PCB_FPREG(reg, offs, base) \
80	FP_L	reg, U_PCB_FPREGS + (SZFPREG * offs) (base)
81
82#define	SAVE_U_PCB_FPSR(reg, offs, base) \
83	REG_S	reg, U_PCB_FPREGS + (SZFPREG * offs) (base)
84
85#define	RESTORE_U_PCB_FPSR(reg, offs, base) \
86	REG_L	reg, U_PCB_FPREGS + (SZFPREG * offs) (base)
87
88#define	SAVE_U_PCB_CONTEXT(reg, offs, base) \
89	REG_S	reg, U_PCB_CONTEXT + (SZREG * offs) (base)
90
91#define	RESTORE_U_PCB_CONTEXT(reg, offs, base) \
92	REG_L	reg, U_PCB_CONTEXT + (SZREG * offs) (base)
93
94/*
95 * Setup for and return to user.
96 */
97LEAF(fork_trampoline)
98	move	a0,s0
99	move	a1,s1
100	jal	_C_LABEL(fork_exit)
101	move	a2,s2			  #BDSlot
102
103	DO_AST
104
105	mfc0	v0, MIPS_COP_0_STATUS
106	and     v0, ~(MIPS_SR_INT_IE)
107	mtc0	v0, MIPS_COP_0_STATUS	# disable interrupts
108	COP0_SYNC
109/*
110 * The use of k1 for storing the PCB pointer must be done only
111 * after interrupts are disabled.  Otherwise it will get overwritten
112 * by the interrupt code.
113 */
114	.set	noat
115	GET_CPU_PCPU(k1)
116	PTR_L	k1, PC_CURPCB(k1)
117
118	RESTORE_U_PCB_REG(t0, MULLO, k1)
119	RESTORE_U_PCB_REG(t1, MULHI, k1)
120	mtlo	t0
121	mthi	t1
122	RESTORE_U_PCB_REG(a0, PC, k1)
123	RESTORE_U_PCB_REG(AT, AST, k1)
124	RESTORE_U_PCB_REG(v0, V0, k1)
125	MTC0	a0, MIPS_COP_0_EXC_PC	# set return address
126
127	RESTORE_U_PCB_REG(v1, V1, k1)
128	RESTORE_U_PCB_REG(a0, A0, k1)
129	RESTORE_U_PCB_REG(a1, A1, k1)
130	RESTORE_U_PCB_REG(a2, A2, k1)
131	RESTORE_U_PCB_REG(a3, A3, k1)
132	RESTORE_U_PCB_REG(t0, T0, k1)
133	RESTORE_U_PCB_REG(t1, T1, k1)
134	RESTORE_U_PCB_REG(t2, T2, k1)
135	RESTORE_U_PCB_REG(t3, T3, k1)
136	RESTORE_U_PCB_REG(ta0, TA0, k1)
137	RESTORE_U_PCB_REG(ta1, TA1, k1)
138	RESTORE_U_PCB_REG(ta2, TA2, k1)
139	RESTORE_U_PCB_REG(ta3, TA3, k1)
140	RESTORE_U_PCB_REG(s0, S0, k1)
141	RESTORE_U_PCB_REG(s1, S1, k1)
142	RESTORE_U_PCB_REG(s2, S2, k1)
143	RESTORE_U_PCB_REG(s3, S3, k1)
144	RESTORE_U_PCB_REG(s4, S4, k1)
145	RESTORE_U_PCB_REG(s5, S5, k1)
146	RESTORE_U_PCB_REG(s6, S6, k1)
147	RESTORE_U_PCB_REG(s7, S7, k1)
148	RESTORE_U_PCB_REG(t8, T8, k1)
149	RESTORE_U_PCB_REG(t9, T9, k1)
150	RESTORE_U_PCB_REG(k0, SR, k1)
151	RESTORE_U_PCB_REG(gp, GP, k1)
152	RESTORE_U_PCB_REG(s8, S8, k1)
153	RESTORE_U_PCB_REG(ra, RA, k1)
154	RESTORE_U_PCB_REG(sp, SP, k1)
155	li	k1, ~MIPS_SR_INT_MASK
156	and	k0, k0, k1
157	mfc0	k1, MIPS_COP_0_STATUS
158	and	k1, k1, MIPS_SR_INT_MASK
159	or	k0, k0, k1
160	mtc0	k0, MIPS_COP_0_STATUS	# switch to user mode (when eret...)
161	HAZARD_DELAY
162	sync
163	eret
164	.set	at
165END(fork_trampoline)
166
167/*
168 * Update pcb, saving current processor state.
169 * Note: this only works if pcbp != curproc's pcb since
170 * cpu_switch() will copy over pcb_context.
171 *
172 *	savectx(struct pcb *pcbp);
173 */
174LEAF(savectx)
175	SAVE_U_PCB_CONTEXT(s0, PREG_S0, a0)
176	SAVE_U_PCB_CONTEXT(s1, PREG_S1, a0)
177	SAVE_U_PCB_CONTEXT(s2, PREG_S2, a0)
178	SAVE_U_PCB_CONTEXT(s3, PREG_S3, a0)
179	mfc0	v0, MIPS_COP_0_STATUS
180	SAVE_U_PCB_CONTEXT(s4, PREG_S4, a0)
181	SAVE_U_PCB_CONTEXT(s5, PREG_S5, a0)
182	SAVE_U_PCB_CONTEXT(s6, PREG_S6, a0)
183	SAVE_U_PCB_CONTEXT(s7, PREG_S7, a0)
184	SAVE_U_PCB_CONTEXT(sp, PREG_SP, a0)
185	SAVE_U_PCB_CONTEXT(s8, PREG_S8, a0)
186	SAVE_U_PCB_CONTEXT(ra, PREG_RA, a0)
187	SAVE_U_PCB_CONTEXT(v0, PREG_SR, a0)
188	SAVE_U_PCB_CONTEXT(gp, PREG_GP, a0)
189
190	move	v0, ra			/* save 'ra' before we trash it */
191	jal	1f
192	nop
1931:
194	SAVE_U_PCB_CONTEXT(ra, PREG_PC, a0)
195	move	ra, v0			/* restore 'ra' before returning */
196
197	/*
198	 * FREEBSD_DEVELOPERS_FIXME:
199	 * In case there are CPU-specific registers that need
200	 * to be saved with the other registers do so here.
201	 */
202	j	ra
203	move	v0, zero
204END(savectx)
205
206NON_LEAF(cpu_throw, CALLFRAME_SIZ, ra)
207	mfc0	t0, MIPS_COP_0_STATUS		# t0 = saved status register
208	nop
209	nop
210	and     a3, t0, ~(MIPS_SR_INT_IE)
211	mtc0	a3, MIPS_COP_0_STATUS		# Disable all interrupts
212	ITLBNOPFIX
213	j	mips_sw1			# We're not interested in old
214						# thread's context, so jump
215						# right to action
216	nop					# BDSLOT
217END(cpu_throw)
218
219/*
220 * cpu_switch(struct thread *old, struct thread *new, struct mutex *mtx);
221 *	a0 - old
222 *	a1 - new
223 *	a2 - mtx
224 * Find the highest priority process and resume it.
225 */
226NON_LEAF(cpu_switch, CALLFRAME_SIZ, ra)
227	mfc0	t0, MIPS_COP_0_STATUS		# t0 = saved status register
228	nop
229	nop
230	and     a3, t0, ~(MIPS_SR_INT_IE)
231	mtc0	a3, MIPS_COP_0_STATUS		# Disable all interrupts
232	ITLBNOPFIX
233	beqz	a0, mips_sw1
234	move	a3, a0
235	PTR_L	a0, TD_PCB(a0)		# load PCB addr of curproc
236	SAVE_U_PCB_CONTEXT(sp, PREG_SP, a0)		# save old sp
237	PTR_SUBU	sp, sp, CALLFRAME_SIZ
238	REG_S	ra, CALLFRAME_RA(sp)
239	.mask	0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ)
240	SAVE_U_PCB_CONTEXT(s0, PREG_S0, a0)		# do a 'savectx()'
241	SAVE_U_PCB_CONTEXT(s1, PREG_S1, a0)
242	SAVE_U_PCB_CONTEXT(s2, PREG_S2, a0)
243	SAVE_U_PCB_CONTEXT(s3, PREG_S3, a0)
244	SAVE_U_PCB_CONTEXT(s4, PREG_S4, a0)
245	SAVE_U_PCB_CONTEXT(s5, PREG_S5, a0)
246	SAVE_U_PCB_CONTEXT(s6, PREG_S6, a0)
247	SAVE_U_PCB_CONTEXT(s7, PREG_S7, a0)
248	SAVE_U_PCB_CONTEXT(s8, PREG_S8, a0)
249	SAVE_U_PCB_CONTEXT(ra, PREG_RA, a0)		# save return address
250	SAVE_U_PCB_CONTEXT(t0, PREG_SR, a0)		# save status register
251	SAVE_U_PCB_CONTEXT(gp, PREG_GP, a0)
252	jal	getpc
253	nop
254getpc:
255	SAVE_U_PCB_CONTEXT(ra, PREG_PC, a0)		# save return address
256	/*
257	 * FREEBSD_DEVELOPERS_FIXME:
258	 * In case there are CPU-specific registers that need
259	 * to be saved with the other registers do so here.
260	 */
261
262	PTR_S	a2, TD_LOCK(a3)			# Switchout td_lock
263
264mips_sw1:
265#if defined(SMP) && defined(SCHED_ULE)
266	PTR_LA	t0, _C_LABEL(blocked_lock)
267blocked_loop:
268	PTR_L	t1, TD_LOCK(a1)
269	beq	t0, t1, blocked_loop
270	nop
271#endif
272	move	s7, a1	# Store newthread
273/*
274 * Switch to new context.
275 */
276	GET_CPU_PCPU(a3)
277	PTR_S	a1, PC_CURTHREAD(a3)
278	PTR_L	a2, TD_PCB(a1)
279	PTR_S	a2, PC_CURPCB(a3)
280	PTR_L	v0, TD_KSTACK(a1)
281#if defined(__mips_n64)
282	PTR_LI	s0, MIPS_XKSEG_START
283#else
284	PTR_LI	s0, MIPS_KSEG2_START		# If Uarea addr is below kseg2,
285#endif
286	bltu	v0, s0, sw2			# no need to insert in TLB.
287	lw	a1, TD_UPTE + 0(s7)		# a1 = u. pte #0
288	lw	a2, TD_UPTE + 4(s7)		# a2 = u. pte #1
289/*
290 * Wiredown the USPACE of newproc in TLB entry#0.  Check whether target
291 * USPACE is already in another place of TLB before that, and if so
292 * invalidate that TLB entry.
293 * NOTE: This is hard coded to UPAGES == 2.
294 * Also, there should be no TLB faults at this point.
295 */
296	MTC0	v0, MIPS_COP_0_TLB_HI		# VPN = va
297	HAZARD_DELAY
298	tlbp					# probe VPN
299	HAZARD_DELAY
300	mfc0	s0, MIPS_COP_0_TLB_INDEX
301	HAZARD_DELAY
302
303	PTR_LI	t1, MIPS_KSEG0_START		# invalidate tlb entry
304	bltz	s0, entry0set
305	nop
306	sll	s0, PAGE_SHIFT + 1
307	addu	t1, s0
308	MTC0	t1, MIPS_COP_0_TLB_HI
309	mtc0	zero, MIPS_COP_0_TLB_LO0
310	mtc0	zero, MIPS_COP_0_TLB_LO1
311	HAZARD_DELAY
312	tlbwi
313	HAZARD_DELAY
314	MTC0	v0, MIPS_COP_0_TLB_HI		# set VPN again
315
316entry0set:
317/* SMP!! - Works only for  unshared TLB case - i.e. no v-cpus */
318	mtc0	zero, MIPS_COP_0_TLB_INDEX		# TLB entry #0
319	HAZARD_DELAY
320	mtc0	a1, MIPS_COP_0_TLB_LO0		# upte[0]
321	HAZARD_DELAY
322	mtc0	a2, MIPS_COP_0_TLB_LO1		# upte[1]
323	HAZARD_DELAY
324	tlbwi					# set TLB entry #0
325	HAZARD_DELAY
326/*
327 * Now running on new u struct.
328 */
329sw2:
330	PTR_LA	t1, _C_LABEL(pmap_activate)	# s7 = new proc pointer
331	jalr	t1				# s7 = new proc pointer
332	move	a0, s7				# BDSLOT
333/*
334 * Restore registers and return.
335 */
336	PTR_L	a0, TD_PCB(s7)
337	RESTORE_U_PCB_CONTEXT(gp, PREG_GP, a0)
338	RESTORE_U_PCB_CONTEXT(v0, PREG_SR, a0)	# restore kernel context
339	RESTORE_U_PCB_CONTEXT(ra, PREG_RA, a0)
340	RESTORE_U_PCB_CONTEXT(s0, PREG_S0, a0)
341	RESTORE_U_PCB_CONTEXT(s1, PREG_S1, a0)
342	RESTORE_U_PCB_CONTEXT(s2, PREG_S2, a0)
343	RESTORE_U_PCB_CONTEXT(s3, PREG_S3, a0)
344	RESTORE_U_PCB_CONTEXT(s4, PREG_S4, a0)
345	RESTORE_U_PCB_CONTEXT(s5, PREG_S5, a0)
346	RESTORE_U_PCB_CONTEXT(s6, PREG_S6, a0)
347	RESTORE_U_PCB_CONTEXT(s7, PREG_S7, a0)
348	RESTORE_U_PCB_CONTEXT(sp, PREG_SP, a0)
349	RESTORE_U_PCB_CONTEXT(s8, PREG_S8, a0)
350	/*
351	 * FREEBSD_DEVELOPERS_FIXME:
352	 * In case there are CPU-specific registers that need
353	 * to be restored with the other registers do so here.
354	 */
355	mfc0	t0, MIPS_COP_0_STATUS
356	and	t0, t0, MIPS_SR_INT_MASK
357	and	v0, v0, ~MIPS_SR_INT_MASK
358	or	v0, v0, t0
359	mtc0	v0, MIPS_COP_0_STATUS
360	ITLBNOPFIX
361
362	j	ra
363	nop
364END(cpu_switch)
365
366/*----------------------------------------------------------------------------
367 *
368 * MipsSwitchFPState --
369 *
370 *	Save the current state into 'from' and restore it from 'to'.
371 *
372 *	MipsSwitchFPState(from, to)
373 *		struct thread *from;
374 *		struct trapframe *to;
375 *
376 * Results:
377 *	None.
378 *
379 * Side effects:
380 *	None.
381 *
382 *----------------------------------------------------------------------------
383 */
384LEAF(MipsSwitchFPState)
385	mfc0	t1, MIPS_COP_0_STATUS	# Save old SR
386	li	t0, MIPS_SR_COP_1_BIT	# enable the coprocessor
387	mtc0	t0, MIPS_COP_0_STATUS
388	ITLBNOPFIX
389
390	beq	a0, zero, 1f		# skip save if NULL pointer
391	nop
392/*
393 * First read out the status register to make sure that all FP operations
394 * have completed.
395 */
396	PTR_L	a0, TD_PCB(a0)			# get pointer to pcb for proc
397	cfc1	t0, MIPS_FPU_CSR		# stall til FP done
398	cfc1	t0, MIPS_FPU_CSR		# now get status
399	li	t3, ~MIPS_SR_COP_1_BIT
400	RESTORE_U_PCB_REG(t2, PS, a0)		# get CPU status register
401	SAVE_U_PCB_FPSR(t0, FSR_NUM, a0)	# save FP status
402	and	t2, t2, t3			# clear COP_1 enable bit
403	SAVE_U_PCB_REG(t2, PS, a0)		# save new status register
404/*
405 * Save the floating point registers.
406 */
407	SAVE_U_PCB_FPREG($f0, F0_NUM, a0)
408	SAVE_U_PCB_FPREG($f1, F1_NUM, a0)
409	SAVE_U_PCB_FPREG($f2, F2_NUM, a0)
410	SAVE_U_PCB_FPREG($f3, F3_NUM, a0)
411	SAVE_U_PCB_FPREG($f4, F4_NUM, a0)
412	SAVE_U_PCB_FPREG($f5, F5_NUM, a0)
413	SAVE_U_PCB_FPREG($f6, F6_NUM, a0)
414	SAVE_U_PCB_FPREG($f7, F7_NUM, a0)
415	SAVE_U_PCB_FPREG($f8, F8_NUM, a0)
416	SAVE_U_PCB_FPREG($f9, F9_NUM, a0)
417	SAVE_U_PCB_FPREG($f10, F10_NUM, a0)
418	SAVE_U_PCB_FPREG($f11, F11_NUM, a0)
419	SAVE_U_PCB_FPREG($f12, F12_NUM, a0)
420	SAVE_U_PCB_FPREG($f13, F13_NUM, a0)
421	SAVE_U_PCB_FPREG($f14, F14_NUM, a0)
422	SAVE_U_PCB_FPREG($f15, F15_NUM, a0)
423	SAVE_U_PCB_FPREG($f16, F16_NUM, a0)
424	SAVE_U_PCB_FPREG($f17, F17_NUM, a0)
425	SAVE_U_PCB_FPREG($f18, F18_NUM, a0)
426	SAVE_U_PCB_FPREG($f19, F19_NUM, a0)
427	SAVE_U_PCB_FPREG($f20, F20_NUM, a0)
428	SAVE_U_PCB_FPREG($f21, F21_NUM, a0)
429	SAVE_U_PCB_FPREG($f22, F22_NUM, a0)
430	SAVE_U_PCB_FPREG($f23, F23_NUM, a0)
431	SAVE_U_PCB_FPREG($f24, F24_NUM, a0)
432	SAVE_U_PCB_FPREG($f25, F25_NUM, a0)
433	SAVE_U_PCB_FPREG($f26, F26_NUM, a0)
434	SAVE_U_PCB_FPREG($f27, F27_NUM, a0)
435	SAVE_U_PCB_FPREG($f28, F28_NUM, a0)
436	SAVE_U_PCB_FPREG($f29, F29_NUM, a0)
437	SAVE_U_PCB_FPREG($f30, F30_NUM, a0)
438	SAVE_U_PCB_FPREG($f31, F31_NUM, a0)
439
4401:
441/*
442 *  Restore the floating point registers.
443 */
444	RESTORE_U_PCB_FPSR(t0, FSR_NUM, a1)	# get status register
445	RESTORE_U_PCB_FPREG($f0, F0_NUM, a1)
446	RESTORE_U_PCB_FPREG($f1, F1_NUM, a1)
447	RESTORE_U_PCB_FPREG($f2, F2_NUM, a1)
448	RESTORE_U_PCB_FPREG($f3, F3_NUM, a1)
449	RESTORE_U_PCB_FPREG($f4, F4_NUM, a1)
450	RESTORE_U_PCB_FPREG($f5, F5_NUM, a1)
451	RESTORE_U_PCB_FPREG($f6, F6_NUM, a1)
452	RESTORE_U_PCB_FPREG($f7, F7_NUM, a1)
453	RESTORE_U_PCB_FPREG($f8, F8_NUM, a1)
454	RESTORE_U_PCB_FPREG($f9, F9_NUM, a1)
455	RESTORE_U_PCB_FPREG($f10, F10_NUM, a1)
456	RESTORE_U_PCB_FPREG($f11, F11_NUM, a1)
457	RESTORE_U_PCB_FPREG($f12, F12_NUM, a1)
458	RESTORE_U_PCB_FPREG($f13, F13_NUM, a1)
459	RESTORE_U_PCB_FPREG($f14, F14_NUM, a1)
460	RESTORE_U_PCB_FPREG($f15, F15_NUM, a1)
461	RESTORE_U_PCB_FPREG($f16, F16_NUM, a1)
462	RESTORE_U_PCB_FPREG($f17, F17_NUM, a1)
463	RESTORE_U_PCB_FPREG($f18, F18_NUM, a1)
464	RESTORE_U_PCB_FPREG($f19, F19_NUM, a1)
465	RESTORE_U_PCB_FPREG($f20, F20_NUM, a1)
466	RESTORE_U_PCB_FPREG($f21, F21_NUM, a1)
467	RESTORE_U_PCB_FPREG($f22, F22_NUM, a1)
468	RESTORE_U_PCB_FPREG($f23, F23_NUM, a1)
469	RESTORE_U_PCB_FPREG($f24, F24_NUM, a1)
470	RESTORE_U_PCB_FPREG($f25, F25_NUM, a1)
471	RESTORE_U_PCB_FPREG($f26, F26_NUM, a1)
472	RESTORE_U_PCB_FPREG($f27, F27_NUM, a1)
473	RESTORE_U_PCB_FPREG($f28, F28_NUM, a1)
474	RESTORE_U_PCB_FPREG($f29, F29_NUM, a1)
475	RESTORE_U_PCB_FPREG($f30, F30_NUM, a1)
476	RESTORE_U_PCB_FPREG($f31, F31_NUM, a1)
477
478	and	t0, t0, ~MIPS_FPU_EXCEPTION_BITS
479	ctc1	t0, MIPS_FPU_CSR
480	nop
481
482	mtc0	t1, MIPS_COP_0_STATUS		# Restore the status register.
483	ITLBNOPFIX
484	j	ra
485	nop
486END(MipsSwitchFPState)
487
488/*----------------------------------------------------------------------------
489 *
490 * MipsSaveCurFPState --
491 *
492 *	Save the current floating point coprocessor state.
493 *
494 *	MipsSaveCurFPState(td)
495 *		struct thread *td;
496 *
497 * Results:
498 *	None.
499 *
500 * Side effects:
501 *	machFPCurProcPtr is cleared.
502 *
503 *----------------------------------------------------------------------------
504 */
505LEAF(MipsSaveCurFPState)
506	PTR_L	a0, TD_PCB(a0)			# get pointer to pcb for thread
507	mfc0	t1, MIPS_COP_0_STATUS		# Disable interrupts and
508	li	t0, MIPS_SR_COP_1_BIT		#  enable the coprocessor
509	mtc0	t0, MIPS_COP_0_STATUS
510	ITLBNOPFIX
511	GET_CPU_PCPU(a1)
512	PTR_S	zero, PC_FPCURTHREAD(a1)	# indicate state has been saved
513/*
514 * First read out the status register to make sure that all FP operations
515 * have completed.
516 */
517	RESTORE_U_PCB_REG(t2, PS, a0)		# get CPU status register
518	li	t3, ~MIPS_SR_COP_1_BIT
519	and	t2, t2, t3			# clear COP_1 enable bit
520	cfc1	t0, MIPS_FPU_CSR		# stall til FP done
521	cfc1	t0, MIPS_FPU_CSR		# now get status
522	SAVE_U_PCB_REG(t2, PS, a0)		# save new status register
523	SAVE_U_PCB_FPSR(t0, FSR_NUM, a0)	# save FP status
524/*
525 * Save the floating point registers.
526 */
527	SAVE_U_PCB_FPREG($f0, F0_NUM, a0)
528	SAVE_U_PCB_FPREG($f1, F1_NUM, a0)
529	SAVE_U_PCB_FPREG($f2, F2_NUM, a0)
530	SAVE_U_PCB_FPREG($f3, F3_NUM, a0)
531	SAVE_U_PCB_FPREG($f4, F4_NUM, a0)
532	SAVE_U_PCB_FPREG($f5, F5_NUM, a0)
533	SAVE_U_PCB_FPREG($f6, F6_NUM, a0)
534	SAVE_U_PCB_FPREG($f7, F7_NUM, a0)
535	SAVE_U_PCB_FPREG($f8, F8_NUM, a0)
536	SAVE_U_PCB_FPREG($f9, F9_NUM, a0)
537	SAVE_U_PCB_FPREG($f10, F10_NUM, a0)
538	SAVE_U_PCB_FPREG($f11, F11_NUM, a0)
539	SAVE_U_PCB_FPREG($f12, F12_NUM, a0)
540	SAVE_U_PCB_FPREG($f13, F13_NUM, a0)
541	SAVE_U_PCB_FPREG($f14, F14_NUM, a0)
542	SAVE_U_PCB_FPREG($f15, F15_NUM, a0)
543	SAVE_U_PCB_FPREG($f16, F16_NUM, a0)
544	SAVE_U_PCB_FPREG($f17, F17_NUM, a0)
545	SAVE_U_PCB_FPREG($f18, F18_NUM, a0)
546	SAVE_U_PCB_FPREG($f19, F19_NUM, a0)
547	SAVE_U_PCB_FPREG($f20, F20_NUM, a0)
548	SAVE_U_PCB_FPREG($f21, F21_NUM, a0)
549	SAVE_U_PCB_FPREG($f22, F22_NUM, a0)
550	SAVE_U_PCB_FPREG($f23, F23_NUM, a0)
551	SAVE_U_PCB_FPREG($f24, F24_NUM, a0)
552	SAVE_U_PCB_FPREG($f25, F25_NUM, a0)
553	SAVE_U_PCB_FPREG($f26, F26_NUM, a0)
554	SAVE_U_PCB_FPREG($f27, F27_NUM, a0)
555	SAVE_U_PCB_FPREG($f28, F28_NUM, a0)
556	SAVE_U_PCB_FPREG($f29, F29_NUM, a0)
557	SAVE_U_PCB_FPREG($f30, F30_NUM, a0)
558	SAVE_U_PCB_FPREG($f31, F31_NUM, a0)
559
560	mtc0	t1, MIPS_COP_0_STATUS		# Restore the status register.
561	ITLBNOPFIX
562	j	ra
563	nop
564END(MipsSaveCurFPState)
565
566/*
567 * When starting init, call this to configure the process for user
568 * mode.  This will be inherited by other processes.
569 */
570LEAF_NOPROFILE(prepare_usermode)
571	j	ra
572	nop
573END(prepare_usermode)
574
575
576/*
577 * This code is copied the user's stack for returning from signal handlers
578 * (see sendsig() and sigreturn()). We have to compute the address
579 * of the sigcontext struct for the sigreturn call.
580 */
581	.globl	_C_LABEL(sigcode)
582_C_LABEL(sigcode):
583	PTR_ADDU	a0, sp, SIGF_UC		# address of ucontext
584	li		v0, SYS_sigreturn
585# sigreturn (ucp)
586	syscall
587	break	0				# just in case sigreturn fails
588	.globl	_C_LABEL(esigcode)
589_C_LABEL(esigcode):
590
591	.data
592	.globl	szsigcode
593szsigcode:
594	.long	esigcode-sigcode
595	.text
596