kvm: x86/mmu: Init / Uninit the TDP MMU
authorBen Gardon <bgardon@google.com>
Wed, 14 Oct 2020 18:26:43 +0000 (11:26 -0700)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 21 Oct 2020 22:17:00 +0000 (18:17 -0400)
The TDP MMU offers an alternative mode of operation to the x86 shadow
paging based MMU, optimized for running an L1 guest with TDP. The TDP MMU
will require new fields that need to be initialized and torn down. Add
hooks into the existing KVM MMU initialization process to do that
initialization / cleanup. Currently the initialization and cleanup
fucntions do not do very much, however more operations will be added in
future patches.

Tested by running kvm-unit-tests and KVM selftests on an Intel Haswell
machine. This series introduced no new failures.

This series can be viewed in Gerrit at:
https://linux-review.googlesource.com/c/virt/kvm/kvm/+/2538

Signed-off-by: Ben Gardon <bgardon@google.com>
Message-Id: <20201014182700.2888246-4-bgardon@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/Makefile
arch/x86/kvm/mmu/mmu.c
arch/x86/kvm/mmu/tdp_mmu.c [new file with mode: 0644]
arch/x86/kvm/mmu/tdp_mmu.h [new file with mode: 0644]

index 8233991386a36a9899133b390897d8da3dcb6679..f6d47ac74a52415310a393bf18a0c114ec11ad50 100644 (file)
@@ -995,6 +995,15 @@ struct kvm_arch {
 
        struct kvm_pmu_event_filter *pmu_event_filter;
        struct task_struct *nx_lpage_recovery_thread;
+
+       /*
+        * Whether the TDP MMU is enabled for this VM. This contains a
+        * snapshot of the TDP MMU module parameter from when the VM was
+        * created and remains unchanged for the life of the VM. If this is
+        * true, TDP MMU handler functions will run for various MMU
+        * operations.
+        */
+       bool tdp_mmu_enabled;
 };
 
 struct kvm_vm_stat {
index a5dd4e5970f8f9393abbffbbf83f2761026a27db..b804444e16d47d017db4d24c9a52872701199128 100644 (file)
@@ -16,7 +16,7 @@ kvm-$(CONFIG_KVM_ASYNC_PF)    += $(KVM)/async_pf.o
 kvm-y                  += x86.o emulate.o i8259.o irq.o lapic.o \
                           i8254.o ioapic.o irq_comm.o cpuid.o pmu.o mtrr.o \
                           hyperv.o debugfs.o mmu/mmu.o mmu/page_track.o \
-                          mmu/spte.o mmu/tdp_iter.o
+                          mmu/spte.o mmu/tdp_iter.o mmu/tdp_mmu.o
 
 kvm-intel-y            += vmx/vmx.o vmx/vmenter.o vmx/pmu_intel.o vmx/vmcs12.o \
                           vmx/evmcs.o vmx/nested.o vmx/posted_intr.o
index 02af304c168a9491edc2a1532cad32ac93e23610..2afaf17284bb864cfa0491fc6a70de3e14850b8c 100644 (file)
@@ -19,6 +19,7 @@
 #include "ioapic.h"
 #include "mmu.h"
 #include "mmu_internal.h"
+#include "tdp_mmu.h"
 #include "x86.h"
 #include "kvm_cache_regs.h"
 #include "kvm_emulate.h"
@@ -5377,6 +5378,8 @@ void kvm_mmu_init_vm(struct kvm *kvm)
 {
        struct kvm_page_track_notifier_node *node = &kvm->arch.mmu_sp_tracker;
 
+       kvm_mmu_init_tdp_mmu(kvm);
+
        node->track_write = kvm_mmu_pte_write;
        node->track_flush_slot = kvm_mmu_invalidate_zap_pages_in_memslot;
        kvm_page_track_register_notifier(kvm, node);
@@ -5387,6 +5390,8 @@ void kvm_mmu_uninit_vm(struct kvm *kvm)
        struct kvm_page_track_notifier_node *node = &kvm->arch.mmu_sp_tracker;
 
        kvm_page_track_unregister_notifier(kvm, node);
+
+       kvm_mmu_uninit_tdp_mmu(kvm);
 }
 
 void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
diff --git a/arch/x86/kvm/mmu/tdp_mmu.c b/arch/x86/kvm/mmu/tdp_mmu.c
new file mode 100644 (file)
index 0000000..e567e8a
--- /dev/null
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "tdp_mmu.h"
+
+static bool __read_mostly tdp_mmu_enabled = false;
+
+static bool is_tdp_mmu_enabled(void)
+{
+#ifdef CONFIG_X86_64
+       return tdp_enabled && READ_ONCE(tdp_mmu_enabled);
+#else
+       return false;
+#endif /* CONFIG_X86_64 */
+}
+
+/* Initializes the TDP MMU for the VM, if enabled. */
+void kvm_mmu_init_tdp_mmu(struct kvm *kvm)
+{
+       if (!is_tdp_mmu_enabled())
+               return;
+
+       /* This should not be changed for the lifetime of the VM. */
+       kvm->arch.tdp_mmu_enabled = true;
+}
+
+void kvm_mmu_uninit_tdp_mmu(struct kvm *kvm)
+{
+       if (!kvm->arch.tdp_mmu_enabled)
+               return;
+}
diff --git a/arch/x86/kvm/mmu/tdp_mmu.h b/arch/x86/kvm/mmu/tdp_mmu.h
new file mode 100644 (file)
index 0000000..cd4a562
--- /dev/null
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#ifndef __KVM_X86_MMU_TDP_MMU_H
+#define __KVM_X86_MMU_TDP_MMU_H
+
+#include <linux/kvm_host.h>
+
+void kvm_mmu_init_tdp_mmu(struct kvm *kvm);
+void kvm_mmu_uninit_tdp_mmu(struct kvm *kvm);
+#endif /* __KVM_X86_MMU_TDP_MMU_H */