>From 1450a09c513a3051e3cf44d948983fe48ef368e0 Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <ma...@codesourcery.com>
Date: Mon, 1 Mar 2010 02:48:31 -0800
Subject: [PATCH 3/4] Fix signal handling for ColdFire

Handle FPU registers.
Pack structures that contain 16-bit fields.  This avoid problems due to
differences between host and target structure alignment requirements.
Use ColdFire version of rt_sigreturn trampoline.

Signed-off-by: Maxim Kuvyrkov <ma...@codesourcery.com>
---
 linux-user/signal.c |   60 ++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 50 insertions(+), 10 deletions(-)

diff --git a/linux-user/signal.c b/linux-user/signal.c
index 8f9da80..dc6f957 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -4058,9 +4058,17 @@ struct target_sigcontext {
     abi_ulong  sc_d1;
     abi_ulong  sc_a0;
     abi_ulong  sc_a1;
-    unsigned short sc_sr;
+    uint16_t sc_sr;
+    /* M68K Linux ABI allows int32_t to be aligned at 2 bytes,
+       as most host architectures align int32's at 4 bytes,
+       we need to pack target_sigcontext so that sc_pc will be at
+       the correct offset.  */
     abi_ulong  sc_pc;
-};
+    uint16_t   sc_formatvec;
+    float64    sc_fpregs[2];   /* room for two fp registers */
+    uint32_t   sc_fpcntl[3];
+    unsigned char sc_fpstate[216];
+} __attribute__((__packed__));
 
 struct target_sigframe
 {
@@ -4078,8 +4086,8 @@ typedef int target_greg_t;
 typedef target_greg_t target_gregset_t[TARGET_NGREG];
 
 typedef struct target_fpregset {
-    int f_fpcntl[3];
-    int f_fpregs[8*3];
+    uint32_t   f_fpcntl[3];
+    float64    f_fpregs[8];
 } target_fpregset_t;
 
 struct target_mcontext {
@@ -4106,7 +4114,7 @@ struct target_rt_sigframe
     abi_ulong pinfo;
     abi_ulong puc;
     char retcode[8];
-    struct target_siginfo info;
+    target_siginfo_t info;
     struct target_ucontext uc;
 };
 
@@ -4123,6 +4131,12 @@ setup_sigcontext(struct target_sigcontext *sc, CPUState 
*env, abi_ulong mask)
     err |= __put_user(env->aregs[1], &sc->sc_a1);
     err |= __put_user(env->sr, &sc->sc_sr);
     err |= __put_user(env->pc, &sc->sc_pc);
+    err |= __put_user(env->fregs[0],   &sc->sc_fpregs[0]);
+    err |= __put_user(env->fregs[1],   &sc->sc_fpregs[1]);
+    err |= __put_user(env->fpcr,       &sc->sc_fpcntl[0]);
+    err |= __put_user(env->fpsr,       &sc->sc_fpcntl[1]);
+    err |= __put_user(0,               &sc->sc_fpcntl[2]);
+    err |= __put_user(0,               (uint32_t *) &sc->sc_fpstate[0]);
 
     return err;
 }
@@ -4140,6 +4154,10 @@ restore_sigcontext(CPUState *env, struct 
target_sigcontext *sc, int *pd0)
     err |= __get_user(env->pc, &sc->sc_pc);
     err |= __get_user(temp, &sc->sc_sr);
     env->sr = (env->sr & 0xff00) | (temp & 0xff);
+    err |= __get_user(env->fregs[0],   &sc->sc_fpregs[0]);
+    err |= __get_user(env->fregs[1],   &sc->sc_fpregs[1]);
+    err |= __get_user(env->fpcr,       &sc->sc_fpcntl[0]);
+    err |= __get_user(env->fpsr,       &sc->sc_fpcntl[1]);
 
     *pd0 = tswapl(sc->sc_d0);
 
@@ -4222,6 +4240,7 @@ static inline int target_rt_setup_ucontext(struct 
target_ucontext *uc,
                                            CPUState *env)
 {
     target_greg_t *gregs = uc->uc_mcontext.gregs;
+    target_fpregset_t *fpregs = &uc->uc_mcontext.fpregs;
     int err;
 
     err = __put_user(TARGET_MCONTEXT_VERSION, &uc->uc_mcontext.version);
@@ -4243,6 +4262,17 @@ static inline int target_rt_setup_ucontext(struct 
target_ucontext *uc,
     err |= __put_user(env->aregs[7], &gregs[15]);
     err |= __put_user(env->pc, &gregs[16]);
     err |= __put_user(env->sr, &gregs[17]);
+    err |= __put_user(env->fpcr,       &fpregs->f_fpcntl[0]);
+    err |= __put_user(env->fpsr,       &fpregs->f_fpcntl[1]);
+    err |= __put_user(0,               &fpregs->f_fpcntl[2]);
+    err |= __put_user(env->fregs[0],   &fpregs->f_fpregs[0]);
+    err |= __put_user(env->fregs[1],   &fpregs->f_fpregs[1]);
+    err |= __put_user(env->fregs[2],   &fpregs->f_fpregs[2]);
+    err |= __put_user(env->fregs[3],   &fpregs->f_fpregs[3]);
+    err |= __put_user(env->fregs[4],   &fpregs->f_fpregs[4]);
+    err |= __put_user(env->fregs[5],   &fpregs->f_fpregs[5]);
+    err |= __put_user(env->fregs[6],   &fpregs->f_fpregs[6]);
+    err |= __put_user(env->fregs[7],   &fpregs->f_fpregs[7]);
 
     return err;
 }
@@ -4254,6 +4284,7 @@ static inline int target_rt_restore_ucontext(CPUState 
*env,
     int temp;
     int err;
     target_greg_t *gregs = uc->uc_mcontext.gregs;
+    target_fpregset_t *fpregs = &uc->uc_mcontext.fpregs;
     
     err = __get_user(temp, &uc->uc_mcontext.version);
     if (temp != TARGET_MCONTEXT_VERSION)
@@ -4279,6 +4310,16 @@ static inline int target_rt_restore_ucontext(CPUState 
*env,
     err |= __get_user(env->pc, &gregs[16]);
     err |= __get_user(temp, &gregs[17]);
     env->sr = (env->sr & 0xff00) | (temp & 0xff);
+    err |= __get_user(env->fpcr,       &fpregs->f_fpcntl[0]);
+    err |= __get_user(env->fpsr,       &fpregs->f_fpcntl[1]);
+    err |= __get_user(env->fregs[0],   &fpregs->f_fpregs[0]);
+    err |= __get_user(env->fregs[1],   &fpregs->f_fpregs[1]);
+    err |= __get_user(env->fregs[2],   &fpregs->f_fpregs[2]);
+    err |= __get_user(env->fregs[3],   &fpregs->f_fpregs[3]);
+    err |= __get_user(env->fregs[4],   &fpregs->f_fpregs[4]);
+    err |= __get_user(env->fregs[5],   &fpregs->f_fpregs[5]);
+    err |= __get_user(env->fregs[6],   &fpregs->f_fpregs[6]);
+    err |= __get_user(env->fregs[7],   &fpregs->f_fpregs[7]);
 
     *pd0 = env->dregs[0];
     return err;
@@ -4338,11 +4379,10 @@ static void setup_rt_frame(int sig, struct 
target_sigaction *ka,
     retcode_addr = frame_addr + offsetof(struct target_sigframe, retcode);
     err |= __put_user(retcode_addr, &frame->pretcode);
 
-    /* moveq #,d0; notb d0; trap #0 */
-
-    err |= __put_user(0x70004600 + ((TARGET_NR_rt_sigreturn ^ 0xff) << 16),
-                      (long *)(frame->retcode + 0));
-    err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
+    /* movel #__NR_rt_sigreturn,d0; trap #0 */
+    err |= __put_user(0x203c0000, (long *)(frame->retcode + 0));
+    err |= __put_user(0x00004e40 + (TARGET_NR_rt_sigreturn << 16),
+                     (long *)(frame->retcode + 4));
 
     if (err)
         goto give_sigsegv;
-- 
1.6.2.4

Reply via email to