Introduce a new KVM device aimed at tracking partition wide VTL state,
it'll be the one responsible from keeping track of VTL's memory
protections. For now its functionality it's limited, it only exposes its
VTL level through a device attribute. Additionally, the device type is
only registered if the VSM cap is enabled.

Signed-off-by: Nicolas Saenz Julienne <nsa...@amazon.com>
---
 arch/x86/kvm/hyperv.c    | 68 ++++++++++++++++++++++++++++++++++++++++
 arch/x86/kvm/hyperv.h    |  3 ++
 arch/x86/kvm/x86.c       |  3 ++
 include/uapi/linux/kvm.h |  5 +++
 4 files changed, 79 insertions(+)

diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
index a266c5d393f5..0d8402dba596 100644
--- a/arch/x86/kvm/hyperv.c
+++ b/arch/x86/kvm/hyperv.c
@@ -3022,3 +3022,71 @@ int kvm_vm_ioctl_get_hv_vsm_state(struct kvm *kvm, 
struct kvm_hv_vsm_state *stat
        state->vsm_code_page_offsets = hv->vsm_code_page_offsets.as_u64;
        return 0;
 }
+
+struct kvm_hv_vtl_dev {
+       int vtl;
+};
+
+static int kvm_hv_vtl_get_attr(struct kvm_device *dev,
+                              struct kvm_device_attr *attr)
+{
+       struct kvm_hv_vtl_dev *vtl_dev = dev->private;
+
+       switch (attr->group) {
+       case KVM_DEV_HV_VTL_GROUP:
+       switch (attr->attr){
+       case KVM_DEV_HV_VTL_GROUP_VTLNUM:
+               return put_user(vtl_dev->vtl, (u32 __user *)attr->addr);
+       }
+       }
+
+       return -EINVAL;
+}
+
+static void kvm_hv_vtl_release(struct kvm_device *dev)
+{
+       struct kvm_hv_vtl_dev *vtl_dev = dev->private;
+
+       kfree(vtl_dev);
+       kfree(dev); /* alloc by kvm_ioctl_create_device, free by .release */
+}
+
+static int kvm_hv_vtl_create(struct kvm_device *dev, u32 type);
+
+static struct kvm_device_ops kvm_hv_vtl_ops = {
+       .name = "kvm-hv-vtl",
+       .create = kvm_hv_vtl_create,
+       .release = kvm_hv_vtl_release,
+       .get_attr = kvm_hv_vtl_get_attr,
+};
+
+static int kvm_hv_vtl_create(struct kvm_device *dev, u32 type)
+{
+       struct kvm_hv_vtl_dev *vtl_dev;
+       struct kvm_device *tmp;
+       int vtl = 0;
+
+       vtl_dev = kzalloc(sizeof(*vtl_dev), GFP_KERNEL_ACCOUNT);
+       if (!vtl_dev)
+               return -ENOMEM;
+
+       /* Device creation is protected by kvm->lock */
+       list_for_each_entry(tmp, &dev->kvm->devices, vm_node)
+               if (tmp->ops == &kvm_hv_vtl_ops)
+                       vtl++;
+
+       vtl_dev->vtl = vtl;
+       dev->private = vtl_dev;
+
+       return 0;
+}
+
+int kvm_hv_vtl_dev_register(void)
+{
+       return kvm_register_device_ops(&kvm_hv_vtl_ops, 
KVM_DEV_TYPE_HV_VSM_VTL);
+}
+
+void kvm_hv_vtl_dev_unregister(void)
+{
+       kvm_unregister_device_ops(KVM_DEV_TYPE_HV_VSM_VTL);
+}
diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
index 605e80b9e5eb..3cc664e144d8 100644
--- a/arch/x86/kvm/hyperv.h
+++ b/arch/x86/kvm/hyperv.h
@@ -269,4 +269,7 @@ static inline void kvm_mmu_role_set_hv_bits(struct kvm_vcpu 
*vcpu,
        role->vtl = kvm_hv_get_active_vtl(vcpu);
 }
 
+int kvm_hv_vtl_dev_register(void);
+void kvm_hv_vtl_dev_unregister(void);
+
 #endif
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index bf4891bc044e..82d3b86d9c93 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -6521,6 +6521,7 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
                mutex_unlock(&kvm->lock);
                break;
        case KVM_CAP_HYPERV_VSM:
+               kvm_hv_vtl_dev_register();
                kvm->arch.hyperv.hv_enable_vsm = true;
                r = 0;
                break;
@@ -9675,6 +9676,8 @@ void kvm_x86_vendor_exit(void)
        mutex_lock(&vendor_module_lock);
        kvm_x86_ops.hardware_enable = NULL;
        mutex_unlock(&vendor_module_lock);
+
+       kvm_hv_vtl_dev_unregister();
 }
 EXPORT_SYMBOL_GPL(kvm_x86_vendor_exit);
 
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 0ddffb8b0c99..bd97c9852142 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1471,6 +1471,9 @@ struct kvm_device_attr {
 #define   KVM_DEV_VFIO_GROUP_DEL       KVM_DEV_VFIO_FILE_DEL
 #define   KVM_DEV_VFIO_GROUP_SET_SPAPR_TCE             3
 
+#define KVM_DEV_HV_VTL_GROUP           1
+#define  KVM_DEV_HV_VTL_GROUP_VTLNUM           1
+
 enum kvm_device_type {
        KVM_DEV_TYPE_FSL_MPIC_20        = 1,
 #define KVM_DEV_TYPE_FSL_MPIC_20       KVM_DEV_TYPE_FSL_MPIC_20
@@ -1494,6 +1497,8 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_ARM_PV_TIME       KVM_DEV_TYPE_ARM_PV_TIME
        KVM_DEV_TYPE_RISCV_AIA,
 #define KVM_DEV_TYPE_RISCV_AIA         KVM_DEV_TYPE_RISCV_AIA
+       KVM_DEV_TYPE_HV_VSM_VTL,
+#define KVM_DEV_TYPE_HV_VSM_VTL                KVM_DEV_TYPE_HV_VSM_VTL
        KVM_DEV_TYPE_MAX,
 };
 
-- 
2.40.1


Reply via email to