All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Gibson <david@gibson.dropbear.id.au>
To: peter.maydell@linaro.org
Cc: agraf@suse.de, qemu-ppc@nongnu.org, qemu-devel@nongnu.org,
	Benjamin Herrenschmidt <benh@kernel.crashing.org>,
	David Gibson <david@gibson.dropbear.id.au>
Subject: [Qemu-devel] [PULL 08/45] ppc: Fix signal delivery in ppc-user and ppc64-user
Date: Fri, 23 Sep 2016 17:14:44 +1000	[thread overview]
Message-ID: <1474614921-2221-9-git-send-email-david@gibson.dropbear.id.au> (raw)
In-Reply-To: <1474614921-2221-1-git-send-email-david@gibson.dropbear.id.au>

From: Benjamin Herrenschmidt <benh@kernel.crashing.org>

There were a number of bugs in the implementation:

 - The structure alignment was wrong for 64-bit.

 - Also 64-bit only does RT signals.

 - On 64-bit, we need to put a pointer to the (aligned) vector registers
   in the frame and use it for restoring

 - We had endian bugs when saving/restoring vector registers

 - My recent fixes for exception NIP broke sigreturn in user mode
   causing us to resume one instruction too far.

 - Add VSR second halves

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
---
 linux-user/main.c           |   2 +-
 linux-user/ppc/syscall_nr.h |   2 +
 linux-user/signal.c         | 124 +++++++++++++++++++++++++++++++-------------
 3 files changed, 90 insertions(+), 38 deletions(-)

diff --git a/linux-user/main.c b/linux-user/main.c
index aba58c7..8daebe0 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1992,12 +1992,12 @@ void cpu_loop(CPUPPCState *env)
             if (ret == -TARGET_ERESTARTSYS) {
                 break;
             }
-            env->nip += 4;
             if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
                 /* Returning from a successful sigreturn syscall.
                    Avoid corrupting register state.  */
                 break;
             }
+            env->nip += 4;
             if (ret > (target_ulong)(-515)) {
                 env->crf[0] |= 0x1;
                 ret = -ret;
diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h
index 46ed8a6..afa3654 100644
--- a/linux-user/ppc/syscall_nr.h
+++ b/linux-user/ppc/syscall_nr.h
@@ -120,7 +120,9 @@
 #define TARGET_NR_sysinfo                116
 #define TARGET_NR_ipc                    117
 #define TARGET_NR_fsync                  118
+#if !defined(TARGET_PPC64)
 #define TARGET_NR_sigreturn              119
+#endif
 #define TARGET_NR_clone                  120
 #define TARGET_NR_setdomainname          121
 #define TARGET_NR_uname                  122
diff --git a/linux-user/signal.c b/linux-user/signal.c
index e4eea69..c750053 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -4454,7 +4454,12 @@ 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
@@ -4464,15 +4469,30 @@ struct target_mcontext {
         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.  */
+           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
+#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
-        ppc_avr_t altivec[QEMU_NVRREG];
+        /* 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 __attribute__((__aligned__(16)));
+    } mc_vregs;
 };
 
 /* See arch/powerpc/include/asm/sigcontext.h.  */
@@ -4626,6 +4646,16 @@ static target_ulong get_sigframe(struct target_sigaction *ka,
     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;
@@ -4652,18 +4682,33 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame)
 
     /* 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 = &frame->mc_vregs.altivec[i];
+            ppc_avr_t *vreg = (ppc_avr_t *)&frame->mc_vregs.altivec[i];
 
-            __put_user(avr->u64[0], &vreg->u64[0]);
-            __put_user(avr->u64[1], &vreg->u64[1]);
+            __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;
-        __put_user((uint32_t)env->spr[SPR_VRSAVE],
-                   &frame->mc_vregs.altivec[32].u32[3]);
+#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.  */
@@ -4743,17 +4788,39 @@ static void restore_user_regs(CPUPPCState *env,
 
     /* 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 = &frame->mc_vregs.altivec[i];
+            ppc_avr_t *vreg = &v_regs[i];
 
-            __get_user(avr->u64[0], &vreg->u64[0]);
-            __get_user(avr->u64[1], &vreg->u64[1]);
+            __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.  */
-        __get_user(env->spr[SPR_VRSAVE],
-                   (target_ulong *)(&frame->mc_vregs.altivec[32].u32[3]));
+#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.  */
@@ -4784,6 +4851,7 @@ static void restore_user_regs(CPUPPCState *env,
     }
 }
 
+#if !defined(TARGET_PPC64)
 static void setup_frame(int sig, struct target_sigaction *ka,
                         target_sigset_t *set, CPUPPCState *env)
 {
@@ -4791,9 +4859,6 @@ static void setup_frame(int sig, struct target_sigaction *ka,
     struct target_sigcontext *sc;
     target_ulong frame_addr, newsp;
     int err = 0;
-#if defined(TARGET_PPC64)
-    struct image_info *image = ((TaskState *)thread_cpu->opaque)->info;
-#endif
 
     frame_addr = get_sigframe(ka, env, sizeof(*frame));
     trace_user_setup_frame(env, frame_addr);
@@ -4803,11 +4868,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
 
     __put_user(ka->_sa_handler, &sc->handler);
     __put_user(set->sig[0], &sc->oldmask);
-#if TARGET_ABI_BITS == 64
-    __put_user(set->sig[0] >> 32, &sc->_unused[3]);
-#else
     __put_user(set->sig[1], &sc->_unused[3]);
-#endif
     __put_user(h2g(&frame->mctx), &sc->regs);
     __put_user(sig, &sc->signal);
 
@@ -4836,22 +4897,7 @@ static void setup_frame(int sig, struct target_sigaction *ka,
     env->gpr[3] = sig;
     env->gpr[4] = frame_addr + offsetof(struct target_sigframe, sctx);
 
-#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);
@@ -4863,6 +4909,7 @@ 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,
@@ -4960,6 +5007,7 @@ sigsegv:
 
 }
 
+#if !defined(TARGET_PPC64)
 long do_sigreturn(CPUPPCState *env)
 {
     struct target_sigcontext *sc = NULL;
@@ -4996,6 +5044,7 @@ sigsegv:
     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)
@@ -5939,7 +5988,8 @@ static void handle_pending_signal(CPUArchState *cpu_env, int sig,
 #endif
         /* prepare the stack frame of the virtual CPU */
 #if defined(TARGET_ABI_MIPSN32) || defined(TARGET_ABI_MIPSN64) \
-    || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX)
+        || defined(TARGET_OPENRISC) || defined(TARGET_TILEGX) \
+        || defined(TARGET_PPC64)
         /* These targets do not have traditional signals.  */
         setup_rt_frame(sig, sa, &k->info, &target_old_set, cpu_env);
 #else
-- 
2.7.4

  parent reply	other threads:[~2016-09-23  7:16 UTC|newest]

Thread overview: 48+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-23  7:14 [Qemu-devel] [PULL 00/45] ppc-for-2.8 queue 20160923 David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 01/45] MAINTAINERS: Add some missing ppc-related files David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 02/45] ppc: restrict the use of the rfi instruction David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 03/45] target-ppc: add vector insert instructions David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 04/45] target-ppc: add vector extract instructions David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 05/45] target-ppc: add vector count trailing zeros instructions David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 06/45] target-ppc: add vector bit permute doubleword instruction David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 07/45] target-ppc: add vector permute right indexed instruction David Gibson
2016-09-23  7:14 ` David Gibson [this message]
2016-09-23  7:14 ` [Qemu-devel] [PULL 09/45] qtest: replace strtoXX() by qemu_strtoXX() David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 10/45] libqos: define SPAPR libqos functions David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 11/45] tests: add RTAS command in the protocol David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 12/45] MAINTAINERS: add sPAPR tests David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 13/45] adb-keys.h: initial commit David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 14/45] adb.c: add support for QKeyCode David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 15/45] adb.c: correct several key assignments David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 16/45] adb.c: prevent NO_KEY value from going to guest David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 17/45] spapr_drc: convert to trace framework instead of DPRINTF David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 18/45] spapr_rtas: " David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 19/45] spapr_vio: " David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 20/45] spapr_llan: " David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 21/45] spapr_vscsi: " David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 22/45] target-ppc: consolidate load operations David Gibson
2016-09-23  7:14 ` [Qemu-devel] [PULL 23/45] target-ppc: convert ld64 to use new macro David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 24/45] target-ppc: convert ld[16, 32, 64]ur " David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 25/45] target-ppc: consolidate store operations David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 26/45] target-ppc: convert st64 to use new macro David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 27/45] target-ppc: convert st[16, 32, 64]r " David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 28/45] target-ppc: consolidate load with reservation David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 29/45] target-ppc: move out stqcx impementation David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 30/45] target-ppc: consolidate store conditional David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 31/45] target-ppc: add xxspltib instruction David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 32/45] target-ppc: add lxsi[bw]zx instruction David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 33/45] target-ppc: add stxsi[bh]x instruction David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 34/45] target-ppc: implement darn instruction David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 35/45] spapr: Introduce sPAPRCPUCoreClass David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 36/45] target-ppc: add TLB_NEED_LOCAL_FLUSH flag David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 37/45] target-ppc: add flag in check_tlb_flush() David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 38/45] target-ppc: tlbie/tlbivax should have global effect David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 39/45] Enable H_CLEAR_MOD and H_CLEAR_REF hypercalls on KVM/PPC64 David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 40/45] ppc/xics: account correct irq status David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 41/45] ppc/xics: An ICS with offset 0 is assumed to be uninitialized David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 42/45] ppc/kvm: Mark 64kB page size support as disabled if not available David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 43/45] linux-user: ppc64: fix ARCH_206 bit in AT_HWCAP David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 44/45] monitor: fix crash for platforms without a CPU 0 David Gibson
2016-09-23  7:15 ` [Qemu-devel] [PULL 45/45] spapr_pci: Add numa node id David Gibson
2016-09-23  8:28 ` [Qemu-devel] [PULL 00/45] ppc-for-2.8 queue 20160923 no-reply
2016-09-23 14:27 ` Peter Maydell

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=1474614921-2221-9-git-send-email-david@gibson.dropbear.id.au \
    --to=david@gibson.dropbear.id.au \
    --cc=agraf@suse.de \
    --cc=benh@kernel.crashing.org \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@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.