linux-mips
[Top] [All Lists]

[PATCH] o32 sigcontext fixes for mips64

To: linux-mips@linux-mips.org
Subject: [PATCH] o32 sigcontext fixes for mips64
From: "Kip Walker" <kwalker@broadcom.com>
Date: Mon, 14 Jul 2003 09:48:58 -0700
Organization: Broadcom Corp. BPBU
Original-recipient: rfc822;linux-mips@linux-mips.org
Sender: linux-mips-bounce@linux-mips.org
This 2.4 patch fixes some issues with the signal context save and
restore for o32 binaries running on the mips64 kernel.

Any comments?

Kip
Index: include/asm-mips64/fpu.h
===================================================================
RCS file: /home/cvs/linux/include/asm-mips64/fpu.h,v
retrieving revision 1.1.2.4
diff -u -r1.1.2.4 fpu.h
--- include/asm-mips64/fpu.h    9 Apr 2003 00:46:24 -0000       1.1.2.4
+++ include/asm-mips64/fpu.h    14 Jul 2003 16:45:05 -0000
@@ -21,9 +21,13 @@
 #include <asm/current.h>
 
 struct sigcontext;
+struct sigcontext32;
 
 extern asmlinkage int (*save_fp_context)(struct sigcontext *sc);
 extern asmlinkage int (*restore_fp_context)(struct sigcontext *sc);
+
+extern asmlinkage int (*save_fp_context32)(struct sigcontext32 *sc);
+extern asmlinkage int (*restore_fp_context32)(struct sigcontext32 *sc);
 
 extern void fpu_emulator_init_fpu(void);
 extern void _init_fpu(void);
Index: include/asm-mips64/sigcontext.h
===================================================================
RCS file: /home/cvs/linux/include/asm-mips64/sigcontext.h,v
retrieving revision 1.3.2.2
diff -u -r1.3.2.2 sigcontext.h
--- include/asm-mips64/sigcontext.h     4 Nov 2002 19:39:56 -0000       1.3.2.2
+++ include/asm-mips64/sigcontext.h     14 Jul 2003 16:45:05 -0000
@@ -27,4 +27,24 @@
        unsigned int       sc_badvaddr;
 };
 
+struct sigcontext32 {
+       u32 sc_regmask;         /* Unused */
+       u32 sc_status;
+       u64 sc_pc;
+       u64 sc_regs[32];
+       u64 sc_fpregs[32];
+       u32 sc_ownedfp;         /* Unused */
+       u32 sc_fpc_csr;
+       u32 sc_fpc_eir;         /* Unused */
+       u32 sc_used_math;
+       u32 sc_ssflags;         /* Unused */
+       u64 sc_mdhi;
+       u64 sc_mdlo;
+
+       u32 sc_cause;           /* Unused */
+       u32 sc_badvaddr;        /* Unused */
+
+       u32 sc_sigset[4];       /* kernel's sigset_t */
+};
+
 #endif /* _ASM_SIGCONTEXT_H */
Index: arch/mips/tools/offset.c
===================================================================
RCS file: /home/cvs/linux/arch/mips/tools/Attic/offset.c,v
retrieving revision 1.16.4.6
diff -u -r1.16.4.6 offset.c
--- arch/mips/tools/offset.c    4 Nov 2002 19:39:56 -0000       1.16.4.6
+++ arch/mips/tools/offset.c    14 Jul 2003 16:45:05 -0000
@@ -8,6 +8,7 @@
  * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
  * Copyright (C) 2000 MIPS Technologies, Inc.
  */
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
@@ -156,6 +157,14 @@
        offset("#define SC_CAUSE      ", struct sigcontext, sc_cause);
        offset("#define SC_BADVADDR   ", struct sigcontext, sc_badvaddr);
        linefeed;
+
+#ifdef CONFIG_MIPS64
+       text("/* Linux 32-bit sigcontext offsets. */");
+       offset("#define SC32_FPREGS     ", struct sigcontext32, sc_fpregs);
+       offset("#define SC32_FPC_CSR    ", struct sigcontext32, sc_fpc_csr);
+       offset("#define SC32_FPC_EIR    ", struct sigcontext32, sc_fpc_eir);
+       linefeed;
+#endif
 }
 
 void output_signal_defined(void)
Index: arch/mips64/kernel/signal32.c
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/signal32.c,v
retrieving revision 1.20.2.12
diff -u -r1.20.2.12 signal32.c
--- arch/mips64/kernel/signal32.c       12 Mar 2003 15:44:06 -0000      
1.20.2.12
+++ arch/mips64/kernel/signal32.c       14 Jul 2003 16:45:06 -0000
@@ -60,6 +60,14 @@
        int ss_flags;
 } stack32_t;
 
+struct ucontext32 {
+       u32                 uc_flags;
+       s32                 uc_link;
+       stack32_t           uc_stack;
+       struct sigcontext32 uc_mcontext;
+       sigset_t32          uc_sigmask;   /* mask last for extensibility */
+};
+
 extern void __put_sigset_unknown_nsig(void);
 extern void __get_sigset_unknown_nsig(void);
 
@@ -250,8 +258,8 @@
        return ret;
 }
 
-static asmlinkage int restore_sigcontext(struct pt_regs *regs,
-                                        struct sigcontext *sc)
+static asmlinkage int restore_sigcontext32(struct pt_regs *regs,
+                                          struct sigcontext32 *sc)
 {
        int err = 0;
 
@@ -280,7 +288,7 @@
        if (current->used_math) {
                /* restore fpu context if we have used it before */
                own_fpu();
-               err |= restore_fp_context(sc);
+               err |= restore_fp_context32(sc);
        } else {
                /* signal handler may have used FPU.  Give it up. */
                loose_fpu();
@@ -292,7 +300,7 @@
 struct sigframe {
        u32 sf_ass[4];                  /* argument save space for o32 */
        u32 sf_code[2];                 /* signal trampoline */
-       struct sigcontext sf_sc;
+       struct sigcontext32 sf_sc;
        sigset_t sf_mask;
 };
 
@@ -300,7 +308,7 @@
        u32 rs_ass[4];                  /* argument save space for o32 */
        u32 rs_code[2];                 /* signal trampoline */
        struct siginfo32 rs_info;
-       struct ucontext rs_uc;
+       struct ucontext32 rs_uc;
 };
 
 static int copy_siginfo_to_user32(siginfo_t32 *to, siginfo_t *from)
@@ -362,7 +370,7 @@
        recalc_sigpending(current);
        spin_unlock_irq(&current->sigmask_lock);
 
-       if (restore_sigcontext(&regs, &frame->sf_sc))
+       if (restore_sigcontext32(&regs, &frame->sf_sc))
                goto badframe;
 
        /*
@@ -386,6 +394,7 @@
        struct rt_sigframe32 *frame;
        sigset_t set;
        stack_t st;
+       s32 sp;
 
        frame = (struct rt_sigframe32 *) regs.regs[29];
        if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
@@ -399,11 +408,18 @@
        recalc_sigpending(current);
        spin_unlock_irq(&current->sigmask_lock);
 
-       if (restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext))
+       if (restore_sigcontext32(&regs, &frame->rs_uc.uc_mcontext))
                goto badframe;
 
-       if (__copy_from_user(&st, &frame->rs_uc.uc_stack, sizeof(st)))
+       /* The ucontext contains a stack32_t, so we must convert!  */
+       if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp))
+               goto badframe;
+       st.ss_size = (long) sp;
+       if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size))
                goto badframe;
+       if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags))
+               goto badframe;
+
        /* It is more difficult to avoid calling this function than to
           call it and ignore errors.  */
        do_sigaltstack(&st, NULL, regs.regs[29]);
@@ -422,8 +438,8 @@
        force_sig(SIGSEGV, current);
 }
 
-static int inline setup_sigcontext(struct pt_regs *regs,
-                                  struct sigcontext *sc)
+static int inline setup_sigcontext32(struct pt_regs *regs,
+                                    struct sigcontext32 *sc)
 {
        int err = 0;
 
@@ -462,7 +478,7 @@
                own_fpu();
                restore_fp(current);
        }
-       err |= save_fp_context(sc);
+       err |= save_fp_context32(sc);
 
 out:
        return err;
@@ -513,7 +529,7 @@
        err |= __put_user(0x0000000c                     , frame->sf_code + 1);
        flush_cache_sigtramp((unsigned long) frame->sf_code);
 
-       err |= setup_sigcontext(regs, &frame->sf_sc);
+       err |= setup_sigcontext32(regs, &frame->sf_sc);
        err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
        if (err)
                goto give_sigsegv;
@@ -554,6 +570,7 @@
 {
        struct rt_sigframe32 *frame;
        int err = 0;
+       s32 sp;
 
        frame = get_sigframe(ka, regs, sizeof(*frame));
        if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
@@ -577,13 +594,14 @@
        /* Create the ucontext.  */
        err |= __put_user(0, &frame->rs_uc.uc_flags);
        err |= __put_user(0, &frame->rs_uc.uc_link);
-       err |= __put_user((void *)current->sas_ss_sp,
+       sp = (int) (long) current->sas_ss_sp;
+       err |= __put_user(sp,
                          &frame->rs_uc.uc_stack.ss_sp);
        err |= __put_user(sas_ss_flags(regs->regs[29]),
                          &frame->rs_uc.uc_stack.ss_flags);
        err |= __put_user(current->sas_ss_size,
                          &frame->rs_uc.uc_stack.ss_size);
-       err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
+       err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext);
        err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
 
        if (err)
Index: arch/mips64/kernel/traps.c
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/traps.c,v
retrieving revision 1.30.2.54
diff -u -r1.30.2.54 traps.c
--- arch/mips64/kernel/traps.c  6 Jun 2003 04:36:37 -0000       1.30.2.54
+++ arch/mips64/kernel/traps.c  14 Jul 2003 16:45:06 -0000
@@ -781,12 +781,21 @@
 asmlinkage int (*save_fp_context)(struct sigcontext *sc);
 asmlinkage int (*restore_fp_context)(struct sigcontext *sc);
 
+asmlinkage int (*save_fp_context32)(struct sigcontext32 *sc);
+asmlinkage int (*restore_fp_context32)(struct sigcontext32 *sc);
+
 extern asmlinkage int _save_fp_context(struct sigcontext *sc);
 extern asmlinkage int _restore_fp_context(struct sigcontext *sc);
 
+extern asmlinkage int _save_fp_context32(struct sigcontext32 *sc);
+extern asmlinkage int _restore_fp_context32(struct sigcontext32 *sc);
+
 extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc);
 extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc);
 
+extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 *sc);
+extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 *sc);
+
 void __init per_cpu_trap_init(void)
 {
        unsigned int cpu = smp_processor_id();
@@ -904,9 +913,13 @@
        if (cpu_has_fpu) {
                save_fp_context = _save_fp_context;
                restore_fp_context = _restore_fp_context;
+               save_fp_context32 = _save_fp_context32;
+               restore_fp_context32 = _restore_fp_context32;
        } else {
                save_fp_context = fpu_emulator_save_context;
                restore_fp_context = fpu_emulator_restore_context;
+               save_fp_context32 = fpu_emulator_save_context32;
+               restore_fp_context32 = fpu_emulator_restore_context32;
        }
 
        flush_icache_range(KSEG0, KSEG0 + 0x400);
Index: arch/mips64/kernel/r4k_fpu.S
===================================================================
RCS file: /home/cvs/linux/arch/mips64/kernel/r4k_fpu.S,v
retrieving revision 1.3.2.1
diff -u -r1.3.2.1 r4k_fpu.S
--- arch/mips64/kernel/r4k_fpu.S        31 Jul 2002 02:41:21 -0000      1.3.2.1
+++ arch/mips64/kernel/r4k_fpu.S        14 Jul 2003 16:45:06 -0000
@@ -5,6 +5,8 @@
  *
  * Save/restore floating point context for signal handlers.
  *
+ * Copyright (C) 2003 Broadcom Corporation
+ *
  * Copyright (C) 1996, 1998, 1999, 2001 by Ralf Baechle
  *
  * Multi-arch abstraction and asm macros for easier reading:
@@ -32,11 +34,8 @@
        .set    noreorder
        /* Save floating point context */
 LEAF(_save_fp_context)
-       mfc0    t1, CP0_STATUS
-       sll     t2, t1,5
+       cfc1    t1, fcr31
 
-       bgez    t2, 1f
-        cfc1   t1, fcr31
        /* Store the 16 odd double precision registers */
        EX      sdc1 $f1, SC_FPREGS+8(a0)
        EX      sdc1 $f3, SC_FPREGS+24(a0)
@@ -56,7 +55,6 @@
        EX      sdc1 $f31, SC_FPREGS+248(a0)
 
        /* Store the 16 even double precision registers */
-1:
        EX      sdc1 $f0, SC_FPREGS+0(a0)
        EX      sdc1 $f2, SC_FPREGS+16(a0)
        EX      sdc1 $f4, SC_FPREGS+32(a0)
@@ -81,24 +79,42 @@
         li     v0, 0                                   # success
        END(_save_fp_context)
 
+       /* Save 32-bit process floating point context */
+LEAF(_save_fp_context32)
+       cfc1    t1, fcr31
+
+       EX      sdc1 $f0, SC32_FPREGS+0(a0)
+       EX      sdc1 $f2, SC32_FPREGS+16(a0)
+       EX      sdc1 $f4, SC32_FPREGS+32(a0)
+       EX      sdc1 $f6, SC32_FPREGS+48(a0)
+       EX      sdc1 $f8, SC32_FPREGS+64(a0)
+       EX      sdc1 $f10, SC32_FPREGS+80(a0)
+       EX      sdc1 $f12, SC32_FPREGS+96(a0)
+       EX      sdc1 $f14, SC32_FPREGS+112(a0)
+       EX      sdc1 $f16, SC32_FPREGS+128(a0)
+       EX      sdc1 $f18, SC32_FPREGS+144(a0)
+       EX      sdc1 $f20, SC32_FPREGS+160(a0)
+       EX      sdc1 $f22, SC32_FPREGS+176(a0)
+       EX      sdc1 $f24, SC32_FPREGS+192(a0)
+       EX      sdc1 $f26, SC32_FPREGS+208(a0)
+       EX      sdc1 $f28, SC32_FPREGS+224(a0)
+       EX      sdc1 $f30, SC32_FPREGS+240(a0)
+       EX      sw t1, SC32_FPC_CSR(a0)
+       cfc1    t0, $0                          # implementation/version
+       EX      sw t0, SC32_FPC_EIR(a0)
+
+       jr      ra
+        li     v0, 0                                   # success
+       END(_save_fp_context32)
+
 /*
  * Restore FPU state:
  *  - fp gp registers
  *  - cp1 status/control register
- *
- * We base the decision which registers to restore from the signal stack
- * frame on the current content of c0_status, not on the content of the
- * stack frame which might have been changed by the user.
  */
 LEAF(_restore_fp_context)
-       mfc0    t1, CP0_STATUS
-       sll     t0, t1,5
-       bgez    t0, 1f
-        EX     lw t0, SC_FPC_CSR(a0)
-
-       /* Restore the 16 odd double precision registers only
-        * when enabled in the cp0 status register.
-        */
+       /* Restore an o32/64 sigcontext. */
+       EX      lw t0, SC_FPC_CSR(a0)
        EX      ldc1 $f1, SC_FPREGS+8(a0)
        EX      ldc1 $f3, SC_FPREGS+24(a0)
        EX      ldc1 $f5, SC_FPREGS+40(a0)
@@ -116,11 +132,7 @@
        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:     EX      ldc1 $f0, SC_FPREGS+0(a0)
+       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)
@@ -140,6 +152,30 @@
        jr      ra
         li     v0, 0                                   # success
        END(_restore_fp_context)
+
+LEAF(_restore_fp_context32)
+       /* Restore an o32 sigcontext.  */
+       EX      lw t0, SC32_FPC_CSR(a0)
+       EX      ldc1 $f0, SC32_FPREGS+0(a0)
+       EX      ldc1 $f2, SC32_FPREGS+16(a0)
+       EX      ldc1 $f4, SC32_FPREGS+32(a0)
+       EX      ldc1 $f6, SC32_FPREGS+48(a0)
+       EX      ldc1 $f8, SC32_FPREGS+64(a0)
+       EX      ldc1 $f10, SC32_FPREGS+80(a0)
+       EX      ldc1 $f12, SC32_FPREGS+96(a0)
+       EX      ldc1 $f14, SC32_FPREGS+112(a0)
+       EX      ldc1 $f16, SC32_FPREGS+128(a0)
+       EX      ldc1 $f18, SC32_FPREGS+144(a0)
+       EX      ldc1 $f20, SC32_FPREGS+160(a0)
+       EX      ldc1 $f22, SC32_FPREGS+176(a0)
+       EX      ldc1 $f24, SC32_FPREGS+192(a0)
+       EX      ldc1 $f26, SC32_FPREGS+208(a0)
+       EX      ldc1 $f28, SC32_FPREGS+224(a0)
+       EX      ldc1 $f30, SC32_FPREGS+240(a0)
+       ctc1    t0, fcr31
+       jr      ra
+        li     v0, 0                                   # success
+       END(_restore_fp_context32)
 
        .type   fault@function
        .ent    fault
Index: arch/mips/math-emu/kernel_linkage.c
===================================================================
RCS file: /home/cvs/linux/arch/mips/math-emu/kernel_linkage.c,v
retrieving revision 1.5.2.1
diff -u -r1.5.2.1 kernel_linkage.c
--- arch/mips/math-emu/kernel_linkage.c 5 Aug 2002 23:53:34 -0000       1.5.2.1
+++ arch/mips/math-emu/kernel_linkage.c 14 Jul 2003 16:45:06 -0000
@@ -90,3 +90,40 @@
        return err;
 }
 
+#ifdef CONFIG_MIPS64
+/*
+ * This is the o32 version
+ */
+
+int fpu_emulator_save_context32(struct sigcontext32 *sc)
+{
+       int i;
+       int err = 0;
+
+       for (i = 0; i < 32; i+=2) {
+               err |=
+                   __put_user(current->thread.fpu.soft.regs[i],
+                              &sc->sc_fpregs[i]);
+       }
+       err |= __put_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
+       err |= __put_user(fpuemuprivate.eir, &sc->sc_fpc_eir);
+
+       return err;
+}
+
+int fpu_emulator_restore_context32(struct sigcontext32 *sc)
+{
+       int i;
+       int err = 0;
+
+       for (i = 0; i < 32; i+=2) {
+               err |=
+                   __get_user(current->thread.fpu.soft.regs[i],
+                              &sc->sc_fpregs[i]);
+       }
+       err |= __get_user(current->thread.fpu.soft.sr, &sc->sc_fpc_csr);
+       err |= __get_user(fpuemuprivate.eir, &sc->sc_fpc_eir);
+
+       return err;
+}
+#endif
<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH] o32 sigcontext fixes for mips64, Kip Walker <=