summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux-user/signal.c121
1 files changed, 73 insertions, 48 deletions
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 7365d5ddbf..56c38db4b3 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -4325,15 +4325,7 @@ badframe:
return 0;
}
-#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. */
+#elif defined(TARGET_PPC)
/* Size of dummy stack frame allocated when calling signal handler.
See arch/powerpc/include/asm/ptrace.h. */
@@ -4343,6 +4335,33 @@ badframe:
#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];
+ 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 QEMU_NVRREG 34
+#else
+#define QEMU_NVRREG 33
+#endif
+ ppc_avr_t altivec[QEMU_NVRREG];
+#undef QEMU_NVRREG
+ } mc_vregs __attribute__((__aligned__(16)));
+};
+
/* See arch/powerpc/include/asm/sigcontext.h. */
struct target_sigcontext {
target_ulong _unused[4];
@@ -4353,7 +4372,9 @@ struct target_sigcontext {
target_ulong handler;
target_ulong oldmask;
target_ulong regs; /* struct pt_regs __user * */
- /* TODO: PPC64 includes extra bits here. */
+#if defined(TARGET_PPC64)
+ struct target_mcontext mcontext;
+#endif
};
/* Indices for target_mcontext.mc_gregs, below.
@@ -4408,32 +4429,6 @@ enum {
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 QEMU_NVRREG 34
-#else
-#define QEMU_NVRREG 33
-#endif
- ppc_avr_t altivec[QEMU_NVRREG];
-#undef QEMU_NVRREG
- } mc_vregs __attribute__((__aligned__(16)));
-};
struct target_ucontext {
target_ulong tuc_flags;
@@ -4447,7 +4442,7 @@ struct target_ucontext {
target_sigset_t tuc_sigmask;
#if defined(TARGET_PPC64)
target_sigset_t unused[15]; /* Allow for uc_sigmask growth */
- struct target_sigcontext tuc_mcontext;
+ struct target_sigcontext tuc_sigcontext;
#else
int32_t tuc_maskext[30];
int32_t tuc_pad2[3];
@@ -4462,12 +4457,32 @@ struct target_sigframe {
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
+
/* We use the mc_pad field for the signal return trampoline. */
#define tramp mc_pad
@@ -4667,7 +4682,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 defined(TARGET_PPC64)
+#if TARGET_ABI_BITS == 64
__put_user(set->sig[0] >> 32, &sc->_unused[3]);
#else
__put_user(set->sig[1], &sc->_unused[3]);
@@ -4717,7 +4732,8 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
target_sigset_t *set, CPUPPCState *env)
{
struct target_rt_sigframe *rt_sf;
- struct target_mcontext *frame;
+ uint32_t *trampptr = 0;
+ struct target_mcontext *mctx = 0;
target_ulong rt_sf_addr, newsp = 0;
int i, err = 0;
int signal;
@@ -4738,19 +4754,28 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
&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]);
}
- frame = &rt_sf->uc.tuc_mcontext;
- save_user_regs(env, frame);
- encode_trampoline(TARGET_NR_rt_sigreturn, (uint32_t *)&frame->tramp);
+#if defined(TARGET_PPC64)
+ mctx = &rt_sf->uc.tuc_sigcontext.mcontext;
+ trampptr = &rt_sf->trampoline[0];
+#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(frame->tramp);
+ env->lr = (target_ulong) h2g(trampptr);
/* Turn off all fp exceptions. */
env->fpscr = 0;
@@ -4795,7 +4820,7 @@ long do_sigreturn(CPUPPCState *env)
goto sigsegv;
#if defined(TARGET_PPC64)
- set.sig[0] = sc->oldmask + ((long)(sc->_unused[3]) << 32);
+ 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]);
@@ -4823,6 +4848,10 @@ sigsegv:
/* See arch/powerpc/kernel/signal_32.c. */
static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
{
+#if defined(TARGET_PPC64)
+ fprintf(stderr, "do_setcontext: not implemented\n");
+ return 0;
+#else
struct target_mcontext *mcp;
target_ulong mcp_addr;
sigset_t blocked;
@@ -4832,10 +4861,6 @@ static int do_setcontext(struct target_ucontext *ucp, CPUPPCState *env, int sig)
sizeof (set)))
return 1;
-#if defined(TARGET_PPC64)
- fprintf (stderr, "do_setcontext: not implemented\n");
- return 0;
-#else
__get_user(mcp_addr, &ucp->tuc_regs);
if (!lock_user_struct(VERIFY_READ, mcp, mcp_addr, 1))