summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/kvm_host.h10
-rw-r--r--arch/x86/kvm/mmu/mmu.c12
-rw-r--r--arch/x86/kvm/x86.c2
3 files changed, 17 insertions, 7 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index fd115feb49b3..cdee59f3d15b 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -2133,7 +2133,15 @@ int kvm_get_nr_pending_nmis(struct kvm_vcpu *vcpu);
void kvm_update_dr7(struct kvm_vcpu *vcpu);
int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn);
-bool kvm_mmu_unprotect_gfn_and_retry(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa);
+bool __kvm_mmu_unprotect_gfn_and_retry(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
+ bool always_retry);
+
+static inline bool kvm_mmu_unprotect_gfn_and_retry(struct kvm_vcpu *vcpu,
+ gpa_t cr2_or_gpa)
+{
+ return __kvm_mmu_unprotect_gfn_and_retry(vcpu, cr2_or_gpa, false);
+}
+
void kvm_mmu_free_roots(struct kvm *kvm, struct kvm_mmu *mmu,
ulong roots_to_free);
void kvm_mmu_free_guest_mode_roots(struct kvm *kvm, struct kvm_mmu *mmu);
diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
index 195ba7430720..4b4edaf7dc06 100644
--- a/arch/x86/kvm/mmu/mmu.c
+++ b/arch/x86/kvm/mmu/mmu.c
@@ -2713,10 +2713,11 @@ int kvm_mmu_unprotect_page(struct kvm *kvm, gfn_t gfn)
return r;
}
-bool kvm_mmu_unprotect_gfn_and_retry(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa)
+bool __kvm_mmu_unprotect_gfn_and_retry(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
+ bool always_retry)
{
gpa_t gpa = cr2_or_gpa;
- bool r;
+ bool r = false;
/*
* Bail early if there aren't any write-protected shadow pages to avoid
@@ -2727,16 +2728,17 @@ bool kvm_mmu_unprotect_gfn_and_retry(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa)
* skipping the unprotect+retry path, which is also an optimization.
*/
if (!READ_ONCE(vcpu->kvm->arch.indirect_shadow_pages))
- return false;
+ goto out;
if (!vcpu->arch.mmu->root_role.direct) {
gpa = kvm_mmu_gva_to_gpa_write(vcpu, cr2_or_gpa, NULL);
if (gpa == INVALID_GPA)
- return false;
+ goto out;
}
r = kvm_mmu_unprotect_page(vcpu->kvm, gpa_to_gfn(gpa));
- if (r) {
+out:
+ if (r || always_retry) {
vcpu->arch.last_retry_eip = kvm_rip_read(vcpu);
vcpu->arch.last_retry_addr = cr2_or_gpa;
}
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index ad942892fa2c..843ddb982b35 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8886,7 +8886,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
* guest to let the CPU re-execute the instruction in the hope that the
* CPU can cleanly execute the instruction that KVM failed to emulate.
*/
- kvm_mmu_unprotect_gfn_and_retry(vcpu, cr2_or_gpa);
+ __kvm_mmu_unprotect_gfn_and_retry(vcpu, cr2_or_gpa, true);
/*
* Retry even if _this_ vCPU didn't unprotect the gfn, as it's possible