[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH for-5.0?] linux-user/ppc: Fix padding in mcontext_t for ppc64
From: |
Laurent Vivier |
Subject: |
Re: [PATCH for-5.0?] linux-user/ppc: Fix padding in mcontext_t for ppc64 |
Date: |
Tue, 7 Apr 2020 13:09:45 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.6.0 |
Le 07/04/2020 à 05:21, Richard Henderson a écrit :
> The padding that was added in 95cda4c44ee was added to a union,
> and so it had no effect. This fixes misalignment errors detected
> by clang sanitizers for ppc64 and ppc64le.
>
> In addition, only ppc64 allocates space for VSX registers, so do
> not save them for ppc32. The kernel only has references to
> CONFIG_SPE in signal_32.c, so do not attempt to save them for ppc64.
>
> Fixes: 95cda4c44ee
> Signed-off-by: Richard Henderson <address@hidden>
> ---
>
> Note that ppc64abi32 is *not* fixed by this patch. It looks to
> me that all of the defined(TARGET_PPC64) tests in this file are
> incorrect, and that we should instead be testing TARGET_ABI_BITS
> vs 32/64. In addition, virtually all of the target_ulong structure
> members would need to be abi_ulong.
>
> Should we in fact disable ppc64abi32?
> I can't see how it could work enough to be useful as-is.
Yes, this part needs definitively more cleanup, anyway:
Acked-by: Laurent Vivier <address@hidden>
Thanks,
Laurent
>
> r~
>
> ---
> linux-user/ppc/signal.c | 69 +++++++++++++++++------------------------
> 1 file 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
> + /*
> + * 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.
> */
> - 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
> + 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)
>