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