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