diff options
| author | Avi Kivity <avi@qumranet.com> | 2007-04-01 09:34:31 -0400 |
|---|---|---|
| committer | Avi Kivity <avi@qumranet.com> | 2007-05-03 03:52:28 -0400 |
| commit | b8836737d92c139be770eae3d6574e33d1224caf (patch) | |
| tree | 9c03b429fda12e6fbdc97469eb039076aa397744 | |
| parent | e8207547d2f7b2f557bdb73015c1f74c32474438 (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.c | 86 | ||||
| -rw-r--r-- | include/linux/kvm.h | 17 |
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 | */ | ||
| 2405 | struct 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 | |||
| 2422 | static 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 | |||
| 2442 | static 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 | |||
| 2401 | static long kvm_vcpu_ioctl(struct file *filp, | 2462 | static 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 */ | ||
| 130 | struct 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 | |||
| 129 | struct kvm_segment { | 144 | struct 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 |
