]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
KVM: x86/xen: Maintain valid mapping of Xen shared_info page
authorDavid Woodhouse <dwmw@amazon.co.uk>
Sat, 30 Oct 2021 18:53:23 +0000 (19:53 +0100)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Fri, 10 Dec 2021 15:48:36 +0000 (15:48 +0000)
Use the newly reinstated gfn_to_pfn_cache to maintain a kernel mapping
of the Xen shared_info page so that it can be accessed in atomic context.

Note that we do not participate in dirty tracking for the shared info
page and we do not explicitly mark it dirty every single tim we deliver
an event channel interrupts. We wouldn't want to do that even if we *did*
have a valid vCPU context with which to do so.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
Documentation/virt/kvm/api.rst
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/xen.c

index aeeb071c7688198cf0f5e29af3b431e8604c742b..455664c39d4275c61f20a08fd385b5908ce3839f 100644 (file)
@@ -371,6 +371,9 @@ The bits in the dirty bitmap are cleared before the ioctl returns, unless
 KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is enabled.  For more information,
 see the description of the capability.
 
+Note that the Xen shared info page, if configured, shall always be assumed
+to be dirty. KVM will not explicitly mark it such.
+
 4.9 KVM_SET_MEMORY_ALIAS
 ------------------------
 
@@ -5134,6 +5137,15 @@ KVM_XEN_ATTR_TYPE_SHARED_INFO
   not aware of the Xen CPU id which is used as the index into the
   vcpu_info[] array, so cannot know the correct default location.
 
+  Note that the shared info page may be constantly written to by KVM;
+  it contains the event channel bitmap used to deliver interrupts to
+  a Xen guest, amongst other things. It is exempt from dirty tracking
+  mechanisms — KVM will not explicitly mark the page as dirty each
+  time an event channel interrupt is delivered to the guest! Thus,
+  userspace should always assume that the designated GFN is dirty if
+  any vCPU has been running or any event channel interrupts can be
+  routed to the guest.
+
 KVM_XEN_ATTR_TYPE_UPCALL_VECTOR
   Sets the exception vector used to deliver Xen event channel upcalls.
 
index d5fede05eb5fc41867852444a3c32ad8e8037e94..a49d503e7296d2293e23f49c02c7f05182d3809c 100644 (file)
@@ -1019,7 +1019,7 @@ struct msr_bitmap_range {
 struct kvm_xen {
        bool long_mode;
        u8 upcall_vector;
-       gfn_t shinfo_gfn;
+       struct gfn_to_pfn_cache shinfo_cache;
 };
 
 enum kvm_irqchip_mode {
index dff2bdf9507a8cf679f449b277666df1ccf34773..da4bf2c6407fff65f3721ca99c9663ba46a36406 100644 (file)
@@ -23,16 +23,21 @@ DEFINE_STATIC_KEY_DEFERRED_FALSE(kvm_xen_enabled, HZ);
 
 static int kvm_xen_shared_info_init(struct kvm *kvm, gfn_t gfn)
 {
+       struct gfn_to_pfn_cache *gpc = &kvm->arch.xen.shinfo_cache;
        gpa_t gpa = gfn_to_gpa(gfn);
        int wc_ofs, sec_hi_ofs;
        int ret = 0;
        int idx = srcu_read_lock(&kvm->srcu);
 
-       if (kvm_is_error_hva(gfn_to_hva(kvm, gfn))) {
-               ret = -EFAULT;
+       if (gfn == GPA_INVALID) {
+               kvm_gfn_to_pfn_cache_destroy(kvm, gpc);
                goto out;
        }
-       kvm->arch.xen.shinfo_gfn = gfn;
+
+       ret = kvm_gfn_to_pfn_cache_init(kvm, gpc, NULL, false, true, gpa,
+                                       PAGE_SIZE, false);
+       if (ret)
+               goto out;
 
        /* Paranoia checks on the 32-bit struct layout */
        BUILD_BUG_ON(offsetof(struct compat_shared_info, wc) != 0x900);
@@ -260,15 +265,9 @@ int kvm_xen_hvm_set_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
                break;
 
        case KVM_XEN_ATTR_TYPE_SHARED_INFO:
-               if (data->u.shared_info.gfn == GPA_INVALID) {
-                       kvm->arch.xen.shinfo_gfn = GPA_INVALID;
-                       r = 0;
-                       break;
-               }
                r = kvm_xen_shared_info_init(kvm, data->u.shared_info.gfn);
                break;
 
-
        case KVM_XEN_ATTR_TYPE_UPCALL_VECTOR:
                if (data->u.vector && data->u.vector < 0x10)
                        r = -EINVAL;
@@ -299,7 +298,10 @@ int kvm_xen_hvm_get_attr(struct kvm *kvm, struct kvm_xen_hvm_attr *data)
                break;
 
        case KVM_XEN_ATTR_TYPE_SHARED_INFO:
-               data->u.shared_info.gfn = kvm->arch.xen.shinfo_gfn;
+               if (kvm->arch.xen.shinfo_cache.active)
+                       data->u.shared_info.gfn = gpa_to_gfn(kvm->arch.xen.shinfo_cache.gpa);
+               else
+                       data->u.shared_info.gfn = GPA_INVALID;
                r = 0;
                break;
 
@@ -661,11 +663,12 @@ int kvm_xen_hvm_config(struct kvm *kvm, struct kvm_xen_hvm_config *xhc)
 
 void kvm_xen_init_vm(struct kvm *kvm)
 {
-       kvm->arch.xen.shinfo_gfn = GPA_INVALID;
 }
 
 void kvm_xen_destroy_vm(struct kvm *kvm)
 {
+       kvm_gfn_to_pfn_cache_destroy(kvm, &kvm->arch.xen.shinfo_cache);
+
        if (kvm->arch.xen_hvm_config.msr)
                static_branch_slow_dec_deferred(&kvm_xen_enabled);
 }