patch-2.4.20 linux-2.4.20/arch/mips64/kernel/signal.c
Next file: linux-2.4.20/arch/mips64/kernel/signal32.c
Previous file: linux-2.4.20/arch/mips64/kernel/setup.c
Back to the patch index
Back to the overall index
- Lines: 241
- Date:
Thu Nov 28 15:53:10 2002
- Orig file:
linux-2.4.19/arch/mips64/kernel/signal.c
- Orig date:
Fri Aug 2 17:39:43 2002
diff -urN linux-2.4.19/arch/mips64/kernel/signal.c linux-2.4.20/arch/mips64/kernel/signal.c
@@ -32,8 +32,8 @@
#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 int (*save_fp_context)(struct sigcontext *sc);
+extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc);
extern asmlinkage void syscall_trace(void);
@@ -72,35 +72,6 @@
}
}
-static inline int store_fp_context(struct sigcontext *sc)
-{
- unsigned int fcr0;
- int err = 0;
-
- err |= __copy_to_user(&sc->sc_fpregs[0],
- ¤t->thread.fpu.hard.fp_regs[0], NUM_FPU_REGS *
- sizeof(unsigned long));
- err |= __copy_to_user(&sc->sc_fpc_csr, ¤t->thread.fpu.hard.control,
- sizeof(unsigned int));
- __asm__ __volatile__("cfc1 %0, $0\n\t" : "=r" (fcr0));
- err |= __copy_to_user(&sc->sc_fpc_eir, &fcr0, sizeof(unsigned int));
-
- return err;
-}
-
-static inline int refill_fp_context(struct sigcontext *sc)
-{
- int err = 0;
-
- if (verify_area(VERIFY_READ, sc, sizeof(*sc)))
- return -EFAULT;
- err |= __copy_from_user(¤t->thread.fpu.hard.fp_regs[0],
- &sc->sc_fpregs[0], NUM_FPU_REGS * sizeof(unsigned long));
- err |= __copy_from_user(¤t->thread.fpu.hard.control, &sc->sc_fpc_csr,
- sizeof(unsigned int));
- return err;
-}
-
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -165,7 +136,7 @@
}
}
-asmlinkage int
+asmlinkage int
sys_sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
{
struct k_sigaction new_ka, old_ka;
@@ -214,6 +185,54 @@
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)
{
@@ -241,15 +260,24 @@
#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) {
- if (IS_FPU_OWNER()) {
- CLEAR_FPU_OWNER();
- regs->cp0_status &= ~ST0_CU1;
- }
- current->used_math = 1;
- err |= refill_fp_context(sc);
+ err |= restore_fp_context(sc);
+ goto out;
+ }
+
+ if (IS_FPU_OWNER()) {
+ /* Signal handler acquired FPU - give it back */
+ CLEAR_FPU_OWNER();
+ regs->cp0_status &= ~ST0_CU1;
+ }
+ if (current->used_math) {
+ /* Undo possible contamination of thread state */
+ err |= restore_thread_fp_context(sc);
}
+out:
return err;
}
@@ -347,9 +375,11 @@
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);
+ err |= __put_user(regs->cp0_status, &sc->sc_status);
#define save_gp_reg(i) do { \
err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \
@@ -370,20 +400,27 @@
err |= __put_user(regs->cp0_cause, &sc->sc_cause);
err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr);
- if (current->used_math) { /* fp is active. */
- if (IS_FPU_OWNER()) {
- lazy_fpu_switch(current, 0);
- CLEAR_FPU_OWNER();
- regs->cp0_status &= ~ST0_CU1;
- }
- err |= __put_user(1, &sc->sc_ownedfp);
- err |= store_fp_context(sc);
- current->used_math = 0;
- } else {
- err |= __put_user(0, &sc->sc_ownedfp);
+ owned_fp = IS_FPU_OWNER();
+ 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;
}
- err |= __put_user(regs->cp0_status, &sc->sc_status);
+ /*
+ * Someone else has FPU.
+ * Copy Thread context into signal context
+ */
+ err |= save_thread_fp_context(sc);
+
+out:
return err;
}
@@ -398,6 +435,13 @@
/* Default to using normal stack */
sp = regs->regs[29];
+ /*
+ * FPU emulator may have it's own trampoline active just
+ * above the user stack, 16-bytes before the next lowest
+ * 16 byte boundary. Try to avoid trashing it.
+ */
+ sp -= 32;
+
/* This is the X/Open sanctioned signal stack switching. */
if ((ka->sa.sa_flags & SA_ONSTACK) && ! on_sig_stack(sp))
sp = current->sas_ss_sp + current->sas_ss_size;
@@ -456,8 +500,9 @@
regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
#if DEBUG_SIG
- printk("SIG deliver (%s:%d): sp=0x%p pc=0x%p ra=0x%p\n",
- current->comm, current->pid, frame, regs->cp0_epc, frame->code);
+ printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
+ current->comm, current->pid,
+ frame, regs->cp0_epc, frame->sf_code);
#endif
return;
@@ -532,8 +577,9 @@
regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
#if DEBUG_SIG
- printk("SIG deliver (%s:%d): sp=0x%p pc=0x%p ra=0x%p\n",
- current->comm, current->pid, frame, regs->cp0_epc, frame->code);
+ printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
+ current->comm, current->pid,
+ frame, regs->cp0_epc, frame->rs_code);
#endif
return;
@@ -661,7 +707,7 @@
continue;
switch (signr) {
- case SIGCONT: case SIGCHLD: case SIGWINCH:
+ case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG:
continue;
case SIGTSTP: case SIGTTIN: case SIGTTOU:
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)