Commit cf6a8b20 authored by Sean Christopherson's avatar Sean Christopherson Committed by Sasha Levin

KVM: nVMX: Plumb L2 GPA through to PML emulation

commit 2dbebf7a upstream.

Explicitly pass the L2 GPA to kvm_arch_write_log_dirty(), which for all
intents and purposes is vmx_write_pml_buffer(), instead of having the
latter pull the GPA from vmcs.GUEST_PHYSICAL_ADDRESS.  If the dirty bit
update is the result of KVM emulation (rare for L2), then the GPA in the
VMCS may be stale and/or hold a completely unrelated GPA.

Fixes: c5f983f6 ("nVMX: Implement emulated Page Modification Logging")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarSean Christopherson <sean.j.christopherson@intel.com>
Message-Id: <20200622215832.22090-2-sean.j.christopherson@intel.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 2e741229
...@@ -1099,7 +1099,7 @@ struct kvm_x86_ops { ...@@ -1099,7 +1099,7 @@ struct kvm_x86_ops {
void (*enable_log_dirty_pt_masked)(struct kvm *kvm, void (*enable_log_dirty_pt_masked)(struct kvm *kvm,
struct kvm_memory_slot *slot, struct kvm_memory_slot *slot,
gfn_t offset, unsigned long mask); gfn_t offset, unsigned long mask);
int (*write_log_dirty)(struct kvm_vcpu *vcpu); int (*write_log_dirty)(struct kvm_vcpu *vcpu, gpa_t l2_gpa);
/* pmu operations of sub-arch */ /* pmu operations of sub-arch */
const struct kvm_pmu_ops *pmu_ops; const struct kvm_pmu_ops *pmu_ops;
......
...@@ -1732,10 +1732,10 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm, ...@@ -1732,10 +1732,10 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
* Emulate arch specific page modification logging for the * Emulate arch specific page modification logging for the
* nested hypervisor * nested hypervisor
*/ */
int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu) int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu, gpa_t l2_gpa)
{ {
if (kvm_x86_ops->write_log_dirty) if (kvm_x86_ops->write_log_dirty)
return kvm_x86_ops->write_log_dirty(vcpu); return kvm_x86_ops->write_log_dirty(vcpu, l2_gpa);
return 0; return 0;
} }
......
...@@ -215,7 +215,7 @@ void kvm_mmu_gfn_disallow_lpage(struct kvm_memory_slot *slot, gfn_t gfn); ...@@ -215,7 +215,7 @@ void kvm_mmu_gfn_disallow_lpage(struct kvm_memory_slot *slot, gfn_t gfn);
void kvm_mmu_gfn_allow_lpage(struct kvm_memory_slot *slot, gfn_t gfn); void kvm_mmu_gfn_allow_lpage(struct kvm_memory_slot *slot, gfn_t gfn);
bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm, bool kvm_mmu_slot_gfn_write_protect(struct kvm *kvm,
struct kvm_memory_slot *slot, u64 gfn); struct kvm_memory_slot *slot, u64 gfn);
int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu); int kvm_arch_write_log_dirty(struct kvm_vcpu *vcpu, gpa_t l2_gpa);
int kvm_mmu_post_init_vm(struct kvm *kvm); int kvm_mmu_post_init_vm(struct kvm *kvm);
void kvm_mmu_pre_destroy_vm(struct kvm *kvm); void kvm_mmu_pre_destroy_vm(struct kvm *kvm);
......
...@@ -202,7 +202,7 @@ static inline unsigned FNAME(gpte_access)(u64 gpte) ...@@ -202,7 +202,7 @@ static inline unsigned FNAME(gpte_access)(u64 gpte)
static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu, static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu,
struct kvm_mmu *mmu, struct kvm_mmu *mmu,
struct guest_walker *walker, struct guest_walker *walker,
int write_fault) gpa_t addr, int write_fault)
{ {
unsigned level, index; unsigned level, index;
pt_element_t pte, orig_pte; pt_element_t pte, orig_pte;
...@@ -227,7 +227,7 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu, ...@@ -227,7 +227,7 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu,
!(pte & PT_GUEST_DIRTY_MASK)) { !(pte & PT_GUEST_DIRTY_MASK)) {
trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte)); trace_kvm_mmu_set_dirty_bit(table_gfn, index, sizeof(pte));
#if PTTYPE == PTTYPE_EPT #if PTTYPE == PTTYPE_EPT
if (kvm_arch_write_log_dirty(vcpu)) if (kvm_arch_write_log_dirty(vcpu, addr))
return -EINVAL; return -EINVAL;
#endif #endif
pte |= PT_GUEST_DIRTY_MASK; pte |= PT_GUEST_DIRTY_MASK;
...@@ -424,7 +424,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, ...@@ -424,7 +424,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
(PT_GUEST_DIRTY_SHIFT - PT_GUEST_ACCESSED_SHIFT); (PT_GUEST_DIRTY_SHIFT - PT_GUEST_ACCESSED_SHIFT);
if (unlikely(!accessed_dirty)) { if (unlikely(!accessed_dirty)) {
ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker, write_fault); ret = FNAME(update_accessed_dirty_bits)(vcpu, mmu, walker,
addr, write_fault);
if (unlikely(ret < 0)) if (unlikely(ret < 0))
goto error; goto error;
else if (ret) else if (ret)
......
...@@ -13845,11 +13845,10 @@ static void vmx_flush_log_dirty(struct kvm *kvm) ...@@ -13845,11 +13845,10 @@ static void vmx_flush_log_dirty(struct kvm *kvm)
kvm_flush_pml_buffers(kvm); kvm_flush_pml_buffers(kvm);
} }
static int vmx_write_pml_buffer(struct kvm_vcpu *vcpu) static int vmx_write_pml_buffer(struct kvm_vcpu *vcpu, gpa_t gpa)
{ {
struct vmcs12 *vmcs12; struct vmcs12 *vmcs12;
struct vcpu_vmx *vmx = to_vmx(vcpu); struct vcpu_vmx *vmx = to_vmx(vcpu);
gpa_t gpa;
struct page *page = NULL; struct page *page = NULL;
u64 *pml_address; u64 *pml_address;
...@@ -13870,7 +13869,7 @@ static int vmx_write_pml_buffer(struct kvm_vcpu *vcpu) ...@@ -13870,7 +13869,7 @@ static int vmx_write_pml_buffer(struct kvm_vcpu *vcpu)
return 1; return 1;
} }
gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS) & ~0xFFFull; gpa &= ~0xFFFull;
page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->pml_address); page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->pml_address);
if (is_error_page(page)) if (is_error_page(page))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment