diff options
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 57 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 3 |
3 files changed, 45 insertions, 16 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 8d1587092851..7892530cbacf 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -1071,6 +1071,7 @@ unsigned int kvm_mmu_calculate_mmu_pages(struct kvm *kvm); | |||
1071 | void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages); | 1071 | void kvm_mmu_change_mmu_pages(struct kvm *kvm, unsigned int kvm_nr_mmu_pages); |
1072 | 1072 | ||
1073 | int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3); | 1073 | int load_pdptrs(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, unsigned long cr3); |
1074 | bool pdptrs_changed(struct kvm_vcpu *vcpu); | ||
1074 | 1075 | ||
1075 | int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, | 1076 | int emulator_write_phys(struct kvm_vcpu *vcpu, gpa_t gpa, |
1076 | const void *val, int bytes); | 1077 | const void *val, int bytes); |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 39a389f17f4a..a0d6e59f4f34 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -9969,6 +9969,44 @@ static int nested_vmx_store_msr(struct kvm_vcpu *vcpu, u64 gpa, u32 count) | |||
9969 | } | 9969 | } |
9970 | 9970 | ||
9971 | /* | 9971 | /* |
9972 | * Load guest's/host's cr3 at nested entry/exit. nested_ept is true if we are | ||
9973 | * emulating VM entry into a guest with EPT enabled. | ||
9974 | * Returns 0 on success, 1 on failure. Invalid state exit qualification code | ||
9975 | * is assigned to entry_failure_code on failure. | ||
9976 | */ | ||
9977 | static int nested_vmx_load_cr3(struct kvm_vcpu *vcpu, unsigned long cr3, bool nested_ept, | ||
9978 | unsigned long *entry_failure_code) | ||
9979 | { | ||
9980 | unsigned long invalid_mask; | ||
9981 | |||
9982 | if (cr3 != kvm_read_cr3(vcpu) || (!nested_ept && pdptrs_changed(vcpu))) { | ||
9983 | invalid_mask = (~0ULL) << cpuid_maxphyaddr(vcpu); | ||
9984 | if (cr3 & invalid_mask) { | ||
9985 | *entry_failure_code = ENTRY_FAIL_DEFAULT; | ||
9986 | return 1; | ||
9987 | } | ||
9988 | |||
9989 | /* | ||
9990 | * If PAE paging and EPT are both on, CR3 is not used by the CPU and | ||
9991 | * must not be dereferenced. | ||
9992 | */ | ||
9993 | if (!is_long_mode(vcpu) && is_pae(vcpu) && is_paging(vcpu) && | ||
9994 | !nested_ept) { | ||
9995 | if (!load_pdptrs(vcpu, vcpu->arch.walk_mmu, cr3)) { | ||
9996 | *entry_failure_code = ENTRY_FAIL_PDPTE; | ||
9997 | return 1; | ||
9998 | } | ||
9999 | } | ||
10000 | |||
10001 | vcpu->arch.cr3 = cr3; | ||
10002 | __set_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail); | ||
10003 | } | ||
10004 | |||
10005 | kvm_mmu_reset_context(vcpu); | ||
10006 | return 0; | ||
10007 | } | ||
10008 | |||
10009 | /* | ||
9972 | * prepare_vmcs02 is called when the L1 guest hypervisor runs its nested | 10010 | * prepare_vmcs02 is called when the L1 guest hypervisor runs its nested |
9973 | * L2 guest. L1 has a vmcs for L2 (vmcs12), and this function "merges" it | 10011 | * L2 guest. L1 has a vmcs for L2 (vmcs12), and this function "merges" it |
9974 | * with L0's requirements for its guest (a.k.a. vmcs01), so we can run the L2 | 10012 | * with L0's requirements for its guest (a.k.a. vmcs01), so we can run the L2 |
@@ -10300,21 +10338,10 @@ static int prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12, | |||
10300 | /* Note: modifies VM_ENTRY/EXIT_CONTROLS and GUEST/HOST_IA32_EFER */ | 10338 | /* Note: modifies VM_ENTRY/EXIT_CONTROLS and GUEST/HOST_IA32_EFER */ |
10301 | vmx_set_efer(vcpu, vcpu->arch.efer); | 10339 | vmx_set_efer(vcpu, vcpu->arch.efer); |
10302 | 10340 | ||
10303 | /* | 10341 | /* Shadow page tables on either EPT or shadow page tables. */ |
10304 | * Shadow page tables on either EPT or shadow page tables. | 10342 | if (nested_vmx_load_cr3(vcpu, vmcs12->guest_cr3, nested_ept_enabled, |
10305 | * If PAE and EPT are both on, CR3 is not used by the CPU and must not | 10343 | entry_failure_code)) |
10306 | * be dereferenced. | 10344 | return 1; |
10307 | */ | ||
10308 | if (is_pae(vcpu) && is_paging(vcpu) && !is_long_mode(vcpu) && | ||
10309 | nested_ept_enabled) { | ||
10310 | vcpu->arch.cr3 = vmcs12->guest_cr3; | ||
10311 | __set_bit(VCPU_EXREG_CR3, (ulong *)&vcpu->arch.regs_avail); | ||
10312 | } else { | ||
10313 | if (kvm_set_cr3(vcpu, vmcs12->guest_cr3)) { | ||
10314 | *entry_failure_code = ENTRY_FAIL_DEFAULT; | ||
10315 | return 1; | ||
10316 | } | ||
10317 | } | ||
10318 | 10345 | ||
10319 | kvm_mmu_reset_context(vcpu); | 10346 | kvm_mmu_reset_context(vcpu); |
10320 | 10347 | ||
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index dd6b41ea61b6..f0aee98e7492 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -566,7 +566,7 @@ out: | |||
566 | } | 566 | } |
567 | EXPORT_SYMBOL_GPL(load_pdptrs); | 567 | EXPORT_SYMBOL_GPL(load_pdptrs); |
568 | 568 | ||
569 | static bool pdptrs_changed(struct kvm_vcpu *vcpu) | 569 | bool pdptrs_changed(struct kvm_vcpu *vcpu) |
570 | { | 570 | { |
571 | u64 pdpte[ARRAY_SIZE(vcpu->arch.walk_mmu->pdptrs)]; | 571 | u64 pdpte[ARRAY_SIZE(vcpu->arch.walk_mmu->pdptrs)]; |
572 | bool changed = true; | 572 | bool changed = true; |
@@ -592,6 +592,7 @@ out: | |||
592 | 592 | ||
593 | return changed; | 593 | return changed; |
594 | } | 594 | } |
595 | EXPORT_SYMBOL_GPL(pdptrs_changed); | ||
595 | 596 | ||
596 | int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) | 597 | int kvm_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) |
597 | { | 598 | { |