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