提交 15c9705f 编写于 作者: D David Hildenbrand 提交者: Christian Borntraeger

KVM: s390: interface to query and configure cpu features

For now, we only have an interface to query and configure facilities
indicated via STFL(E). However, we also have features indicated via
SCLP, that have to be indicated to the guest by user space and usually
require KVM support.

This patch allows user space to query and configure available cpu features
for the guest.

Please note that disabling a feature doesn't necessarily mean that it is
completely disabled (e.g. ESOP is mostly handled by the SIE). We will try
our best to disable it.

Most features (e.g. SCLP) can't directly be forwarded, as most of them need
in addition to hardware support, support in KVM. As we later on want to
turn these features in KVM explicitly on/off (to simulate different
behavior), we have to filter all features provided by the hardware and
make them configurable.
Signed-off-by: NDavid Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: NChristian Borntraeger <borntraeger@de.ibm.com>
上级 c1778e51
...@@ -85,6 +85,33 @@ Returns: -EBUSY in case 1 or more vcpus are already activated (only in write ...@@ -85,6 +85,33 @@ Returns: -EBUSY in case 1 or more vcpus are already activated (only in write
-ENOMEM if not enough memory is available to process the ioctl -ENOMEM if not enough memory is available to process the ioctl
0 in case of success 0 in case of success
2.3. ATTRIBUTE: KVM_S390_VM_CPU_MACHINE_FEAT (r/o)
Allows user space to retrieve available cpu features. A feature is available if
provided by the hardware and supported by kvm. In theory, cpu features could
even be completely emulated by kvm.
struct kvm_s390_vm_cpu_feat {
__u64 feat[16]; # Bitmap (1 = feature available), MSB 0 bit numbering
};
Parameters: address of a buffer to load the feature list from.
Returns: -EFAULT if the given address is not accessible from kernel space.
0 in case of success.
2.4. ATTRIBUTE: KVM_S390_VM_CPU_PROCESSOR_FEAT (r/w)
Allows user space to retrieve or change enabled cpu features for all VCPUs of a
VM. Features that are not available cannot be enabled.
See 2.3. for a description of the parameter struct.
Parameters: address of a buffer to store/load the feature list from.
Returns: -EFAULT if the given address is not accessible from kernel space.
-EINVAL if a cpu feature that is not available is to be enabled.
-EBUSY if at least one VCPU has already been defined.
0 in case of success.
3. GROUP: KVM_S390_VM_TOD 3. GROUP: KVM_S390_VM_TOD
Architectures: s390 Architectures: s390
......
...@@ -658,6 +658,8 @@ struct kvm_arch{ ...@@ -658,6 +658,8 @@ struct kvm_arch{
struct kvm_s390_cpu_model model; struct kvm_s390_cpu_model model;
struct kvm_s390_crypto crypto; struct kvm_s390_crypto crypto;
u64 epoch; u64 epoch;
/* subset of available cpu features enabled by user space */
DECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
}; };
#define KVM_HVA_ERR_BAD (-1UL) #define KVM_HVA_ERR_BAD (-1UL)
......
...@@ -93,6 +93,14 @@ struct kvm_s390_vm_cpu_machine { ...@@ -93,6 +93,14 @@ struct kvm_s390_vm_cpu_machine {
__u64 fac_list[256]; __u64 fac_list[256];
}; };
#define KVM_S390_VM_CPU_PROCESSOR_FEAT 2
#define KVM_S390_VM_CPU_MACHINE_FEAT 3
#define KVM_S390_VM_CPU_FEAT_NR_BITS 1024
struct kvm_s390_vm_cpu_feat {
__u64 feat[16];
};
/* kvm attributes for crypto */ /* kvm attributes for crypto */
#define KVM_S390_VM_CRYPTO_ENABLE_AES_KW 0 #define KVM_S390_VM_CRYPTO_ENABLE_AES_KW 0
#define KVM_S390_VM_CRYPTO_ENABLE_DEA_KW 1 #define KVM_S390_VM_CRYPTO_ENABLE_DEA_KW 1
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/bitmap.h>
#include <asm/asm-offsets.h> #include <asm/asm-offsets.h>
#include <asm/lowcore.h> #include <asm/lowcore.h>
#include <asm/etr.h> #include <asm/etr.h>
...@@ -132,6 +133,9 @@ unsigned long kvm_s390_fac_list_mask_size(void) ...@@ -132,6 +133,9 @@ unsigned long kvm_s390_fac_list_mask_size(void)
return ARRAY_SIZE(kvm_s390_fac_list_mask); 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; static struct gmap_notifier gmap_notifier;
debug_info_t *kvm_s390_dbf; debug_info_t *kvm_s390_dbf;
...@@ -677,6 +681,29 @@ static int kvm_s390_set_processor(struct kvm *kvm, struct kvm_device_attr *attr) ...@@ -677,6 +681,29 @@ static int kvm_s390_set_processor(struct kvm *kvm, struct kvm_device_attr *attr)
return ret; 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) static int kvm_s390_set_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr)
{ {
int ret = -ENXIO; int ret = -ENXIO;
...@@ -685,6 +712,9 @@ static int kvm_s390_set_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr) ...@@ -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: case KVM_S390_VM_CPU_PROCESSOR:
ret = kvm_s390_set_processor(kvm, attr); ret = kvm_s390_set_processor(kvm, attr);
break; break;
case KVM_S390_VM_CPU_PROCESSOR_FEAT:
ret = kvm_s390_set_processor_feat(kvm, attr);
break;
} }
return ret; return ret;
} }
...@@ -733,6 +763,31 @@ static int kvm_s390_get_machine(struct kvm *kvm, struct kvm_device_attr *attr) ...@@ -733,6 +763,31 @@ static int kvm_s390_get_machine(struct kvm *kvm, struct kvm_device_attr *attr)
return ret; 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) static int kvm_s390_get_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr)
{ {
int ret = -ENXIO; int ret = -ENXIO;
...@@ -744,6 +799,12 @@ static int kvm_s390_get_cpu_model(struct kvm *kvm, struct kvm_device_attr *attr) ...@@ -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: case KVM_S390_VM_CPU_MACHINE:
ret = kvm_s390_get_machine(kvm, attr); ret = kvm_s390_get_machine(kvm, attr);
break; 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; return ret;
} }
...@@ -827,6 +888,8 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr) ...@@ -827,6 +888,8 @@ static int kvm_s390_vm_has_attr(struct kvm *kvm, struct kvm_device_attr *attr)
switch (attr->attr) { switch (attr->attr) {
case KVM_S390_VM_CPU_PROCESSOR: case KVM_S390_VM_CPU_PROCESSOR:
case KVM_S390_VM_CPU_MACHINE: case KVM_S390_VM_CPU_MACHINE:
case KVM_S390_VM_CPU_PROCESSOR_FEAT:
case KVM_S390_VM_CPU_MACHINE_FEAT:
ret = 0; ret = 0;
break; break;
default: default:
......
...@@ -175,6 +175,12 @@ static inline int set_kvm_facility(u64 *fac_list, unsigned long nr) ...@@ -175,6 +175,12 @@ static inline int set_kvm_facility(u64 *fac_list, unsigned long nr)
return 0; return 0;
} }
static inline int test_kvm_cpu_feat(struct kvm *kvm, unsigned long nr)
{
WARN_ON_ONCE(nr >= KVM_S390_VM_CPU_FEAT_NR_BITS);
return test_bit_inv(nr, kvm->arch.cpu_feat);
}
/* are cpu states controlled by user space */ /* are cpu states controlled by user space */
static inline int kvm_s390_user_cpu_state_ctrl(struct kvm *kvm) static inline int kvm_s390_user_cpu_state_ctrl(struct kvm *kvm)
{ {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册