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