]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/mips/mips/swtch.S
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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 #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  */
158 LEAF(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)
173 1:
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
232 END(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  */
241 LEAF(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
263 END(savectx)
264
265
266 KSEG0TEXT_START;
267
268 NON_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
279 END(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  */
287 NON_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
321 mips_sw1:
322 #if defined(SMP) && defined(SCHED_ULE)
323         la      t0, _C_LABEL(blocked_lock)
324 blocked_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  */
355 entry0:
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
362 pgm:
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
374 entry0set:
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  */
387 sw2:
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
418 END(cpu_switch)
419 KSEG0TEXT_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  */
439 LEAF(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
495 1:
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
541 END(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  */
560 LEAF(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
619 END(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  */
625 LEAF_NOPROFILE(prepare_usermode)
626         j       ra
627         nop
628 END(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
648 szsigcode:
649         .long   esigcode-sigcode
650         .text