diff options
Diffstat (limited to 'drivers/kvm/kvm_main.c')
| -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 | } |
