[PATCH] add prctls for FP exception control

From: Paul Mackerras (paulus@samba.org)
Date: Sun Jan 26 2003 - 05:27:51 EST


Marcelo,

The patch below adds a couple of new prctl calls to allow processes to
get and set their floating-point exception mode. We need this on
PowerPC since the exception mode is controlled by bits in the MSR,
which only the kernel can access. (The 4 modes are exceptions
disabled, asynchronous non-recoverable exceptions, asynchronous
recoverable exceptions, and precise exceptions. There can be
significant differences in floating-point performance depending on the
mode in some PPC implementations.)

This patch is back-ported from 2.5. Linus accepted the equivalent
change for 2.5 several months ago. The patch also tidies up the
sys_prctl() code a little as was done in the 2.5 tree. Please apply
this to your tree.

Thanks,
Paul.

diff -urN linux-2.4/include/linux/prctl.h test/include/linux/prctl.h
--- linux-2.4/include/linux/prctl.h 2002-02-06 01:10:25.000000000 +1100
+++ test/include/linux/prctl.h 2003-01-25 22:14:15.000000000 +1100
@@ -26,4 +26,12 @@
 # define PR_FPEMU_NOPRINT 1 /* silently emulate fp operations accesses */
 # define PR_FPEMU_SIGFPE 2 /* don't emulate fp operations, send SIGFPE instead */
 
+/* Get/set floating-point exception mode (if meaningful) */
+#define PR_GET_FPEXC 11
+#define PR_SET_FPEXC 12
+# define PR_FP_EXC_DISABLED 0 /* FP exceptions disabled */
+# define PR_FP_EXC_NONRECOV 1 /* async non-recoverable exc. mode */
+# define PR_FP_EXC_ASYNC 2 /* async recoverable exception mode */
+# define PR_FP_EXC_PRECISE 3 /* precise exception mode */
+
 #endif /* _LINUX_PRCTL_H */
diff -urN linux-2.4/kernel/sys.c test/kernel/sys.c
--- linux-2.4/kernel/sys.c 2002-05-10 02:50:20.000000000 +1000
+++ test/kernel/sys.c 2003-01-25 22:14:15.000000000 +1100
@@ -18,6 +18,25 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
+#ifndef SET_UNALIGN_CTL
+# define SET_UNALIGN_CTL(a,b) (-EINVAL)
+#endif
+#ifndef GET_UNALIGN_CTL
+# define GET_UNALIGN_CTL(a,b) (-EINVAL)
+#endif
+#ifndef SET_FPEMU_CTL
+# define SET_FPEMU_CTL(a,b) (-EINVAL)
+#endif
+#ifndef GET_FPEMU_CTL
+# define GET_FPEMU_CTL(a,b) (-EINVAL)
+#endif
+#ifndef SET_FPEXC_CTL
+# define SET_FPEXC_CTL(a,b) (-EINVAL)
+#endif
+#ifndef GET_FPEXC_CTL
+# define GET_FPEXC_CTL(a,b) (-EINVAL)
+#endif
+
 /*
  * this is where the system-wide overflow UID and GID are defined, for
  * architectures that now have 32-bit UID/GID but didn't in the past
@@ -1229,36 +1248,24 @@
                         }
                         current->mm->dumpable = arg2;
                         break;
+
                 case PR_SET_UNALIGN:
-#ifdef SET_UNALIGN_CTL
                         error = SET_UNALIGN_CTL(current, arg2);
-#else
- error = -EINVAL;
-#endif
                         break;
-
                 case PR_GET_UNALIGN:
-#ifdef GET_UNALIGN_CTL
                         error = GET_UNALIGN_CTL(current, arg2);
-#else
- error = -EINVAL;
-#endif
                         break;
-
                 case PR_SET_FPEMU:
-#ifdef SET_FPEMU_CTL
                         error = SET_FPEMU_CTL(current, arg2);
-#else
- error = -EINVAL;
-#endif
                         break;
-
                 case PR_GET_FPEMU:
-#ifdef GET_FPEMU_CTL
                         error = GET_FPEMU_CTL(current, arg2);
-#else
- error = -EINVAL;
-#endif
+ break;
+ case PR_SET_FPEXC:
+ error = SET_FPEXC_CTL(current, arg2);
+ break;
+ case PR_GET_FPEXC:
+ error = GET_FPEXC_CTL(current, arg2);
                         break;
 
                 case PR_GET_KEEPCAPS:
diff -urN linux-2.4/arch/ppc/kernel/process.c test/arch/ppc/kernel/process.c
--- linux-2.4/arch/ppc/kernel/process.c 2002-02-05 18:58:43.000000000 +1100
+++ test/arch/ppc/kernel/process.c 2003-01-25 22:16:03.000000000 +1100
@@ -34,6 +34,7 @@
 #include <linux/user.h>
 #include <linux/elf.h>
 #include <linux/init.h>
+#include <linux/prctl.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -403,6 +404,40 @@
         current->thread.fpscr = 0;
 }
 
+/*
+ * Support for the PR_GET/SET_FPEXC prctl() calls.
+ */
+static inline unsigned int __unpack_fe01(unsigned int msr_bits)
+{
+ return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8);
+}
+
+static inline unsigned int __pack_fe01(unsigned int fpmode)
+{
+ return ((fpmode << 10) & MSR_FE0) | ((fpmode << 8) & MSR_FE1);
+}
+
+int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
+{
+ struct pt_regs *regs = tsk->thread.regs;
+
+ if (val > PR_FP_EXC_PRECISE)
+ return -EINVAL;
+ tsk->thread.fpexc_mode = __pack_fe01(val);
+ if (regs != NULL && (regs->msr & MSR_FP) != 0)
+ regs->msr = (regs->msr & ~(MSR_FE0|MSR_FE1))
+ | tsk->thread.fpexc_mode;
+ return 0;
+}
+
+int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
+{
+ unsigned int val;
+
+ val = __unpack_fe01(tsk->thread.fpexc_mode);
+ return put_user(val, (unsigned int *) adr);
+}
+
 int sys_clone(int p1, int p2, int p3, int p4, int p5, int p6,
               struct pt_regs *regs)
 {
diff -urN linux-2.4/include/asm-ppc/processor.h test/include/asm-ppc/processor.h
--- linux-2.4/include/asm-ppc/processor.h 2002-10-09 08:18:47.000000000 +1000
+++ test/include/asm-ppc/processor.h 2003-01-25 22:19:33.000000000 +1100
@@ -659,10 +659,10 @@
 
 struct thread_struct {
         unsigned long ksp; /* Kernel stack pointer */
- unsigned long wchan; /* Event task is sleeping on */
         struct pt_regs *regs; /* Pointer to saved register state */
         mm_segment_t fs; /* for get_fs() validation */
         void *pgdir; /* root of page-table tree */
+ int fpexc_mode; /* floating-point exception mode */
         signed long last_syscall;
         double fpr[32]; /* Complete floating point set */
         unsigned long fpscr_pad; /* fpr ... fpscr must be contiguous */
@@ -677,13 +677,10 @@
 #define INIT_SP (sizeof(init_stack) + (unsigned long) &init_stack)
 
 #define INIT_THREAD { \
- INIT_SP, /* ksp */ \
- 0, /* wchan */ \
- 0, /* regs */ \
- KERNEL_DS, /*fs*/ \
- swapper_pg_dir, /* pgdir */ \
- 0, /* last_syscall */ \
- {0}, 0, 0 \
+ .ksp = INIT_SP, \
+ .fs = KERNEL_DS, \
+ .pgdir = swapper_pg_dir, \
+ .fpexc_mode = MSR_FE0 | MSR_FE1, \
 }
 
 /*
@@ -702,6 +699,13 @@
 #define KSTK_EIP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->nip: 0)
 #define KSTK_ESP(tsk) ((tsk)->thread.regs? (tsk)->thread.regs->gpr[1]: 0)
 
+/* Get/set floating-point exception mode */
+#define GET_FPEXC_CTL(tsk, adr) get_fpexc_mode((tsk), (adr))
+#define SET_FPEXC_CTL(tsk, val) set_fpexc_mode((tsk), (val))
+
+extern int get_fpexc_mode(struct task_struct *tsk, unsigned long adr);
+extern int set_fpexc_mode(struct task_struct *tsk, unsigned int val);
+
 /*
  * NOTE! The task struct and the stack go together
  */
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Jan 31 2003 - 22:00:15 EST