All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nathan Froyd <froydnj@codesourcery.com>
To: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling
Date: Tue, 12 May 2009 19:13:18 -0700	[thread overview]
Message-ID: <20090513021318.GV23911@codesourcery.com> (raw)
In-Reply-To: <1242156419-23821-3-git-send-email-froydnj@codesourcery.com>

Implement setup_{,rt_}frame and do_{,rt_}sigreturn for PPC 32-bit.  Use
the same TARGET_QEMU_ESIGRETURN hack as for MIPS to avoid clobbering
register state on a sigreturn.

Signed-off-by: Nathan Froyd <froydnj@codesourcery.com>
---
Remove the trailing whitespace and tabs that malc noticed.

 linux-user/main.c        |    5 +
 linux-user/ppc/syscall.h |    3 +
 linux-user/signal.c      |  596 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 604 insertions(+), 0 deletions(-)

diff --git a/linux-user/main.c b/linux-user/main.c
index dc39b05..9c57c17 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1461,6 +1461,11 @@ void cpu_loop(CPUPPCState *env)
             ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
                              env->gpr[5], env->gpr[6], env->gpr[7],
                              env->gpr[8]);
+            if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) {
+                /* Returning from a successful sigreturn syscall.
+                   Avoid corrupting register state.  */
+                break;
+            }
             if (ret > (uint32_t)(-515)) {
                 env->crf[0] |= 0x1;
                 ret = -ret;
diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h
index a21d61b..d789911 100644
--- a/linux-user/ppc/syscall.h
+++ b/linux-user/ppc/syscall.h
@@ -51,6 +51,9 @@ struct target_revectored_struct {
 	abi_ulong __map[8];			/* 256 bits */
 };
 
+/* Nasty hack: define a fake errno value for use by sigreturn.  */
+#define TARGET_QEMU_ESIGRETURN 255
+
 /*
  * flags masks
  */
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 742d52a..9c9c7eb 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -3182,6 +3182,602 @@ long do_rt_sigreturn(CPUState *env)
     return -TARGET_ENOSYS;
 }
 
+#elif defined(TARGET_PPC) && !defined(TARGET_PPC64)
+
+/* FIXME: Many of the structures are defined for both PPC and PPC64, but
+   the signal handling is different enough that we haven't implemented
+   support for PPC64 yet.  Hence the restriction above.
+
+   There are various #if'd blocks for code for TARGET_PPC64.  These
+   blocks should go away so that we can successfully run 32-bit and
+   64-bit binaries on a QEMU configured for PPC64.  */
+
+/* Size of dummy stack frame allocated when calling signal handler.
+   See arch/powerpc/include/asm/ptrace.h.  */
+#if defined(TARGET_PPC64)
+#define SIGNAL_FRAMESIZE 128
+#else
+#define SIGNAL_FRAMESIZE 64
+#endif
+
+/* See arch/powerpc/include/asm/sigcontext.h.  */
+struct target_sigcontext {
+    target_ulong _unused[4];
+    int32_t signal;
+#if defined(TARGET_PPC64)
+    int32_t pad0;
+#endif
+    target_ulong handler;
+    target_ulong oldmask;
+    target_ulong regs;      /* struct pt_regs __user * */
+    /* TODO: PPC64 includes extra bits here.  */
+};
+
+/* Indices for target_mcontext.mc_gregs, below.
+   See arch/powerpc/include/asm/ptrace.h for details.  */
+enum {
+    TARGET_PT_R0 = 0,
+    TARGET_PT_R1 = 1,
+    TARGET_PT_R2 = 2,
+    TARGET_PT_R3 = 3,
+    TARGET_PT_R4 = 4,
+    TARGET_PT_R5 = 5,
+    TARGET_PT_R6 = 6,
+    TARGET_PT_R7 = 7,
+    TARGET_PT_R8 = 8,
+    TARGET_PT_R9 = 9,
+    TARGET_PT_R10 = 10,
+    TARGET_PT_R11 = 11,
+    TARGET_PT_R12 = 12,
+    TARGET_PT_R13 = 13,
+    TARGET_PT_R14 = 14,
+    TARGET_PT_R15 = 15,
+    TARGET_PT_R16 = 16,
+    TARGET_PT_R17 = 17,
+    TARGET_PT_R18 = 18,
+    TARGET_PT_R19 = 19,
+    TARGET_PT_R20 = 20,
+    TARGET_PT_R21 = 21,
+    TARGET_PT_R22 = 22,
+    TARGET_PT_R23 = 23,
+    TARGET_PT_R24 = 24,
+    TARGET_PT_R25 = 25,
+    TARGET_PT_R26 = 26,
+    TARGET_PT_R27 = 27,
+    TARGET_PT_R28 = 28,
+    TARGET_PT_R29 = 29,
+    TARGET_PT_R30 = 30,
+    TARGET_PT_R31 = 31,
+    TARGET_PT_NIP = 32,
+    TARGET_PT_MSR = 33,
+    TARGET_PT_ORIG_R3 = 34,
+    TARGET_PT_CTR = 35,
+    TARGET_PT_LNK = 36,
+    TARGET_PT_XER = 37,
+    TARGET_PT_CCR = 38,
+    /* Yes, there are two registers with #39.  One is 64-bit only.  */
+    TARGET_PT_MQ = 39,
+    TARGET_PT_SOFTE = 39,
+    TARGET_PT_TRAP = 40,
+    TARGET_PT_DAR = 41,
+    TARGET_PT_DSISR = 42,
+    TARGET_PT_RESULT = 43,
+    TARGET_PT_REGS_COUNT = 44
+};
+
+/* See arch/powerpc/include/asm/ucontext.h.  Only used for 32-bit PPC;
+   on 64-bit PPC, sigcontext and mcontext are one and the same.  */
+struct target_mcontext {
+    target_ulong mc_gregs[48];
+    /* Includes fpscr.  */
+    uint64_t mc_fregs[33];
+    target_ulong mc_pad[2];
+    /* We need to handle Altivec and SPE at the same time, which no
+       kernel needs to do.  Fortunately, the kernel defines this bit to
+       be Altivec-register-large all the time, rather than trying to
+       twiddle it based on the specific platform.  */
+    union {
+        /* SPE vector registers.  One extra for SPEFSCR.  */
+        uint32_t spe[33];
+        /* Altivec vector registers.  The packing of VSCR and VRSAVE
+           varies depending on whether we're PPC64 or not: PPC64 splits
+           them apart; PPC32 stuffs them together.  */
+#if defined(TARGET_PPC64)
+#define NVRREG 34
+#else
+#define NVRREG 33
+#endif
+        ppc_avr_t altivec[NVRREG];
+#undef NVRREG
+    } mc_vregs __attribute__((__aligned__(16)));
+};
+
+struct target_ucontext {
+    target_ulong uc_flags;
+    target_ulong uc_link;    /* struct ucontext __user * */
+    struct target_sigaltstack uc_stack;
+#if !defined(TARGET_PPC64)
+    int32_t uc_pad[7];
+    target_ulong uc_regs;    /* struct mcontext __user *
+                                points to uc_mcontext field */
+#endif
+    target_sigset_t uc_sigmask;
+#if defined(TARGET_PPC64)
+    target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
+    struct target_sigcontext uc_mcontext;
+#else
+    int32_t uc_maskext[30];
+    int32_t uc_pad2[3];
+    struct target_mcontext uc_mcontext;
+#endif
+};
+
+/* See arch/powerpc/kernel/signal_32.c.  */
+struct target_sigframe {
+    struct target_sigcontext sctx;
+    struct target_mcontext mctx;
+    int32_t abigap[56];
+};
+
+struct target_rt_sigframe {
+    struct target_siginfo info;
+    struct target_ucontext uc;
+    int32_t abigap[56];
+};
+
+/* We use the mc_pad field for the signal return trampoline.  */
+#define tramp mc_pad
+
+/* See arch/powerpc/kernel/signal.c.  */
+static target_ulong get_sigframe(struct target_sigaction *ka,
+                                 CPUState *env,
+                                 int frame_size)
+{
+    target_ulong oldsp, newsp;
+
+    oldsp = env->gpr[1];
+
+    if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
+        (sas_ss_flags(oldsp))) {
+        oldsp = (target_sigaltstack_used.ss_sp
+                 + target_sigaltstack_used.ss_size);
+    }
+
+    newsp = (oldsp - frame_size) & ~0xFUL;
+
+    return newsp;
+}
+
+static int save_user_regs(CPUState *env, struct target_mcontext *frame,
+                          int sigret)
+{
+    target_ulong msr = env->msr;
+    int i;
+    target_ulong ccr = 0;
+
+    /* In general, the kernel attempts to be intelligent about what it
+       needs to save for Altivec/FP/SPE registers.  We don't care that
+       much, so we just go ahead and save everything.  */
+
+    /* Save general registers.  */
+    for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+        if (__put_user(env->gpr[i], &frame->mc_gregs[i])) {
+            return 1;
+        }
+    }
+    if (__put_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
+        || __put_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
+        || __put_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
+        || __put_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
+        return 1;
+
+    for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
+        ccr |= env->crf[i] << (32 - ((i + 1) * 4));
+    }
+    if (__put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
+        return 1;
+
+    /* Save Altivec registers if necessary.  */
+    if (env->insns_flags & PPC_ALTIVEC) {
+        for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
+            ppc_avr_t *avr = &env->avr[i];
+            ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
+
+            if (__put_user(avr->u64[0], &vreg->u64[0]) ||
+                __put_user(avr->u64[1], &vreg->u64[1])) {
+                return 1;
+            }
+        }
+        /* Set MSR_VR in the saved MSR value to indicate that
+           frame->mc_vregs contains valid data.  */
+        msr |= MSR_VR;
+        if (__put_user((uint32_t)env->spr[SPR_VRSAVE],
+                       &frame->mc_vregs.altivec[32].u32[3]))
+            return 1;
+    }
+
+    /* Save floating point registers.  */
+    if (env->insns_flags & PPC_FLOAT) {
+        for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
+            if (__put_user(env->fpr[i], &frame->mc_fregs[i])) {
+                return 1;
+            }
+        }
+        if (__put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]))
+            return 1;
+    }
+
+    /* Save SPE registers.  The kernel only saves the high half.  */
+    if (env->insns_flags & PPC_SPE) {
+#if defined(TARGET_PPC64)
+        for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+            if (__put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i])) {
+                return 1;
+            }
+        }
+#else
+        for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
+            if (__put_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
+                return 1;
+            }
+        }
+#endif
+        /* Set MSR_SPE in the saved MSR value to indicate that
+           frame->mc_vregs contains valid data.  */
+        msr |= MSR_SPE;
+        if (__put_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
+            return 1;
+    }
+
+    /* Store MSR.  */
+    if (__put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
+        return 1;
+
+    /* Set up the sigreturn trampoline: li r0,sigret; sc.  */
+    if (sigret) {
+        if (__put_user(0x38000000UL | sigret, &frame->tramp[0]) ||
+            __put_user(0x44000002UL, &frame->tramp[1])) {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+static int restore_user_regs(CPUState *env,
+                             struct target_mcontext *frame, int sig)
+{
+    target_ulong save_r2 = 0;
+    target_ulong msr;
+    target_ulong ccr;
+
+    int i;
+
+    if (!sig) {
+        save_r2 = env->gpr[2];
+    }
+
+    /* Restore general registers.  */
+    for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+        if (__get_user(env->gpr[i], &frame->mc_gregs[i])) {
+            return 1;
+        }
+    }
+    if (__get_user(env->nip, &frame->mc_gregs[TARGET_PT_NIP])
+        || __get_user(env->ctr, &frame->mc_gregs[TARGET_PT_CTR])
+        || __get_user(env->lr, &frame->mc_gregs[TARGET_PT_LNK])
+        || __get_user(env->xer, &frame->mc_gregs[TARGET_PT_XER]))
+        return 1;
+    if (__get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]))
+        return 1;
+
+    for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
+        env->crf[i] = (ccr >> (32 - ((i + 1) * 4))) & 0xf;
+    }
+
+    if (!sig) {
+        env->gpr[2] = save_r2;
+    }
+    /* Restore MSR.  */
+    if (__get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]))
+        return 1;
+
+    /* If doing signal return, restore the previous little-endian mode.  */
+    if (sig)
+        env->msr = (env->msr & ~MSR_LE) | (msr & MSR_LE);
+
+    /* Restore Altivec registers if necessary.  */
+    if (env->insns_flags & PPC_ALTIVEC) {
+        for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
+            ppc_avr_t *avr = &env->avr[i];
+            ppc_avr_t *vreg = &frame->mc_vregs.altivec[i];
+
+            if (__get_user(avr->u64[0], &vreg->u64[0]) ||
+                __get_user(avr->u64[1], &vreg->u64[1])) {
+                return 1;
+            }
+        }
+        /* Set MSR_VEC in the saved MSR value to indicate that
+           frame->mc_vregs contains valid data.  */
+        if (__get_user(env->spr[SPR_VRSAVE],
+                       (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3])))
+            return 1;
+    }
+
+    /* Restore floating point registers.  */
+    if (env->insns_flags & PPC_FLOAT) {
+        uint64_t fpscr;
+        for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
+            if (__get_user(env->fpr[i], &frame->mc_fregs[i])) {
+                return 1;
+            }
+        }
+        if (__get_user(fpscr, &frame->mc_fregs[32]))
+            return 1;
+        env->fpscr = (uint32_t) fpscr;
+    }
+
+    /* Save SPE registers.  The kernel only saves the high half.  */
+    if (env->insns_flags & PPC_SPE) {
+#if defined(TARGET_PPC64)
+        for (i = 0; i < ARRAY_SIZE(env->gpr); i++) {
+            uint32_t hi;
+
+            if (__get_user(hi, &frame->mc_vregs.spe[i])) {
+                return 1;
+            }
+            env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
+        }
+#else
+        for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
+            if (__get_user(env->gprh[i], &frame->mc_vregs.spe[i])) {
+                return 1;
+            }
+        }
+#endif
+        if (__get_user(env->spe_fscr, &frame->mc_vregs.spe[32]))
+            return 1;
+    }
+
+    return 0;
+}
+
+static void setup_frame(int sig, struct target_sigaction *ka,
+                        target_sigset_t *set, CPUState *env)
+{
+    struct target_sigframe *frame;
+    struct target_sigcontext *sc;
+    target_ulong frame_addr, newsp;
+    int err = 0;
+    int signal;
+
+    frame_addr = get_sigframe(ka, env, sizeof(*frame));
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
+        goto sigsegv;
+    sc = &frame->sctx;
+
+    signal = current_exec_domain_sig(sig);
+
+    err |= __put_user(h2g(ka->_sa_handler), &sc->handler);
+    err |= __put_user(set->sig[0], &sc->oldmask);
+#if defined(TARGET_PPC64)
+    err |= __put_user(set->sig[0] >> 32, &sc->_unused[3]);
+#else
+    err |= __put_user(set->sig[1], &sc->_unused[3]);
+#endif
+    err |= __put_user(h2g(&frame->mctx), &sc->regs);
+    err |= __put_user(sig, &sc->signal);
+
+    /* Save user regs.  */
+    err |= save_user_regs(env, &frame->mctx, TARGET_NR_sigreturn);
+
+    /* The kernel checks for the presence of a VDSO here.  We don't
+       emulate a vdso, so use a sigreturn system call.  */
+    env->lr = (target_ulong) h2g(frame->mctx.tramp);
+
+    /* Turn off all fp exceptions.  */
+    env->fpscr = 0;
+
+    /* Create a stack frame for the caller of the handler.  */
+    newsp = frame_addr - SIGNAL_FRAMESIZE;
+    err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
+
+    if (err)
+        goto sigsegv;
+
+    /* Set up registers for signal handler.  */
+    env->gpr[1] = newsp;
+    env->gpr[3] = signal;
+    env->gpr[4] = (target_ulong) h2g(sc);
+    env->nip = (target_ulong) ka->_sa_handler;
+    /* Signal handlers are entered in big-endian mode.  */
+    env->msr &= ~MSR_LE;
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    if (logfile)
+        fprintf (logfile, "segfaulting from setup_frame\n");
+    force_sig(SIGSEGV);
+}
+
+static void setup_rt_frame(int sig, struct target_sigaction *ka,
+                           target_siginfo_t *info,
+                           target_sigset_t *set, CPUState *env)
+{
+    struct target_rt_sigframe *rt_sf;
+    struct target_mcontext *frame;
+    target_ulong rt_sf_addr, newsp = 0;
+    int i, err = 0;
+    int signal;
+
+    rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
+    if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
+        goto sigsegv;
+
+    signal = current_exec_domain_sig(sig);
+
+    err |= copy_siginfo_to_user(&rt_sf->info, info);
+
+    err |= __put_user(0, &rt_sf->uc.uc_flags);
+    err |= __put_user(0, &rt_sf->uc.uc_link);
+    err |= __put_user((target_ulong)target_sigaltstack_used.ss_sp,
+                      &rt_sf->uc.uc_stack.ss_sp);
+    err |= __put_user(sas_ss_flags(env->gpr[1]),
+                      &rt_sf->uc.uc_stack.ss_flags);
+    err |= __put_user(target_sigaltstack_used.ss_size,
+                      &rt_sf->uc.uc_stack.ss_size);
+    err |= __put_user(h2g (&rt_sf->uc.uc_mcontext),
+                      &rt_sf->uc.uc_regs);
+    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+        err |= __put_user(set->sig[i], &rt_sf->uc.uc_sigmask.sig[i]);
+    }
+
+    frame = &rt_sf->uc.uc_mcontext;
+    err |= save_user_regs(env, frame, TARGET_NR_rt_sigreturn);
+
+    /* The kernel checks for the presence of a VDSO here.  We don't
+       emulate a vdso, so use a sigreturn system call.  */
+    env->lr = (target_ulong) h2g(frame->tramp);
+
+    /* Turn off all fp exceptions.  */
+    env->fpscr = 0;
+
+    /* Create a stack frame for the caller of the handler.  */
+    newsp = rt_sf_addr - (SIGNAL_FRAMESIZE + 16);
+    err |= __put_user(env->gpr[1], (target_ulong *)(uintptr_t) newsp);
+
+    if (err)
+        goto sigsegv;
+
+    /* Set up registers for signal handler.  */
+    env->gpr[1] = newsp;
+    env->gpr[3] = (target_ulong) signal;
+    env->gpr[4] = (target_ulong) h2g(&rt_sf->info);
+    env->gpr[5] = (target_ulong) h2g(&rt_sf->uc);
+    env->gpr[6] = (target_ulong) h2g(rt_sf);
+    env->nip = (target_ulong) ka->_sa_handler;
+    /* Signal handlers are entered in big-endian mode.  */
+    env->msr &= ~MSR_LE;
+
+    unlock_user_struct(rt_sf, rt_sf_addr, 1);
+    return;
+
+sigsegv:
+    unlock_user_struct(rt_sf, rt_sf_addr, 1);
+    if (logfile)
+        fprintf (logfile, "segfaulting from setup_rt_frame\n");
+    force_sig(SIGSEGV);
+
+}
+
+long do_sigreturn(CPUState *env)
+{
+    struct target_sigcontext *sc = NULL;
+    struct target_mcontext *sr = NULL;
+    target_ulong sr_addr, sc_addr;
+    sigset_t blocked;
+    target_sigset_t set;
+
+    sc_addr = env->gpr[1] + SIGNAL_FRAMESIZE;
+    if (!lock_user_struct(VERIFY_READ, sc, sc_addr, 1))
+        goto sigsegv;
+
+#if defined(TARGET_PPC64)
+    set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
+#else
+    if(__get_user(set.sig[0], &sc->oldmask) ||
+       __get_user(set.sig[1], &sc->_unused[3]))
+       goto sigsegv;
+#endif
+    target_to_host_sigset_internal(&blocked, &set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+
+    if (__get_user(sr_addr, &sc->regs))
+        goto sigsegv;
+    if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
+        goto sigsegv;
+    if (restore_user_regs(env, sr, 1))
+        goto sigsegv;
+
+    unlock_user_struct(sr, sr_addr, 1);
+    unlock_user_struct(sc, sc_addr, 1);
+    return -TARGET_QEMU_ESIGRETURN;
+
+sigsegv:
+    unlock_user_struct(sr, sr_addr, 1);
+    unlock_user_struct(sc, sc_addr, 1);
+    if (logfile)
+        fprintf (logfile, "segfaulting from do_sigreturn\n");
+    force_sig(SIGSEGV);
+    return 0;
+}
+
+/* See arch/powerpc/kernel/signal_32.c.  */
+static int do_setcontext(struct target_ucontext *ucp, CPUState *env, int sig)
+{
+    struct target_mcontext *mcp;
+    target_ulong mcp_addr;
+    sigset_t blocked;
+    target_sigset_t set;
+
+    if (copy_from_user(&set, h2g(ucp) + offsetof(struct target_ucontext, uc_sigmask),
+                       sizeof (set)))
+        return 1;
+
+#if defined(TARGET_PPC64)
+    fprintf (stderr, "do_setcontext: not implemented\n");
+    return 0;
+#else
+    if (__get_user(mcp_addr, &ucp->uc_regs))
+        return 1;
+
+    if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
+        return 1;
+
+    target_to_host_sigset_internal(&blocked, &set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
+    if (restore_user_regs(env, mcp, sig))
+        goto sigsegv;
+
+    unlock_user_struct(mcp, mcp_addr, 1);
+    return 0;
+
+sigsegv:
+    unlock_user_struct(mcp, mcp_addr, 1);
+    return 1;
+#endif
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    struct target_rt_sigframe *rt_sf = NULL;
+    target_ulong rt_sf_addr;
+
+    rt_sf_addr = env->gpr[1] + SIGNAL_FRAMESIZE + 16;
+    if (!lock_user_struct(VERIFY_READ, rt_sf, rt_sf_addr, 1))
+        goto sigsegv;
+
+    if (do_setcontext(&rt_sf->uc, env, 1))
+        goto sigsegv;
+
+    do_sigaltstack(rt_sf_addr
+                   + offsetof(struct target_rt_sigframe, uc.uc_stack),
+                   0, env->gpr[1]);
+
+    unlock_user_struct(rt_sf, rt_sf_addr, 1);
+    return -TARGET_QEMU_ESIGRETURN;
+
+sigsegv:
+    unlock_user_struct(rt_sf, rt_sf_addr, 1);
+    if (logfile)
+        fprintf (logfile, "segfaulting from do_rt_sigreturn\n");
+    force_sig(SIGSEGV);
+    return 0;
+}
+
 #else
 
 static void setup_frame(int sig, struct target_sigaction *ka,
-- 
1.6.0.5

  reply	other threads:[~2009-05-13  2:13 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-12 19:26 [Qemu-devel] [PATCH 0/3] linux-user: add ppc signal handling, v2 Nathan Froyd
2009-05-12 19:26 ` [Qemu-devel] [PATCH 1/3] target-ppc: expose cpu capability flags Nathan Froyd
2009-05-12 19:26 ` [Qemu-devel] [PATCH 2/3] linux-user: ppc signal handling Nathan Froyd
2009-05-13  2:13   ` Nathan Froyd [this message]
2009-05-12 19:26 ` [Qemu-devel] [PATCH 3/3] support ELF_HWCAP for PPPC Nathan Froyd
2009-05-12 23:13 ` [Qemu-devel] [PATCH 0/3] linux-user: add ppc signal handling, v2 malc
2009-05-13  2:15   ` Nathan Froyd
2009-05-13 11:27     ` malc
2009-05-13 11:37       ` Laurent Desnogues
2009-05-13 11:52         ` malc
  -- strict thread matches above, loose matches on Subject: below --
2009-04-22  2:32 [Qemu-devel] [PATCH 0/3] linux-user: add ppc signal handling Nathan Froyd
2009-04-22  2:32 ` [Qemu-devel] [PATCH 2/3] linux-user: " Nathan Froyd
2009-04-23  1:22   ` malc
2009-04-23  1:55     ` Nathan Froyd
2009-04-23 14:44       ` malc
2009-04-23 16:11         ` Nathan Froyd
2009-04-23 23:18           ` malc

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090513021318.GV23911@codesourcery.com \
    --to=froydnj@codesourcery.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.