summaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-04-05 11:23:36 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-04-05 11:23:36 +0000
commit4318fbda2a7ee51caafdc4eb1f8028a3f0605142 (patch)
treecddb50a81d7d1a628cc400519162080c6d87868e /arch/mips/kernel
parent36ea5120664550fae6d31f1c6f695e4f8975cb06 (diff)
o Merge with Linux 2.1.91.
o First round of bugfixes for the SC/MC CPUs. o FPU context switch fixes. o Lazy context switches. o Faster syscalls. o Removed dead code. o Shitloads of other things I forgot ...
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/entry.S5
-rw-r--r--arch/mips/kernel/fpe.c4
-rw-r--r--arch/mips/kernel/irixinv.c6
-rw-r--r--arch/mips/kernel/process.c23
-rw-r--r--arch/mips/kernel/ptrace.c8
-rw-r--r--arch/mips/kernel/r2300_switch.S6
-rw-r--r--arch/mips/kernel/r4k_fpu.S165
-rw-r--r--arch/mips/kernel/r4k_switch.S159
-rw-r--r--arch/mips/kernel/signal.c59
-rw-r--r--arch/mips/kernel/traps.c46
10 files changed, 320 insertions, 161 deletions
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index afabc6156..413eb8a2f 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -7,7 +7,7 @@
*
* Copyright (C) 1994, 1995 by Ralf Baechle
*
- * $Id: entry.S,v 1.10 1998/03/26 07:39:09 ralf Exp $
+ * $Id: entry.S,v 1.8 1998/03/27 04:47:53 ralf Exp $
*/
/*
@@ -104,7 +104,8 @@ LEAF(spurious_interrupt)
cfc1 a1,fcr31; \
li a2,~(0x3f<<12); \
and a2,a1; \
- ctc1 a2,fcr31;
+ ctc1 a2,fcr31; \
+ STI
#define __BUILD_clear_ade(exception) \
MFC0 t0,CP0_BADVADDR; \
REG_S t0,PT_BVADDR(sp); \
diff --git a/arch/mips/kernel/fpe.c b/arch/mips/kernel/fpe.c
index ee47f016f..8491c95d1 100644
--- a/arch/mips/kernel/fpe.c
+++ b/arch/mips/kernel/fpe.c
@@ -6,7 +6,7 @@
*
* Copyright (C) 1997 Ralf Baechle
*
- * $Id: fpe.c,v 1.1 1997/08/11 04:17:18 ralf Exp $
+ * $Id: fpe.c,v 1.2 1997/12/01 17:57:26 ralf Exp $
*/
#include <linux/kernel.h>
#include <linux/module.h>
@@ -18,7 +18,7 @@
#include <asm/branch.h>
#include <asm/ptrace.h>
-MODULE_AUTHOR("Ralf Baechle <ralf@gnu.ai.mit.edu>");
+MODULE_AUTHOR("Ralf Baechle <ralf@gnu.org>");
MODULE_DESCRIPTION("Experimental floating point exception handler");
MODULE_SUPPORTED_DEVICE("MIPS FPU");
diff --git a/arch/mips/kernel/irixinv.c b/arch/mips/kernel/irixinv.c
index 3fa785b1d..105b29f23 100644
--- a/arch/mips/kernel/irixinv.c
+++ b/arch/mips/kernel/irixinv.c
@@ -5,9 +5,10 @@
*
* Miguel de Icaza, 1997.
*
- * $Id$
+ * $Id: irixinv.c,v 1.2 1997/12/06 23:52:04 ralf Exp $
*/
#include <linux/mm.h>
+#include <linux/init.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/inventory.h>
@@ -52,8 +53,7 @@ dump_inventory_to_user (void *userbuf, int size)
return inventory_items * sizeof (inventory_t);
}
-void
-init_inventory (void)
+__initfunc(void init_inventory (void))
{
/* gross hack while we put the right bits all over the kernel
* most likely this will not let just anyone run the X server
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 45d58730c..64c8cff16 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -7,7 +7,7 @@
*
* Copyright (C) 1994 - 1998 by Ralf Baechle and others.
*
- * $Id: process.c,v 1.7 1998/03/22 20:43:43 ralf Exp $
+ * $Id: process.c,v 1.7 1998/03/27 04:47:55 ralf Exp $
*/
#include <linux/config.h>
#include <linux/errno.h>
@@ -51,10 +51,22 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
void exit_thread(void)
{
+ /* Forget lazy fpu state */
+ if (last_task_used_math == current) {
+ set_cp0_status(ST0_CU1, ST0_CU1);
+ __asm__ __volatile__("cfc1\t$0,$31");
+ last_task_used_math = NULL;
+ }
}
void flush_thread(void)
{
+ /* Forget lazy fpu state */
+ if (last_task_used_math == current) {
+ set_cp0_status(ST0_CU1, ST0_CU1);
+ __asm__ __volatile__("cfc1\t$0,$31");
+ last_task_used_math = NULL;
+ }
}
void release_thread(struct task_struct *dead_task)
@@ -69,6 +81,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
childksp = (unsigned long)p + KERNEL_STACK_SIZE - 32;
+ if (last_task_used_math == current) {
+ set_cp0_status(ST0_CU1, ST0_CU1);
+ r4xx0_save_fp(p);
+ }
/* set up new TSS. */
childregs = (struct pt_regs *) childksp - 1;
*childregs = *regs;
@@ -84,14 +100,13 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
regs->regs[3] = 0;
}
if (childregs->cp0_status & ST0_CU0) {
- childregs->regs[28] = p;
+ childregs->regs[28] = (unsigned long) p;
childregs->regs[29] = childksp;
p->tss.current_ds = KERNEL_DS;
} else {
childregs->regs[29] = usp;
p->tss.current_ds = USER_DS;
}
- p->tss.ksp = childksp;
p->tss.reg29 = (unsigned long) childregs;
p->tss.reg31 = (unsigned long) ret_from_sys_call;
@@ -100,7 +115,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
* switching for most programs since they don't use the fpu.
*/
p->tss.cp0_status = read_32bit_cp0_register(CP0_STATUS) &
- ~(ST0_CU3|ST0_CU2|ST0_CU1|ST0_KSU|ST0_ERL|ST0_EXL);
+ ~(ST0_CU3|ST0_CU2|ST0_CU1|ST0_KSU);
childregs->cp0_status &= ~(ST0_CU3|ST0_CU2|ST0_CU1);
p->mm->context = 0;
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index ebd657d4c..b8d604d2d 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -342,8 +342,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
struct pt_regs *regs;
unsigned long tmp;
- regs = (struct pt_regs *)
- (child->tss.ksp - sizeof(struct pt_regs));
+ regs = (struct pt_regs *) ((unsigned long) child +
+ KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
tmp = 0; /* Default return value. */
if(addr < 32 && addr >= 0) {
tmp = regs->regs[addr];
@@ -398,8 +398,8 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
struct pt_regs *regs;
int res = 0;
- regs = (struct pt_regs *)
- (child->tss.ksp - sizeof(struct pt_regs));
+ regs = (struct pt_regs *) ((unsigned long) child +
+ KERNEL_STACK_SIZE - 32 - sizeof(struct pt_regs));
if(addr < 32 && addr >= 0) {
regs->regs[addr] = data;
} else if(addr >= 32 && addr < 64) {
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S
index f4470e54d..b2b55bf0b 100644
--- a/arch/mips/kernel/r2300_switch.S
+++ b/arch/mips/kernel/r2300_switch.S
@@ -6,7 +6,7 @@
* Multi-cpu abstraction and macros for easier reading:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: r2300_switch.S,v 1.3 1998/03/23 06:34:37 ralf Exp $
+ * $Id: r2300_switch.S,v 1.3 1998/03/27 04:47:55 ralf Exp $
*/
#include <asm/asm.h>
#include <asm/bootinfo.h>
@@ -83,8 +83,8 @@ MODE_ALIAS = 0x00e0 # uncachable, dirty, valid
FPU_RESTORE($28, t0)
1:
CPU_RESTORE_NONSCRATCH($28)
- lw t0,THREAD_KSP($28) # Restore status register
+ addiu t0, $28, KERNEL_STACK_SIZE-32
sw t0,kernelsp
jr ra
- mtc0 a2,CP0_STATUS
+ mtc0 a2,CP0_STATUS # Restore status register
END(r2300_resume)
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S
index 72638d462..c37b90612 100644
--- a/arch/mips/kernel/r4k_fpu.S
+++ b/arch/mips/kernel/r4k_fpu.S
@@ -5,12 +5,12 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1996 by Ralf Baechle
+ * Copyright (C) 1996, 1998 by Ralf Baechle
*
* Multi-arch abstraction and asm macros for easier reading:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
*
- * $Id: r4k_fpu.S,v 1.3 1997/12/01 16:56:06 ralf Exp $
+ * $Id: r4k_fpu.S,v 1.3 1997/12/01 17:57:30 ralf Exp $
*/
#include <asm/asm.h>
#include <asm/fpregdef.h>
@@ -18,65 +18,63 @@
#include <asm/offset.h>
#include <asm/regdef.h>
+#define EX(a,b) \
+9: a,##b; \
+ .section __ex_table,"a"; \
+ PTR 9b,bad_stack; \
+ .previous
+
.set noreorder
.set mips3
/* Save floating point context */
LEAF(r4k_save_fp_context)
mfc0 t1,CP0_STATUS
- sll t2,t1,2
- bgez t2,2f
sll t2,t1,5
- cfc1 t1,fcr31
bgez t2,1f
- nop
+ cfc1 t1,fcr31
/* Store the 16 odd double precision registers */
- sdc1 $f1,(SC_FPREGS+8)(a0)
- sdc1 $f3,(SC_FPREGS+24)(a0)
- sdc1 $f5,(SC_FPREGS+40)(a0)
- sdc1 $f7,(SC_FPREGS+56)(a0)
- sdc1 $f9,(SC_FPREGS+72)(a0)
- sdc1 $f11,(SC_FPREGS+88)(a0)
- sdc1 $f13,(SC_FPREGS+104)(a0)
- sdc1 $f15,(SC_FPREGS+120)(a0)
- sdc1 $f17,(SC_FPREGS+136)(a0)
- sdc1 $f19,(SC_FPREGS+152)(a0)
- sdc1 $f21,(SC_FPREGS+168)(a0)
- sdc1 $f23,(SC_FPREGS+184)(a0)
- sdc1 $f25,(SC_FPREGS+200)(a0)
- sdc1 $f27,(SC_FPREGS+216)(a0)
- sdc1 $f29,(SC_FPREGS+232)(a0)
- sdc1 $f31,(SC_FPREGS+248)(a0)
+ EX(sdc1 $f1,(SC_FPREGS+8)(a0))
+ EX(sdc1 $f3,(SC_FPREGS+24)(a0))
+ EX(sdc1 $f5,(SC_FPREGS+40)(a0))
+ EX(sdc1 $f7,(SC_FPREGS+56)(a0))
+ EX(sdc1 $f9,(SC_FPREGS+72)(a0))
+ EX(sdc1 $f11,(SC_FPREGS+88)(a0))
+ EX(sdc1 $f13,(SC_FPREGS+104)(a0))
+ EX(sdc1 $f15,(SC_FPREGS+120)(a0))
+ EX(sdc1 $f17,(SC_FPREGS+136)(a0))
+ EX(sdc1 $f19,(SC_FPREGS+152)(a0))
+ EX(sdc1 $f21,(SC_FPREGS+168)(a0))
+ EX(sdc1 $f23,(SC_FPREGS+184)(a0))
+ EX(sdc1 $f25,(SC_FPREGS+200)(a0))
+ EX(sdc1 $f27,(SC_FPREGS+216)(a0))
+ EX(sdc1 $f29,(SC_FPREGS+232)(a0))
+ EX(sdc1 $f31,(SC_FPREGS+248)(a0))
/* Store the 16 even double precision registers */
1:
- sdc1 $f0,(SC_FPREGS+0)(a0)
- sdc1 $f2,(SC_FPREGS+16)(a0)
- sdc1 $f4,(SC_FPREGS+32)(a0)
- sdc1 $f6,(SC_FPREGS+48)(a0)
- sdc1 $f8,(SC_FPREGS+64)(a0)
- sdc1 $f10,(SC_FPREGS+80)(a0)
- sdc1 $f12,(SC_FPREGS+96)(a0)
- sdc1 $f14,(SC_FPREGS+112)(a0)
- sdc1 $f16,(SC_FPREGS+128)(a0)
- sdc1 $f18,(SC_FPREGS+144)(a0)
- sdc1 $f20,(SC_FPREGS+160)(a0)
- sdc1 $f22,(SC_FPREGS+176)(a0)
- sdc1 $f24,(SC_FPREGS+192)(a0)
- sdc1 $f26,(SC_FPREGS+208)(a0)
- sdc1 $f28,(SC_FPREGS+224)(a0)
- sdc1 $f30,(SC_FPREGS+240)(a0)
- sw t1,SC_FPC_CSR(a0)
+ EX(sdc1 $f0,(SC_FPREGS+0)(a0))
+ EX(sdc1 $f2,(SC_FPREGS+16)(a0))
+ EX(sdc1 $f4,(SC_FPREGS+32)(a0))
+ EX(sdc1 $f6,(SC_FPREGS+48)(a0))
+ EX(sdc1 $f8,(SC_FPREGS+64)(a0))
+ EX(sdc1 $f10,(SC_FPREGS+80)(a0))
+ EX(sdc1 $f12,(SC_FPREGS+96)(a0))
+ EX(sdc1 $f14,(SC_FPREGS+112)(a0))
+ EX(sdc1 $f16,(SC_FPREGS+128)(a0))
+ EX(sdc1 $f18,(SC_FPREGS+144)(a0))
+ EX(sdc1 $f20,(SC_FPREGS+160)(a0))
+ EX(sdc1 $f22,(SC_FPREGS+176)(a0))
+ EX(sdc1 $f24,(SC_FPREGS+192)(a0))
+ EX(sdc1 $f26,(SC_FPREGS+208)(a0))
+ EX(sdc1 $f28,(SC_FPREGS+224)(a0))
+ EX(sdc1 $f30,(SC_FPREGS+240)(a0))
+ EX(sw t1,SC_FPC_CSR(a0))
cfc1 t0,$0 # implementation/version
jr ra
.set nomacro
- sw t0,SC_FPC_EIR(a0)
- .set macro
-2:
- jr ra
- .set nomacro
- nop
+ EX(sw t0,SC_FPC_EIR(a0))
.set macro
END(r4k_save_fp_context)
@@ -90,56 +88,51 @@ LEAF(r4k_save_fp_context)
* stack frame which might have been changed by the user.
*/
LEAF(r4k_restore_fp_context)
- mfc0 t1,CP0_STATUS
- sll t0,t1,2
- bgez t0,2f
- sll t0,t1,5
-
+ mfc0 t1, CP0_STATUS
+ sll t0,t1,5
bgez t0,1f
- lw t0,SC_FPC_CSR(a0)
+ EX(lw t0,SC_FPC_CSR(a0))
+
/* Restore the 16 odd double precision registers only
* when enabled in the cp0 status register.
*/
- ldc1 $f1,(SC_FPREGS+8)(a0)
- ldc1 $f3,(SC_FPREGS+24)(a0)
- ldc1 $f5,(SC_FPREGS+40)(a0)
- ldc1 $f7,(SC_FPREGS+56)(a0)
- ldc1 $f9,(SC_FPREGS+72)(a0)
- ldc1 $f11,(SC_FPREGS+88)(a0)
- ldc1 $f13,(SC_FPREGS+104)(a0)
- ldc1 $f15,(SC_FPREGS+120)(a0)
- ldc1 $f17,(SC_FPREGS+136)(a0)
- ldc1 $f19,(SC_FPREGS+152)(a0)
- ldc1 $f21,(SC_FPREGS+168)(a0)
- ldc1 $f23,(SC_FPREGS+184)(a0)
- ldc1 $f25,(SC_FPREGS+200)(a0)
- ldc1 $f27,(SC_FPREGS+216)(a0)
- ldc1 $f29,(SC_FPREGS+232)(a0)
- ldc1 $f31,(SC_FPREGS+248)(a0)
+ EX(ldc1 $f1,(SC_FPREGS+8)(a0))
+ EX(ldc1 $f3,(SC_FPREGS+24)(a0))
+ EX(ldc1 $f5,(SC_FPREGS+40)(a0))
+ EX(ldc1 $f7,(SC_FPREGS+56)(a0))
+ EX(ldc1 $f9,(SC_FPREGS+72)(a0))
+ EX(ldc1 $f11,(SC_FPREGS+88)(a0))
+ EX(ldc1 $f13,(SC_FPREGS+104)(a0))
+ EX(ldc1 $f15,(SC_FPREGS+120)(a0))
+ EX(ldc1 $f17,(SC_FPREGS+136)(a0))
+ EX(ldc1 $f19,(SC_FPREGS+152)(a0))
+ EX(ldc1 $f21,(SC_FPREGS+168)(a0))
+ EX(ldc1 $f23,(SC_FPREGS+184)(a0))
+ EX(ldc1 $f25,(SC_FPREGS+200)(a0))
+ EX(ldc1 $f27,(SC_FPREGS+216)(a0))
+ EX(ldc1 $f29,(SC_FPREGS+232)(a0))
+ EX(ldc1 $f31,(SC_FPREGS+248)(a0))
/*
* Restore the 16 even double precision registers
* when cp1 was enabled in the cp0 status register.
*/
-1: ldc1 $f0,(SC_FPREGS+0)(a0)
- ldc1 $f2,(SC_FPREGS+16)(a0)
- ldc1 $f4,(SC_FPREGS+32)(a0)
- ldc1 $f6,(SC_FPREGS+48)(a0)
- ldc1 $f8,(SC_FPREGS+64)(a0)
- ldc1 $f10,(SC_FPREGS+80)(a0)
- ldc1 $f12,(SC_FPREGS+96)(a0)
- ldc1 $f14,(SC_FPREGS+112)(a0)
- ldc1 $f16,(SC_FPREGS+128)(a0)
- ldc1 $f18,(SC_FPREGS+144)(a0)
- ldc1 $f20,(SC_FPREGS+160)(a0)
- ldc1 $f22,(SC_FPREGS+176)(a0)
- ldc1 $f24,(SC_FPREGS+192)(a0)
- ldc1 $f26,(SC_FPREGS+208)(a0)
- ldc1 $f28,(SC_FPREGS+224)(a0)
- ldc1 $f30,(SC_FPREGS+240)(a0)
+1: EX(ldc1 $f0,(SC_FPREGS+0)(a0))
+ EX(ldc1 $f2,(SC_FPREGS+16)(a0))
+ EX(ldc1 $f4,(SC_FPREGS+32)(a0))
+ EX(ldc1 $f6,(SC_FPREGS+48)(a0))
+ EX(ldc1 $f8,(SC_FPREGS+64)(a0))
+ EX(ldc1 $f10,(SC_FPREGS+80)(a0))
+ EX(ldc1 $f12,(SC_FPREGS+96)(a0))
+ EX(ldc1 $f14,(SC_FPREGS+112)(a0))
+ EX(ldc1 $f16,(SC_FPREGS+128)(a0))
+ EX(ldc1 $f18,(SC_FPREGS+144)(a0))
+ EX(ldc1 $f20,(SC_FPREGS+160)(a0))
+ EX(ldc1 $f22,(SC_FPREGS+176)(a0))
+ EX(ldc1 $f24,(SC_FPREGS+192)(a0))
+ EX(ldc1 $f26,(SC_FPREGS+208)(a0))
+ EX(ldc1 $f28,(SC_FPREGS+224)(a0))
+ EX(ldc1 $f30,(SC_FPREGS+240)(a0))
jr ra
ctc1 t0,fcr31
-
-2: jr ra
- nop
END(r4k_restore_fp_context)
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S
index cb7f9891f..765de0d85 100644
--- a/arch/mips/kernel/r4k_switch.S
+++ b/arch/mips/kernel/r4k_switch.S
@@ -5,6 +5,8 @@
*
* Multi-cpu abstraction and macros for easier reading:
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ *
+ * $Id: r4k_switch.S,v 1.3 1998/04/04 13:59:38 ralf Exp $
*/
#include <asm/asm.h>
#include <asm/bootinfo.h>
@@ -13,6 +15,7 @@
#include <asm/fpregdef.h>
#include <asm/mipsconfig.h>
#include <asm/mipsregs.h>
+#include <asm/offset.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
@@ -25,43 +28,139 @@
.set mips3
.align 5
LEAF(r4xx0_resume)
- mfc0 t1, CP0_STATUS
- sw t1, THREAD_STATUS($28)
- ori t2, t1, 0x1f
- xori t2, t2, 0x1e
- mtc0 t2, CP0_STATUS
+ mfc0 t1, CP0_STATUS # fp exception boundary
+ sll t0, t1, 2
+ bgez t0, 1f
+ nop
+ cfc1 zero, fcr31
+1: sw t1, THREAD_STATUS($28)
CPU_SAVE_NONSCRATCH($28)
- sll t2, t1, 2 # Save floating point state
- bgez t2, 2f
- sw ra, THREAD_REG31($28)
- sll t2, t1, 5
- bgez t2, 1f
- swc1 $f0, (THREAD_FPU + 0x00)($28)
- FPU_SAVE_16ODD($28)
-1:
- FPU_SAVE_16EVEN($28, t1) # clobbers t1
-2:
+ sw ra, THREAD_REG31($28)
+
+ /*
+ * The order of restoring the registers takes care of the race
+ * updating $28, $29 and kernelsp without disabling ints.
+ */
move $28, a0
+ CPU_RESTORE_NONSCRATCH($28)
+ addiu t0, $28, KERNEL_STACK_SIZE-32
+ sw t0, kernelsp
lw a3, TASK_MM($28)
lw a2, THREAD_STATUS($28)
lw a3, MM_CONTEXT(a3)
- ori t1, a2, 1 # restore fpu, pipeline magic
+ mtc0 a2, CP0_STATUS
andi a3, a3, 0xff
- xori t1, t1, 1
- mtc0 a3, CP0_ENTRYHI
- mtc0 t1, CP0_STATUS
- sll t0, a2, 2
- bgez t0, 2f
- sll t0, a2, 5
+ jr ra
+ mtc0 a3, CP0_ENTRYHI
+ END(r4xx0_resume)
+
+/*
+ * Do lazy fpu context switch. Saves FPU context to the process in a0
+ * and loads the new context of the current process.
+ */
+
+#define ST_OFF (KERNEL_STACK_SIZE - 32 - PT_SIZE + PT_STATUS)
+
+LEAF(r4xx0_lazy_fpu_switch)
+ mfc0 t0, CP0_STATUS # enable cp1
+ li t3, 0x20000000
+ or t0, t3
+ mtc0 t0, CP0_STATUS
+
+ beqz a0, 2f # Save floating point state
+ nor t3, zero, t3
+ lw t1, ST_OFF(a0) # last thread looses fpu
+ and t1, t3
+ sw t1, ST_OFF(a0)
+ sll t2, t1, 5
+ bgez t2, 1f
+ sdc1 $f0, (THREAD_FPU + 0x00)(a0)
+ FPU_SAVE_16ODD(a0)
+1:
+ FPU_SAVE_16EVEN(a0, t1) # clobbers t1
+2:
+
+ sll t0, t0, 5 # load new fp state
bgez t0, 1f
- lwc1 $f0, (THREAD_FPU + 0x00)($28)
+ ldc1 $f0, (THREAD_FPU + 0x00)($28)
FPU_RESTORE_16ODD($28)
1:
- FPU_RESTORE_16EVEN($28, t0) # clobbers t0
-2:
- CPU_RESTORE_NONSCRATCH($28)
- lw t0, THREAD_KSP($28)
- sw t0, kernelsp
+ .set reorder
+ FPU_RESTORE_16EVEN($28, t0) # clobbers t0
jr ra
- mtc0 a2, CP0_STATUS
- END(r4xx0_resume)
+ END(r4xx0_lazy_fpu_switch)
+
+/*
+ * Save a thread's fp context.
+ */
+ .set noreorder
+LEAF(r4xx0_save_fp)
+ mfc0 t0, CP0_STATUS
+ sll t1, t0, 5
+ bgez t1, 1f # 16 register mode?
+ nop
+ FPU_SAVE_16ODD(a0)
+1:
+ FPU_SAVE_16EVEN(a0, t1) # clobbers t1
+ jr ra
+ sdc1 $f0, (THREAD_FPU + 0x00)(a0)
+ END(r4xx0_save_fp)
+
+/*
+ * Load the FPU with signalling NANS. This bit pattern we're using has
+ * the property that no matter wether considered as single or as double
+ * precission represents signaling NANS.
+ *
+ * We initialize fcr31 to rounding to nearest, no exceptions.
+ */
+
+#define FPU_DEFAULT 0x00000600
+
+LEAF(r4xx0_init_fpu)
+ mfc0 t0, CP0_STATUS
+ li t1, 0x20000000
+ or t0, t1
+ mtc0 t0, CP0_STATUS
+ sll t0, t0, 5
+
+ li t1, FPU_DEFAULT
+ ctc1 t1, fcr31
+
+ bgez t0, 1f # 16 / 32 register mode?
+ li t0, -1
+
+ dmtc1 t0, $f1
+ dmtc1 t0, $f3
+ dmtc1 t0, $f5
+ dmtc1 t0, $f7
+ dmtc1 t0, $f9
+ dmtc1 t0, $f11
+ dmtc1 t0, $f13
+ dmtc1 t0, $f15
+ dmtc1 t0, $f17
+ dmtc1 t0, $f19
+ dmtc1 t0, $f21
+ dmtc1 t0, $f23
+ dmtc1 t0, $f25
+ dmtc1 t0, $f27
+ dmtc1 t0, $f29
+ dmtc1 t0, $f31
+
+1: dmtc1 t0, $f0
+ dmtc1 t0, $f2
+ dmtc1 t0, $f4
+ dmtc1 t0, $f6
+ dmtc1 t0, $f8
+ dmtc1 t0, $f10
+ dmtc1 t0, $f12
+ dmtc1 t0, $f14
+ dmtc1 t0, $f16
+ dmtc1 t0, $f18
+ dmtc1 t0, $f20
+ dmtc1 t0, $f22
+ dmtc1 t0, $f24
+ dmtc1 t0, $f26
+ dmtc1 t0, $f28
+ jr ra
+ dmtc1 t0, $f30
+ END(r4xx0_init_fpu)
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 007e95452..954e8bfb0 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -4,7 +4,9 @@
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1994, 1995, 1996 Ralf Baechle
*
- * $Id: signal.c,v 1.17 1998/03/26 07:39:10 ralf Exp $
+ * $Id: signal.c,v 1.11 1998/03/27 04:47:55 ralf Exp $
+ *
+ * XXX Handle lazy fp context switches correctly.
*/
#include <linux/config.h>
#include <linux/sched.h>
@@ -125,17 +127,10 @@ asmlinkage void
restore_sigcontext(struct pt_regs *regs, struct sigcontext *context)
{
long long reg;
- int i;
+ int owned_fp;
__get_user(regs->cp0_epc, &context->sc_pc);
- /*
- * Restore all integer registers.
- */
- for(i = 31;i >= 0;i--) {
- __get_user(reg, &context->sc_regs[i]);
- regs->regs[i] = (int) reg;
- }
__get_user(reg, &context->sc_mdhi);
regs->hi = (int) reg;
__get_user(reg, &context->sc_mdlo);
@@ -156,11 +151,15 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext *context)
restore_gp_reg(31);
#undef restore_gp_reg
- /*
- * FP depends on what FPU in what mode we have. Best done in
- * Assembler ...
- */
- restore_fp_context(context);
+ /* FP depends on what FPU in what mode we have. */
+ __get_user(owned_fp, &context->sc_ownedfp);
+#if 0
+ if (owned_fp) {
+ restore_fp_context(context);
+ last_task_used_math = current;
+ }
+#endif
+restore_fp_context(context);
}
/*
@@ -191,8 +190,16 @@ asmlinkage int sys_sigreturn(struct pt_regs regs)
(regs.regs[29] & (SZREG - 1)))
goto badframe;
+#if 1
+ if (__get_user(blocked.sig[0], &context->sc_sigset[0]) ||
+ __get_user(blocked.sig[1], &context->sc_sigset[1]) ||
+ __get_user(blocked.sig[2], &context->sc_sigset[2]) ||
+ __get_user(blocked.sig[3], &context->sc_sigset[3]))
+ goto badframe;
+#else
if (__copy_from_user(&blocked, &context->sc_sigset, sizeof(blocked)))
goto badframe;
+#endif
sigdelsetmask(&blocked, ~_BLOCKABLE);
spin_lock_irq(&current->sigmask_lock);
@@ -251,6 +258,8 @@ setup_trampoline(unsigned int *code)
static void inline
setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc, sigset_t *set)
{
+ int owned_fp;
+
__put_user(regs->cp0_epc, &sc->sc_pc);
__put_user(regs->cp0_status, &sc->sc_status); /* Status register */
@@ -266,13 +275,29 @@ setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc, sigset_t *set)
save_gp_reg(31);
#undef save_gp_reg
- save_fp_context(sc); /* cpu dependant */
__put_user(regs->hi, &sc->sc_mdhi);
__put_user(regs->lo, &sc->sc_mdlo);
__put_user(regs->cp0_cause, &sc->sc_cause);
- __put_user((regs->cp0_status & ST0_CU1) != 0, &sc->sc_ownedfp);
- __copy_to_user(sc->sc_sigset, set, sizeof(*set));
+ owned_fp = (current == last_task_used_math);
+ __put_user(owned_fp, &sc->sc_ownedfp);
+
+#if 0
+ if (current->used_math) { /* fp is active. */
+ set_cp0_status(ST0_CU1, ST0_CU1);
+ save_fp_context(sc); /* cpu dependant */
+ last_task_used_math = NULL;
+ regs->cp0_status &= ~ST0_CU1;
+ current->used_math = 0;
+ }
+#endif
+set_cp0_status(ST0_CU1, ST0_CU1);
+save_fp_context(sc); /* cpu dependant */
+
+ __put_user(set->sig[0], &sc->sc_sigset[0]);
+ __put_user(set->sig[1], &sc->sc_sigset[1]);
+ __put_user(set->sig[2], &sc->sc_sigset[2]);
+ __put_user(set->sig[3], &sc->sc_sigset[3]);
}
static void inline
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 629a07836..b554cad39 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -8,11 +8,12 @@
* Copyright 1994, 1995, 1996, 1997 by Ralf Baechle
* Modified for R3000 by Paul M. Antoine, 1995, 1996
*
- * $Id: traps.c,v 1.12 1998/03/26 07:39:11 ralf Exp $
+ * $Id: traps.c,v 1.9 1998/03/27 04:47:56 ralf Exp $
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/mm.h>
+#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -229,6 +230,9 @@ int unregister_fpe(void (*handler)(struct pt_regs *regs, unsigned int fcr31))
}
#endif
+/*
+ * XXX Delayed fp exceptions when doing a lazy ctx switch XXX
+ */
void do_fpe(struct pt_regs *regs, unsigned long fcr31)
{
#ifdef CONFIG_MIPS_FPE_MODULE
@@ -257,6 +261,7 @@ void do_fpe(struct pt_regs *regs, unsigned long fcr31)
printk("Unimplemented exception at 0x%08lx in %s.\n",
regs->cp0_epc, current->comm);
}
+
if (compute_return_epc(regs))
goto out;
force_sig(SIGFPE, current);
@@ -354,11 +359,24 @@ void do_cpu(struct pt_regs *regs)
unsigned int cpid;
cpid = (regs->cp0_cause >> CAUSEB_CE) & 3;
- if (cpid == 1) {
- regs->cp0_status |= ST0_CU1;
+ if (cpid != 1)
+ goto bad_cid;
+
+ regs->cp0_status |= ST0_CU1;
+ if (last_task_used_math == current)
goto out;
+
+ if (current->used_math) { /* Using the FPU again. */
+ r4xx0_lazy_fpu_switch(last_task_used_math);
+ } else { /* First time FPU user. */
+
+ r4xx0_init_fpu();
+ current->used_math = 1;
}
+ last_task_used_math = current;
+ return;
+bad_cid:
lock_kernel();
force_sig(SIGILL, current);
unlock_kernel();
@@ -369,8 +387,9 @@ void do_vcei(struct pt_regs *regs)
{
lock_kernel();
/*
- * Only possible on R4[04]00[SM]C. No handler because I don't have
- * such a cpu. Theory says this exception doesn't happen.
+ * Theory says this exception doesn't happen.
+ *
+ * Murphy is right. It does happen ...
*/
panic("Caught VCEI exception - should not happen");
unlock_kernel();
@@ -380,10 +399,11 @@ void do_vced(struct pt_regs *regs)
{
lock_kernel();
/*
- * Only possible on R4[04]00[SM]C. No handler because I don't have
- * such a cpu. Theory says this exception doesn't happen.
+ * Theory says this exception doesn't happen.
+ *
+ * Murphy is right. It does happen ...
*/
- panic("Caught VCE exception - should not happen");
+ panic("Caught VCED exception - should not happen");
unlock_kernel();
}
@@ -527,8 +547,14 @@ __initfunc(void trap_init(void))
case CPU_R4400MC:
case CPU_R4000SC:
case CPU_R4400SC:
- /* XXX The following won't work because we _cannot_
- * XXX perform any load/store before the VCE handler.
+ /*
+ * The following won't work because we _cannot_ perform any
+ * load/store before the VCE handler. We deal with this
+ * by checking for for vced / vcei exceptions before doing
+ * the generic exception handling thing. This costs us
+ * several instructions, therefore there should be a special
+ * handler for those CPUs which have these exceptions.
+ *
*/
set_except_vector(14, handle_vcei);
set_except_vector(31, handle_vced);