Added two fields .exported_tdp_meta_size and .exported_tdp_meta_compose in
kvm_x86_ops to allow vendor specific code to compose meta data of exported
TDP and provided an arch interface for external components to get the
composed meta data.
As the meta data is consumed in IOMMU's vendor driver to check if the
exported TDP is compatible to the IOMMU hardware before reusing them as
IOMMU's stage 2 page tables, it's better to compose them in KVM's vendor
spcific code too.
Signed-off-by: Yan Zhao <yan.y.zhao@intel.com>
---
arch/x86/include/asm/kvm-x86-ops.h | 3 +++
arch/x86/include/asm/kvm_host.h | 7 +++++++
arch/x86/kvm/x86.c | 23 ++++++++++++++++++++++-
include/linux/kvm_host.h | 6 ++++++
virt/kvm/tdp_fd.c | 2 +-
5 files changed, 39 insertions(+), 2 deletions(-)
@@ -136,6 +136,9 @@ KVM_X86_OP(msr_filter_changed)
KVM_X86_OP(complete_emulated_msr)
KVM_X86_OP(vcpu_deliver_sipi_vector)
KVM_X86_OP_OPTIONAL_RET0(vcpu_get_apicv_inhibit_reasons);
+#if IS_ENABLED(CONFIG_HAVE_KVM_EXPORTED_TDP)
+KVM_X86_OP_OPTIONAL(exported_tdp_meta_compose);
+#endif
#undef KVM_X86_OP
#undef KVM_X86_OP_OPTIONAL
@@ -26,6 +26,7 @@
#include <linux/irqbypass.h>
#include <linux/hyperv.h>
#include <linux/kfifo.h>
+#include <linux/kvm_tdp_fd.h>
#include <asm/apic.h>
#include <asm/pvclock-abi.h>
@@ -1493,6 +1494,7 @@ struct kvm_exported_tdp_mmu {
};
struct kvm_arch_exported_tdp {
struct kvm_exported_tdp_mmu mmu;
+ void *meta;
};
#endif
@@ -1784,6 +1786,11 @@ struct kvm_x86_ops {
* Returns vCPU specific APICv inhibit reasons
*/
unsigned long (*vcpu_get_apicv_inhibit_reasons)(struct kvm_vcpu *vcpu);
+
+#ifdef CONFIG_HAVE_KVM_EXPORTED_TDP
+ unsigned long exported_tdp_meta_size;
+ void (*exported_tdp_meta_compose)(struct kvm_exported_tdp *tdp);
+#endif
};
struct kvm_x86_nested_ops {
@@ -13432,18 +13432,39 @@ EXPORT_SYMBOL_GPL(kvm_arch_no_poll);
#ifdef CONFIG_HAVE_KVM_EXPORTED_TDP
int kvm_arch_exported_tdp_init(struct kvm *kvm, struct kvm_exported_tdp *tdp)
{
+ void *meta;
int ret;
+ if (!kvm_x86_ops.exported_tdp_meta_size ||
+ !kvm_x86_ops.exported_tdp_meta_compose)
+ return -EOPNOTSUPP;
+
+ meta = __vmalloc(kvm_x86_ops.exported_tdp_meta_size,
+ GFP_KERNEL_ACCOUNT | __GFP_ZERO);
+ if (!meta)
+ return -ENOMEM;
+
+ tdp->arch.meta = meta;
+
ret = kvm_mmu_get_exported_tdp(kvm, tdp);
- if (ret)
+ if (ret) {
+ kvfree(meta);
return ret;
+ }
+ static_call(kvm_x86_exported_tdp_meta_compose)(tdp);
return 0;
}
void kvm_arch_exported_tdp_destroy(struct kvm_exported_tdp *tdp)
{
kvm_mmu_put_exported_tdp(tdp);
+ kvfree(tdp->arch.meta);
+}
+
+void *kvm_arch_exported_tdp_get_metadata(struct kvm_exported_tdp *tdp)
+{
+ return tdp->arch.meta;
}
int kvm_arch_fault_exported_tdp(struct kvm_exported_tdp *tdp, unsigned long gfn,
@@ -2348,6 +2348,7 @@ int kvm_arch_exported_tdp_init(struct kvm *kvm, struct kvm_exported_tdp *tdp);
void kvm_arch_exported_tdp_destroy(struct kvm_exported_tdp *tdp);
int kvm_arch_fault_exported_tdp(struct kvm_exported_tdp *tdp, unsigned long gfn,
struct kvm_tdp_fault_type type);
+void *kvm_arch_exported_tdp_get_metadata(struct kvm_exported_tdp *tdp);
#else
static inline int kvm_arch_exported_tdp_init(struct kvm *kvm,
struct kvm_exported_tdp *tdp)
@@ -2364,6 +2365,11 @@ static inline int kvm_arch_fault_exported_tdp(struct kvm_exported_tdp *tdp,
{
return -EOPNOTSUPP;
}
+
+static inline void *kvm_arch_exported_tdp_get_metadata(struct kvm_exported_tdp *tdp)
+{
+ return NULL;
+}
#endif /* __KVM_HAVE_ARCH_EXPORTED_TDP */
void kvm_tdp_fd_flush_notify(struct kvm *kvm, unsigned long gfn, unsigned long npages);
@@ -217,7 +217,7 @@ static void kvm_tdp_unregister_all_importers(struct kvm_exported_tdp *tdp)
static void *kvm_tdp_get_metadata(struct kvm_tdp_fd *tdp_fd)
{
- return ERR_PTR(-EOPNOTSUPP);
+ return kvm_arch_exported_tdp_get_metadata(tdp_fd->priv);
}
static int kvm_tdp_fault(struct kvm_tdp_fd *tdp_fd, struct mm_struct *mm,