|
@@ -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_fprs;
|
|
|
+ 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_fpregs.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);
|