|
@@ -26,6 +26,7 @@
|
|
|
#include <linux/slab.h>
|
|
|
#include <linux/timer.h>
|
|
|
#include <linux/vmalloc.h>
|
|
|
+#include <linux/bitmap.h>
|
|
|
#include <asm/asm-offsets.h>
|
|
|
#include <asm/lowcore.h>
|
|
|
#include <asm/etr.h>
|
|
@@ -132,6 +133,9 @@ unsigned long kvm_s390_fac_list_mask_size(void)
|
|
|
return ARRAY_SIZE(kvm_s390_fac_list_mask);
|
|
|
}
|
|
|
|
|
|
+/* available cpu features supported by kvm */
|
|
|
+static DECLARE_BITMAP(kvm_s390_available_cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
|
|
|
+
|
|
|
static struct gmap_notifier gmap_notifier;
|
|
|
debug_info_t *kvm_s390_dbf;
|
|
|
|
|
@@ -677,6 +681,29 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int kvm_s390_set_processor_feat(struct kvm *kvm,
|
|
|
+ struct kvm_device_attr *attr)
|
|
|
+{
|
|
|
+ struct kvm_s390_vm_cpu_feat data;
|
|
|
+ int ret = -EBUSY;
|
|
|
+
|
|
|
+ if (copy_from_user(&data, (void __user *)attr->addr, sizeof(data)))
|
|
|
+ return -EFAULT;
|
|
|
+ if (!bitmap_subset((unsigned long *) data.feat,
|
|
|
+ kvm_s390_available_cpu_feat,
|
|
|
+ KVM_S390_VM_CPU_FEAT_NR_BITS))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ mutex_lock(&kvm->lock);
|
|
|
+ if (!atomic_read(&kvm->online_vcpus)) {
|
|
|
+ bitmap_copy(kvm->arch.cpu_feat, (unsigned long *) data.feat,
|
|
|
+ KVM_S390_VM_CPU_FEAT_NR_BITS);
|
|
|
+ ret = 0;
|
|
|
+ }
|
|
|
+ mutex_unlock(&kvm->lock);
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
static int kvm_s390_set_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr)
|
|
|
{
|
|
|
int ret = -ENXIO;
|
|
@@ -685,6 +712,9 @@ static int kvm_s390_set_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr)
|
|
|
case KVM_S390_VM_CPU_PROCESSOR:
|
|
|
ret = kvm_s390_set_processor(kvm, attr);
|
|
|
break;
|
|
|
+ case KVM_S390_VM_CPU_PROCESSOR_FEAT:
|
|
|
+ ret = kvm_s390_set_processor_feat(kvm, attr);
|
|
|
+ break;
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
@@ -733,6 +763,31 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static int kvm_s390_get_processor_feat(struct kvm *kvm,
|
|
|
+ struct kvm_device_attr *attr)
|
|
|
+{
|
|
|
+ struct kvm_s390_vm_cpu_feat data;
|
|
|
+
|
|
|
+ bitmap_copy((unsigned long *) data.feat, kvm->arch.cpu_feat,
|
|
|
+ KVM_S390_VM_CPU_FEAT_NR_BITS);
|
|
|
+ if (copy_to_user((void __user *)attr->addr, &data, sizeof(data)))
|
|
|
+ return -EFAULT;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int kvm_s390_get_machine_feat(struct kvm *kvm,
|
|
|
+ struct kvm_device_attr *attr)
|
|
|
+{
|
|
|
+ struct kvm_s390_vm_cpu_feat data;
|
|
|
+
|
|
|
+ bitmap_copy((unsigned long *) data.feat,
|
|
|
+ kvm_s390_available_cpu_feat,
|
|
|
+ KVM_S390_VM_CPU_FEAT_NR_BITS);
|
|
|
+ if (copy_to_user((void __user *)attr->addr, &data, sizeof(data)))
|
|
|
+ return -EFAULT;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int kvm_s390_get_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr)
|
|
|
{
|
|
|
int ret = -ENXIO;
|
|
@@ -744,6 +799,12 @@ static int kvm_s390_get_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr)
|
|
|
case KVM_S390_VM_CPU_MACHINE:
|
|
|
ret = kvm_s390_get_machine(kvm, attr);
|
|
|
break;
|
|
|
+ case KVM_S390_VM_CPU_PROCESSOR_FEAT:
|
|
|
+ ret = kvm_s390_get_processor_feat(kvm, attr);
|
|
|
+ break;
|
|
|
+ case KVM_S390_VM_CPU_MACHINE_FEAT:
|
|
|
+ ret = kvm_s390_get_machine_feat(kvm, attr);
|
|
|
+ break;
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
@@ -827,6 +888,8 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
|
|
|
switch (attr->attr) {
|
|
|
case KVM_S390_VM_CPU_PROCESSOR:
|
|
|
case KVM_S390_VM_CPU_MACHINE:
|
|
|
+ case KVM_S390_VM_CPU_PROCESSOR_FEAT:
|
|
|
+ case KVM_S390_VM_CPU_MACHINE_FEAT:
|
|
|
ret = 0;
|
|
|
break;
|
|
|
default:
|