diff options
author | Sheng Yang <sheng@linux.intel.com> | 2010-06-13 05:29:39 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-08-01 03:46:37 -0400 |
commit | 2d5b5a665508c60577c1088e0405850a965b6795 (patch) | |
tree | 3549325770a39b0c7fd2b7f81aa6fa42295803e2 /arch/x86/kvm/x86.c | |
parent | 69b61833f7ce6e61e196c8a724e4d1278b24ac02 (diff) |
KVM: x86: XSAVE/XRSTOR live migration support
This patch enable save/restore of xsave state.
Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r-- | arch/x86/kvm/x86.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 795999e1ac19..0c8dc9614e7d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -1680,6 +1680,7 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
1680 | case KVM_CAP_PCI_SEGMENT: | 1680 | case KVM_CAP_PCI_SEGMENT: |
1681 | case KVM_CAP_DEBUGREGS: | 1681 | case KVM_CAP_DEBUGREGS: |
1682 | case KVM_CAP_X86_ROBUST_SINGLESTEP: | 1682 | case KVM_CAP_X86_ROBUST_SINGLESTEP: |
1683 | case KVM_CAP_XSAVE: | ||
1683 | r = 1; | 1684 | r = 1; |
1684 | break; | 1685 | break; |
1685 | case KVM_CAP_COALESCED_MMIO: | 1686 | case KVM_CAP_COALESCED_MMIO: |
@@ -1703,6 +1704,9 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
1703 | case KVM_CAP_MCE: | 1704 | case KVM_CAP_MCE: |
1704 | r = KVM_MAX_MCE_BANKS; | 1705 | r = KVM_MAX_MCE_BANKS; |
1705 | break; | 1706 | break; |
1707 | case KVM_CAP_XCRS: | ||
1708 | r = cpu_has_xsave; | ||
1709 | break; | ||
1706 | default: | 1710 | default: |
1707 | r = 0; | 1711 | r = 0; |
1708 | break; | 1712 | break; |
@@ -2355,6 +2359,77 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu, | |||
2355 | return 0; | 2359 | return 0; |
2356 | } | 2360 | } |
2357 | 2361 | ||
2362 | static void kvm_vcpu_ioctl_x86_get_xsave(struct kvm_vcpu *vcpu, | ||
2363 | struct kvm_xsave *guest_xsave) | ||
2364 | { | ||
2365 | if (cpu_has_xsave) | ||
2366 | memcpy(guest_xsave->region, | ||
2367 | &vcpu->arch.guest_fpu.state->xsave, | ||
2368 | sizeof(struct xsave_struct)); | ||
2369 | else { | ||
2370 | memcpy(guest_xsave->region, | ||
2371 | &vcpu->arch.guest_fpu.state->fxsave, | ||
2372 | sizeof(struct i387_fxsave_struct)); | ||
2373 | *(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)] = | ||
2374 | XSTATE_FPSSE; | ||
2375 | } | ||
2376 | } | ||
2377 | |||
2378 | static int kvm_vcpu_ioctl_x86_set_xsave(struct kvm_vcpu *vcpu, | ||
2379 | struct kvm_xsave *guest_xsave) | ||
2380 | { | ||
2381 | u64 xstate_bv = | ||
2382 | *(u64 *)&guest_xsave->region[XSAVE_HDR_OFFSET / sizeof(u32)]; | ||
2383 | |||
2384 | if (cpu_has_xsave) | ||
2385 | memcpy(&vcpu->arch.guest_fpu.state->xsave, | ||
2386 | guest_xsave->region, sizeof(struct xsave_struct)); | ||
2387 | else { | ||
2388 | if (xstate_bv & ~XSTATE_FPSSE) | ||
2389 | return -EINVAL; | ||
2390 | memcpy(&vcpu->arch.guest_fpu.state->fxsave, | ||
2391 | guest_xsave->region, sizeof(struct i387_fxsave_struct)); | ||
2392 | } | ||
2393 | return 0; | ||
2394 | } | ||
2395 | |||
2396 | static void kvm_vcpu_ioctl_x86_get_xcrs(struct kvm_vcpu *vcpu, | ||
2397 | struct kvm_xcrs *guest_xcrs) | ||
2398 | { | ||
2399 | if (!cpu_has_xsave) { | ||
2400 | guest_xcrs->nr_xcrs = 0; | ||
2401 | return; | ||
2402 | } | ||
2403 | |||
2404 | guest_xcrs->nr_xcrs = 1; | ||
2405 | guest_xcrs->flags = 0; | ||
2406 | guest_xcrs->xcrs[0].xcr = XCR_XFEATURE_ENABLED_MASK; | ||
2407 | guest_xcrs->xcrs[0].value = vcpu->arch.xcr0; | ||
2408 | } | ||
2409 | |||
2410 | static int kvm_vcpu_ioctl_x86_set_xcrs(struct kvm_vcpu *vcpu, | ||
2411 | struct kvm_xcrs *guest_xcrs) | ||
2412 | { | ||
2413 | int i, r = 0; | ||
2414 | |||
2415 | if (!cpu_has_xsave) | ||
2416 | return -EINVAL; | ||
2417 | |||
2418 | if (guest_xcrs->nr_xcrs > KVM_MAX_XCRS || guest_xcrs->flags) | ||
2419 | return -EINVAL; | ||
2420 | |||
2421 | for (i = 0; i < guest_xcrs->nr_xcrs; i++) | ||
2422 | /* Only support XCR0 currently */ | ||
2423 | if (guest_xcrs->xcrs[0].xcr == XCR_XFEATURE_ENABLED_MASK) { | ||
2424 | r = __kvm_set_xcr(vcpu, XCR_XFEATURE_ENABLED_MASK, | ||
2425 | guest_xcrs->xcrs[0].value); | ||
2426 | break; | ||
2427 | } | ||
2428 | if (r) | ||
2429 | r = -EINVAL; | ||
2430 | return r; | ||
2431 | } | ||
2432 | |||
2358 | long kvm_arch_vcpu_ioctl(struct file *filp, | 2433 | long kvm_arch_vcpu_ioctl(struct file *filp, |
2359 | unsigned int ioctl, unsigned long arg) | 2434 | unsigned int ioctl, unsigned long arg) |
2360 | { | 2435 | { |
@@ -2556,6 +2631,70 @@ long kvm_arch_vcpu_ioctl(struct file *filp, | |||
2556 | r = kvm_vcpu_ioctl_x86_set_debugregs(vcpu, &dbgregs); | 2631 | r = kvm_vcpu_ioctl_x86_set_debugregs(vcpu, &dbgregs); |
2557 | break; | 2632 | break; |
2558 | } | 2633 | } |
2634 | case KVM_GET_XSAVE: { | ||
2635 | struct kvm_xsave *xsave; | ||
2636 | |||
2637 | xsave = kzalloc(sizeof(struct kvm_xsave), GFP_KERNEL); | ||
2638 | r = -ENOMEM; | ||
2639 | if (!xsave) | ||
2640 | break; | ||
2641 | |||
2642 | kvm_vcpu_ioctl_x86_get_xsave(vcpu, xsave); | ||
2643 | |||
2644 | r = -EFAULT; | ||
2645 | if (copy_to_user(argp, xsave, sizeof(struct kvm_xsave))) | ||
2646 | break; | ||
2647 | r = 0; | ||
2648 | break; | ||
2649 | } | ||
2650 | case KVM_SET_XSAVE: { | ||
2651 | struct kvm_xsave *xsave; | ||
2652 | |||
2653 | xsave = kzalloc(sizeof(struct kvm_xsave), GFP_KERNEL); | ||
2654 | r = -ENOMEM; | ||
2655 | if (!xsave) | ||
2656 | break; | ||
2657 | |||
2658 | r = -EFAULT; | ||
2659 | if (copy_from_user(xsave, argp, sizeof(struct kvm_xsave))) | ||
2660 | break; | ||
2661 | |||
2662 | r = kvm_vcpu_ioctl_x86_set_xsave(vcpu, xsave); | ||
2663 | break; | ||
2664 | } | ||
2665 | case KVM_GET_XCRS: { | ||
2666 | struct kvm_xcrs *xcrs; | ||
2667 | |||
2668 | xcrs = kzalloc(sizeof(struct kvm_xcrs), GFP_KERNEL); | ||
2669 | r = -ENOMEM; | ||
2670 | if (!xcrs) | ||
2671 | break; | ||
2672 | |||
2673 | kvm_vcpu_ioctl_x86_get_xcrs(vcpu, xcrs); | ||
2674 | |||
2675 | r = -EFAULT; | ||
2676 | if (copy_to_user(argp, xcrs, | ||
2677 | sizeof(struct kvm_xcrs))) | ||
2678 | break; | ||
2679 | r = 0; | ||
2680 | break; | ||
2681 | } | ||
2682 | case KVM_SET_XCRS: { | ||
2683 | struct kvm_xcrs *xcrs; | ||
2684 | |||
2685 | xcrs = kzalloc(sizeof(struct kvm_xcrs), GFP_KERNEL); | ||
2686 | r = -ENOMEM; | ||
2687 | if (!xcrs) | ||
2688 | break; | ||
2689 | |||
2690 | r = -EFAULT; | ||
2691 | if (copy_from_user(xcrs, argp, | ||
2692 | sizeof(struct kvm_xcrs))) | ||
2693 | break; | ||
2694 | |||
2695 | r = kvm_vcpu_ioctl_x86_set_xcrs(vcpu, xcrs); | ||
2696 | break; | ||
2697 | } | ||
2559 | default: | 2698 | default: |
2560 | r = -EINVAL; | 2699 | r = -EINVAL; |
2561 | } | 2700 | } |