KVM: x86: do not deliver asynchronous page faults if CR0.PG=0
authorPaolo Bonzini <pbonzini@redhat.com>
Wed, 9 Feb 2022 10:17:38 +0000 (05:17 -0500)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 25 Feb 2022 13:20:16 +0000 (08:20 -0500)
Enabling async page faults is nonsensical if paging is disabled, but
it is allowed because CR0.PG=0 does not clear the async page fault
MSR.  Just ignore them and only use the artificial halt state,
similar to what happens in guest mode if async #PF vmexits are disabled.

Given the increasingly complex logic, and the nicer code if the new
"if" is placed last, opportunistically change the "||" into a chain
of "if (...) return false" statements.

Reviewed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/x86.c

index b724273493d81d1902111ac89fdd5437ccb7879a..365a70ec738ee2a51459d78b5acf7c7bd0951aa1 100644 (file)
@@ -12287,14 +12287,28 @@ static inline bool apf_pageready_slot_free(struct kvm_vcpu *vcpu)
 
 static bool kvm_can_deliver_async_pf(struct kvm_vcpu *vcpu)
 {
-       if (!vcpu->arch.apf.delivery_as_pf_vmexit && is_guest_mode(vcpu))
+
+       if (!kvm_pv_async_pf_enabled(vcpu))
                return false;
 
-       if (!kvm_pv_async_pf_enabled(vcpu) ||
-           (vcpu->arch.apf.send_user_only && static_call(kvm_x86_get_cpl)(vcpu) == 0))
+       if (vcpu->arch.apf.send_user_only &&
+           static_call(kvm_x86_get_cpl)(vcpu) == 0)
                return false;
 
-       return true;
+       if (is_guest_mode(vcpu)) {
+               /*
+                * L1 needs to opt into the special #PF vmexits that are
+                * used to deliver async page faults.
+                */
+               return vcpu->arch.apf.delivery_as_pf_vmexit;
+       } else {
+               /*
+                * Play it safe in case the guest temporarily disables paging.
+                * The real mode IDT in particular is unlikely to have a #PF
+                * exception setup.
+                */
+               return is_paging(vcpu);
+       }
 }
 
 bool kvm_can_do_async_pf(struct kvm_vcpu *vcpu)