aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2007-04-01 09:34:31 -0400
committerAvi Kivity <avi@qumranet.com>2007-05-03 03:52:28 -0400
commitb8836737d92c139be770eae3d6574e33d1224caf (patch)
tree9c03b429fda12e6fbdc97469eb039076aa397744
parente8207547d2f7b2f557bdb73015c1f74c32474438 (diff)
KVM: Add fpu get/set operations
These are really helpful when migrating an floating point app to another machine. Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r--drivers/kvm/kvm_main.c86
-rw-r--r--include/linux/kvm.h17
2 files changed, 103 insertions, 0 deletions
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c
index e495855727e2..b065c4991568 100644
--- a/drivers/kvm/kvm_main.c
+++ b/drivers/kvm/kvm_main.c
@@ -2398,6 +2398,67 @@ static int kvm_vcpu_ioctl_set_sigmask(struct kvm_vcpu *vcpu, sigset_t *sigset)
2398 return 0; 2398 return 0;
2399} 2399}
2400 2400
2401/*
2402 * fxsave fpu state. Taken from x86_64/processor.h. To be killed when
2403 * we have asm/x86/processor.h
2404 */
2405struct fxsave {
2406 u16 cwd;
2407 u16 swd;
2408 u16 twd;
2409 u16 fop;
2410 u64 rip;
2411 u64 rdp;
2412 u32 mxcsr;
2413 u32 mxcsr_mask;
2414 u32 st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */
2415#ifdef CONFIG_X86_64
2416 u32 xmm_space[64]; /* 16*16 bytes for each XMM-reg = 256 bytes */
2417#else
2418 u32 xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */
2419#endif
2420};
2421
2422static int kvm_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
2423{
2424 struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
2425
2426 vcpu_load(vcpu);
2427
2428 memcpy(fpu->fpr, fxsave->st_space, 128);
2429 fpu->fcw = fxsave->cwd;
2430 fpu->fsw = fxsave->swd;
2431 fpu->ftwx = fxsave->twd;
2432 fpu->last_opcode = fxsave->fop;
2433 fpu->last_ip = fxsave->rip;
2434 fpu->last_dp = fxsave->rdp;
2435 memcpy(fpu->xmm, fxsave->xmm_space, sizeof fxsave->xmm_space);
2436
2437 vcpu_put(vcpu);
2438
2439 return 0;
2440}
2441
2442static int kvm_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
2443{
2444 struct fxsave *fxsave = (struct fxsave *)vcpu->guest_fx_image;
2445
2446 vcpu_load(vcpu);
2447
2448 memcpy(fxsave->st_space, fpu->fpr, 128);
2449 fxsave->cwd = fpu->fcw;
2450 fxsave->swd = fpu->fsw;
2451 fxsave->twd = fpu->ftwx;
2452 fxsave->fop = fpu->last_opcode;
2453 fxsave->rip = fpu->last_ip;
2454 fxsave->rdp = fpu->last_dp;
2455 memcpy(fxsave->xmm_space, fpu->xmm, sizeof fxsave->xmm_space);
2456
2457 vcpu_put(vcpu);
2458
2459 return 0;
2460}
2461
2401static long kvm_vcpu_ioctl(struct file *filp, 2462static long kvm_vcpu_ioctl(struct file *filp,
2402 unsigned int ioctl, unsigned long arg) 2463 unsigned int ioctl, unsigned long arg)
2403{ 2464{
@@ -2542,6 +2603,31 @@ static long kvm_vcpu_ioctl(struct file *filp,
2542 r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset); 2603 r = kvm_vcpu_ioctl_set_sigmask(vcpu, &sigset);
2543 break; 2604 break;
2544 } 2605 }
2606 case KVM_GET_FPU: {
2607 struct kvm_fpu fpu;
2608
2609 memset(&fpu, 0, sizeof fpu);
2610 r = kvm_vcpu_ioctl_get_fpu(vcpu, &fpu);
2611 if (r)
2612 goto out;
2613 r = -EFAULT;
2614 if (copy_to_user(argp, &fpu, sizeof fpu))
2615 goto out;
2616 r = 0;
2617 break;
2618 }
2619 case KVM_SET_FPU: {
2620 struct kvm_fpu fpu;
2621
2622 r = -EFAULT;
2623 if (copy_from_user(&fpu, argp, sizeof fpu))
2624 goto out;
2625 r = kvm_vcpu_ioctl_set_fpu(vcpu, &fpu);
2626 if (r)
2627 goto out;
2628 r = 0;
2629 break;
2630 }
2545 default: 2631 default:
2546 ; 2632 ;
2547 } 2633 }
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index da9b23fa4b6c..07bf353eeb6f 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -126,6 +126,21 @@ struct kvm_regs {
126 __u64 rip, rflags; 126 __u64 rip, rflags;
127}; 127};
128 128
129/* for KVM_GET_FPU and KVM_SET_FPU */
130struct kvm_fpu {
131 __u8 fpr[8][16];
132 __u16 fcw;
133 __u16 fsw;
134 __u8 ftwx; /* in fxsave format */
135 __u8 pad1;
136 __u16 last_opcode;
137 __u64 last_ip;
138 __u64 last_dp;
139 __u8 xmm[16][16];
140 __u32 mxcsr;
141 __u32 pad2;
142};
143
129struct kvm_segment { 144struct kvm_segment {
130 __u64 base; 145 __u64 base;
131 __u32 limit; 146 __u32 limit;
@@ -285,5 +300,7 @@ struct kvm_signal_mask {
285#define KVM_SET_MSRS _IOW(KVMIO, 0x89, struct kvm_msrs) 300#define KVM_SET_MSRS _IOW(KVMIO, 0x89, struct kvm_msrs)
286#define KVM_SET_CPUID _IOW(KVMIO, 0x8a, struct kvm_cpuid) 301#define KVM_SET_CPUID _IOW(KVMIO, 0x8a, struct kvm_cpuid)
287#define KVM_SET_SIGNAL_MASK _IOW(KVMIO, 0x8b, struct kvm_signal_mask) 302#define KVM_SET_SIGNAL_MASK _IOW(KVMIO, 0x8b, struct kvm_signal_mask)
303#define KVM_GET_FPU _IOR(KVMIO, 0x8c, struct kvm_fpu)
304#define KVM_SET_FPU _IOW(KVMIO, 0x8d, struct kvm_fpu)
288 305
289#endif 306#endif