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 |