]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/mips/mips/swtch.S
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / mips / mips / swtch.S
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$
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 <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 #include <machine/pcb.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  */
99 LEAF(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
167 END(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  */
176 LEAF(savectx)
177         SAVE_U_PCB_CONTEXT(s0, PCB_REG_S0, a0)
178         SAVE_U_PCB_CONTEXT(s1, PCB_REG_S1, a0)
179         SAVE_U_PCB_CONTEXT(s2, PCB_REG_S2, a0)
180         SAVE_U_PCB_CONTEXT(s3, PCB_REG_S3, a0)
181         mfc0    v0, MIPS_COP_0_STATUS
182         SAVE_U_PCB_CONTEXT(s4, PCB_REG_S4, a0)
183         SAVE_U_PCB_CONTEXT(s5, PCB_REG_S5, a0)
184         SAVE_U_PCB_CONTEXT(s6, PCB_REG_S6, a0)
185         SAVE_U_PCB_CONTEXT(s7, PCB_REG_S7, a0)
186         SAVE_U_PCB_CONTEXT(sp, PCB_REG_SP, a0)
187         SAVE_U_PCB_CONTEXT(s8, PCB_REG_S8, a0)
188         SAVE_U_PCB_CONTEXT(ra, PCB_REG_RA, a0)
189         SAVE_U_PCB_CONTEXT(v0, PCB_REG_SR, a0)
190         SAVE_U_PCB_CONTEXT(gp, PCB_REG_GP, a0)
191
192         move    v0, ra                  /* save 'ra' before we trash it */
193         jal     1f
194         nop
195 1:
196         SAVE_U_PCB_CONTEXT(ra, PCB_REG_PC, a0)
197         move    ra, v0                  /* restore 'ra' before returning */
198
199         j       ra
200         move    v0, zero
201 END(savectx)
202
203 NON_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
214 END(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  */
223 NON_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, PCB_REG_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, PCB_REG_S0, a0)          # do a 'savectx()'
238         SAVE_U_PCB_CONTEXT(s1, PCB_REG_S1, a0)
239         SAVE_U_PCB_CONTEXT(s2, PCB_REG_S2, a0)
240         SAVE_U_PCB_CONTEXT(s3, PCB_REG_S3, a0)
241         SAVE_U_PCB_CONTEXT(s4, PCB_REG_S4, a0)
242         SAVE_U_PCB_CONTEXT(s5, PCB_REG_S5, a0)
243         SAVE_U_PCB_CONTEXT(s6, PCB_REG_S6, a0)
244         SAVE_U_PCB_CONTEXT(s7, PCB_REG_S7, a0)
245         SAVE_U_PCB_CONTEXT(s8, PCB_REG_S8, a0)
246         SAVE_U_PCB_CONTEXT(ra, PCB_REG_RA, a0)          # save return address
247         SAVE_U_PCB_CONTEXT(t0, PCB_REG_SR, a0)          # save status register
248         SAVE_U_PCB_CONTEXT(gp, PCB_REG_GP, a0)
249         jal     getpc
250         nop
251 getpc:
252         SAVE_U_PCB_CONTEXT(ra, PCB_REG_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, PCB_REG_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
290 userland_cop2:
291
292         PTR_L   a0, TD_UCOP2(a3)
293         beqz    a0, no_cop2_context
294         nop
295
296 do_cop2_save:
297         jal     octeon_cop2_save
298         nop
299
300 no_cop2_context:
301         move    a3, s3
302         move    a2, s2
303         move    a1, s1
304         move    a0, s0
305
306 cop2_untouched:
307 #endif
308
309         PTR_S   a2, TD_LOCK(a3)                 # Switchout td_lock 
310
311 mips_sw1:
312 #if defined(SMP) && defined(SCHED_ULE)
313         PTR_LA  t0, _C_LABEL(blocked_lock)
314 blocked_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
363 entry0set:
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  */
376 sw2:
377         PTR_L   s0, TD_PCB(s7)
378         RESTORE_U_PCB_CONTEXT(sp, PCB_REG_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, PCB_REG_GP, a0)
387         RESTORE_U_PCB_CONTEXT(v0, PCB_REG_SR, a0)       # restore kernel context
388         RESTORE_U_PCB_CONTEXT(ra, PCB_REG_RA, a0)
389         RESTORE_U_PCB_CONTEXT(s0, PCB_REG_S0, a0)
390         RESTORE_U_PCB_CONTEXT(s1, PCB_REG_S1, a0)
391         RESTORE_U_PCB_CONTEXT(s2, PCB_REG_S2, a0)
392         RESTORE_U_PCB_CONTEXT(s3, PCB_REG_S3, a0)
393         RESTORE_U_PCB_CONTEXT(s4, PCB_REG_S4, a0)
394         RESTORE_U_PCB_CONTEXT(s5, PCB_REG_S5, a0)
395         RESTORE_U_PCB_CONTEXT(s6, PCB_REG_S6, a0)
396         RESTORE_U_PCB_CONTEXT(s7, PCB_REG_S7, a0)
397         RESTORE_U_PCB_CONTEXT(s8, PCB_REG_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
408 END(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  */
428 LEAF(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
484 1:
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
530 END(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  */
549 LEAF(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
608 END(MipsSaveCurFPState)
609
610 /*
611  * This code is copied the user's stack for returning from signal handlers
612  * (see sendsig() and sigreturn()). We have to compute the address
613  * of the sigcontext struct for the sigreturn call.
614  */
615         .globl  _C_LABEL(sigcode)
616 _C_LABEL(sigcode):
617         PTR_ADDU        a0, sp, SIGF_UC         # address of ucontext
618         li              v0, SYS_sigreturn
619 # sigreturn (ucp)
620         syscall
621         break   0                               # just in case sigreturn fails
622         .globl  _C_LABEL(esigcode)
623 _C_LABEL(esigcode):
624
625         .data
626         .globl  szsigcode
627 szsigcode:
628         .long   esigcode-sigcode
629         .text
630
631 #if (defined(__mips_n32) || defined(__mips_n64)) && defined(COMPAT_FREEBSD32)
632         .globl  _C_LABEL(sigcode32)
633 _C_LABEL(sigcode32):
634         addu            a0, sp, SIGF32_UC       # address of ucontext
635         li              v0, SYS_sigreturn
636 # sigreturn (ucp)
637         syscall
638         break   0                               # just in case sigreturn fails
639         .globl  _C_LABEL(esigcode32)
640 _C_LABEL(esigcode32):
641
642         .data
643         .globl  szsigcode32
644 szsigcode32:
645         .long   esigcode32-sigcode32
646         .text
647 #endif