提交 801e459a 编写于 作者: T Tom Lendacky 提交者: Radim Krčmář

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: NTom Lendacky <thomas.lendacky@amd.com>
Signed-off-by: NPaolo Bonzini <pbonzini@redhat.com>
[Tweaked documentation. - Radim]
Signed-off-by: NRadim Krčmář <rkrcmar@redhat.com>
上级 d4858aaf
...@@ -123,14 +123,15 @@ memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the ...@@ -123,14 +123,15 @@ memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the
flag KVM_VM_MIPS_VZ. 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 Architectures: x86
Type: system Type: system ioctl
Parameters: struct kvm_msr_list (in/out) Parameters: struct kvm_msr_list (in/out)
Returns: 0 on success; -1 on error Returns: 0 on success; -1 on error
Errors: 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 E2BIG: the msr index list is to be to fit in the array specified by
the user. the user.
...@@ -139,16 +140,23 @@ struct kvm_msr_list { ...@@ -139,16 +140,23 @@ struct kvm_msr_list {
__u32 indices[0]; __u32 indices[0];
}; };
This ioctl returns the guest msrs that are supported. The list varies The user fills in the size of the indices array in nmsrs, and in return
by kvm version and host processor, but does not change otherwise. The kvm adjusts nmsrs to reflect the actual number of msrs and fills in the
user fills in the size of the indices array in nmsrs, and in return indices array with their numbers.
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 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 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. 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 4.4 KVM_CHECK_EXTENSION
...@@ -475,14 +483,22 @@ Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead. ...@@ -475,14 +483,22 @@ Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead.
4.18 KVM_GET_MSRS 4.18 KVM_GET_MSRS
Capability: basic Capability: basic (vcpu), KVM_CAP_GET_MSR_FEATURES (system)
Architectures: x86 Architectures: x86
Type: vcpu ioctl Type: system ioctl, vcpu ioctl
Parameters: struct kvm_msrs (in/out) 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 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 { struct kvm_msrs {
__u32 nmsrs; /* number of msrs in entries */ __u32 nmsrs; /* number of msrs in entries */
......
...@@ -1095,6 +1095,8 @@ struct kvm_x86_ops { ...@@ -1095,6 +1095,8 @@ struct kvm_x86_ops {
int (*mem_enc_op)(struct kvm *kvm, void __user *argp); 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_reg_region)(struct kvm *kvm, struct kvm_enc_region *argp);
int (*mem_enc_unreg_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 { struct kvm_arch_async_pf {
......
...@@ -3869,6 +3869,11 @@ static int cr8_write_interception(struct vcpu_svm *svm) ...@@ -3869,6 +3869,11 @@ static int cr8_write_interception(struct vcpu_svm *svm)
return 0; 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) static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{ {
struct vcpu_svm *svm = to_svm(vcpu); struct vcpu_svm *svm = to_svm(vcpu);
...@@ -6832,6 +6837,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = { ...@@ -6832,6 +6837,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
.vcpu_unblocking = svm_vcpu_unblocking, .vcpu_unblocking = svm_vcpu_unblocking,
.update_bp_intercept = update_bp_intercept, .update_bp_intercept = update_bp_intercept,
.get_msr_feature = svm_get_msr_feature,
.get_msr = svm_get_msr, .get_msr = svm_get_msr,
.set_msr = svm_set_msr, .set_msr = svm_set_msr,
.get_segment_base = svm_get_segment_base, .get_segment_base = svm_get_segment_base,
......
...@@ -3226,6 +3226,11 @@ static inline bool vmx_feature_control_msr_valid(struct kvm_vcpu *vcpu, ...@@ -3226,6 +3226,11 @@ static inline bool vmx_feature_control_msr_valid(struct kvm_vcpu *vcpu,
return !(val & ~valid_bits); 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'. * Reads an msr value (of 'msr_index') into 'pdata'.
* Returns 0 on success, non-0 otherwise. * Returns 0 on success, non-0 otherwise.
...@@ -12296,6 +12301,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = { ...@@ -12296,6 +12301,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
.vcpu_put = vmx_vcpu_put, .vcpu_put = vmx_vcpu_put,
.update_bp_intercept = update_exception_bitmap, .update_bp_intercept = update_exception_bitmap,
.get_msr_feature = vmx_get_msr_feature,
.get_msr = vmx_get_msr, .get_msr = vmx_get_msr,
.set_msr = vmx_set_msr, .set_msr = vmx_set_msr,
.get_segment_base = vmx_get_segment_base, .get_segment_base = vmx_get_segment_base,
......
...@@ -1049,6 +1049,28 @@ static u32 emulated_msrs[] = { ...@@ -1049,6 +1049,28 @@ static u32 emulated_msrs[] = {
static unsigned num_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) bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
{ {
if (efer & efer_reserved_bits) if (efer & efer_reserved_bits)
...@@ -2680,13 +2702,11 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs, ...@@ -2680,13 +2702,11 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs,
int (*do_msr)(struct kvm_vcpu *vcpu, int (*do_msr)(struct kvm_vcpu *vcpu,
unsigned index, u64 *data)) unsigned index, u64 *data))
{ {
int i, idx; int i;
idx = srcu_read_lock(&vcpu->kvm->srcu);
for (i = 0; i < msrs->nmsrs; ++i) for (i = 0; i < msrs->nmsrs; ++i)
if (do_msr(vcpu, entries[i].index, &entries[i].data)) if (do_msr(vcpu, entries[i].index, &entries[i].data))
break; break;
srcu_read_unlock(&vcpu->kvm->srcu, idx);
return i; return i;
} }
...@@ -2785,6 +2805,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) ...@@ -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_SET_BOOT_CPU_ID:
case KVM_CAP_SPLIT_IRQCHIP: case KVM_CAP_SPLIT_IRQCHIP:
case KVM_CAP_IMMEDIATE_EXIT: case KVM_CAP_IMMEDIATE_EXIT:
case KVM_CAP_GET_MSR_FEATURES:
r = 1; r = 1;
break; break;
case KVM_CAP_ADJUST_CLOCK: case KVM_CAP_ADJUST_CLOCK:
...@@ -2899,6 +2920,31 @@ long kvm_arch_dev_ioctl(struct file *filp, ...@@ -2899,6 +2920,31 @@ long kvm_arch_dev_ioctl(struct file *filp,
goto out; goto out;
r = 0; r = 0;
break; 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: default:
r = -EINVAL; r = -EINVAL;
...@@ -3636,12 +3682,18 @@ long kvm_arch_vcpu_ioctl(struct file *filp, ...@@ -3636,12 +3682,18 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = 0; r = 0;
break; 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); r = msr_io(vcpu, argp, do_get_msr, 1);
srcu_read_unlock(&vcpu->kvm->srcu, idx);
break; 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); r = msr_io(vcpu, argp, do_set_msr, 0);
srcu_read_unlock(&vcpu->kvm->srcu, idx);
break; break;
}
case KVM_TPR_ACCESS_REPORTING: { case KVM_TPR_ACCESS_REPORTING: {
struct kvm_tpr_access_ctl tac; struct kvm_tpr_access_ctl tac;
...@@ -4464,6 +4516,19 @@ static void kvm_init_msr_list(void) ...@@ -4464,6 +4516,19 @@ static void kvm_init_msr_list(void)
j++; j++;
} }
num_emulated_msrs = 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, static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len,
......
...@@ -761,6 +761,7 @@ struct kvm_ppc_resize_hpt { ...@@ -761,6 +761,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07 #define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07
#define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08 #define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08
#define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2) #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. * Extension capability list.
...@@ -934,6 +935,7 @@ struct kvm_ppc_resize_hpt { ...@@ -934,6 +935,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_S390_AIS_MIGRATION 150 #define KVM_CAP_S390_AIS_MIGRATION 150
#define KVM_CAP_PPC_GET_CPU_CHAR 151 #define KVM_CAP_PPC_GET_CPU_CHAR 151
#define KVM_CAP_S390_BPB 152 #define KVM_CAP_S390_BPB 152
#define KVM_CAP_GET_MSR_FEATURES 153
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册