Index: arch/mips/kernel/cpu-probe.c =================================================================== RCS file: /home/cvs/linux/arch/mips/kernel/cpu-probe.c,v retrieving revision 1.5 diff -u -r1.5 cpu-probe.c --- arch/mips/kernel/cpu-probe.c 2 Sep 2002 14:41:15 -0000 1.5 +++ arch/mips/kernel/cpu-probe.c 4 Nov 2002 19:41:43 -0000 @@ -3,6 +3,7 @@ #include #include #include +#include #include /* Index: arch/mips/kernel/offset.c =================================================================== RCS file: /home/cvs/linux/arch/mips/kernel/offset.c,v retrieving revision 1.1 diff -u -r1.1 offset.c --- arch/mips/kernel/offset.c 1 Nov 2002 22:08:29 -0000 1.1 +++ arch/mips/kernel/offset.c 4 Nov 2002 19:41:43 -0000 @@ -155,7 +155,6 @@ offset("#define SC_MDLO ", struct sigcontext, sc_mdlo); offset("#define SC_PC ", struct sigcontext, sc_pc); offset("#define SC_STATUS ", struct sigcontext, sc_status); - offset("#define SC_OWNEDFP ", struct sigcontext, sc_ownedfp); offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr); offset("#define SC_FPC_EIR ", struct sigcontext, sc_fpc_eir); offset("#define SC_CAUSE ", struct sigcontext, sc_cause); Index: arch/mips/kernel/process.c =================================================================== RCS file: /home/cvs/linux/arch/mips/kernel/process.c,v retrieving revision 1.45 diff -u -r1.45 process.c --- arch/mips/kernel/process.c 31 Oct 2002 12:27:31 -0000 1.45 +++ arch/mips/kernel/process.c 4 Nov 2002 19:41:43 -0000 @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -56,28 +57,25 @@ } } -struct task_struct *last_task_used_math = NULL; - asmlinkage void ret_from_fork(void); +void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) +{ + regs->cp0_status &= ~(ST0_CU0|ST0_KSU|ST0_CU1); + regs->cp0_status |= KU_USER; + current->used_math = 0; + loose_fpu(); + regs->cp0_epc = pc; + regs->regs[29] = sp; + current->thread.current_ds = USER_DS; +} + void exit_thread(void) { - /* Forget lazy fpu state */ - if (last_task_used_math == current && mips_cpu.options & MIPS_CPU_FPU) { - __enable_fpu(); - __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 && mips_cpu.options & MIPS_CPU_FPU) { - __enable_fpu(); - __asm__ __volatile__("cfc1\t$0,$31"); - last_task_used_math = NULL; - } } int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, @@ -90,11 +88,9 @@ childksp = (unsigned long)ti + KERNEL_STACK_SIZE - 32; - if (last_task_used_math == current) - if (mips_cpu.options & MIPS_CPU_FPU) { - __enable_fpu(); - save_fp(p); - } + if (is_fpu_owner()) { + save_fp(p); + } /* set up new TSS. */ childregs = (struct pt_regs *) childksp - 1; Index: arch/mips/kernel/ptrace.c =================================================================== RCS file: /home/cvs/linux/arch/mips/kernel/ptrace.c,v retrieving revision 1.43 diff -u -r1.43 ptrace.c --- arch/mips/kernel/ptrace.c 29 Oct 2002 20:55:57 -0000 1.43 +++ arch/mips/kernel/ptrace.c 4 Nov 2002 19:41:43 -0000 @@ -28,6 +28,7 @@ #include #include #include +#include /* * Called by kernel/ptrace.c when detaching.. @@ -43,7 +44,6 @@ { struct task_struct *child; int ret; - extern void save_fp(struct task_struct *); lock_kernel(); #if 0 @@ -114,20 +114,7 @@ break; case FPR_BASE ... FPR_BASE + 31: if (child->used_math) { - unsigned long long *fregs - = (unsigned long long *) - &child->thread.fpu.hard.fp_regs[0]; - if(!(mips_cpu.options & MIPS_CPU_FPU)) { - fregs = (unsigned long long *) - child->thread.fpu.soft.regs; - } else - if (last_task_used_math == child) { - __enable_fpu(); - save_fp(child); - __disable_fpu(); - last_task_used_math = NULL; - regs->cp0_status &= ~ST0_CU1; - } + unsigned long long *fregs = get_fpu_regs(child); /* * The odd registers are actually the high * order bits of the values stored in the even @@ -205,21 +192,8 @@ break; case FPR_BASE ... FPR_BASE + 31: { unsigned long long *fregs; - fregs = (unsigned long long *)&child->thread.fpu.hard.fp_regs[0]; - if (child->used_math) { - if (last_task_used_math == child) { - if(!(mips_cpu.options & MIPS_CPU_FPU)) { - fregs = (unsigned long long *) - child->thread.fpu.soft.regs; - } else { - __enable_fpu(); - save_fp(child); - __disable_fpu(); - last_task_used_math = NULL; - regs->cp0_status &= ~ST0_CU1; - } - } - } else { + fregs = (unsigned long long *)get_fpu_regs(child); + if (!child->used_math) { /* FP not yet used */ memset(&child->thread.fpu.hard, ~0, sizeof(child->thread.fpu.hard)); Index: arch/mips/kernel/r2300_switch.S =================================================================== RCS file: /home/cvs/linux/arch/mips/kernel/r2300_switch.S,v retrieving revision 1.23 diff -u -r1.23 r2300_switch.S --- arch/mips/kernel/r2300_switch.S 29 Oct 2002 00:56:59 -0000 1.23 +++ arch/mips/kernel/r2300_switch.S 4 Nov 2002 19:41:44 -0000 @@ -26,6 +26,19 @@ .set mips1 .align 5 +#define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */ +#define ST_OFF (KERNEL_STACK_SIZE - 32 - PT_SIZE + PT_STATUS) + +/* + * [jsun] FPU context is saved if and only if the process has used FPU in + * the current run (PF_USEDFPU). In any case, the CU1 bit for user space + * STATUS register should be 0, so that a process *always* starts its + * userland with FPU disabled after each context switch. + * + * FPU will be enabled as soon as the process accesses FPU again, through + * do_cpu() trap. + */ + /* * task_struct *resume(task_struct *prev, task_struct *next, * struct thread_info *next_ti) ) @@ -39,6 +52,32 @@ CPU_SAVE_NONSCRATCH(a0) sw ra, THREAD_REG31(a0) + /* + * check if we need to save FPU registers + */ + lw t0, TASK_FLAGS(a0) + li t1, PF_USEDFPU + and t2, t0, t1 + beqz t2, 1f + nor t1, zero, t1 + + /* + * clear PF_USEDFPU bit in task flags + */ + and t0, t0, t1 + sw t0, TASK_FLAGS(a0) + + /* + * clear user-saved stack CU1 bit + */ + lw t0, ST_OFF(a0) + li t1, ~ST0_CU1 + and t0, t0, t1 + sw t0, ST_OFF(a0) + + FPU_SAVE_SINGLE(a0, t0) # clobbers t0 + +1: /* * The order of restoring the registers takes care of the race * updating $28, $29 and kernelsp without disabling ints. @@ -62,45 +101,20 @@ END(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(lazy_fpu_switch) - mfc0 t0, CP0_STATUS # enable cp1 - li t3, ST0_CU1 - or t0, t3 - mtc0 t0, CP0_STATUS - - nor t3, zero, t3 - beqz a0, 2f # Save floating point state - lw t1, ST_OFF(a0) # last thread looses fpu - and t1, t3 - sw t1, ST_OFF(a0) - FPU_SAVE_SINGLE(a0, t1) # clobbers t1 - -2: - FPU_RESTORE_SINGLE(a1, t0) # clobbers t0 - jr ra - END(lazy_fpu_switch) - -/* * Save a thread's fp context. */ -LEAF(save_fp) +LEAF(_save_fp) FPU_SAVE_SINGLE(a0, t1) # clobbers t1 jr ra - END(save_fp) + END(_save_fp) /* * Restore a thread's fp context. */ -LEAF(restore_fp) +LEAF(_restore_fp) FPU_RESTORE_SINGLE(a0, t1) # clobbers t1 jr ra - END(restore_fp) + END(_estore_fp) /* * Load the FPU with signalling NANS. This bit pattern we're using has @@ -112,7 +126,7 @@ #define FPU_DEFAULT 0x00000000 -LEAF(init_fpu) +LEAF(_init_fpu) mfc0 t0, CP0_STATUS li t1, ST0_CU1 or t0, t1 @@ -156,4 +170,4 @@ mtc1 t0, $f30 mtc1 t0, $f31 jr ra - END(init_fpu) + END(_init_fpu) Index: arch/mips/kernel/r4k_switch.S =================================================================== RCS file: /home/cvs/linux/arch/mips/kernel/r4k_switch.S,v retrieving revision 1.26 diff -u -r1.26 r4k_switch.S --- arch/mips/kernel/r4k_switch.S 29 Oct 2002 00:56:59 -0000 1.26 +++ arch/mips/kernel/r4k_switch.S 4 Nov 2002 19:41:44 -0000 @@ -24,6 +24,19 @@ #include +#define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */ +#define ST_OFF (KERNEL_STACK_SIZE - 32 - PT_SIZE + PT_STATUS) + +/* + * [jsun] FPU context is saved if and only if the process has used FPU in + * the current run (PF_USEDFPU). In any case, the CU1 bit for user space + * STATUS register should be 0, so that a process *always* starts its + * userland with FPU disabled after each context switch. + * + * FPU will be enabled as soon as the process accesses FPU again, through + * do_cpu() trap. + */ + /* * task_struct *r4xx0_resume(task_struct *prev, task_struct *next, * struct thread_info *next_ti) @@ -38,6 +51,32 @@ CPU_SAVE_NONSCRATCH(a0) sw ra, THREAD_REG31(a0) + /* + * check if we need to save FPU registers + */ + lw t0, TASK_FLAGS(a0) + li t1, PF_USEDFPU + and t2, t0, t1 + beqz t2, 1f + nor t1, zero, t1 + + /* + * clear PF_USEDFPU bit in task flags + */ + and t0, t0, t1 + sw t0, TASK_FLAGS(a0) + + /* + * clear saved user stack CU1 bit + */ + lw t0, ST_OFF(a0) + li t1, ~ST0_CU1 + and t0, t0, t1 + sw t0, ST_OFF(a0) + + FPU_SAVE_DOUBLE(a0, t0) # clobbers t0 + +1: /* * The order of restoring the registers takes care of the race * updating $28, $29 and kernelsp without disabling ints. @@ -70,39 +109,12 @@ END(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(lazy_fpu_switch) - mfc0 t0, CP0_STATUS # enable cp1 - li t3, ST0_CU1 - or t0, t3 - mtc0 t0, CP0_STATUS - FPU_ENABLE_HAZARD - - nor t3, zero, t3 - beqz a0, 2f # Save floating point state - - lw t1, ST_OFF(a0) # last thread looses fpu - and t1, t3 - sw t1, ST_OFF(a0) - - - FPU_SAVE_DOUBLE(a0, t1) # clobbers t1 -2: FPU_RESTORE_DOUBLE(a1, t0) # clobbers t0 - jr ra - END(lazy_fpu_switch) - -/* * Save a thread's fp context. */ -LEAF(save_fp) +LEAF(_save_fp) FPU_SAVE_DOUBLE(a0, t1) # clobbers t1 jr ra - END(save_fp) + END(_save_fp) /* * Restore a thread's fp context. @@ -110,7 +122,7 @@ LEAF(restore_fp) FPU_RESTORE_DOUBLE(a0, t1) # clobbers t1 jr ra - END(restore_fp) + END(_restore_fp) /* * Load the FPU with signalling NANS. This bit pattern we're using has @@ -122,7 +134,7 @@ #define FPU_DEFAULT 0x00000000 -LEAF(init_fpu) +LEAF(_init_fpu) .set mips3 mfc0 t0, CP0_STATUS li t1, ST0_CU1 @@ -152,4 +164,4 @@ dmtc1 t0, $f28 dmtc1 t0, $f30 jr ra - END(init_fpu) + END(_init_fpu) Index: arch/mips/kernel/signal.c =================================================================== RCS file: /home/cvs/linux/arch/mips/kernel/signal.c,v retrieving revision 1.55 diff -u -r1.55 signal.c --- arch/mips/kernel/signal.c 1 Nov 2002 19:20:32 -0000 1.55 +++ arch/mips/kernel/signal.c 4 Nov 2002 19:41:44 -0000 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -34,9 +35,6 @@ extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); -extern asmlinkage int (*save_fp_context)(struct sigcontext *sc); -extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc); - extern asmlinkage void do_syscall_trace(void); /* @@ -150,59 +148,8 @@ return do_sigaltstack(uss, uoss, usp); } -static inline int restore_thread_fp_context(struct sigcontext *sc) -{ - u64 *pfreg = ¤t->thread.fpu.soft.regs[0]; - int err = 0; - - /* - * Copy all 32 64-bit values, for two reasons. First, the R3000 and - * R4000/MIPS32 kernels use the thread FP register storage differently, - * such that a full copy is essentially necessary to support both. - */ - -#define restore_fpr(i) \ - do { err |= __get_user(pfreg[i], &sc->sc_fpregs[i]); } while(0) - - restore_fpr( 0); restore_fpr( 1); restore_fpr( 2); restore_fpr( 3); - restore_fpr( 4); restore_fpr( 5); restore_fpr( 6); restore_fpr( 7); - restore_fpr( 8); restore_fpr( 9); restore_fpr(10); restore_fpr(11); - restore_fpr(12); restore_fpr(13); restore_fpr(14); restore_fpr(15); - restore_fpr(16); restore_fpr(17); restore_fpr(18); restore_fpr(19); - restore_fpr(20); restore_fpr(21); restore_fpr(22); restore_fpr(23); - restore_fpr(24); restore_fpr(25); restore_fpr(26); restore_fpr(27); - restore_fpr(28); restore_fpr(29); restore_fpr(30); restore_fpr(31); - - err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr); - - return err; -} - -static inline int save_thread_fp_context(struct sigcontext *sc) -{ - u64 *pfreg = ¤t->thread.fpu.soft.regs[0]; - int err = 0; - -#define save_fpr(i) \ - do { err |= __put_user(pfreg[i], &sc->sc_fpregs[i]); } while(0) - - save_fpr( 0); save_fpr( 1); save_fpr( 2); save_fpr( 3); - save_fpr( 4); save_fpr( 5); save_fpr( 6); save_fpr( 7); - save_fpr( 8); save_fpr( 9); save_fpr(10); save_fpr(11); - save_fpr(12); save_fpr(13); save_fpr(14); save_fpr(15); - save_fpr(16); save_fpr(17); save_fpr(18); save_fpr(19); - save_fpr(20); save_fpr(21); save_fpr(22); save_fpr(23); - save_fpr(24); save_fpr(25); save_fpr(26); save_fpr(27); - save_fpr(28); save_fpr(29); save_fpr(30); save_fpr(31); - - err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr); - - return err; -} - static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { - int owned_fp; int err = 0; u64 reg; @@ -230,25 +177,17 @@ restore_gp_reg(31); #undef restore_gp_reg - err |= __get_user(owned_fp, &sc->sc_ownedfp); err |= __get_user(current->used_math, &sc->sc_used_math); - if (owned_fp) { - err |= restore_fp_context(sc); - goto out; - } - - if (current == last_task_used_math) { - /* Signal handler acquired FPU - give it back */ - last_task_used_math = NULL; - regs->cp0_status &= ~ST0_CU1; - } if (current->used_math) { - /* Undo possible contamination of thread state */ - err |= restore_thread_fp_context(sc); + /* restore fpu context if we have used it before */ + own_fpu(); + err |= restore_fp_context(sc); + } else { + /* signal handler may have used FPU. Give it up. */ + loose_fpu(); } -out: return err; } @@ -345,7 +284,6 @@ static int inline setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { - int owned_fp; int err = 0; u64 reg; @@ -373,25 +311,20 @@ err |= __put_user(regs->cp0_cause, &sc->sc_cause); err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); - owned_fp = (current == last_task_used_math); - err |= __put_user(owned_fp, &sc->sc_ownedfp); err |= __put_user(current->used_math, &sc->sc_used_math); if (!current->used_math) goto out; - /* There exists FP thread state that may be trashed by signal */ - if (owned_fp) { - /* fp is active. Save context from FPU */ - err |= save_fp_context(sc); - goto out; - } - - /* - * Someone else has FPU. - * Copy Thread context into signal context + /* + * Save FPU state to signal context. Signal handler will "inherit" + * current FPU state. */ - err |= save_thread_fp_context(sc); + if (!is_fpu_owner()) { + own_fpu(); + restore_fp(current); + } + err |= save_fp_context(sc); out: return err; Index: arch/mips/kernel/traps.c =================================================================== RCS file: /home/cvs/linux/arch/mips/kernel/traps.c,v retrieving revision 1.132 diff -u -r1.132 traps.c --- arch/mips/kernel/traps.c 1 Nov 2002 03:26:31 -0000 1.132 +++ arch/mips/kernel/traps.c 4 Nov 2002 19:41:44 -0000 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -672,49 +673,32 @@ asmlinkage void do_cpu(struct pt_regs *regs) { unsigned int cpid; - void fpu_emulator_init_fpu(void); - int sig; cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; if (cpid != 1) goto bad_cid; - if (!(mips_cpu.options & MIPS_CPU_FPU)) - goto fp_emul; - - regs->cp0_status |= ST0_CU1; - if (last_task_used_math == current) - return; + die_if_kernel("do_cpu invoked from kernel context!", regs); + own_fpu(); if (current->used_math) { /* Using the FPU again. */ - lazy_fpu_switch(last_task_used_math, current); + restore_fp(current); } else { /* First time FPU user. */ - if (last_task_used_math != NULL) - save_fp(last_task_used_math); init_fpu(); current->used_math = 1; } - last_task_used_math = current; - - return; - -fp_emul: - if (last_task_used_math != current) { - if (!current->used_math) { - fpu_emulator_init_fpu(); - current->used_math = 1; + if (!(mips_cpu.options & MIPS_CPU_FPU)) { + int sig = fpu_emulator_cop1Handler(0, regs, ¤t->thread.fpu.soft); + if (sig) { + /* + * Return EPC is not calculated in the FPU emulator, if + * a signal is being send. So we calculate it here. + */ + compute_return_epc(regs); + force_sig(sig, current); } } - sig = fpu_emulator_cop1Handler(0, regs, ¤t->thread.fpu.soft); - last_task_used_math = current; - if (sig) { - /* - * Return EPC is not calculated in the FPU emulator, if - * a signal is being send. So we calculate it here. - */ - compute_return_epc(regs); - force_sig(sig, current); - } + return; bad_cid: @@ -896,6 +880,7 @@ asmlinkage int (*save_fp_context)(struct sigcontext *sc); asmlinkage int (*restore_fp_context)(struct sigcontext *sc); + extern asmlinkage int _save_fp_context(struct sigcontext *sc); extern asmlinkage int _restore_fp_context(struct sigcontext *sc); Index: arch/mips64/kernel/cpu-probe.c =================================================================== RCS file: /home/cvs/linux/arch/mips64/kernel/cpu-probe.c,v retrieving revision 1.6 diff -u -r1.6 cpu-probe.c --- arch/mips64/kernel/cpu-probe.c 2 Sep 2002 14:41:15 -0000 1.6 +++ arch/mips64/kernel/cpu-probe.c 4 Nov 2002 19:41:44 -0000 @@ -3,6 +3,7 @@ #include #include #include +#include #include /* Index: arch/mips64/kernel/offset.c =================================================================== RCS file: /home/cvs/linux/arch/mips64/kernel/offset.c,v retrieving revision 1.1 diff -u -r1.1 offset.c --- arch/mips64/kernel/offset.c 1 Nov 2002 22:08:29 -0000 1.1 +++ arch/mips64/kernel/offset.c 4 Nov 2002 19:41:44 -0000 @@ -155,7 +155,6 @@ offset("#define SC_MDLO ", struct sigcontext, sc_mdlo); offset("#define SC_PC ", struct sigcontext, sc_pc); offset("#define SC_STATUS ", struct sigcontext, sc_status); - offset("#define SC_OWNEDFP ", struct sigcontext, sc_ownedfp); offset("#define SC_FPC_CSR ", struct sigcontext, sc_fpc_csr); offset("#define SC_FPC_EIR ", struct sigcontext, sc_fpc_eir); offset("#define SC_CAUSE ", struct sigcontext, sc_cause); Index: arch/mips64/kernel/process.c =================================================================== RCS file: /home/cvs/linux/arch/mips64/kernel/process.c,v retrieving revision 1.30 diff -u -r1.30 process.c --- arch/mips64/kernel/process.c 29 Sep 2002 01:43:16 -0000 1.30 +++ arch/mips64/kernel/process.c 4 Nov 2002 19:41:44 -0000 @@ -30,6 +30,7 @@ #include #include #include +#include /* * We use this if we don't have any better idle routine.. @@ -55,28 +56,30 @@ } } -struct task_struct *last_task_used_math = NULL; - asmlinkage void ret_from_fork(void); +void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) +{ + unsigned long status; + + /* New thread looses kernel privileges. */ + status = regs->cp0_status & ~(ST0_CU0|ST0_FR|ST0_KSU); + status |= KSU_USER; + status |= (current->thread.mflags & MF_32BIT) ? 0 : ST0_FR; + regs->cp0_status = status; + current->used_math = 0; + loose_fpu(); + regs->cp0_epc = pc; + regs->regs[29] = sp; + current_thread_info()->addr_limit = USER_DS; +} + void exit_thread(void) { - /* Forget lazy fpu state */ - if (last_task_used_math == current && mips_cpu.options & MIPS_CPU_FPU) { - __enable_fpu(); - __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 && mips_cpu.options & MIPS_CPU_FPU) { - __enable_fpu(); - __asm__ __volatile__("cfc1\t$0,$31"); - last_task_used_math = NULL; - } } int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, @@ -89,10 +92,8 @@ childksp = (unsigned long)ti + KERNEL_STACK_SIZE - 32; - if (last_task_used_math == current) - if (mips_cpu.options & MIPS_CPU_FPU) { - __enable_fpu(); - save_fp(p); + if (is_fpu_owner()) { + save_fp(p); } /* set up new TSS. */ Index: arch/mips64/kernel/ptrace.c =================================================================== RCS file: /home/cvs/linux/arch/mips64/kernel/ptrace.c,v retrieving revision 1.22 diff -u -r1.22 ptrace.c --- arch/mips64/kernel/ptrace.c 29 Oct 2002 20:55:57 -0000 1.22 +++ arch/mips64/kernel/ptrace.c 4 Nov 2002 19:41:45 -0000 @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -112,23 +113,7 @@ break; case FPR_BASE ... FPR_BASE + 31: if (child->used_math) { - unsigned long *fregs - = (unsigned long *) - &child->thread.fpu.hard.fp_regs[0]; - if (mips_cpu.options & MIPS_CPU_FPU) { -#ifndef CONFIG_SMP - if (last_task_used_math == child) { - __enable_fpu(); - save_fp(child); - __disable_fpu(); - last_task_used_math = NULL; - } -#endif - } else { - fregs = (unsigned long *) - child->thread.fpu.soft.regs; - } - + unsigned long *fregs = get_fpu_regs(child); tmp = (unsigned long) fregs[addr - FPR_BASE]; } else { tmp = -EIO; @@ -191,24 +176,8 @@ regs->regs[addr] = data; break; case FPR_BASE ... FPR_BASE + 31: { - unsigned long *fregs; - fregs = (unsigned long *)&child->thread.fpu.hard.fp_regs[0]; - if (child->used_math) { -#ifndef CONFIG_SMP - if (last_task_used_math == child) { - if (mips_cpu.options & MIPS_CPU_FPU) { - __enable_fpu(); - save_fp(child); - __disable_fpu(); - last_task_used_math = NULL; - regs->cp0_status &= ~ST0_CU1; - } else { - fregs = (unsigned long *) - child->thread.fpu.soft.regs; - } - } -#endif - } else { + unsigned long *fregs = get_fpu_regs(child); + if (!child->used_math) { /* FP not yet used */ memset(&child->thread.fpu.hard, ~0, sizeof(child->thread.fpu.hard)); Index: arch/mips64/kernel/r4k_switch.S =================================================================== RCS file: /home/cvs/linux/arch/mips64/kernel/r4k_switch.S,v retrieving revision 1.19 diff -u -r1.19 r4k_switch.S --- arch/mips64/kernel/r4k_switch.S 29 Oct 2002 00:56:59 -0000 1.19 +++ arch/mips64/kernel/r4k_switch.S 4 Nov 2002 19:41:45 -0000 @@ -23,6 +23,19 @@ .set mips3 +#define PF_USEDFPU 0x00100000 /* task used FPU this quantum (SMP) */ +#define ST_OFF (KERNEL_STACK_SIZE - 32 - PT_SIZE + PT_STATUS) + +/* + * [jsun] FPU context is saved if and only if the process has used FPU in + * the current run (PF_USEDFPU). In any case, the CU1 bit for user space + * STATUS register should be 0, so that a process *always* starts its + * userland with FPU disabled after each context switch. + * + * FPU will be enabled as soon as the process accesses FPU again, through + * do_cpu() trap. + */ + /* * task_struct *resume(task_struct *prev, task_struct *next, * struct thread_info *next_ti)) @@ -35,6 +48,38 @@ sd ra, THREAD_REG31(a0) /* + * check if we need to save FPU registers + */ + ld t0, TASK_FLAGS(a0) + li t1, PF_USEDFPU + and t2, t0, t1 + beqz t2, 1f + nor t1, zero, t1 + + /* + * clear PF_USEDFPU bit in task flags + */ + and t0, t0, t1 + sd t0, TASK_FLAGS(a0) + + /* + * clear saved user stack CU1 bit + */ + ld t0, ST_OFF(a0) + li t1, ~ST0_CU1 + and t0, t0, t1 + sd t0, ST_OFF(a0) + + + sll t2, t0, 5 + bgez t2, 2f + sdc1 $f0, (THREAD_FPU + 0x00)(a0) + fpu_save_16odd a0 +2: + fpu_save_16even a0 t1 # clobbers t1 +1: + + /* * The order of restoring the registers takes care of the race * updating $28, $29 and kernelsp without disabling ints. */ @@ -57,49 +102,9 @@ END(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(lazy_fpu_switch) - mfc0 t0, CP0_STATUS # enable cp1 - li t3, ST0_CU1 - or t0, t3 - mtc0 t0, CP0_STATUS - FPU_ENABLE_HAZARD - - nor t3, zero, t3 - beqz a0, 2f # Save floating point state - - ld t1, ST_OFF(a0) # last thread looses fpu - and t1, t3 - sd t1, ST_OFF(a0) - sll t2, t1, 5 - sdc1 $f0, (THREAD_FPU + 0x00)(a0) - bgez t2, 1f - fpu_save_16odd a0 -1: - fpu_save_16even a0 t1 # clobbers t1 -2: - - beqz a1, 3f - - sll t0, t0, 5 # load new fp state - ldc1 $f0, (THREAD_FPU + 0x00)(a1) - bgez t0, 1f - fpu_restore_16odd a1 -1: - fpu_restore_16even a1, t0 # clobbers t0 -3: - jr ra - END(lazy_fpu_switch) - -/* * Save a thread's fp context. */ -LEAF(save_fp) +LEAF(_save_fp) mfc0 t0, CP0_STATUS sll t1, t0, 5 bgez t1, 1f # 16 register mode? @@ -108,12 +113,12 @@ fpu_save_16even a0 t1 # clobbers t1 sdc1 $f0, (THREAD_FPU + 0x00)(a0) jr ra - END(save_fp) + END(_save_fp) /* * Restore a thread's fp context. */ -LEAF(restore_fp) +LEAF(_restore_fp) mfc0 t0, CP0_STATUS sll t1, t0, 5 bgez t1, 1f # 16 register mode? @@ -123,7 +128,7 @@ ldc1 $f0, (THREAD_FPU + 0x00)(a0) jr ra - END(restore_fp) + END(_restore_fp) /* * Load the FPU with signalling NANS. This bit pattern we're using has @@ -135,7 +140,7 @@ #define FPU_DEFAULT 0x00000000 -LEAF(init_fpu) +LEAF(_init_fpu) mfc0 t0, CP0_STATUS li t1, ST0_CU1 or t0, t1 @@ -183,4 +188,4 @@ dmtc1 t0, $f28 dmtc1 t0, $f30 jr ra - END(init_fpu) + END(_init_fpu) Index: arch/mips64/kernel/signal.c =================================================================== RCS file: /home/cvs/linux/arch/mips64/kernel/signal.c,v retrieving revision 1.32 diff -u -r1.32 signal.c --- arch/mips64/kernel/signal.c 1 Nov 2002 19:20:32 -0000 1.32 +++ arch/mips64/kernel/signal.c 4 Nov 2002 19:41:45 -0000 @@ -27,14 +27,13 @@ #include #include #include +#include #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) extern asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); -extern asmlinkage int (*save_fp_context)(struct sigcontext *sc); -extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc); extern asmlinkage void do_syscall_trace(void); @@ -83,57 +82,8 @@ return do_sigaltstack(uss, uoss, usp); } -static inline int restore_thread_fp_context(struct sigcontext *sc) -{ - u64 *pfreg = ¤t->thread.fpu.soft.regs[0]; - int err = 0; - - /* - * Copy all 32 64-bit values. - */ - -#define restore_fpr(i) \ - do { err |= __get_user(pfreg[i], &sc->sc_fpregs[i]); } while(0) - - restore_fpr( 0); restore_fpr( 1); restore_fpr( 2); restore_fpr( 3); - restore_fpr( 4); restore_fpr( 5); restore_fpr( 6); restore_fpr( 7); - restore_fpr( 8); restore_fpr( 9); restore_fpr(10); restore_fpr(11); - restore_fpr(12); restore_fpr(13); restore_fpr(14); restore_fpr(15); - restore_fpr(16); restore_fpr(17); restore_fpr(18); restore_fpr(19); - restore_fpr(20); restore_fpr(21); restore_fpr(22); restore_fpr(23); - restore_fpr(24); restore_fpr(25); restore_fpr(26); restore_fpr(27); - restore_fpr(28); restore_fpr(29); restore_fpr(30); restore_fpr(31); - - err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr); - - return err; -} - -static inline int save_thread_fp_context(struct sigcontext *sc) -{ - u64 *pfreg = ¤t->thread.fpu.soft.regs[0]; - int err = 0; - -#define save_fpr(i) \ - do { err |= __put_user(pfreg[i], &sc->sc_fpregs[i]); } while(0) - - save_fpr( 0); save_fpr( 1); save_fpr( 2); save_fpr( 3); - save_fpr( 4); save_fpr( 5); save_fpr( 6); save_fpr( 7); - save_fpr( 8); save_fpr( 9); save_fpr(10); save_fpr(11); - save_fpr(12); save_fpr(13); save_fpr(14); save_fpr(15); - save_fpr(16); save_fpr(17); save_fpr(18); save_fpr(19); - save_fpr(20); save_fpr(21); save_fpr(22); save_fpr(23); - save_fpr(24); save_fpr(25); save_fpr(26); save_fpr(27); - save_fpr(28); save_fpr(29); save_fpr(30); save_fpr(31); - - err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr); - - return err; -} - asmlinkage int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { - int owned_fp; int err = 0; err |= __get_user(regs->cp0_epc, &sc->sc_pc); @@ -156,26 +106,17 @@ restore_gp_reg(31); #undef restore_gp_reg - err |= __get_user(owned_fp, &sc->sc_ownedfp); err |= __get_user(current->used_math, &sc->sc_used_math); - if (owned_fp) { - err |= restore_fp_context(sc); - goto out; - } - - if (current == last_task_used_math) { - /* Signal handler acquired FPU - give it back */ - last_task_used_math = NULL; - regs->cp0_status &= ~ST0_CU1; - } - if (current->used_math) { - /* Undo possible contamination of thread state */ - err |= restore_thread_fp_context(sc); + /* restore fpu context if we have used it before */ + own_fpu(); + err |= restore_fp_context(sc); + } else { + /* signal handler may have used FPU. Give it up. */ + loose_fpu(); } -out: return err; } @@ -195,7 +136,6 @@ static int inline setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { - int owned_fp; int err = 0; err |= __put_user(regs->cp0_epc, &sc->sc_pc); @@ -220,25 +160,20 @@ err |= __put_user(regs->cp0_cause, &sc->sc_cause); err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); - owned_fp = (current == last_task_used_math); - err |= __put_user(owned_fp, &sc->sc_ownedfp); err |= __put_user(current->used_math, &sc->sc_used_math); if (!current->used_math) goto out; - /* There exists FP thread state that may be trashed by signal */ - if (owned_fp) { - /* fp is active. Save context from FPU */ - err |= save_fp_context(sc); - goto out; - } - /* - * Someone else has FPU. - * Copy Thread context into signal context + * Save FPU state to signal context. Signal handler will "inherit" + * current FPU state. */ - err |= save_thread_fp_context(sc); + if (!is_fpu_owner()) { + own_fpu(); + restore_fp(current); + } + err |= save_fp_context(sc); out: return err; Index: arch/mips64/kernel/signal32.c =================================================================== RCS file: /home/cvs/linux/arch/mips64/kernel/signal32.c,v retrieving revision 1.38 diff -u -r1.38 signal32.c --- arch/mips64/kernel/signal32.c 1 Nov 2002 19:20:32 -0000 1.38 +++ arch/mips64/kernel/signal32.c 4 Nov 2002 19:41:45 -0000 @@ -25,14 +25,13 @@ #include #include #include +#include #define DEBUG_SIG 0 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) extern asmlinkage int do_signal32(sigset_t *oldset, struct pt_regs *regs); -extern asmlinkage int (*save_fp_context)(struct sigcontext *sc); -extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc); extern asmlinkage void do_syscall_trace(void); @@ -257,58 +256,9 @@ return ret; } -static inline int restore_thread_fp_context(struct sigcontext *sc) -{ - u64 *pfreg = ¤t->thread.fpu.soft.regs[0]; - int err = 0; - - /* - * Copy all 32 64-bit values. - */ - -#define restore_fpr(i) \ - do { err |= __get_user(pfreg[i], &sc->sc_fpregs[i]); } while(0) - - restore_fpr( 0); restore_fpr( 1); restore_fpr( 2); restore_fpr( 3); - restore_fpr( 4); restore_fpr( 5); restore_fpr( 6); restore_fpr( 7); - restore_fpr( 8); restore_fpr( 9); restore_fpr(10); restore_fpr(11); - restore_fpr(12); restore_fpr(13); restore_fpr(14); restore_fpr(15); - restore_fpr(16); restore_fpr(17); restore_fpr(18); restore_fpr(19); - restore_fpr(20); restore_fpr(21); restore_fpr(22); restore_fpr(23); - restore_fpr(24); restore_fpr(25); restore_fpr(26); restore_fpr(27); - restore_fpr(28); restore_fpr(29); restore_fpr(30); restore_fpr(31); - - err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr); - - return err; -} - -static inline int save_thread_fp_context(struct sigcontext *sc) -{ - u64 *pfreg = ¤t->thread.fpu.soft.regs[0]; - int err = 0; - -#define save_fpr(i) \ - do { err |= __put_user(pfreg[i], &sc->sc_fpregs[i]); } while(0) - - save_fpr( 0); save_fpr( 1); save_fpr( 2); save_fpr( 3); - save_fpr( 4); save_fpr( 5); save_fpr( 6); save_fpr( 7); - save_fpr( 8); save_fpr( 9); save_fpr(10); save_fpr(11); - save_fpr(12); save_fpr(13); save_fpr(14); save_fpr(15); - save_fpr(16); save_fpr(17); save_fpr(18); save_fpr(19); - save_fpr(20); save_fpr(21); save_fpr(22); save_fpr(23); - save_fpr(24); save_fpr(25); save_fpr(26); save_fpr(27); - save_fpr(28); save_fpr(29); save_fpr(30); save_fpr(31); - - err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr); - - return err; -} - static asmlinkage int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { - int owned_fp; int err = 0; err |= __get_user(regs->cp0_epc, &sc->sc_pc); @@ -331,26 +281,17 @@ restore_gp_reg(31); #undef restore_gp_reg - err |= __get_user(owned_fp, &sc->sc_ownedfp); err |= __get_user(current->used_math, &sc->sc_used_math); - if (owned_fp) { - err |= restore_fp_context(sc); - goto out; - } - - if (current == last_task_used_math) { - /* Signal handler acquired FPU - give it back */ - last_task_used_math = NULL; - regs->cp0_status &= ~ST0_CU1; - } - if (current->used_math) { - /* Undo possible contamination of thread state */ - err |= restore_thread_fp_context(sc); + /* restore fpu context if we have used it before */ + own_fpu(); + err |= restore_fp_context(sc); + } else { + /* signal handler may have used FPU. Give it up. */ + loose_fpu(); } -out: return err; } @@ -490,7 +431,6 @@ static int inline setup_sigcontext(struct pt_regs *regs, struct sigcontext *sc) { - int owned_fp; int err = 0; err |= __put_user(regs->cp0_epc, &sc->sc_pc); @@ -515,25 +455,20 @@ err |= __put_user(regs->cp0_cause, &sc->sc_cause); err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); - owned_fp = (current == last_task_used_math); - err |= __put_user(owned_fp, &sc->sc_ownedfp); err |= __put_user(current->used_math, &sc->sc_used_math); if (!current->used_math) goto out; - /* There exists FP thread state that may be trashed by signal */ - if (owned_fp) { - /* fp is active. Save context from FPU */ - err |= save_fp_context(sc); - goto out; - } - - /* - * Someone else has FPU. - * Copy Thread context into signal context + /* + * Save FPU state to signal context. Signal handler will "inherit" + * current FPU state. */ - err |= save_thread_fp_context(sc); + if (!is_fpu_owner()) { + own_fpu(); + restore_fp(current); + } + err |= save_fp_context(sc); out: return err; Index: arch/mips64/kernel/traps.c =================================================================== RCS file: /home/cvs/linux/arch/mips64/kernel/traps.c,v retrieving revision 1.66 diff -u -r1.66 traps.c --- arch/mips64/kernel/traps.c 1 Nov 2002 03:26:31 -0000 1.66 +++ arch/mips64/kernel/traps.c 4 Nov 2002 19:41:45 -0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -560,49 +561,33 @@ asmlinkage void do_cpu(struct pt_regs *regs) { unsigned int cpid; - void fpu_emulator_init_fpu(void); - int sig; cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; if (cpid != 1) goto bad_cid; - if (!(mips_cpu.options & MIPS_CPU_FPU)) - goto fp_emul; + die_if_kernel("do_cpu invoked from kernel context!", regs); - regs->cp0_status |= ST0_CU1; - if (last_task_used_math == current) - return; - - if (current->used_math) { /* Using the FPU again. */ - lazy_fpu_switch(last_task_used_math, current); - } else { /* First time FPU user. */ - if (last_task_used_math != NULL) - save_fp(last_task_used_math); + own_fpu(); + if (current->used_math) { /* Using the FPU again. */ + restore_fp(current); + } else { init_fpu(); current->used_math = 1; } - last_task_used_math = current; - return; - -fp_emul: - if (last_task_used_math != current) { - if (!current->used_math) { - fpu_emulator_init_fpu(); - current->used_math = 1; + if (!(mips_cpu.options & MIPS_CPU_FPU)) { + int sig = fpu_emulator_cop1Handler(0, regs, ¤t->thread.fpu.soft); + if (sig) { + /* + * Return EPC is not calculated in the FPU emulator, if + * a signal is being send. So we calculate it here. + */ + compute_return_epc(regs); + force_sig(sig, current); } } - sig = fpu_emulator_cop1Handler(0, regs, ¤t->thread.fpu.soft); - last_task_used_math = current; - if (sig) { - /* - * Return EPC is not calculated in the FPU emulator, if - * a signal is being send. So we calculate it here. - */ - compute_return_epc(regs); - force_sig(sig, current); - } + return; bad_cid: @@ -676,6 +661,7 @@ asmlinkage int (*save_fp_context)(struct sigcontext *sc); asmlinkage int (*restore_fp_context)(struct sigcontext *sc); + extern asmlinkage int _save_fp_context(struct sigcontext *sc); extern asmlinkage int _restore_fp_context(struct sigcontext *sc); Index: include/asm-mips/fpu.h =================================================================== RCS file: include/asm-mips/fpu.h diff -N include/asm-mips/fpu.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/asm-mips/fpu.h 4 Nov 2002 19:41:48 -0000 @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2002 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef _ASM_FPU_H +#define _ASM_FPU_H + +#include +#include + +#include +#include +#include +#include + +struct sigcontext; + +extern asmlinkage int (*save_fp_context)(struct sigcontext *sc); +extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc); + +extern void fpu_emulator_init_fpu(void); +extern void _init_fpu(void); +extern void _save_fp(struct task_struct *); +extern void _restore_fp(struct task_struct *); + +#if defined(CONFIG_CPU_SB1) +#define __enable_fpu_hazard() \ +do { \ + asm(".set push \n\t" \ + ".set mips64 \n\t" \ + ".set noreorder \n\t" \ + "ssnop \n\t" \ + "bnezl $0, .+4 \n\t" \ + "ssnop \n\t" \ + ".set pop"); \ +} while (0) +#else +#define __enable_fpu_hazard() \ +do { \ + asm("nop;nop;nop;nop"); /* max. hazard */ \ +} while (0) +#endif + +#define __enable_fpu() \ +do { \ + set_cp0_status(ST0_CU1); \ + __enable_fpu_hazard(); \ +} while (0) + +#define __disable_fpu() \ +do { \ + clear_cp0_status(ST0_CU1); \ + /* We don't care about the cp0 hazard here */ \ +} while (0) + +#define enable_fpu() \ +do { \ + if (mips_cpu.options & MIPS_CPU_FPU) \ + __enable_fpu(); \ +} while (0) + +#define disable_fpu() \ +do { \ + if (mips_cpu.options & MIPS_CPU_FPU) \ + __disable_fpu(); \ +} while (0) + + +#define clear_fpu_owner() do {current->flags &= ~PF_USEDFPU; } while(0) + +static inline int is_fpu_owner(void) +{ + return (mips_cpu.options & MIPS_CPU_FPU) && + ((current->flags & PF_USEDFPU) != 0); +} + +static inline void own_fpu(void) +{ + if(mips_cpu.options & MIPS_CPU_FPU) { + __enable_fpu(); + KSTK_STATUS(current) |= ST0_CU1; + current->flags |= PF_USEDFPU; + } +} + +static inline void loose_fpu(void) +{ + if (mips_cpu.options & MIPS_CPU_FPU) { + KSTK_STATUS(current) &= ~ST0_CU1; + current->flags &= ~PF_USEDFPU; + __disable_fpu(); + } +} + +static inline void init_fpu(void) +{ + if (mips_cpu.options & MIPS_CPU_FPU) { + _init_fpu(); + } else { + fpu_emulator_init_fpu(); + } +} + +static inline void save_fp(struct task_struct *tsk) +{ + if (mips_cpu.options & MIPS_CPU_FPU) + _save_fp(tsk); +} + +static inline void restore_fp(struct task_struct *tsk) +{ + if (mips_cpu.options & MIPS_CPU_FPU) + _restore_fp(tsk); +} + +static inline unsigned long long *get_fpu_regs(struct task_struct *tsk) +{ + if(mips_cpu.options & MIPS_CPU_FPU) { + if ((tsk == current) && is_fpu_owner()) + _save_fp(current); + return (unsigned long long *)&tsk->thread.fpu.hard.fp_regs[0]; + } else { + return (unsigned long long *)tsk->thread.fpu.soft.regs; + } +} + +#endif /* _ASM_FPU_H */ + Index: include/asm-mips/mipsregs.h =================================================================== RCS file: /home/cvs/linux/include/asm-mips/mipsregs.h,v retrieving revision 1.47 diff -u -r1.47 mipsregs.h --- include/asm-mips/mipsregs.h 29 Oct 2002 20:56:02 -0000 1.47 +++ include/asm-mips/mipsregs.h 4 Nov 2002 19:41:48 -0000 @@ -1002,48 +1002,6 @@ __BUILD_SET_CP0(cause,CP0_CAUSE) __BUILD_SET_CP0(config,CP0_CONFIG) -#if defined(CONFIG_CPU_SB1) -#define __enable_fpu_hazard() \ -do { \ - asm(".set push \n\t" \ - ".set mips64 \n\t" \ - ".set noreorder \n\t" \ - "ssnop \n\t" \ - "bnezl $0, .+4 \n\t" \ - "ssnop \n\t" \ - ".set pop"); \ -} while (0) -#else -#define __enable_fpu_hazard() \ -do { \ - asm("nop;nop;nop;nop"); /* max. hazard */ \ -} while (0) -#endif - -#define __enable_fpu() \ -do { \ - set_cp0_status(ST0_CU1); \ - __enable_fpu_hazard(); \ -} while (0) - -#define __disable_fpu() \ -do { \ - clear_cp0_status(ST0_CU1); \ - /* We don't care about the cp0 hazard here */ \ -} while (0) - -#define enable_fpu() \ -do { \ - if (mips_cpu.options & MIPS_CPU_FPU) \ - __enable_fpu(); \ -} while (0) - -#define disable_fpu() \ -do { \ - if (mips_cpu.options & MIPS_CPU_FPU) \ - __disable_fpu(); \ -} while (0) - #endif /* !__ASSEMBLY__ */ #endif /* _ASM_MIPSREGS_H */ Index: include/asm-mips/processor.h =================================================================== RCS file: /home/cvs/linux/include/asm-mips/processor.h,v retrieving revision 1.57 diff -u -r1.57 processor.h --- include/asm-mips/processor.h 4 Nov 2002 02:22:51 -0000 1.57 +++ include/asm-mips/processor.h 4 Nov 2002 19:41:48 -0000 @@ -71,9 +71,6 @@ #define wp_works_ok 1 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */ -/* Lazy FPU handling on uni-processor */ -extern struct task_struct *last_task_used_math; - /* * User space process size: 2GB. This is hardcoded into a few places, * so don't change it unless you know what you are doing. TASK_SIZE @@ -196,20 +193,16 @@ /* * Do necessary setup to start up a newly executed thread. */ -#define start_thread(regs, new_pc, new_sp) do { \ - /* New thread loses kernel and FPU privileges. */ \ - regs->cp0_status = (regs->cp0_status & ~(ST0_CU0|ST0_KSU|ST0_CU1)) | KU_USER;\ - regs->cp0_epc = new_pc; \ - regs->regs[29] = new_sp; \ - current_thread_info()->addr_limit = USER_DS; \ -} while (0) +extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp); +struct task_struct; unsigned long get_wchan(struct task_struct *p); #define __PT_REG(reg) ((long)&((struct pt_regs *)0)->reg - sizeof(struct pt_regs)) #define __KSTK_TOS(tsk) ((unsigned long)(tsk->thread_info) + KERNEL_STACK_SIZE - 32) #define KSTK_EIP(tsk) (*(unsigned long *)(__KSTK_TOS(tsk) + __PT_REG(cp0_epc))) #define KSTK_ESP(tsk) (*(unsigned long *)(__KSTK_TOS(tsk) + __PT_REG(regs[29]))) +#define KSTK_STATUS(tsk) (*(unsigned long *)(__KSTK_TOS(tsk) + __PT_REG(cp0_status))) #define cpu_relax() barrier() Index: include/asm-mips/sigcontext.h =================================================================== RCS file: /home/cvs/linux/include/asm-mips/sigcontext.h,v retrieving revision 1.8 diff -u -r1.8 sigcontext.h --- include/asm-mips/sigcontext.h 26 Dec 2001 23:36:06 -0000 1.8 +++ include/asm-mips/sigcontext.h 4 Nov 2002 19:41:48 -0000 @@ -18,7 +18,6 @@ unsigned long long sc_pc; unsigned long long sc_regs[32]; unsigned long long sc_fpregs[32]; - unsigned int sc_ownedfp; unsigned int sc_fpc_csr; unsigned int sc_fpc_eir; /* Unused */ unsigned int sc_used_math; Index: include/asm-mips/system.h =================================================================== RCS file: /home/cvs/linux/include/asm-mips/system.h,v retrieving revision 1.51 diff -u -r1.51 system.h --- include/asm-mips/system.h 3 Nov 2002 17:26:57 -0000 1.51 +++ include/asm-mips/system.h 4 Nov 2002 19:41:48 -0000 @@ -281,11 +281,6 @@ struct task_struct; -extern asmlinkage void lazy_fpu_switch(void *prev, void *next); -extern asmlinkage void init_fpu(void); -extern asmlinkage void save_fp(struct task_struct *); -extern asmlinkage void restore_fp(struct task_struct *); - #define switch_to(prev,next,last) \ do { \ (last) =resume(prev, next, next->thread_info); \ Index: include/asm-mips64/fpu.h =================================================================== RCS file: include/asm-mips64/fpu.h diff -N include/asm-mips64/fpu.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/asm-mips64/fpu.h 4 Nov 2002 19:41:48 -0000 @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2002 MontaVista Software Inc. + * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#ifndef _ASM_FPU_H +#define _ASM_FPU_H + +#include +#include + +#include +#include +#include +#include + +struct sigcontext; + +extern asmlinkage int (*save_fp_context)(struct sigcontext *sc); +extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc); + +extern void fpu_emulator_init_fpu(void); +extern void _init_fpu(void); +extern void _save_fp(struct task_struct *); +extern void _restore_fp(struct task_struct *); + +#if defined(CONFIG_CPU_SB1) +#define __enable_fpu_hazard() \ +do { \ + asm(".set push \n\t" \ + ".set mips2 #.set mips64 \n\t" \ + ".set noreorder \n\t" \ + "sll $0,$0,1 #ssnop \n\t" \ + "bnezl $0, .+4 \n\t" \ + "sll $0,$0,1 #ssnop \n\t" \ + ".set pop"); \ +} while (0) +#else +#define __enable_fpu_hazard() \ +do { \ + asm("nop;nop;nop;nop"); /* max. hazard */ \ +} while (0) +#endif + +#define __enable_fpu() \ +do { \ + set_cp0_status(ST0_CU1); \ + __enable_fpu_hazard(); \ +} while (0) + +#define __disable_fpu() \ +do { \ + clear_cp0_status(ST0_CU1); \ + /* We don't care about the cp0 hazard here */ \ +} while (0) + +#define enable_fpu() \ +do { \ + if (mips_cpu.options & MIPS_CPU_FPU) \ + __enable_fpu(); \ +} while (0) + +#define disable_fpu() \ +do { \ + if (mips_cpu.options & MIPS_CPU_FPU) \ + __disable_fpu(); \ +} while (0) + + +#define clear_fpu_owner() do {current->flags &= ~PF_USEDFPU; } while(0) + +static inline int is_fpu_owner(void) +{ + return (mips_cpu.options & MIPS_CPU_FPU) && + ((current->flags & PF_USEDFPU) != 0); +} + +static inline void own_fpu(void) +{ + if(mips_cpu.options & MIPS_CPU_FPU) { + __enable_fpu(); + KSTK_STATUS(current) |= ST0_CU1; + current->flags |= PF_USEDFPU; + } +} + +static inline void loose_fpu(void) +{ + if (mips_cpu.options & MIPS_CPU_FPU) { + KSTK_STATUS(current) &= ~ST0_CU1; + current->flags &= ~PF_USEDFPU; + __disable_fpu(); + } +} + +static inline void init_fpu(void) +{ + if (mips_cpu.options & MIPS_CPU_FPU) { + _init_fpu(); + } else { + fpu_emulator_init_fpu(); + } +} + +static inline void save_fp(struct task_struct *tsk) +{ + if (mips_cpu.options & MIPS_CPU_FPU) + _save_fp(tsk); +} + +static inline void restore_fp(struct task_struct *tsk) +{ + if (mips_cpu.options & MIPS_CPU_FPU) + _restore_fp(tsk); +} + +static inline unsigned long *get_fpu_regs(struct task_struct *tsk) +{ + if(mips_cpu.options & MIPS_CPU_FPU) { + if ((tsk == current) && is_fpu_owner()) + _save_fp(current); + return (unsigned long *)&tsk->thread.fpu.hard.fp_regs[0]; + } else { + return (unsigned long *)tsk->thread.fpu.soft.regs; + } +} + +#endif /* _ASM_FPU_H */ + Index: include/asm-mips64/mipsregs.h =================================================================== RCS file: /home/cvs/linux/include/asm-mips64/mipsregs.h,v retrieving revision 1.27 diff -u -r1.27 mipsregs.h --- include/asm-mips64/mipsregs.h 3 Oct 2002 00:09:26 -0000 1.27 +++ include/asm-mips64/mipsregs.h 4 Nov 2002 19:41:49 -0000 @@ -896,47 +896,6 @@ __BUILD_SET_CP0(cause,CP0_CAUSE) __BUILD_SET_CP0(config,CP0_CONFIG) -#if defined(CONFIG_CPU_SB1) -#define __enable_fpu_hazard() \ -do { \ - asm(".set push \n\t" \ - ".set mips2 \n\t" \ - ".set noreorder \n\t" \ - "sll $0,$0,1 \n\t" \ - "bnezl $0, .+4 \n\t" \ - " sll $0,$0,1 \n\t" \ - ".set pop"); \ -} while (0) -#else -#define __enable_fpu_hazard() \ -do { \ - asm("nop;nop;nop;nop"); /* max. hazard */ \ -} while (0) -#endif - -#define __enable_fpu() \ -do { \ - set_cp0_status(ST0_CU1); \ - __enable_fpu_hazard(); \ -} while (0) - -#define __disable_fpu() \ -do { \ - clear_cp0_status(ST0_CU1); \ - /* We don't care about the cp0 hazard here */ \ -} while (0) - -#define enable_fpu() \ -do { \ - if (mips_cpu.options & MIPS_CPU_FPU) \ - __enable_fpu(); \ -} while (0) - -#define disable_fpu() \ -do { \ - if (mips_cpu.options & MIPS_CPU_FPU) \ - __disable_fpu(); \ -} while (0) #endif /* !__ASSEMBLY__ */ #endif /* _ASM_MIPSREGS_H */ Index: include/asm-mips64/processor.h =================================================================== RCS file: /home/cvs/linux/include/asm-mips64/processor.h,v retrieving revision 1.48 diff -u -r1.48 processor.h --- include/asm-mips64/processor.h 4 Nov 2002 02:22:51 -0000 1.48 +++ include/asm-mips64/processor.h 4 Nov 2002 19:41:49 -0000 @@ -100,9 +100,6 @@ #define wp_works_ok 1 #define wp_works_ok__is_a_macro /* for versions in ksyms.c */ -/* Lazy FPU handling on uni-processor */ -extern struct task_struct *last_task_used_math; - /* * User space process size: 1TB. This is hardcoded into a few places, * so don't change it unless you know what you are doing. TASK_SIZE @@ -231,26 +228,16 @@ /* * Do necessary setup to start up a newly executed thread. */ -#define start_thread(regs, pc, sp) \ -do { \ - unsigned long __status; \ - \ - /* New thread looses kernel privileges. */ \ - __status = regs->cp0_status & ~(ST0_CU0|ST0_FR|ST0_KSU); \ - __status |= KSU_USER; \ - __status |= (current->thread.mflags & MF_32BIT) ? 0 : ST0_FR; \ - regs->cp0_status = __status; \ - regs->cp0_epc = pc; \ - regs->regs[29] = sp; \ - current_thread_info()->addr_limit = USER_DS; \ -} while(0) +extern void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp); +struct task_struct; unsigned long get_wchan(struct task_struct *p); #define __PT_REG(reg) ((long)&((struct pt_regs *)0)->reg - sizeof(struct pt_regs)) #define __KSTK_TOS(tsk) ((unsigned long)(tsk->thread_info) + KERNEL_STACK_SIZE - 32) #define KSTK_EIP(tsk) (*(unsigned long *)(__KSTK_TOS(tsk) + __PT_REG(cp0_epc))) #define KSTK_ESP(tsk) (*(unsigned long *)(__KSTK_TOS(tsk) + __PT_REG(regs[29]))) +#define KSTK_STATUS(tsk) (*(unsigned long *)(__KSTK_TOS(tsk) + __PT_REG(cp0_status))) #define cpu_relax() barrier() Index: include/asm-mips64/sigcontext.h =================================================================== RCS file: /home/cvs/linux/include/asm-mips64/sigcontext.h,v retrieving revision 1.4 diff -u -r1.4 sigcontext.h --- include/asm-mips64/sigcontext.h 31 Jul 2002 02:41:28 -0000 1.4 +++ include/asm-mips64/sigcontext.h 4 Nov 2002 19:41:49 -0000 @@ -20,7 +20,6 @@ unsigned long long sc_mdlo; unsigned long long sc_pc; unsigned int sc_status; - unsigned int sc_ownedfp; unsigned int sc_fpc_csr; unsigned int sc_fpc_eir; unsigned int sc_used_math; Index: include/asm-mips64/system.h =================================================================== RCS file: /home/cvs/linux/include/asm-mips64/system.h,v retrieving revision 1.37 diff -u -r1.37 system.h --- include/asm-mips64/system.h 2 Nov 2002 06:05:39 -0000 1.37 +++ include/asm-mips64/system.h 4 Nov 2002 19:41:49 -0000 @@ -267,11 +267,6 @@ struct task_struct; -extern asmlinkage void lazy_fpu_switch(void *prev, void *next); -extern asmlinkage void init_fpu(void); -extern asmlinkage void save_fp(struct task_struct *); -extern asmlinkage void restore_fp(struct task_struct *); - #define switch_to(prev,next,last) \ do { \ (last) = resume(prev, next, next->thread_info); \