[ARM] 3664/1: crunch: add signal frame save/restore
authorLennert Buytenhek <buytenh@wantstofly.org>
Tue, 27 Jun 2006 21:56:18 +0000 (22:56 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Wed, 28 Jun 2006 16:54:59 +0000 (17:54 +0100)
Patch from Lennert Buytenhek

This patch makes the kernel save Crunch state in userland signal frames,
so that any userland signal handler can safely use the Crunch coprocessor
without corrupting the Crunch state of the code it preempted.

Signed-off-by: Lennert Buytenhek <buytenh@wantstofly.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/kernel/signal.c
include/asm-arm/ucontext.h

index 1ce05ec..83a8d3c 100644 (file)
@@ -132,6 +132,37 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
        return ret;
 }
 
+#ifdef CONFIG_CRUNCH
+static int preserve_crunch_context(struct crunch_sigframe *frame)
+{
+       char kbuf[sizeof(*frame) + 8];
+       struct crunch_sigframe *kframe;
+
+       /* the crunch context must be 64 bit aligned */
+       kframe = (struct crunch_sigframe *)((unsigned long)(kbuf + 8) & ~7);
+       kframe->magic = CRUNCH_MAGIC;
+       kframe->size = CRUNCH_STORAGE_SIZE;
+       crunch_task_copy(current_thread_info(), &kframe->storage);
+       return __copy_to_user(frame, kframe, sizeof(*frame));
+}
+
+static int restore_crunch_context(struct crunch_sigframe *frame)
+{
+       char kbuf[sizeof(*frame) + 8];
+       struct crunch_sigframe *kframe;
+
+       /* the crunch context must be 64 bit aligned */
+       kframe = (struct crunch_sigframe *)((unsigned long)(kbuf + 8) & ~7);
+       if (__copy_from_user(kframe, frame, sizeof(*frame)))
+               return -1;
+       if (kframe->magic != CRUNCH_MAGIC ||
+           kframe->size != CRUNCH_STORAGE_SIZE)
+               return -1;
+       crunch_task_restore(current_thread_info(), &kframe->storage);
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_IWMMXT
 
 static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
@@ -214,6 +245,10 @@ static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
        err |= !valid_user_regs(regs);
 
        aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
+#ifdef CONFIG_CRUNCH
+       if (err == 0)
+               err |= restore_crunch_context(&aux->crunch);
+#endif
 #ifdef CONFIG_IWMMXT
        if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
                err |= restore_iwmmxt_context(&aux->iwmmxt);
@@ -333,6 +368,10 @@ setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
        err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
 
        aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
+#ifdef CONFIG_CRUNCH
+       if (err == 0)
+               err |= preserve_crunch_context(&aux->crunch);
+#endif
 #ifdef CONFIG_IWMMXT
        if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
                err |= preserve_iwmmxt_context(&aux->iwmmxt);
index 9e6f7ca..bf65e9f 100644 (file)
@@ -35,6 +35,17 @@ struct ucontext {
  * bytes, to prevent unpredictable padding in the signal frame.
  */
 
+#ifdef CONFIG_CRUNCH
+#define CRUNCH_MAGIC           0x5065cf03
+#define CRUNCH_STORAGE_SIZE    (CRUNCH_SIZE + 8)
+
+struct crunch_sigframe {
+       unsigned long   magic;
+       unsigned long   size;
+       struct crunch_state     storage;
+} __attribute__((__aligned__(8)));
+#endif
+
 #ifdef CONFIG_IWMMXT
 /* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */
 #define IWMMXT_MAGIC           0x12ef842a
@@ -74,6 +85,9 @@ struct vfp_sigframe
  * one of these.
  */
 struct aux_sigframe {
+#ifdef CONFIG_CRUNCH
+       struct crunch_sigframe  crunch;
+#endif
 #ifdef CONFIG_IWMMXT
        struct iwmmxt_sigframe  iwmmxt;
 #endif