diff mbox

[3/4] Fix signal handling for ColdFire

Message ID 4B8C1660.5080009@codesourcery.com
State New
Headers show

Commit Message

Maxim Kuvyrkov March 1, 2010, 7:32 p.m. UTC
From 1450a09c513a3051e3cf44d948983fe48ef368e0 Mon Sep 17 00:00:00 2001
From: Maxim Kuvyrkov <maxim@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

Comments

Richard Henderson March 3, 2010, 1:17 p.m. UTC | #1
> +    float64	sc_fpregs[2];	/* room for two fp registers */
...
> -    int f_fpcntl[3];
> -    int f_fpregs[8*3];
> +    uint32_t	f_fpcntl[3];
> +    float64	f_fpregs[8];

Surely these float64 uses are incorrect.  The kernel uses 3*int
at both of these places, which matches up with the 96-bit values
in the regular m68k fpu.


r~
Maxim Kuvyrkov March 3, 2010, 1:36 p.m. UTC | #2
On 3/3/10 4:17 PM, Richard Henderson wrote:
>> +  float64  sc_fpregs[2];  /* room for two fp registers */
> ...
>> - int f_fpcntl[3];
>> - int f_fpregs[8*3];
>> + uint32_t f_fpcntl[3];
>> + float64 f_fpregs[8];
>
> Surely these float64 uses are incorrect. The kernel uses 3*int
> at both of these places, which matches up with the 96-bit values
> in the regular m68k fpu.

ColdFire FPU registers are 64-bit wide, this is one of the difference 
between ColdFire and classic m68k.

The kernel patch to sigcontext.h to support ColdFire was merged several 
days ago at 
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=arch/m68k/include/asm/sigcontext.h;h=1320eaa4cc2aab4b531a565c57ab62afb30bd0ec;hb=HEAD 
.

And thanks to your comment I noticed that an old version of the 
sigcontext patch was merged into the kernel in the above commit.  Will 
need to fix it.

Regards,
diff mbox

Patch

differences between host and target structure alignment requirements.
Use ColdFire version of rt_sigreturn trampoline.

Signed-off-by: Maxim Kuvyrkov <maxim@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;