linux-old/arch/mips64/kernel/r4k_switch.S
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 1994, 1995, 1996, 1998, 1999 by Ralf Baechle
   7 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
   8 * Copyright (C) 1994, 1995, 1996, by Andreas Busse
   9 * Copyright (C) 1999 Silicon Graphics, Inc.
  10 */
  11#include <asm/asm.h>
  12#include <asm/cachectl.h>
  13#include <asm/fpregdef.h>
  14#include <asm/mipsregs.h>
  15#include <asm/offset.h>
  16#include <asm/page.h>
  17#include <asm/pgtable.h>
  18#include <asm/processor.h>
  19#include <asm/regdef.h>
  20#include <asm/stackframe.h>
  21
  22#include <asm/asmmacro.h>
  23
  24        .set    mips3
  25
  26#define PF_USEDFPU      0x00100000      /* task used FPU this quantum (SMP) */
  27#define ST_OFF (KERNEL_STACK_SIZE - 32 - PT_SIZE + PT_STATUS)
  28
  29/*
  30 * [jsun] FPU context is saved if and only if the process has used FPU in 
  31 * the current run (PF_USEDFPU).  In any case, the CU1 bit for user space 
  32 * STATUS register should be 0, so that a process *always* starts its 
  33 * userland with FPU disabled after each context switch.
  34 *
  35 * FPU will be enabled as soon as the process accesses FPU again, through
  36 * do_cpu() trap.
  37 */
  38
  39/*
  40 * task_struct *resume(task_struct *prev, task_struct *next)
  41 */
  42        .set    noreorder
  43        .align  5
  44        LEAF(resume)
  45        mfc0    t1, CP0_STATUS
  46        sd      t1, THREAD_STATUS(a0)
  47        cpu_save_nonscratch a0
  48        sd      ra, THREAD_REG31(a0)
  49
  50        /*
  51         * check if we need to save FPU registers
  52         */
  53        ld      t0, TASK_FLAGS(a0)
  54        li      t1, PF_USEDFPU
  55        and     t2, t0, t1
  56        beqz    t2, 1f
  57        nor     t1, zero, t1
  58
  59        /*
  60         * clear PF_USEDFPU bit in task flags
  61         */
  62        and     t0, t0, t1
  63        sd      t0, TASK_FLAGS(a0)
  64
  65        /*
  66         * clear saved user stack CU1 bit
  67         */
  68        ld      t0, ST_OFF(a0)
  69        li      t1, ~ST0_CU1
  70        and     t0, t0, t1
  71        sd      t0, ST_OFF(a0)
  72
  73        
  74        sll     t2, t0, 5
  75        bgez    t2, 2f
  76        sdc1    $f0, (THREAD_FPU + 0x00)(a0)
  77        fpu_save_16odd a0
  782:
  79        fpu_save_16even a0 t1                   # clobbers t1
  801:
  81
  82        /*
  83         * The order of restoring the registers takes care of the race
  84         * updating $28, $29 and kernelsp without disabling ints.
  85         */
  86        move    $28, a1
  87        cpu_restore_nonscratch $28
  88
  89        daddiu  a1, $28, KERNEL_STACK_SIZE-32
  90        set_saved_sp    a1, t0, t1
  91
  92        mfc0    t1, CP0_STATUS          /* Do we really need this? */
  93        li      a3, 0xff00
  94        and     t1, a3
  95        ld      a2, THREAD_STATUS($28)
  96        nor     a3, $0, a3
  97        and     a2, a3
  98        or      a2, t1
  99        mtc0    a2, CP0_STATUS
 100        jr      ra
 101         move   v0, a0
 102        END(resume)
 103
 104/*
 105 * Save a thread's fp context.
 106 */
 107        .set    noreorder
 108LEAF(_save_fp)
 109        mfc0    t0, CP0_STATUS
 110        sll     t1, t0, 5
 111        bgez    t1, 1f                          # 16 register mode?
 112         nop
 113        fpu_save_16odd a0
 1141:
 115        fpu_save_16even a0 t1                   # clobbers t1
 116        jr      ra
 117         sdc1   $f0, (THREAD_FPU + 0x00)(a0)
 118        END(_save_fp)
 119
 120/*
 121 * Restore a thread's fp context.
 122 */
 123LEAF(_restore_fp)
 124        mfc0    t0, CP0_STATUS
 125        sll     t1, t0, 5
 126        bgez    t1, 1f                          # 16 register mode?
 127         nop
 128
 129        fpu_restore_16odd a0
 1301:
 131        fpu_restore_16even a0, t0               # clobbers t0
 132
 133        jr      ra
 134         ldc1   $f0, (THREAD_FPU + 0x00)(a0)
 135        END(_restore_fp)
 136
 137/*
 138 * Load the FPU with signalling NANS.  This bit pattern we're using has
 139 * the property that no matter whether considered as single or as double
 140 * precision represents signaling NANS.
 141 *
 142 * We initialize fcr31 to rounding to nearest, no exceptions.
 143 */
 144
 145#define FPU_DEFAULT  0x00000000
 146
 147LEAF(_init_fpu)
 148        mfc0    t0, CP0_STATUS
 149        li      t1, ST0_CU1
 150        or      t0, t1
 151        mtc0    t0, CP0_STATUS
 152        FPU_ENABLE_HAZARD
 153        sll     t0, t0, 5
 154
 155        li      t1, FPU_DEFAULT
 156        ctc1    t1, fcr31
 157
 158        bgez    t0, 1f                          # 16 / 32 register mode?
 159         li     t0, -1
 160
 161        dmtc1   t0, $f1
 162        dmtc1   t0, $f3
 163        dmtc1   t0, $f5
 164        dmtc1   t0, $f7
 165        dmtc1   t0, $f9
 166        dmtc1   t0, $f11
 167        dmtc1   t0, $f13
 168        dmtc1   t0, $f15
 169        dmtc1   t0, $f17
 170        dmtc1   t0, $f19
 171        dmtc1   t0, $f21
 172        dmtc1   t0, $f23
 173        dmtc1   t0, $f25
 174        dmtc1   t0, $f27
 175        dmtc1   t0, $f29
 176        dmtc1   t0, $f31
 177
 1781:      dmtc1   t0, $f0
 179        dmtc1   t0, $f2
 180        dmtc1   t0, $f4
 181        dmtc1   t0, $f6
 182        dmtc1   t0, $f8
 183        dmtc1   t0, $f10
 184        dmtc1   t0, $f12
 185        dmtc1   t0, $f14
 186        dmtc1   t0, $f16
 187        dmtc1   t0, $f18
 188        dmtc1   t0, $f20
 189        dmtc1   t0, $f22
 190        dmtc1   t0, $f24
 191        dmtc1   t0, $f26
 192        dmtc1   t0, $f28
 193        jr      ra
 194         dmtc1  t0, $f30
 195        END(_init_fpu)
 196
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.