diff options
Diffstat (limited to 'drivers/kvm')
-rw-r--r-- | drivers/kvm/kvm_main.c | 86 |
1 files changed, 86 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 | } |