KVM: SVM: Implement hsave
authorAlexander Graf <agraf@suse.de>
Tue, 25 Nov 2008 19:17:05 +0000 (20:17 +0100)
committerAvi Kivity <avi@redhat.com>
Tue, 24 Mar 2009 09:02:46 +0000 (11:02 +0200)
Implement the hsave MSR, that gives the VCPU a GPA to save the
old guest state in.

v2 allows userspace to save/restore hsave
v4 dummys out the hsave MSR, so we use a host page
v6 remembers the guest's hsave and exports the MSR

Acked-by: Joerg Roedel <joro@8bytes.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
arch/x86/kvm/kvm_svm.h
arch/x86/kvm/svm.c
arch/x86/kvm/x86.c

index 8e5ee99551f6e75bf5c2a2ea64627abe98b12607..a0877cac7b9c192abd73a22897f2d266b712e1ea 100644 (file)
@@ -41,6 +41,8 @@ struct vcpu_svm {
        unsigned long host_dr7;
 
        u32 *msrpm;
+       struct vmcb *hsave;
+       u64 hsave_msr;
 };
 
 #endif
index 79cc06bfe57c0d62dfa2699821a3d137c2bc4436..59aaff1c9597467d3c79926c5d7988282dcdc31c 100644 (file)
@@ -626,6 +626,7 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
        struct vcpu_svm *svm;
        struct page *page;
        struct page *msrpm_pages;
+       struct page *hsave_page;
        int err;
 
        svm = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
@@ -651,6 +652,11 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
        svm->msrpm = page_address(msrpm_pages);
        svm_vcpu_init_msrpm(svm->msrpm);
 
+       hsave_page = alloc_page(GFP_KERNEL);
+       if (!hsave_page)
+               goto uninit;
+       svm->hsave = page_address(hsave_page);
+
        svm->vmcb = page_address(page);
        clear_page(svm->vmcb);
        svm->vmcb_pa = page_to_pfn(page) << PAGE_SHIFT;
@@ -680,6 +686,7 @@ static void svm_free_vcpu(struct kvm_vcpu *vcpu)
 
        __free_page(pfn_to_page(svm->vmcb_pa >> PAGE_SHIFT));
        __free_pages(virt_to_page(svm->msrpm), MSRPM_ALLOC_ORDER);
+       __free_page(virt_to_page(svm->hsave));
        kvm_vcpu_uninit(vcpu);
        kmem_cache_free(kvm_vcpu_cache, svm);
 }
@@ -1377,6 +1384,9 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
        case MSR_IA32_LASTINTTOIP:
                *data = svm->vmcb->save.last_excp_to;
                break;
+       case MSR_VM_HSAVE_PA:
+               *data = svm->hsave_msr;
+               break;
        default:
                return kvm_get_msr_common(vcpu, ecx, data);
        }
@@ -1470,6 +1480,9 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
                 */
                pr_unimpl(vcpu, "unimplemented perfctr wrmsr: 0x%x data 0x%llx\n", ecx, data);
 
+               break;
+       case MSR_VM_HSAVE_PA:
+               svm->hsave_msr = data;
                break;
        default:
                return kvm_set_msr_common(vcpu, ecx, data);
index 758b7a155ae9113559b5993b38abfc3cf603fe70..99165a961f087c1836760a95b3c422282319c79b 100644 (file)
@@ -456,7 +456,7 @@ static u32 msrs_to_save[] = {
        MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
 #endif
        MSR_IA32_TIME_STAMP_COUNTER, MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
-       MSR_IA32_PERF_STATUS, MSR_IA32_CR_PAT
+       MSR_IA32_PERF_STATUS, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA
 };
 
 static unsigned num_msrs_to_save;