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