[3/4] Fix signal handling for ColdFire

Submitted by Maxim Kuvyrkov on March 1, 2010, 7:32 p.m.

Details

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

Commit Message

Maxim Kuvyrkov March 1, 2010, 7:32 p.m.
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.
> +    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.
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,

Patch hide | download patch | download mbox

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;