[ARM] 3648/1: Update struct ucontext layout for coprocessor registers
authorDaniel Jacobowitz <drow@false.org>
Sat, 24 Jun 2006 22:46:21 +0000 (23:46 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sat, 24 Jun 2006 22:46:21 +0000 (23:46 +0100)
Patch from Daniel Jacobowitz

In order for userspace to find saved coprocessor registers, move them from
struct rt_sigframe into struct ucontext.  Also allow space for glibc's
sigset_t, so that userspace and kernelspace can use the same ucontext
layout.  Define the magic numbers for iWMMXt in the header file for easier
reference.  Include the size of the coprocessor data in the magic numbers.

Also define magic numbers and layout for VFP, not yet saved.

Signed-off-by: Daniel Jacobowitz <dan@codesourcery.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/kernel/signal.c
include/asm-arm/ucontext.h

index c0ba8afee42fd4b3c984c02a3b0b68d36716ca79..e5802bfda31df24346ee2aa2e472bf0bf1bd6042 100644 (file)
@@ -134,17 +134,6 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
 
 #ifdef CONFIG_IWMMXT
 
-/* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */
-#define IWMMXT_STORAGE_SIZE    (0x98 + 8)
-#define IWMMXT_MAGIC0          0x12ef842a
-#define IWMMXT_MAGIC1          0x1c07ca71
-
-struct iwmmxt_sigframe {
-       unsigned long   magic0;
-       unsigned long   magic1;
-       unsigned long   storage[0x98/4];
-};
-
 static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
 {
        char kbuf[sizeof(*frame) + 8];
@@ -152,8 +141,8 @@ static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
 
        /* the iWMMXt context must be 64 bit aligned */
        kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7);
-       kframe->magic0 = IWMMXT_MAGIC0;
-       kframe->magic1 = IWMMXT_MAGIC1;
+       kframe->magic = IWMMXT_MAGIC;
+       kframe->size = IWMMXT_STORAGE_SIZE;
        iwmmxt_task_copy(current_thread_info(), &kframe->storage);
        return __copy_to_user(frame, kframe, sizeof(*frame));
 }
@@ -167,8 +156,8 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)
        kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7);
        if (__copy_from_user(kframe, frame, sizeof(*frame)))
                return -1;
-       if (kframe->magic0 != IWMMXT_MAGIC0 ||
-           kframe->magic1 != IWMMXT_MAGIC1)
+       if (kframe->magic != IWMMXT_MAGIC ||
+           kframe->size != IWMMXT_STORAGE_SIZE)
                return -1;
        iwmmxt_task_restore(current_thread_info(), &kframe->storage);
        return 0;
@@ -176,26 +165,12 @@ static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)
 
 #endif
 
-/*
- * Auxiliary signal frame.  This saves stuff like FP state.
- * The layout of this structure is not part of the user ABI.
- */
-struct aux_sigframe {
-#ifdef CONFIG_IWMMXT
-       struct iwmmxt_sigframe  iwmmxt;
-#endif
-#ifdef CONFIG_VFP
-       union vfp_state         vfp;
-#endif
-};
-
 /*
  * Do a signal return; undo the signal stack.  These are aligned to 64-bit.
  */
 struct sigframe {
        struct ucontext uc;
        unsigned long retcode[2];
-       struct aux_sigframe aux __attribute__((aligned(8)));
 };
 
 struct rt_sigframe {
@@ -205,6 +180,7 @@ struct rt_sigframe {
 
 static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
 {
+       struct aux_sigframe __user *aux;
        sigset_t set;
        int err;
 
@@ -237,9 +213,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_IWMMXT
        if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
-               err |= restore_iwmmxt_context(&sf->aux.iwmmxt);
+               err |= restore_iwmmxt_context(&aux->iwmmxt);
 #endif
 #ifdef CONFIG_VFP
 //     if (err == 0)
@@ -327,6 +304,7 @@ badframe:
 static int
 setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
 {
+       struct aux_sigframe __user *aux;
        int err = 0;
 
        __put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
@@ -354,14 +332,16 @@ 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_IWMMXT
        if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
-               err |= preserve_iwmmxt_context(&sf->aux.iwmmxt);
+               err |= preserve_iwmmxt_context(&aux->iwmmxt);
 #endif
 #ifdef CONFIG_VFP
 //     if (err == 0)
 //             err |= vfp_save_state(&sf->aux.vfp);
 #endif
+       __put_user_error(0, &aux->end_magic, err);
 
        return err;
 }
index f853130137ccec87983d9879d82a3065c6d47478..9e6f7ca9f5ae3623f9eed2bb11e6e236dc561fb5 100644 (file)
@@ -1,12 +1,89 @@
 #ifndef _ASMARM_UCONTEXT_H
 #define _ASMARM_UCONTEXT_H
 
+#include <asm/fpstate.h>
+
+/*
+ * struct sigcontext only has room for the basic registers, but struct
+ * ucontext now has room for all registers which need to be saved and
+ * restored.  Coprocessor registers are stored in uc_regspace.  Each
+ * coprocessor's saved state should start with a documented 32-bit magic
+ * number, followed by a 32-bit word giving the coproccesor's saved size.
+ * uc_regspace may be expanded if necessary, although this takes some
+ * coordination with glibc.
+ */
+
 struct ucontext {
        unsigned long     uc_flags;
        struct ucontext  *uc_link;
        stack_t           uc_stack;
        struct sigcontext uc_mcontext;
-       sigset_t          uc_sigmask;   /* mask last for extensibility */
+       sigset_t          uc_sigmask;
+       /* Allow for uc_sigmask growth.  Glibc uses a 1024-bit sigset_t.  */
+       int               __unused[32 - (sizeof (sigset_t) / sizeof (int))];
+       /* Last for extensibility.  Eight byte aligned because some
+          coprocessors require eight byte alignment.  */
+       unsigned long     uc_regspace[128] __attribute__((__aligned__(8)));
 };
 
+#ifdef __KERNEL__
+
+/*
+ * Coprocessor save state.  The magic values and specific
+ * coprocessor's layouts are part of the userspace ABI.  Each one of
+ * these should be a multiple of eight bytes and aligned to eight
+ * bytes, to prevent unpredictable padding in the signal frame.
+ */
+
+#ifdef CONFIG_IWMMXT
+/* iwmmxt_area is 0x98 bytes long, preceeded by 8 bytes of signature */
+#define IWMMXT_MAGIC           0x12ef842a
+#define IWMMXT_STORAGE_SIZE    (IWMMXT_SIZE + 8)
+
+struct iwmmxt_sigframe {
+       unsigned long   magic;
+       unsigned long   size;
+       struct iwmmxt_struct storage;
+} __attribute__((__aligned__(8)));
+#endif /* CONFIG_IWMMXT */
+
+#ifdef CONFIG_VFP
+#if __LINUX_ARM_ARCH__ < 6
+/* For ARM pre-v6, we use fstmiax and fldmiax.  This adds one extra
+ * word after the registers, and a word of padding at the end for
+ * alignment.  */
+#define VFP_MAGIC              0x56465001
+#define VFP_STORAGE_SIZE       152
+#else
+#define VFP_MAGIC              0x56465002
+#define VFP_STORAGE_SIZE       144
+#endif
+
+struct vfp_sigframe
+{
+       unsigned long           magic;
+       unsigned long           size;
+       union vfp_state         storage;
+};
+#endif /* CONFIG_VFP */
+
+/*
+ * Auxiliary signal frame.  This saves stuff like FP state.
+ * The layout of this structure is not part of the user ABI,
+ * because the config options aren't.  uc_regspace is really
+ * one of these.
+ */
+struct aux_sigframe {
+#ifdef CONFIG_IWMMXT
+       struct iwmmxt_sigframe  iwmmxt;
+#endif
+#if 0 && defined CONFIG_VFP /* Not yet saved.  */
+       struct vfp_sigframe     vfp;
+#endif
+       /* Something that isn't a valid magic number for any coprocessor.  */
+       unsigned long           end_magic;
+} __attribute__((__aligned__(8)));
+
+#endif
+
 #endif /* !_ASMARM_UCONTEXT_H */