From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
To: qemu-ppc@nongnu.org
Cc: qemu-devel@nongnu.org, david@gibson.dropbear.id.au
Subject: [Qemu-devel] [PATCH v3] ppc: Fix signal delivery in ppc-user and ppc64-user
Date: Wed, 03 Aug 2016 15:32:19 +1000 [thread overview]
Message-ID: <1470202339.12584.53.camel@kernel.crashing.org> (raw)
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>
---
v2. Fix endian bugs too
Fix bad PC on sigreturn
v3. Add missing VSX second halves
Tested with ppc32, ppc64be and ppc64le, verified reading
and writing VSX and VMX registers from a signal handler
and observing the result in the main program. Compared
successfully to running in actual hardware.
linux-user/main.c | 2 +-
linux-user/ppc/syscall_nr.h | 2 +
linux-user/signal.c | 118 ++++++++++++++++++++++++++++++--------------
3 files changed, 84 insertions(+), 38 deletions(-)
diff --git a/linux-user/main.c b/linux-user/main.c
index 1d149dc..24f34e6 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2003,12 +2003,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 9a4d894..f01437e 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -4408,7 +4408,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
@@ -4418,15 +4423,24 @@ 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, we need to align to 16 bytes by hand */
+ 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 32-bit variant is already aligned.
+ */
+ uint64_t altivec[QEMU_NVRREG][2];
#undef QEMU_NVRREG
- } mc_vregs __attribute__((__aligned__(16)));
+ } mc_vregs;
};
/* See arch/powerpc/include/asm/sigcontext.h. */
@@ -4580,6 +4594,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;
@@ -4606,18 +4630,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. */
@@ -4697,17 +4736,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. */
@@ -4738,6 +4799,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)
{
@@ -4745,9 +4807,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);
@@ -4757,11 +4816,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);
@@ -4790,22 +4845,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);
@@ -4817,6 +4857,7 @@ sigsegv:
unlock_user_struct(frame, frame_addr, 1);
force_sig(TARGET_SIGSEGV);
}
+#endif /* !defined(TARGET_PPC64) */
static void setup_rt_frame(int sig, struct target_sigaction *ka,
target_siginfo_t *info,
@@ -4914,6 +4955,7 @@ sigsegv:
}
+#if !defined(TARGET_PPC64)
long do_sigreturn(CPUPPCState *env)
{
struct target_sigcontext *sc = NULL;
@@ -4950,6 +4992,7 @@ sigsegv:
force_sig(TARGET_SIGSEGV);
return 0;
}
+#endif /* !defined(TARGET_PPC64) */
/* See arch/powerpc/kernel/signal_32.c. */
static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
@@ -5893,7 +5936,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
next reply other threads:[~2016-08-03 5:32 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-08-03 5:32 Benjamin Herrenschmidt [this message]
2016-08-03 12:15 ` [Qemu-devel] [Qemu-ppc] [PATCH v3] ppc: Fix signal delivery in ppc-user and ppc64-user BALATON Zoltan
2016-08-03 12:24 ` Benjamin Herrenschmidt
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=1470202339.12584.53.camel@kernel.crashing.org \
--to=benh@kernel.crashing.org \
--cc=david@gibson.dropbear.id.au \
--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.