@ -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)