@ -1244,7 +1244,6 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
if ( vcpu - > kvm - > arch . use_cmma )
kvm_s390_vcpu_unsetup_cmma ( vcpu ) ;
kfree ( vcpu - > arch . guest_fpregs . fprs ) ;
free_page ( ( unsigned long ) ( vcpu - > arch . sie_block ) ) ;
kvm_vcpu_uninit ( vcpu ) ;
@ -1424,44 +1423,18 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
return 0 ;
}
/*
* Backs up the current FP / VX register save area on a particular
* destination . Used to switch between different register save
* areas .
*/
static inline void save_fpu_to ( struct fpu * dst )
{
dst - > fpc = current - > thread . fpu . fpc ;
dst - > regs = current - > thread . fpu . regs ;
}
/*
* Switches the FP / VX register save area from which to lazy
* restore register contents .
*/
static inline void load_fpu_from ( struct fpu * from )
{
current - > thread . fpu . fpc = from - > fpc ;
current - > thread . fpu . regs = from - > regs ;
}
void kvm_arch_vcpu_load ( struct kvm_vcpu * vcpu , int cpu )
{
/* Save host register state */
save_fpu_regs ( ) ;
save_fpu_to ( & vcpu - > arch . host_fpregs ) ;
if ( test_kvm_facility ( vcpu - > kvm , 129 ) ) {
current - > thread . fpu . fpc = vcpu - > run - > s . regs . fpc ;
/*
* Use the register save area in the SIE - control block
* for register restore and save in kvm_arch_vcpu_put ( )
*/
current - > thread . fpu . vxrs =
( __vector128 * ) & vcpu - > run - > s . regs . vrs ;
} else
load_fpu_from ( & vcpu - > arch . guest_fpregs ) ;
vcpu - > arch . host_fpregs . fpc = current - > thread . fpu . fpc ;
vcpu - > arch . host_fpregs . regs = current - > thread . fpu . regs ;
/* Depending on MACHINE_HAS_VX, data stored to vrs either
* has vector register or floating point register format .
*/
current - > thread . fpu . regs = vcpu - > run - > s . regs . vrs ;
current - > thread . fpu . fpc = vcpu - > run - > s . regs . fpc ;
if ( test_fp_ctl ( current - > thread . fpu . fpc ) )
/* User space provided an invalid FPC, let's clear it */
current - > thread . fpu . fpc = 0 ;
@ -1477,19 +1450,13 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
atomic_andnot ( CPUSTAT_RUNNING , & vcpu - > arch . sie_block - > cpuflags ) ;
gmap_disable ( vcpu - > arch . gmap ) ;
/* Save guest register state */
save_fpu_regs ( ) ;
vcpu - > run - > s . regs . fpc = current - > thread . fpu . fpc ;
if ( test_kvm_facility ( vcpu - > kvm , 129 ) )
/*
* kvm_arch_vcpu_load ( ) set up the register save area to
* the & vcpu - > run - > s . regs . vrs and , thus , the vector registers
* are already saved . Only the floating - point control must be
* copied .
*/
vcpu - > run - > s . regs . fpc = current - > thread . fpu . fpc ;
else
save_fpu_to ( & vcpu - > arch . guest_fpregs ) ;
load_fpu_from ( & vcpu - > arch . host_fpregs ) ;
/* Restore host register state */
current - > thread . fpu . fpc = vcpu - > arch . host_fpregs . fpc ;
current - > thread . fpu . regs = vcpu - > arch . host_fpregs . regs ;
save_access_regs ( vcpu - > run - > s . regs . acrs ) ;
restore_access_regs ( vcpu - > arch . host_acrs ) ;
@ -1507,8 +1474,9 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
memset ( vcpu - > arch . sie_block - > gcr , 0 , 16 * sizeof ( __u64 ) ) ;
vcpu - > arch . sie_block - > gcr [ 0 ] = 0xE0UL ;
vcpu - > arch . sie_block - > gcr [ 14 ] = 0xC2000000UL ;
vcpu - > arch . guest_fpregs . fpc = 0 ;
asm volatile ( " lfpc %0 " : : " Q " ( vcpu - > arch . guest_fpregs . fpc ) ) ;
/* make sure the new fpc will be lazily loaded */
save_fpu_regs ( ) ;
current - > thread . fpu . fpc = 0 ;
vcpu - > arch . sie_block - > gbea = 1 ;
vcpu - > arch . sie_block - > pp = 0 ;
vcpu - > arch . pfault_token = KVM_S390_PFAULT_TOKEN_INVALID ;
@ -1649,27 +1617,14 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
vcpu - > arch . local_int . wq = & vcpu - > wq ;
vcpu - > arch . local_int . cpuflags = & vcpu - > arch . sie_block - > cpuflags ;
/*
* Allocate a save area for floating - point registers . If the vector
* extension is available , register contents are saved in the SIE
* control block . The allocated save area is still required in
* particular places , for example , in kvm_s390_vcpu_store_status ( ) .
*/
vcpu - > arch . guest_fpregs . fprs = kzalloc ( sizeof ( freg_t ) * __NUM_FPRS ,
GFP_KERNEL ) ;
if ( ! vcpu - > arch . guest_fpregs . fprs )
goto out_free_sie_block ;
rc = kvm_vcpu_init ( vcpu , kvm , id ) ;
if ( rc )
goto out_free_fpr s ;
goto out_free_sie_block ;
VM_EVENT ( kvm , 3 , " create cpu %d at 0x%pK, sie block at 0x%pK " , id , vcpu ,
vcpu - > arch . sie_block ) ;
trace_kvm_s390_create_vcpu ( id , vcpu , vcpu - > arch . sie_block ) ;
return vcpu ;
out_free_fprs :
kfree ( vcpu - > arch . guest_fpregs . fprs ) ;
out_free_sie_block :
free_page ( ( unsigned long ) ( vcpu - > arch . sie_block ) ) ;
out_free_cpu :
@ -1882,19 +1837,27 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
int kvm_arch_vcpu_ioctl_set_fpu ( struct kvm_vcpu * vcpu , struct kvm_fpu * fpu )
{
/* make sure the new values will be lazily loaded */
save_fpu_regs ( ) ;
if ( test_fp_ctl ( fpu - > fpc ) )
return - EINVAL ;
memcpy ( vcpu - > arch . guest_fpregs . fprs , & fpu - > fprs , sizeof ( fpu - > fprs ) ) ;
vcpu - > arch . guest_fpregs . fpc = fpu - > fpc ;
save_fpu_regs ( ) ;
load_fpu_from ( & vcpu - > arch . guest_fpregs ) ;
current - > thread . fpu . fpc = fpu - > fpc ;
if ( MACHINE_HAS_VX )
convert_fp_to_vx ( current - > thread . fpu . vxrs , ( freg_t * ) fpu - > fprs ) ;
else
memcpy ( current - > thread . fpu . fprs , & fpu - > fprs , sizeof ( fpu - > fprs ) ) ;
return 0 ;
}
int kvm_arch_vcpu_ioctl_get_fpu ( struct kvm_vcpu * vcpu , struct kvm_fpu * fpu )
{
memcpy ( & fpu - > fprs , vcpu - > arch . guest_fpregs . fprs , sizeof ( fpu - > fprs ) ) ;
fpu - > fpc = vcpu - > arch . guest_fpregs . fpc ;
/* make sure we have the latest values */
save_fpu_regs ( ) ;
if ( MACHINE_HAS_VX )
convert_vx_to_fp ( ( freg_t * ) fpu - > fprs , current - > thread . fpu . vxrs ) ;
else
memcpy ( fpu - > fprs , current - > thread . fpu . fprs , sizeof ( fpu - > fprs ) ) ;
fpu - > fpc = current - > thread . fpu . fpc ;
return 0 ;
}
@ -2399,6 +2362,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
int kvm_s390_store_status_unloaded ( struct kvm_vcpu * vcpu , unsigned long gpa )
{
unsigned char archmode = 1 ;
freg_t fprs [ NUM_FPRS ] ;
unsigned int px ;
u64 clkcomp ;
int rc ;
@ -2414,8 +2378,16 @@ int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long gpa)
gpa = px ;
} else
gpa - = __LC_FPREGS_SAVE_AREA ;
rc = write_guest_abs ( vcpu , gpa + __LC_FPREGS_SAVE_AREA ,
vcpu - > arch . guest_fpregs . fprs , 128 ) ;
/* manually convert vector registers if necessary */
if ( MACHINE_HAS_VX ) {
convert_vx_to_fp ( fprs , current - > thread . fpu . vxrs ) ;
rc = write_guest_abs ( vcpu , gpa + __LC_FPREGS_SAVE_AREA ,
fprs , 128 ) ;
} else {
rc = write_guest_abs ( vcpu , gpa + __LC_FPREGS_SAVE_AREA ,
vcpu - > run - > s . regs . vrs , 128 ) ;
}
rc | = write_guest_abs ( vcpu , gpa + __LC_GPREGS_SAVE_AREA ,
vcpu - > run - > s . regs . gprs , 128 ) ;
rc | = write_guest_abs ( vcpu , gpa + __LC_PSW_SAVE_AREA ,
@ -2423,7 +2395,7 @@ int kvm_s390_store_status_unloaded(struct kvm_vcpu *vcpu, unsigned long gpa)
rc | = write_guest_abs ( vcpu , gpa + __LC_PREFIX_SAVE_AREA ,
& px , 4 ) ;
rc | = write_guest_abs ( vcpu , gpa + __LC_FP_CREG_SAVE_AREA ,
& vcpu - > arch . guest_fp regs. fpc , 4 ) ;
& vcpu - > run - > s . regs . fpc , 4 ) ;
rc | = write_guest_abs ( vcpu , gpa + __LC_TOD_PROGREG_SAVE_AREA ,
& vcpu - > arch . sie_block - > todpr , 4 ) ;
rc | = write_guest_abs ( vcpu , gpa + __LC_CPU_TIMER_SAVE_AREA ,
@ -2446,19 +2418,7 @@ int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
* it into the save area
*/
save_fpu_regs ( ) ;
if ( test_kvm_facility ( vcpu - > kvm , 129 ) ) {
/*
* If the vector extension is available , the vector registers
* which overlaps with floating - point registers are saved in
* the SIE - control block . Hence , extract the floating - point
* registers and the FPC value and store them in the
* guest_fpregs structure .
*/
vcpu - > arch . guest_fpregs . fpc = current - > thread . fpu . fpc ;
convert_vx_to_fp ( vcpu - > arch . guest_fpregs . fprs ,
current - > thread . fpu . vxrs ) ;
} else
save_fpu_to ( & vcpu - > arch . guest_fpregs ) ;
vcpu - > run - > s . regs . fpc = current - > thread . fpu . fpc ;
save_access_regs ( vcpu - > run - > s . regs . acrs ) ;
return kvm_s390_store_status_unloaded ( vcpu , addr ) ;