KVM: x86: Add a framework for supporting MSR-based features
Provide a new KVM capability that allows bits within MSRs to be recognized as features. Two new ioctls are added to the /dev/kvm ioctl routine to retrieve the list of these MSRs and then retrieve their values. A kvm_x86_ops callback is used to determine support for the listed MSR-based features. Signed-off-by: Tom Lendacky <thomas.lendacky@amd.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> [Tweaked documentation. - Radim] Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
This commit is contained in:
parent
d4858aaf6b
commit
801e459a6f
@ -123,14 +123,15 @@ memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the
|
||||
flag KVM_VM_MIPS_VZ.
|
||||
|
||||
|
||||
4.3 KVM_GET_MSR_INDEX_LIST
|
||||
4.3 KVM_GET_MSR_INDEX_LIST, KVM_GET_MSR_FEATURE_INDEX_LIST
|
||||
|
||||
Capability: basic
|
||||
Capability: basic, KVM_CAP_GET_MSR_FEATURES for KVM_GET_MSR_FEATURE_INDEX_LIST
|
||||
Architectures: x86
|
||||
Type: system
|
||||
Type: system ioctl
|
||||
Parameters: struct kvm_msr_list (in/out)
|
||||
Returns: 0 on success; -1 on error
|
||||
Errors:
|
||||
EFAULT: the msr index list cannot be read from or written to
|
||||
E2BIG: the msr index list is to be to fit in the array specified by
|
||||
the user.
|
||||
|
||||
@ -139,16 +140,23 @@ struct kvm_msr_list {
|
||||
__u32 indices[0];
|
||||
};
|
||||
|
||||
This ioctl returns the guest msrs that are supported. The list varies
|
||||
by kvm version and host processor, but does not change otherwise. The
|
||||
user fills in the size of the indices array in nmsrs, and in return
|
||||
kvm adjusts nmsrs to reflect the actual number of msrs and fills in
|
||||
the indices array with their numbers.
|
||||
The user fills in the size of the indices array in nmsrs, and in return
|
||||
kvm adjusts nmsrs to reflect the actual number of msrs and fills in the
|
||||
indices array with their numbers.
|
||||
|
||||
KVM_GET_MSR_INDEX_LIST returns the guest msrs that are supported. The list
|
||||
varies by kvm version and host processor, but does not change otherwise.
|
||||
|
||||
Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are
|
||||
not returned in the MSR list, as different vcpus can have a different number
|
||||
of banks, as set via the KVM_X86_SETUP_MCE ioctl.
|
||||
|
||||
KVM_GET_MSR_FEATURE_INDEX_LIST returns the list of MSRs that can be passed
|
||||
to the KVM_GET_MSRS system ioctl. This lets userspace probe host capabilities
|
||||
and processor features that are exposed via MSRs (e.g., VMX capabilities).
|
||||
This list also varies by kvm version and host processor, but does not change
|
||||
otherwise.
|
||||
|
||||
|
||||
4.4 KVM_CHECK_EXTENSION
|
||||
|
||||
@ -475,14 +483,22 @@ Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead.
|
||||
|
||||
4.18 KVM_GET_MSRS
|
||||
|
||||
Capability: basic
|
||||
Capability: basic (vcpu), KVM_CAP_GET_MSR_FEATURES (system)
|
||||
Architectures: x86
|
||||
Type: vcpu ioctl
|
||||
Type: system ioctl, vcpu ioctl
|
||||
Parameters: struct kvm_msrs (in/out)
|
||||
Returns: 0 on success, -1 on error
|
||||
Returns: number of msrs successfully returned;
|
||||
-1 on error
|
||||
|
||||
When used as a system ioctl:
|
||||
Reads the values of MSR-based features that are available for the VM. This
|
||||
is similar to KVM_GET_SUPPORTED_CPUID, but it returns MSR indices and values.
|
||||
The list of msr-based features can be obtained using KVM_GET_MSR_FEATURE_INDEX_LIST
|
||||
in a system ioctl.
|
||||
|
||||
When used as a vcpu ioctl:
|
||||
Reads model-specific registers from the vcpu. Supported msr indices can
|
||||
be obtained using KVM_GET_MSR_INDEX_LIST.
|
||||
be obtained using KVM_GET_MSR_INDEX_LIST in a system ioctl.
|
||||
|
||||
struct kvm_msrs {
|
||||
__u32 nmsrs; /* number of msrs in entries */
|
||||
|
@ -1095,6 +1095,8 @@ struct kvm_x86_ops {
|
||||
int (*mem_enc_op)(struct kvm *kvm, void __user *argp);
|
||||
int (*mem_enc_reg_region)(struct kvm *kvm, struct kvm_enc_region *argp);
|
||||
int (*mem_enc_unreg_region)(struct kvm *kvm, struct kvm_enc_region *argp);
|
||||
|
||||
int (*get_msr_feature)(struct kvm_msr_entry *entry);
|
||||
};
|
||||
|
||||
struct kvm_arch_async_pf {
|
||||
|
@ -3869,6 +3869,11 @@ static int cr8_write_interception(struct vcpu_svm *svm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int svm_get_msr_feature(struct kvm_msr_entry *msr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
{
|
||||
struct vcpu_svm *svm = to_svm(vcpu);
|
||||
@ -6832,6 +6837,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
|
||||
.vcpu_unblocking = svm_vcpu_unblocking,
|
||||
|
||||
.update_bp_intercept = update_bp_intercept,
|
||||
.get_msr_feature = svm_get_msr_feature,
|
||||
.get_msr = svm_get_msr,
|
||||
.set_msr = svm_set_msr,
|
||||
.get_segment_base = svm_get_segment_base,
|
||||
|
@ -3226,6 +3226,11 @@ static inline bool vmx_feature_control_msr_valid(struct kvm_vcpu *vcpu,
|
||||
return !(val & ~valid_bits);
|
||||
}
|
||||
|
||||
static int vmx_get_msr_feature(struct kvm_msr_entry *msr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads an msr value (of 'msr_index') into 'pdata'.
|
||||
* Returns 0 on success, non-0 otherwise.
|
||||
@ -12296,6 +12301,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
|
||||
.vcpu_put = vmx_vcpu_put,
|
||||
|
||||
.update_bp_intercept = update_exception_bitmap,
|
||||
.get_msr_feature = vmx_get_msr_feature,
|
||||
.get_msr = vmx_get_msr,
|
||||
.set_msr = vmx_set_msr,
|
||||
.get_segment_base = vmx_get_segment_base,
|
||||
|
@ -1049,6 +1049,28 @@ static u32 emulated_msrs[] = {
|
||||
|
||||
static unsigned num_emulated_msrs;
|
||||
|
||||
/*
|
||||
* List of msr numbers which are used to expose MSR-based features that
|
||||
* can be used by a hypervisor to validate requested CPU features.
|
||||
*/
|
||||
static u32 msr_based_features[] = {
|
||||
};
|
||||
|
||||
static unsigned int num_msr_based_features;
|
||||
|
||||
static int do_get_msr_feature(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
|
||||
{
|
||||
struct kvm_msr_entry msr;
|
||||
|
||||
msr.index = index;
|
||||
if (kvm_x86_ops->get_msr_feature(&msr))
|
||||
return 1;
|
||||
|
||||
*data = msr.data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
|
||||
{
|
||||
if (efer & efer_reserved_bits)
|
||||
@ -2680,13 +2702,11 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs,
|
||||
int (*do_msr)(struct kvm_vcpu *vcpu,
|
||||
unsigned index, u64 *data))
|
||||
{
|
||||
int i, idx;
|
||||
int i;
|
||||
|
||||
idx = srcu_read_lock(&vcpu->kvm->srcu);
|
||||
for (i = 0; i < msrs->nmsrs; ++i)
|
||||
if (do_msr(vcpu, entries[i].index, &entries[i].data))
|
||||
break;
|
||||
srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
||||
|
||||
return i;
|
||||
}
|
||||
@ -2785,6 +2805,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
||||
case KVM_CAP_SET_BOOT_CPU_ID:
|
||||
case KVM_CAP_SPLIT_IRQCHIP:
|
||||
case KVM_CAP_IMMEDIATE_EXIT:
|
||||
case KVM_CAP_GET_MSR_FEATURES:
|
||||
r = 1;
|
||||
break;
|
||||
case KVM_CAP_ADJUST_CLOCK:
|
||||
@ -2899,6 +2920,31 @@ long kvm_arch_dev_ioctl(struct file *filp,
|
||||
goto out;
|
||||
r = 0;
|
||||
break;
|
||||
case KVM_GET_MSR_FEATURE_INDEX_LIST: {
|
||||
struct kvm_msr_list __user *user_msr_list = argp;
|
||||
struct kvm_msr_list msr_list;
|
||||
unsigned int n;
|
||||
|
||||
r = -EFAULT;
|
||||
if (copy_from_user(&msr_list, user_msr_list, sizeof(msr_list)))
|
||||
goto out;
|
||||
n = msr_list.nmsrs;
|
||||
msr_list.nmsrs = num_msr_based_features;
|
||||
if (copy_to_user(user_msr_list, &msr_list, sizeof(msr_list)))
|
||||
goto out;
|
||||
r = -E2BIG;
|
||||
if (n < msr_list.nmsrs)
|
||||
goto out;
|
||||
r = -EFAULT;
|
||||
if (copy_to_user(user_msr_list->indices, &msr_based_features,
|
||||
num_msr_based_features * sizeof(u32)))
|
||||
goto out;
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
case KVM_GET_MSRS:
|
||||
r = msr_io(NULL, argp, do_get_msr_feature, 1);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
r = -EINVAL;
|
||||
@ -3636,12 +3682,18 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
case KVM_GET_MSRS:
|
||||
case KVM_GET_MSRS: {
|
||||
int idx = srcu_read_lock(&vcpu->kvm->srcu);
|
||||
r = msr_io(vcpu, argp, do_get_msr, 1);
|
||||
srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
||||
break;
|
||||
case KVM_SET_MSRS:
|
||||
}
|
||||
case KVM_SET_MSRS: {
|
||||
int idx = srcu_read_lock(&vcpu->kvm->srcu);
|
||||
r = msr_io(vcpu, argp, do_set_msr, 0);
|
||||
srcu_read_unlock(&vcpu->kvm->srcu, idx);
|
||||
break;
|
||||
}
|
||||
case KVM_TPR_ACCESS_REPORTING: {
|
||||
struct kvm_tpr_access_ctl tac;
|
||||
|
||||
@ -4464,6 +4516,19 @@ static void kvm_init_msr_list(void)
|
||||
j++;
|
||||
}
|
||||
num_emulated_msrs = j;
|
||||
|
||||
for (i = j = 0; i < ARRAY_SIZE(msr_based_features); i++) {
|
||||
struct kvm_msr_entry msr;
|
||||
|
||||
msr.index = msr_based_features[i];
|
||||
if (kvm_x86_ops->get_msr_feature(&msr))
|
||||
continue;
|
||||
|
||||
if (j < i)
|
||||
msr_based_features[j] = msr_based_features[i];
|
||||
j++;
|
||||
}
|
||||
num_msr_based_features = j;
|
||||
}
|
||||
|
||||
static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len,
|
||||
|
@ -761,6 +761,7 @@ struct kvm_ppc_resize_hpt {
|
||||
#define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07
|
||||
#define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08
|
||||
#define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2)
|
||||
#define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list)
|
||||
|
||||
/*
|
||||
* Extension capability list.
|
||||
@ -934,6 +935,7 @@ struct kvm_ppc_resize_hpt {
|
||||
#define KVM_CAP_S390_AIS_MIGRATION 150
|
||||
#define KVM_CAP_PPC_GET_CPU_CHAR 151
|
||||
#define KVM_CAP_S390_BPB 152
|
||||
#define KVM_CAP_GET_MSR_FEATURES 153
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user