All of lore.kernel.org
 help / color / mirror / Atom feed
From: Laurent Vivier <laurent@vivier.eu>
To: qemu-devel@nongnu.org
Cc: "Laurent Vivier" <laurent@vivier.eu>,
	"Peter Maydell" <peter.maydell@linaro.org>,
	"Philippe Mathieu-Daudé" <f4bug@amsat.org>,
	"Cornelia Huck" <cohuck@redhat.com>,
	"Riku Voipio" <riku.voipio@iki.fi>,
	qemu-s390x@nongnu.org
Subject: [Qemu-devel] [PATCH for 2.13 v2 19/20] linux-user: move ppc/ppc64 signal.c parts to ppc directory
Date: Fri, 23 Mar 2018 23:57:38 +0100	[thread overview]
Message-ID: <20180323225739.17329-20-laurent@vivier.eu> (raw)
In-Reply-To: <20180323225739.17329-1-laurent@vivier.eu>

No code change, only move code from signal.c to
ppc/signal.c, except adding includes and
exporting setup_frame() and setup_rt_frame().

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
---
 linux-user/ppc/signal.c        | 671 +++++++++++++++++++++++++++++++++++++++++
 linux-user/ppc/target_signal.h |   8 +-
 linux-user/signal.c            | 670 ----------------------------------------
 3 files changed, 678 insertions(+), 671 deletions(-)

diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c
index 02ca338b6c..15148d54a9 100644
--- a/linux-user/ppc/signal.c
+++ b/linux-user/ppc/signal.c
@@ -16,3 +16,674 @@
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
+#include "qemu/osdep.h"
+#include "qemu.h"
+#include "target_signal.h"
+#include "signal-common.h"
+#include "linux-user/trace.h"
+
+/* 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/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];
+#if defined(TARGET_PPC64)
+    /* Pointer to the vector regs */
+    target_ulong v_regs;
+#else
+    target_ulong mc_pad[2];
+#endif
+    /* 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.
+           We also need to account for the VSX registers on PPC64
+        */
+#if defined(TARGET_PPC64)
+#define QEMU_NVRREG (34 + 16)
+        /* On ppc64, this mcontext structure is naturally *unaligned*,
+         * or rather it is aligned on a 8 bytes boundary but not on
+         * a 16 bytes one. This pad fixes it up. This is also why the
+         * vector regs are referenced by the v_regs pointer above so
+         * any amount of padding can be added here
+         */
+        target_ulong pad;
+#else
+        /* On ppc32, we are already aligned to 16 bytes */
+#define QEMU_NVRREG 33
+#endif
+        /* We cannot use ppc_avr_t here as we do *not* want the implied
+         * 16-bytes alignment that would result from it. This would have
+         * the effect of making the whole struct target_mcontext aligned
+         * which breaks the layout of struct target_ucontext on ppc64.
+         */
+        uint64_t altivec[QEMU_NVRREG][2];
+#undef QEMU_NVRREG
+    } mc_vregs;
+};
+
+/* 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 * */
+#if defined(TARGET_PPC64)
+    struct target_mcontext mcontext;
+#endif
+};
+
+/* 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
+};
+
+
+struct target_ucontext {
+    target_ulong tuc_flags;
+    target_ulong tuc_link;    /* ucontext_t __user * */
+    struct target_sigaltstack tuc_stack;
+#if !defined(TARGET_PPC64)
+    int32_t tuc_pad[7];
+    target_ulong tuc_regs;    /* struct mcontext __user *
+                                points to uc_mcontext field */
+#endif
+    target_sigset_t tuc_sigmask;
+#if defined(TARGET_PPC64)
+    target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
+    struct target_sigcontext tuc_sigcontext;
+#else
+    int32_t tuc_maskext[30];
+    int32_t tuc_pad2[3];
+    struct target_mcontext tuc_mcontext;
+#endif
+};
+
+/* See arch/powerpc/kernel/signal_32.c.  */
+struct target_sigframe {
+    struct target_sigcontext sctx;
+    struct target_mcontext mctx;
+    int32_t abigap[56];
+};
+
+#if defined(TARGET_PPC64)
+
+#define TARGET_TRAMP_SIZE 6
+
+struct target_rt_sigframe {
+    /* sys_rt_sigreturn requires the ucontext be the first field */
+    struct target_ucontext uc;
+    target_ulong  _unused[2];
+    uint32_t trampoline[TARGET_TRAMP_SIZE];
+    target_ulong pinfo; /* struct siginfo __user * */
+    target_ulong puc; /* void __user * */
+    struct target_siginfo info;
+    /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
+    char abigap[288];
+} __attribute__((aligned(16)));
+
+#else
+
+struct target_rt_sigframe {
+    struct target_siginfo info;
+    struct target_ucontext uc;
+    int32_t abigap[56];
+};
+
+#endif
+
+#if defined(TARGET_PPC64)
+
+struct target_func_ptr {
+    target_ulong entry;
+    target_ulong toc;
+};
+
+#endif
+
+/* 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,
+                                 CPUPPCState *env,
+                                 int frame_size)
+{
+    target_ulong oldsp;
+
+    oldsp = env->gpr[1];
+
+    if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
+            (sas_ss_flags(oldsp) == 0)) {
+        oldsp = (target_sigaltstack_used.ss_sp
+                 + target_sigaltstack_used.ss_size);
+    }
+
+    return (oldsp - frame_size) & ~0xFUL;
+}
+
+#if ((defined(TARGET_WORDS_BIGENDIAN) && defined(HOST_WORDS_BIGENDIAN)) || \
+     (!defined(HOST_WORDS_BIGENDIAN) && !defined(TARGET_WORDS_BIGENDIAN)))
+#define PPC_VEC_HI      0
+#define PPC_VEC_LO      1
+#else
+#define PPC_VEC_HI      1
+#define PPC_VEC_LO      0
+#endif
+
+
+static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
+{
+    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++) {
+        __put_user(env->gpr[i], &frame->mc_gregs[i]);
+    }
+    __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]);
+
+    for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
+        ccr |= env->crf[i] << (32 - ((i + 1) * 4));
+    }
+    __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
+
+    /* Save Altivec registers if necessary.  */
+    if (env->insns_flags & PPC_ALTIVEC) {
+        uint32_t *vrsave;
+        for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
+            ppc_avr_t *avr = &env->avr[i];
+            ppc_avr_t *vreg = (ppc_avr_t *)&frame->mc_vregs.altivec[i];
+
+            __put_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]);
+            __put_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]);
+        }
+        /* Set MSR_VR in the saved MSR value to indicate that
+           frame->mc_vregs contains valid data.  */
+        msr |= MSR_VR;
+#if defined(TARGET_PPC64)
+        vrsave = (uint32_t *)&frame->mc_vregs.altivec[33];
+        /* 64-bit needs to put a pointer to the vectors in the frame */
+        __put_user(h2g(frame->mc_vregs.altivec), &frame->v_regs);
+#else
+        vrsave = (uint32_t *)&frame->mc_vregs.altivec[32];
+#endif
+        __put_user((uint32_t)env->spr[SPR_VRSAVE], vrsave);
+    }
+
+    /* Save VSX second halves */
+    if (env->insns_flags2 & PPC2_VSX) {
+        uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34];
+        for (i = 0; i < ARRAY_SIZE(env->vsr); i++) {
+            __put_user(env->vsr[i], &vsregs[i]);
+        }
+    }
+
+    /* Save floating point registers.  */
+    if (env->insns_flags & PPC_FLOAT) {
+        for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
+            __put_user(env->fpr[i], &frame->mc_fregs[i]);
+        }
+        __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
+    }
+
+    /* 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++) {
+            __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
+        }
+#else
+        for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
+            __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
+        }
+#endif
+        /* Set MSR_SPE in the saved MSR value to indicate that
+           frame->mc_vregs contains valid data.  */
+        msr |= MSR_SPE;
+        __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
+    }
+
+    /* Store MSR.  */
+    __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
+}
+
+static void encode_trampoline(int sigret, uint32_t *tramp)
+{
+    /* Set up the sigreturn trampoline: li r0,sigret; sc.  */
+    if (sigret) {
+        __put_user(0x38000000 | sigret, &tramp[0]);
+        __put_user(0x44000002, &tramp[1]);
+    }
+}
+
+static void restore_user_regs(CPUPPCState *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++) {
+        __get_user(env->gpr[i], &frame->mc_gregs[i]);
+    }
+    __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]);
+    __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
+
+    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.  */
+    __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
+
+    /* If doing signal return, restore the previous little-endian mode.  */
+    if (sig)
+        env->msr = (env->msr & ~(1ull << MSR_LE)) | (msr & (1ull << MSR_LE));
+
+    /* Restore Altivec registers if necessary.  */
+    if (env->insns_flags & PPC_ALTIVEC) {
+        ppc_avr_t *v_regs;
+        uint32_t *vrsave;
+#if defined(TARGET_PPC64)
+        uint64_t v_addr;
+        /* 64-bit needs to recover the pointer to the vectors from the frame */
+        __get_user(v_addr, &frame->v_regs);
+        v_regs = g2h(v_addr);
+#else
+        v_regs = (ppc_avr_t *)frame->mc_vregs.altivec;
+#endif
+        for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
+            ppc_avr_t *avr = &env->avr[i];
+            ppc_avr_t *vreg = &v_regs[i];
+
+            __get_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]);
+            __get_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]);
+        }
+        /* Set MSR_VEC in the saved MSR value to indicate that
+           frame->mc_vregs contains valid data.  */
+#if defined(TARGET_PPC64)
+        vrsave = (uint32_t *)&v_regs[33];
+#else
+        vrsave = (uint32_t *)&v_regs[32];
+#endif
+        __get_user(env->spr[SPR_VRSAVE], vrsave);
+    }
+
+    /* Restore VSX second halves */
+    if (env->insns_flags2 & PPC2_VSX) {
+        uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34];
+        for (i = 0; i < ARRAY_SIZE(env->vsr); i++) {
+            __get_user(env->vsr[i], &vsregs[i]);
+        }
+    }
+
+    /* Restore floating point registers.  */
+    if (env->insns_flags & PPC_FLOAT) {
+        uint64_t fpscr;
+        for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
+            __get_user(env->fpr[i], &frame->mc_fregs[i]);
+        }
+        __get_user(fpscr, &frame->mc_fregs[32]);
+        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;
+
+            __get_user(hi, &frame->mc_vregs.spe[i]);
+            env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
+        }
+#else
+        for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
+            __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
+        }
+#endif
+        __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
+    }
+}
+
+#if !defined(TARGET_PPC64)
+void setup_frame(int sig, struct target_sigaction *ka,
+                 target_sigset_t *set, CPUPPCState *env)
+{
+    struct target_sigframe *frame;
+    struct target_sigcontext *sc;
+    target_ulong frame_addr, newsp;
+    int err = 0;
+
+    frame_addr = get_sigframe(ka, env, sizeof(*frame));
+    trace_user_setup_frame(env, frame_addr);
+    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
+        goto sigsegv;
+    sc = &frame->sctx;
+
+    __put_user(ka->_sa_handler, &sc->handler);
+    __put_user(set->sig[0], &sc->oldmask);
+    __put_user(set->sig[1], &sc->_unused[3]);
+    __put_user(h2g(&frame->mctx), &sc->regs);
+    __put_user(sig, &sc->signal);
+
+    /* Save user regs.  */
+    save_user_regs(env, &frame->mctx);
+
+    /* Construct the trampoline code on the stack. */
+    encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
+
+    /* 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], newsp, target_ulong);
+
+    if (err)
+        goto sigsegv;
+
+    /* Set up registers for signal handler.  */
+    env->gpr[1] = newsp;
+    env->gpr[3] = sig;
+    env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
+
+    env->nip = (target_ulong) ka->_sa_handler;
+
+    /* Signal handlers are entered in big-endian mode.  */
+    env->msr &= ~(1ull << MSR_LE);
+
+    unlock_user_struct(frame, frame_addr, 1);
+    return;
+
+sigsegv:
+    unlock_user_struct(frame, frame_addr, 1);
+    force_sigsegv(sig);
+}
+#endif /* !defined(TARGET_PPC64) */
+
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+                    target_siginfo_t *info,
+                    target_sigset_t *set, CPUPPCState *env)
+{
+    struct target_rt_sigframe *rt_sf;
+    uint32_t *trampptr = 0;
+    struct target_mcontext *mctx = 0;
+    target_ulong rt_sf_addr, newsp = 0;
+    int i, err = 0;
+#if defined(TARGET_PPC64)
+    struct target_sigcontext *sc = 0;
+    struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
+#endif
+
+    rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
+    if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
+        goto sigsegv;
+
+    tswap_siginfo(&rt_sf->info, info);
+
+    __put_user(0, &rt_sf->uc.tuc_flags);
+    __put_user(0, &rt_sf->uc.tuc_link);
+    __put_user((target_ulong)target_sigaltstack_used.ss_sp,
+               &rt_sf->uc.tuc_stack.ss_sp);
+    __put_user(sas_ss_flags(env->gpr[1]),
+               &rt_sf->uc.tuc_stack.ss_flags);
+    __put_user(target_sigaltstack_used.ss_size,
+               &rt_sf->uc.tuc_stack.ss_size);
+#if !defined(TARGET_PPC64)
+    __put_user(h2g (&rt_sf->uc.tuc_mcontext),
+               &rt_sf->uc.tuc_regs);
+#endif
+    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+        __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
+    }
+
+#if defined(TARGET_PPC64)
+    mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
+    trampptr = &rt_sf->trampoline[0];
+
+    sc = &rt_sf->uc.tuc_sigcontext;
+    __put_user(h2g(mctx), &sc->regs);
+    __put_user(sig, &sc->signal);
+#else
+    mctx = &rt_sf->uc.tuc_mcontext;
+    trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
+#endif
+
+    save_user_regs(env, mctx);
+    encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
+
+    /* 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(trampptr);
+
+    /* 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], newsp, target_ulong);
+
+    if (err)
+        goto sigsegv;
+
+    /* Set up registers for signal handler.  */
+    env->gpr[1] = newsp;
+    env->gpr[3] = (target_ulong) sig;
+    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);
+
+#if defined(TARGET_PPC64)
+    if (get_ppc64_abi(image) < 2) {
+        /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
+        struct target_func_ptr *handler =
+            (struct target_func_ptr *)g2h(ka->_sa_handler);
+        env->nip = tswapl(handler->entry);
+        env->gpr[2] = tswapl(handler->toc);
+    } else {
+        /* ELFv2 PPC64 function pointers are entry points, but R12
+         * must also be set */
+        env->nip = tswapl((target_ulong) ka->_sa_handler);
+        env->gpr[12] = env->nip;
+    }
+#else
+    env->nip = (target_ulong) ka->_sa_handler;
+#endif
+
+    /* Signal handlers are entered in big-endian mode.  */
+    env->msr &= ~(1ull << MSR_LE);
+
+    unlock_user_struct(rt_sf, rt_sf_addr, 1);
+    return;
+
+sigsegv:
+    unlock_user_struct(rt_sf, rt_sf_addr, 1);
+    force_sigsegv(sig);
+
+}
+
+#if !defined(TARGET_PPC64)
+long do_sigreturn(CPUPPCState *env)
+{
+    struct target_sigcontext *sc = NULL;
+    struct target_mcontext *sr = NULL;
+    target_ulong sr_addr = 0, 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 + ((uint64_t)(sc->_unused[3]) << 32);
+#else
+    __get_user(set.sig[0], &sc->oldmask);
+    __get_user(set.sig[1], &sc->_unused[3]);
+#endif
+    target_to_host_sigset_internal(&blocked, &set);
+    set_sigmask(&blocked);
+
+    __get_user(sr_addr, &sc->regs);
+    if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
+        goto sigsegv;
+    restore_user_regs(env, sr, 1);
+
+    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);
+    force_sig(TARGET_SIGSEGV);
+    return -TARGET_QEMU_ESIGRETURN;
+}
+#endif /* !defined(TARGET_PPC64) */
+
+/* See arch/powerpc/kernel/signal_32.c.  */
+static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *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, tuc_sigmask),
+                       sizeof (set)))
+        return 1;
+
+#if defined(TARGET_PPC64)
+    mcp_addr = h2g(ucp) +
+        offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
+#else
+    __get_user(mcp_addr, &ucp->tuc_regs);
+#endif
+
+    if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
+        return 1;
+
+    target_to_host_sigset_internal(&blocked, &set);
+    set_sigmask(&blocked);
+    restore_user_regs(env, mcp, sig);
+
+    unlock_user_struct(mcp, mcp_addr, 1);
+    return 0;
+}
+
+long do_rt_sigreturn(CPUPPCState *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.tuc_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);
+    force_sig(TARGET_SIGSEGV);
+    return -TARGET_QEMU_ESIGRETURN;
+}
diff --git a/linux-user/ppc/target_signal.h b/linux-user/ppc/target_signal.h
index 865c52f3e8..5e293e3b03 100644
--- a/linux-user/ppc/target_signal.h
+++ b/linux-user/ppc/target_signal.h
@@ -26,5 +26,11 @@ static inline abi_ulong get_sp_from_cpustate(CPUPPCState *state)
     return state->gpr[1];
 }
 
-
+#if !defined(TARGET_PPC64)
+void setup_frame(int sig, struct target_sigaction *ka,
+                 target_sigset_t *set, CPUPPCState *env);
+#endif
+void setup_rt_frame(int sig, struct target_sigaction *ka,
+                    target_siginfo_t *info,
+                    target_sigset_t *set, CPUPPCState *env);
 #endif /* PPC_TARGET_SIGNAL_H */
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 92d7347b14..7f435c4606 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -803,676 +803,6 @@ int do_sigaction(int sig, const struct target_sigaction *act,
     return ret;
 }
 
-#if defined(TARGET_PPC)
-
-/* 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/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];
-#if defined(TARGET_PPC64)
-    /* Pointer to the vector regs */
-    target_ulong v_regs;
-#else
-    target_ulong mc_pad[2];
-#endif
-    /* 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.
-           We also need to account for the VSX registers on PPC64
-        */
-#if defined(TARGET_PPC64)
-#define QEMU_NVRREG (34 + 16)
-        /* On ppc64, this mcontext structure is naturally *unaligned*,
-         * or rather it is aligned on a 8 bytes boundary but not on
-         * a 16 bytes one. This pad fixes it up. This is also why the
-         * vector regs are referenced by the v_regs pointer above so
-         * any amount of padding can be added here
-         */
-        target_ulong pad;
-#else
-        /* On ppc32, we are already aligned to 16 bytes */
-#define QEMU_NVRREG 33
-#endif
-        /* We cannot use ppc_avr_t here as we do *not* want the implied
-         * 16-bytes alignment that would result from it. This would have
-         * the effect of making the whole struct target_mcontext aligned
-         * which breaks the layout of struct target_ucontext on ppc64.
-         */
-        uint64_t altivec[QEMU_NVRREG][2];
-#undef QEMU_NVRREG
-    } mc_vregs;
-};
-
-/* 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 * */
-#if defined(TARGET_PPC64)
-    struct target_mcontext mcontext;
-#endif
-};
-
-/* 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
-};
-
-
-struct target_ucontext {
-    target_ulong tuc_flags;
-    target_ulong tuc_link;    /* ucontext_t __user * */
-    struct target_sigaltstack tuc_stack;
-#if !defined(TARGET_PPC64)
-    int32_t tuc_pad[7];
-    target_ulong tuc_regs;    /* struct mcontext __user *
-                                points to uc_mcontext field */
-#endif
-    target_sigset_t tuc_sigmask;
-#if defined(TARGET_PPC64)
-    target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
-    struct target_sigcontext tuc_sigcontext;
-#else
-    int32_t tuc_maskext[30];
-    int32_t tuc_pad2[3];
-    struct target_mcontext tuc_mcontext;
-#endif
-};
-
-/* See arch/powerpc/kernel/signal_32.c.  */
-struct target_sigframe {
-    struct target_sigcontext sctx;
-    struct target_mcontext mctx;
-    int32_t abigap[56];
-};
-
-#if defined(TARGET_PPC64)
-
-#define TARGET_TRAMP_SIZE 6
-
-struct target_rt_sigframe {
-    /* sys_rt_sigreturn requires the ucontext be the first field */
-    struct target_ucontext uc;
-    target_ulong  _unused[2];
-    uint32_t trampoline[TARGET_TRAMP_SIZE];
-    target_ulong pinfo; /* struct siginfo __user * */
-    target_ulong puc; /* void __user * */
-    struct target_siginfo info;
-    /* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
-    char abigap[288];
-} __attribute__((aligned(16)));
-
-#else
-
-struct target_rt_sigframe {
-    struct target_siginfo info;
-    struct target_ucontext uc;
-    int32_t abigap[56];
-};
-
-#endif
-
-#if defined(TARGET_PPC64)
-
-struct target_func_ptr {
-    target_ulong entry;
-    target_ulong toc;
-};
-
-#endif
-
-/* 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,
-                                 CPUPPCState *env,
-                                 int frame_size)
-{
-    target_ulong oldsp;
-
-    oldsp = env->gpr[1];
-
-    if ((ka->sa_flags & TARGET_SA_ONSTACK) &&
-            (sas_ss_flags(oldsp) == 0)) {
-        oldsp = (target_sigaltstack_used.ss_sp
-                 + target_sigaltstack_used.ss_size);
-    }
-
-    return (oldsp - frame_size) & ~0xFUL;
-}
-
-#if ((defined(TARGET_WORDS_BIGENDIAN) && defined(HOST_WORDS_BIGENDIAN)) || \
-     (!defined(HOST_WORDS_BIGENDIAN) && !defined(TARGET_WORDS_BIGENDIAN)))
-#define PPC_VEC_HI      0
-#define PPC_VEC_LO      1
-#else
-#define PPC_VEC_HI      1
-#define PPC_VEC_LO      0
-#endif
-
-
-static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
-{
-    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++) {
-        __put_user(env->gpr[i], &frame->mc_gregs[i]);
-    }
-    __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]);
-
-    for (i = 0; i < ARRAY_SIZE(env->crf); i++) {
-        ccr |= env->crf[i] << (32 - ((i + 1) * 4));
-    }
-    __put_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
-
-    /* Save Altivec registers if necessary.  */
-    if (env->insns_flags & PPC_ALTIVEC) {
-        uint32_t *vrsave;
-        for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
-            ppc_avr_t *avr = &env->avr[i];
-            ppc_avr_t *vreg = (ppc_avr_t *)&frame->mc_vregs.altivec[i];
-
-            __put_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]);
-            __put_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]);
-        }
-        /* Set MSR_VR in the saved MSR value to indicate that
-           frame->mc_vregs contains valid data.  */
-        msr |= MSR_VR;
-#if defined(TARGET_PPC64)
-        vrsave = (uint32_t *)&frame->mc_vregs.altivec[33];
-        /* 64-bit needs to put a pointer to the vectors in the frame */
-        __put_user(h2g(frame->mc_vregs.altivec), &frame->v_regs);
-#else
-        vrsave = (uint32_t *)&frame->mc_vregs.altivec[32];
-#endif
-        __put_user((uint32_t)env->spr[SPR_VRSAVE], vrsave);
-    }
-
-    /* Save VSX second halves */
-    if (env->insns_flags2 & PPC2_VSX) {
-        uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34];
-        for (i = 0; i < ARRAY_SIZE(env->vsr); i++) {
-            __put_user(env->vsr[i], &vsregs[i]);
-        }
-    }
-
-    /* Save floating point registers.  */
-    if (env->insns_flags & PPC_FLOAT) {
-        for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
-            __put_user(env->fpr[i], &frame->mc_fregs[i]);
-        }
-        __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]);
-    }
-
-    /* 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++) {
-            __put_user(env->gpr[i] >> 32, &frame->mc_vregs.spe[i]);
-        }
-#else
-        for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
-            __put_user(env->gprh[i], &frame->mc_vregs.spe[i]);
-        }
-#endif
-        /* Set MSR_SPE in the saved MSR value to indicate that
-           frame->mc_vregs contains valid data.  */
-        msr |= MSR_SPE;
-        __put_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
-    }
-
-    /* Store MSR.  */
-    __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
-}
-
-static void encode_trampoline(int sigret, uint32_t *tramp)
-{
-    /* Set up the sigreturn trampoline: li r0,sigret; sc.  */
-    if (sigret) {
-        __put_user(0x38000000 | sigret, &tramp[0]);
-        __put_user(0x44000002, &tramp[1]);
-    }
-}
-
-static void restore_user_regs(CPUPPCState *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++) {
-        __get_user(env->gpr[i], &frame->mc_gregs[i]);
-    }
-    __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]);
-    __get_user(ccr, &frame->mc_gregs[TARGET_PT_CCR]);
-
-    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.  */
-    __get_user(msr, &frame->mc_gregs[TARGET_PT_MSR]);
-
-    /* If doing signal return, restore the previous little-endian mode.  */
-    if (sig)
-        env->msr = (env->msr & ~(1ull << MSR_LE)) | (msr & (1ull << MSR_LE));
-
-    /* Restore Altivec registers if necessary.  */
-    if (env->insns_flags & PPC_ALTIVEC) {
-        ppc_avr_t *v_regs;
-        uint32_t *vrsave;
-#if defined(TARGET_PPC64)
-        uint64_t v_addr;
-        /* 64-bit needs to recover the pointer to the vectors from the frame */
-        __get_user(v_addr, &frame->v_regs);
-        v_regs = g2h(v_addr);
-#else
-        v_regs = (ppc_avr_t *)frame->mc_vregs.altivec;
-#endif
-        for (i = 0; i < ARRAY_SIZE(env->avr); i++) {
-            ppc_avr_t *avr = &env->avr[i];
-            ppc_avr_t *vreg = &v_regs[i];
-
-            __get_user(avr->u64[PPC_VEC_HI], &vreg->u64[0]);
-            __get_user(avr->u64[PPC_VEC_LO], &vreg->u64[1]);
-        }
-        /* Set MSR_VEC in the saved MSR value to indicate that
-           frame->mc_vregs contains valid data.  */
-#if defined(TARGET_PPC64)
-        vrsave = (uint32_t *)&v_regs[33];
-#else
-        vrsave = (uint32_t *)&v_regs[32];
-#endif
-        __get_user(env->spr[SPR_VRSAVE], vrsave);
-    }
-
-    /* Restore VSX second halves */
-    if (env->insns_flags2 & PPC2_VSX) {
-        uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34];
-        for (i = 0; i < ARRAY_SIZE(env->vsr); i++) {
-            __get_user(env->vsr[i], &vsregs[i]);
-        }
-    }
-
-    /* Restore floating point registers.  */
-    if (env->insns_flags & PPC_FLOAT) {
-        uint64_t fpscr;
-        for (i = 0; i < ARRAY_SIZE(env->fpr); i++) {
-            __get_user(env->fpr[i], &frame->mc_fregs[i]);
-        }
-        __get_user(fpscr, &frame->mc_fregs[32]);
-        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;
-
-            __get_user(hi, &frame->mc_vregs.spe[i]);
-            env->gpr[i] = ((uint64_t)hi << 32) | ((uint32_t) env->gpr[i]);
-        }
-#else
-        for (i = 0; i < ARRAY_SIZE(env->gprh); i++) {
-            __get_user(env->gprh[i], &frame->mc_vregs.spe[i]);
-        }
-#endif
-        __get_user(env->spe_fscr, &frame->mc_vregs.spe[32]);
-    }
-}
-
-#if !defined(TARGET_PPC64)
-static void setup_frame(int sig, struct target_sigaction *ka,
-                        target_sigset_t *set, CPUPPCState *env)
-{
-    struct target_sigframe *frame;
-    struct target_sigcontext *sc;
-    target_ulong frame_addr, newsp;
-    int err = 0;
-
-    frame_addr = get_sigframe(ka, env, sizeof(*frame));
-    trace_user_setup_frame(env, frame_addr);
-    if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1))
-        goto sigsegv;
-    sc = &frame->sctx;
-
-    __put_user(ka->_sa_handler, &sc->handler);
-    __put_user(set->sig[0], &sc->oldmask);
-    __put_user(set->sig[1], &sc->_unused[3]);
-    __put_user(h2g(&frame->mctx), &sc->regs);
-    __put_user(sig, &sc->signal);
-
-    /* Save user regs.  */
-    save_user_regs(env, &frame->mctx);
-
-    /* Construct the trampoline code on the stack. */
-    encode_trampoline(TARGET_NR_sigreturn, (uint32_t *)&frame->mctx.tramp);
-
-    /* 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], newsp, target_ulong);
-
-    if (err)
-        goto sigsegv;
-
-    /* Set up registers for signal handler.  */
-    env->gpr[1] = newsp;
-    env->gpr[3] = sig;
-    env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
-
-    env->nip = (target_ulong) ka->_sa_handler;
-
-    /* Signal handlers are entered in big-endian mode.  */
-    env->msr &= ~(1ull << MSR_LE);
-
-    unlock_user_struct(frame, frame_addr, 1);
-    return;
-
-sigsegv:
-    unlock_user_struct(frame, frame_addr, 1);
-    force_sigsegv(sig);
-}
-#endif /* !defined(TARGET_PPC64) */
-
-static void setup_rt_frame(int sig, struct target_sigaction *ka,
-                           target_siginfo_t *info,
-                           target_sigset_t *set, CPUPPCState *env)
-{
-    struct target_rt_sigframe *rt_sf;
-    uint32_t *trampptr = 0;
-    struct target_mcontext *mctx = 0;
-    target_ulong rt_sf_addr, newsp = 0;
-    int i, err = 0;
-#if defined(TARGET_PPC64)
-    struct target_sigcontext *sc = 0;
-    struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
-#endif
-
-    rt_sf_addr = get_sigframe(ka, env, sizeof(*rt_sf));
-    if (!lock_user_struct(VERIFY_WRITE, rt_sf, rt_sf_addr, 1))
-        goto sigsegv;
-
-    tswap_siginfo(&rt_sf->info, info);
-
-    __put_user(0, &rt_sf->uc.tuc_flags);
-    __put_user(0, &rt_sf->uc.tuc_link);
-    __put_user((target_ulong)target_sigaltstack_used.ss_sp,
-               &rt_sf->uc.tuc_stack.ss_sp);
-    __put_user(sas_ss_flags(env->gpr[1]),
-               &rt_sf->uc.tuc_stack.ss_flags);
-    __put_user(target_sigaltstack_used.ss_size,
-               &rt_sf->uc.tuc_stack.ss_size);
-#if !defined(TARGET_PPC64)
-    __put_user(h2g (&rt_sf->uc.tuc_mcontext),
-               &rt_sf->uc.tuc_regs);
-#endif
-    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
-        __put_user(set->sig[i], &rt_sf->uc.tuc_sigmask.sig[i]);
-    }
-
-#if defined(TARGET_PPC64)
-    mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
-    trampptr = &rt_sf->trampoline[0];
-
-    sc = &rt_sf->uc.tuc_sigcontext;
-    __put_user(h2g(mctx), &sc->regs);
-    __put_user(sig, &sc->signal);
-#else
-    mctx = &rt_sf->uc.tuc_mcontext;
-    trampptr = (uint32_t *)&rt_sf->uc.tuc_mcontext.tramp;
-#endif
-
-    save_user_regs(env, mctx);
-    encode_trampoline(TARGET_NR_rt_sigreturn, trampptr);
-
-    /* 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(trampptr);
-
-    /* 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], newsp, target_ulong);
-
-    if (err)
-        goto sigsegv;
-
-    /* Set up registers for signal handler.  */
-    env->gpr[1] = newsp;
-    env->gpr[3] = (target_ulong) sig;
-    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);
-
-#if defined(TARGET_PPC64)
-    if (get_ppc64_abi(image) < 2) {
-        /* ELFv1 PPC64 function pointers are pointers to OPD entries. */
-        struct target_func_ptr *handler =
-            (struct target_func_ptr *)g2h(ka->_sa_handler);
-        env->nip = tswapl(handler->entry);
-        env->gpr[2] = tswapl(handler->toc);
-    } else {
-        /* ELFv2 PPC64 function pointers are entry points, but R12
-         * must also be set */
-        env->nip = tswapl((target_ulong) ka->_sa_handler);
-        env->gpr[12] = env->nip;
-    }
-#else
-    env->nip = (target_ulong) ka->_sa_handler;
-#endif
-
-    /* Signal handlers are entered in big-endian mode.  */
-    env->msr &= ~(1ull << MSR_LE);
-
-    unlock_user_struct(rt_sf, rt_sf_addr, 1);
-    return;
-
-sigsegv:
-    unlock_user_struct(rt_sf, rt_sf_addr, 1);
-    force_sigsegv(sig);
-
-}
-
-#if !defined(TARGET_PPC64)
-long do_sigreturn(CPUPPCState *env)
-{
-    struct target_sigcontext *sc = NULL;
-    struct target_mcontext *sr = NULL;
-    target_ulong sr_addr = 0, 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 + ((uint64_t)(sc->_unused[3]) << 32);
-#else
-    __get_user(set.sig[0], &sc->oldmask);
-    __get_user(set.sig[1], &sc->_unused[3]);
-#endif
-    target_to_host_sigset_internal(&blocked, &set);
-    set_sigmask(&blocked);
-
-    __get_user(sr_addr, &sc->regs);
-    if (!lock_user_struct(VERIFY_READ, sr, sr_addr, 1))
-        goto sigsegv;
-    restore_user_regs(env, sr, 1);
-
-    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);
-    force_sig(TARGET_SIGSEGV);
-    return -TARGET_QEMU_ESIGRETURN;
-}
-#endif /* !defined(TARGET_PPC64) */
-
-/* See arch/powerpc/kernel/signal_32.c.  */
-static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *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, tuc_sigmask),
-                       sizeof (set)))
-        return 1;
-
-#if defined(TARGET_PPC64)
-    mcp_addr = h2g(ucp) +
-        offsetof(struct target_ucontext, tuc_sigcontext.mcontext);
-#else
-    __get_user(mcp_addr, &ucp->tuc_regs);
-#endif
-
-    if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))
-        return 1;
-
-    target_to_host_sigset_internal(&blocked, &set);
-    set_sigmask(&blocked);
-    restore_user_regs(env, mcp, sig);
-
-    unlock_user_struct(mcp, mcp_addr, 1);
-    return 0;
-}
-
-long do_rt_sigreturn(CPUPPCState *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.tuc_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);
-    force_sig(TARGET_SIGSEGV);
-    return -TARGET_QEMU_ESIGRETURN;
-}
-
-#endif
-
 static void handle_pending_signal(CPUArchState *cpu_env, int sig,
                                   struct emulated_sigtable *k)
 {
-- 
2.14.3

  parent reply	other threads:[~2018-03-23 22:58 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-23 22:57 [Qemu-devel] [PATCH for 2.13 v2 00/20] linux-user: move arch specific parts to arch directories Laurent Vivier
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 01/20] linux-user: create a dummy per arch signal.c Laurent Vivier
2018-03-28 13:55   ` Alex Bennée
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 02/20] linux-user: move aarch64 signal.c parts to aarch64 directory Laurent Vivier
2018-03-28 14:33   ` Alex Bennée
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 03/20] linux-user: move arm signal.c parts to arm directory Laurent Vivier
2018-03-28 14:34   ` Alex Bennée
2018-03-28 14:35   ` Alex Bennée
2018-03-28 14:40     ` Laurent Vivier
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 04/20] linux-user: move sh4 signal.c parts to sh4 directory Laurent Vivier
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 05/20] linux-user: move microblaze signal.c parts to microblaze directory Laurent Vivier
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 06/20] linux-user: move cris signal.c parts to cris directory Laurent Vivier
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 07/20] linux-user: move nios2 signal.c parts to nios2 directory Laurent Vivier
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 08/20] linux-user: move openrisc signal.c parts to openrisc directory Laurent Vivier
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 09/20] linux-user: move s390x signal.c parts to s390x directory Laurent Vivier
2018-03-27  8:47   ` Cornelia Huck
2018-03-27  9:13     ` Laurent Vivier
2018-03-27  9:33       ` Cornelia Huck
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 10/20] linux-user: move m68k signal.c parts to m68k directory Laurent Vivier
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 11/20] linux-user: move alpha signal.c parts to alpha directory Laurent Vivier
2018-03-24  0:58   ` Philippe Mathieu-Daudé
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 12/20] linux-user: move tilegx signal.c parts to tilegx directory Laurent Vivier
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 13/20] linux-user: move riscv signal.c parts to riscv directory Laurent Vivier
2018-03-24  1:04   ` Philippe Mathieu-Daudé
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 14/20] linux-user: move hppa signal.c parts to hppa directory Laurent Vivier
2018-03-24  1:05   ` Philippe Mathieu-Daudé
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 15/20] linux-user: move xtensa signal.c parts to xtensa directory Laurent Vivier
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 16/20] linux-user: move i386/x86_64 signal.c parts to i386 directory Laurent Vivier
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 17/20] linux-user: move sparc/sparc64 signal.c parts to sparc directory Laurent Vivier
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 18/20] linux-user: move mips/mips64 signal.c parts to mips directory Laurent Vivier
2018-03-24  0:57   ` Philippe Mathieu-Daudé
2018-03-23 22:57 ` Laurent Vivier [this message]
2018-03-23 22:57 ` [Qemu-devel] [PATCH for 2.13 v2 20/20] linux-user: define TARGET_ARCH_HAS_SETUP_FRAME Laurent Vivier
2018-03-24  0:32 ` [Qemu-devel] [PATCH for 2.13 v2 00/20] linux-user: move arch specific parts to arch directories no-reply
2018-03-28  5:56 ` Richard Henderson
2018-03-28 14:41 ` Alex Bennée
2018-03-28 14:44   ` Daniel P. Berrangé
2018-03-28 14:52   ` Laurent Vivier

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=20180323225739.17329-20-laurent@vivier.eu \
    --to=laurent@vivier.eu \
    --cc=cohuck@redhat.com \
    --cc=f4bug@amsat.org \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-s390x@nongnu.org \
    --cc=riku.voipio@iki.fi \
    /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.