|
@@ -2398,6 +2398,67 @@ static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * fxsave fpu state. Taken from x86_64/processor.h. To be killed when
|
|
|
+ * we have asm/x86/processor.h
|
|
|
+ */
|
|
|
+struct fxsave {
|
|
|
+ u16 cwd;
|
|
|
+ u16 swd;
|
|
|
+ u16 twd;
|
|
|
+ u16 fop;
|
|
|
+ u64 rip;
|
|
|
+ u64 rdp;
|
|
|
+ u32 mxcsr;
|
|
|
+ u32 mxcsr_mask;
|
|
|
+ u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
|
|
|
+#ifdef CONFIG_X86_64
|
|
|
+ u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */
|
|
|
+#else
|
|
|
+ u32 xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
|
|
|
+#endif
|
|
|
+};
|
|
|
+
|
|
|
+static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
|
|
|
+{
|
|
|
+ struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
|
|
|
+
|
|
|
+ vcpu_load(vcpu);
|
|
|
+
|
|
|
+ memcpy(fpu->fpr, fxsave->st_space, 128);
|
|
|
+ fpu->fcw = fxsave->cwd;
|
|
|
+ fpu->fsw = fxsave->swd;
|
|
|
+ fpu->ftwx = fxsave->twd;
|
|
|
+ fpu->last_opcode = fxsave->fop;
|
|
|
+ fpu->last_ip = fxsave->rip;
|
|
|
+ fpu->last_dp = fxsave->rdp;
|
|
|
+ memcpy(fpu->xmm, fxsave->xmm_space, sizeof fxsave->xmm_space);
|
|
|
+
|
|
|
+ vcpu_put(vcpu);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
|
|
|
+{
|
|
|
+ struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
|
|
|
+
|
|
|
+ vcpu_load(vcpu);
|
|
|
+
|
|
|
+ memcpy(fxsave->st_space, fpu->fpr, 128);
|
|
|
+ fxsave->cwd = fpu->fcw;
|
|
|
+ fxsave->swd = fpu->fsw;
|
|
|
+ fxsave->twd = fpu->ftwx;
|
|
|
+ fxsave->fop = fpu->last_opcode;
|
|
|
+ fxsave->rip = fpu->last_ip;
|
|
|
+ fxsave->rdp = fpu->last_dp;
|
|
|
+ memcpy(fxsave->xmm_space, fpu->xmm, sizeof fxsave->xmm_space);
|
|
|
+
|
|
|
+ vcpu_put(vcpu);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static long kvm_vcpu_ioctl(struct file *filp,
|
|
|
unsigned int ioctl, unsigned long arg)
|
|
|
{
|
|
@@ -2542,6 +2603,31 @@ static long kvm_vcpu_ioctl(struct file *filp,
|
|
|
r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset);
|
|
|
break;
|
|
|
}
|
|
|
+ case KVM_GET_FPU: {
|
|
|
+ struct kvm_fpu fpu;
|
|
|
+
|
|
|
+ memset(&fpu, 0, sizeof fpu);
|
|
|
+ r = kvm_vcpu_ioctl_get_fpu(vcpu, &fpu);
|
|
|
+ if (r)
|
|
|
+ goto out;
|
|
|
+ r = -EFAULT;
|
|
|
+ if (copy_to_user(argp, &fpu, sizeof fpu))
|
|
|
+ goto out;
|
|
|
+ r = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case KVM_SET_FPU: {
|
|
|
+ struct kvm_fpu fpu;
|
|
|
+
|
|
|
+ r = -EFAULT;
|
|
|
+ if (copy_from_user(&fpu, argp, sizeof fpu))
|
|
|
+ goto out;
|
|
|
+ r = kvm_vcpu_ioctl_set_fpu(vcpu, &fpu);
|
|
|
+ if (r)
|
|
|
+ goto out;
|
|
|
+ r = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
default:
|
|
|
;
|
|
|
}
|