diff options
-rw-r--r-- | linux-user/ppc/signal.c | 69 |
1 files changed, 29 insertions, 40 deletions
diff --git a/linux-user/ppc/signal.c b/linux-user/ppc/signal.c index ecd99736b7..20a02c197c 100644 --- a/linux-user/ppc/signal.c +++ b/linux-user/ppc/signal.c @@ -35,12 +35,26 @@ 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; + /* + * On ppc64, this mcontext structure is naturally *unaligned*, + * or rather it is aligned on a 8 bytes boundary but not on + * a 16 byte boundary. This pad fixes it up. This is why we + * cannot use ppc_avr_t, which would force alignment. This is + * also why the vector regs are referenced in the ABI by the + * v_regs pointer above so any amount of padding can be added here. + */ + target_ulong pad; + /* VSCR and VRSAVE are saved separately. Also reserve space for VSX. */ + struct { + uint64_t altivec[34 + 16][2]; + } mc_vregs; #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 @@ -48,32 +62,14 @@ struct target_mcontext { 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. + /* + * Altivec vector registers. One extra for VRSAVE. + * On ppc32, we are already aligned to 16 bytes. We could + * use ppc_avr_t, but choose to share the same type as ppc64. */ - uint64_t altivec[QEMU_NVRREG][2]; -#undef QEMU_NVRREG + uint64_t altivec[33][2]; } mc_vregs; +#endif }; /* See arch/powerpc/include/asm/sigcontext.h. */ @@ -278,6 +274,7 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) __put_user((uint32_t)env->spr[SPR_VRSAVE], vrsave); } +#if defined(TARGET_PPC64) /* Save VSX second halves */ if (env->insns_flags2 & PPC2_VSX) { uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34]; @@ -286,6 +283,7 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) __put_user(*vsrl, &vsregs[i]); } } +#endif /* Save floating point registers. */ if (env->insns_flags & PPC_FLOAT) { @@ -296,22 +294,18 @@ static void save_user_regs(CPUPPCState *env, struct target_mcontext *frame) __put_user((uint64_t) env->fpscr, &frame->mc_fregs[32]); } +#if !defined(TARGET_PPC64) /* 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]); } +#endif /* Store MSR. */ __put_user(msr, &frame->mc_gregs[TARGET_PT_MSR]); @@ -392,6 +386,7 @@ static void restore_user_regs(CPUPPCState *env, __get_user(env->spr[SPR_VRSAVE], vrsave); } +#if defined(TARGET_PPC64) /* Restore VSX second halves */ if (env->insns_flags2 & PPC2_VSX) { uint64_t *vsregs = (uint64_t *)&frame->mc_vregs.altivec[34]; @@ -400,6 +395,7 @@ static void restore_user_regs(CPUPPCState *env, __get_user(*vsrl, &vsregs[i]); } } +#endif /* Restore floating point registers. */ if (env->insns_flags & PPC_FLOAT) { @@ -412,22 +408,15 @@ static void restore_user_regs(CPUPPCState *env, env->fpscr = (uint32_t) fpscr; } +#if !defined(TARGET_PPC64) /* 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]); } +#endif } #if !defined(TARGET_PPC64) |