diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-04-05 11:23:36 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-04-05 11:23:36 +0000 |
commit | 4318fbda2a7ee51caafdc4eb1f8028a3f0605142 (patch) | |
tree | cddb50a81d7d1a628cc400519162080c6d87868e /arch/mips/kernel | |
parent | 36ea5120664550fae6d31f1c6f695e4f8975cb06 (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.S | 5 | ||||
-rw-r--r-- | arch/mips/kernel/fpe.c | 4 | ||||
-rw-r--r-- | arch/mips/kernel/irixinv.c | 6 | ||||
-rw-r--r-- | arch/mips/kernel/process.c | 23 | ||||
-rw-r--r-- | arch/mips/kernel/ptrace.c | 8 | ||||
-rw-r--r-- | arch/mips/kernel/r2300_switch.S | 6 | ||||
-rw-r--r-- | arch/mips/kernel/r4k_fpu.S | 165 | ||||
-rw-r--r-- | arch/mips/kernel/r4k_switch.S | 159 | ||||
-rw-r--r-- | arch/mips/kernel/signal.c | 59 | ||||
-rw-r--r-- | arch/mips/kernel/traps.c | 46 |
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(¤t->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); |