Skip to content

Commit 801e459

Browse files
tlendackyrkrcmar
authored andcommitted
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 <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]> [Tweaked documentation. - Radim] Signed-off-by: Radim Krčmář <[email protected]>
1 parent d4858aa commit 801e459

File tree

6 files changed

+114
-17
lines changed

6 files changed

+114
-17
lines changed

Documentation/virtual/kvm/api.txt

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,15 @@ memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the
123123
flag KVM_VM_MIPS_VZ.
124124

125125

126-
4.3 KVM_GET_MSR_INDEX_LIST
126+
4.3 KVM_GET_MSR_INDEX_LIST, KVM_GET_MSR_FEATURE_INDEX_LIST
127127

128-
Capability: basic
128+
Capability: basic, KVM_CAP_GET_MSR_FEATURES for KVM_GET_MSR_FEATURE_INDEX_LIST
129129
Architectures: x86
130-
Type: system
130+
Type: system ioctl
131131
Parameters: struct kvm_msr_list (in/out)
132132
Returns: 0 on success; -1 on error
133133
Errors:
134+
EFAULT: the msr index list cannot be read from or written to
134135
E2BIG: the msr index list is to be to fit in the array specified by
135136
the user.
136137

@@ -139,16 +140,23 @@ struct kvm_msr_list {
139140
__u32 indices[0];
140141
};
141142

142-
This ioctl returns the guest msrs that are supported. The list varies
143-
by kvm version and host processor, but does not change otherwise. The
144-
user fills in the size of the indices array in nmsrs, and in return
145-
kvm adjusts nmsrs to reflect the actual number of msrs and fills in
146-
the indices array with their numbers.
143+
The user fills in the size of the indices array in nmsrs, and in return
144+
kvm adjusts nmsrs to reflect the actual number of msrs and fills in the
145+
indices array with their numbers.
146+
147+
KVM_GET_MSR_INDEX_LIST returns the guest msrs that are supported. The list
148+
varies by kvm version and host processor, but does not change otherwise.
147149

148150
Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are
149151
not returned in the MSR list, as different vcpus can have a different number
150152
of banks, as set via the KVM_X86_SETUP_MCE ioctl.
151153

154+
KVM_GET_MSR_FEATURE_INDEX_LIST returns the list of MSRs that can be passed
155+
to the KVM_GET_MSRS system ioctl. This lets userspace probe host capabilities
156+
and processor features that are exposed via MSRs (e.g., VMX capabilities).
157+
This list also varies by kvm version and host processor, but does not change
158+
otherwise.
159+
152160

153161
4.4 KVM_CHECK_EXTENSION
154162

@@ -475,14 +483,22 @@ Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead.
475483

476484
4.18 KVM_GET_MSRS
477485

478-
Capability: basic
486+
Capability: basic (vcpu), KVM_CAP_GET_MSR_FEATURES (system)
479487
Architectures: x86
480-
Type: vcpu ioctl
488+
Type: system ioctl, vcpu ioctl
481489
Parameters: struct kvm_msrs (in/out)
482-
Returns: 0 on success, -1 on error
490+
Returns: number of msrs successfully returned;
491+
-1 on error
492+
493+
When used as a system ioctl:
494+
Reads the values of MSR-based features that are available for the VM. This
495+
is similar to KVM_GET_SUPPORTED_CPUID, but it returns MSR indices and values.
496+
The list of msr-based features can be obtained using KVM_GET_MSR_FEATURE_INDEX_LIST
497+
in a system ioctl.
483498

499+
When used as a vcpu ioctl:
484500
Reads model-specific registers from the vcpu. Supported msr indices can
485-
be obtained using KVM_GET_MSR_INDEX_LIST.
501+
be obtained using KVM_GET_MSR_INDEX_LIST in a system ioctl.
486502

487503
struct kvm_msrs {
488504
__u32 nmsrs; /* number of msrs in entries */

arch/x86/include/asm/kvm_host.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,8 @@ struct kvm_x86_ops {
10951095
int (*mem_enc_op)(struct kvm *kvm, void __user *argp);
10961096
int (*mem_enc_reg_region)(struct kvm *kvm, struct kvm_enc_region *argp);
10971097
int (*mem_enc_unreg_region)(struct kvm *kvm, struct kvm_enc_region *argp);
1098+
1099+
int (*get_msr_feature)(struct kvm_msr_entry *entry);
10981100
};
10991101

11001102
struct kvm_arch_async_pf {

arch/x86/kvm/svm.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3869,6 +3869,11 @@ static int cr8_write_interception(struct vcpu_svm *svm)
38693869
return 0;
38703870
}
38713871

3872+
static int svm_get_msr_feature(struct kvm_msr_entry *msr)
3873+
{
3874+
return 1;
3875+
}
3876+
38723877
static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
38733878
{
38743879
struct vcpu_svm *svm = to_svm(vcpu);
@@ -6832,6 +6837,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
68326837
.vcpu_unblocking = svm_vcpu_unblocking,
68336838

68346839
.update_bp_intercept = update_bp_intercept,
6840+
.get_msr_feature = svm_get_msr_feature,
68356841
.get_msr = svm_get_msr,
68366842
.set_msr = svm_set_msr,
68376843
.get_segment_base = svm_get_segment_base,

arch/x86/kvm/vmx.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3226,6 +3226,11 @@ static inline bool vmx_feature_control_msr_valid(struct kvm_vcpu *vcpu,
32263226
return !(val & ~valid_bits);
32273227
}
32283228

3229+
static int vmx_get_msr_feature(struct kvm_msr_entry *msr)
3230+
{
3231+
return 1;
3232+
}
3233+
32293234
/*
32303235
* Reads an msr value (of 'msr_index') into 'pdata'.
32313236
* Returns 0 on success, non-0 otherwise.
@@ -12296,6 +12301,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
1229612301
.vcpu_put = vmx_vcpu_put,
1229712302

1229812303
.update_bp_intercept = update_exception_bitmap,
12304+
.get_msr_feature = vmx_get_msr_feature,
1229912305
.get_msr = vmx_get_msr,
1230012306
.set_msr = vmx_set_msr,
1230112307
.get_segment_base = vmx_get_segment_base,

arch/x86/kvm/x86.c

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,28 @@ static u32 emulated_msrs[] = {
10491049

10501050
static unsigned num_emulated_msrs;
10511051

1052+
/*
1053+
* List of msr numbers which are used to expose MSR-based features that
1054+
* can be used by a hypervisor to validate requested CPU features.
1055+
*/
1056+
static u32 msr_based_features[] = {
1057+
};
1058+
1059+
static unsigned int num_msr_based_features;
1060+
1061+
static int do_get_msr_feature(struct kvm_vcpu *vcpu, unsigned index, u64 *data)
1062+
{
1063+
struct kvm_msr_entry msr;
1064+
1065+
msr.index = index;
1066+
if (kvm_x86_ops->get_msr_feature(&msr))
1067+
return 1;
1068+
1069+
*data = msr.data;
1070+
1071+
return 0;
1072+
}
1073+
10521074
bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer)
10531075
{
10541076
if (efer & efer_reserved_bits)
@@ -2680,13 +2702,11 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs,
26802702
int (*do_msr)(struct kvm_vcpu *vcpu,
26812703
unsigned index, u64 *data))
26822704
{
2683-
int i, idx;
2705+
int i;
26842706

2685-
idx = srcu_read_lock(&vcpu->kvm->srcu);
26862707
for (i = 0; i < msrs->nmsrs; ++i)
26872708
if (do_msr(vcpu, entries[i].index, &entries[i].data))
26882709
break;
2689-
srcu_read_unlock(&vcpu->kvm->srcu, idx);
26902710

26912711
return i;
26922712
}
@@ -2785,6 +2805,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
27852805
case KVM_CAP_SET_BOOT_CPU_ID:
27862806
case KVM_CAP_SPLIT_IRQCHIP:
27872807
case KVM_CAP_IMMEDIATE_EXIT:
2808+
case KVM_CAP_GET_MSR_FEATURES:
27882809
r = 1;
27892810
break;
27902811
case KVM_CAP_ADJUST_CLOCK:
@@ -2899,6 +2920,31 @@ long kvm_arch_dev_ioctl(struct file *filp,
28992920
goto out;
29002921
r = 0;
29012922
break;
2923+
case KVM_GET_MSR_FEATURE_INDEX_LIST: {
2924+
struct kvm_msr_list __user *user_msr_list = argp;
2925+
struct kvm_msr_list msr_list;
2926+
unsigned int n;
2927+
2928+
r = -EFAULT;
2929+
if (copy_from_user(&msr_list, user_msr_list, sizeof(msr_list)))
2930+
goto out;
2931+
n = msr_list.nmsrs;
2932+
msr_list.nmsrs = num_msr_based_features;
2933+
if (copy_to_user(user_msr_list, &msr_list, sizeof(msr_list)))
2934+
goto out;
2935+
r = -E2BIG;
2936+
if (n < msr_list.nmsrs)
2937+
goto out;
2938+
r = -EFAULT;
2939+
if (copy_to_user(user_msr_list->indices, &msr_based_features,
2940+
num_msr_based_features * sizeof(u32)))
2941+
goto out;
2942+
r = 0;
2943+
break;
2944+
}
2945+
case KVM_GET_MSRS:
2946+
r = msr_io(NULL, argp, do_get_msr_feature, 1);
2947+
break;
29022948
}
29032949
default:
29042950
r = -EINVAL;
@@ -3636,12 +3682,18 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
36363682
r = 0;
36373683
break;
36383684
}
3639-
case KVM_GET_MSRS:
3685+
case KVM_GET_MSRS: {
3686+
int idx = srcu_read_lock(&vcpu->kvm->srcu);
36403687
r = msr_io(vcpu, argp, do_get_msr, 1);
3688+
srcu_read_unlock(&vcpu->kvm->srcu, idx);
36413689
break;
3642-
case KVM_SET_MSRS:
3690+
}
3691+
case KVM_SET_MSRS: {
3692+
int idx = srcu_read_lock(&vcpu->kvm->srcu);
36433693
r = msr_io(vcpu, argp, do_set_msr, 0);
3694+
srcu_read_unlock(&vcpu->kvm->srcu, idx);
36443695
break;
3696+
}
36453697
case KVM_TPR_ACCESS_REPORTING: {
36463698
struct kvm_tpr_access_ctl tac;
36473699

@@ -4464,6 +4516,19 @@ static void kvm_init_msr_list(void)
44644516
j++;
44654517
}
44664518
num_emulated_msrs = j;
4519+
4520+
for (i = j = 0; i < ARRAY_SIZE(msr_based_features); i++) {
4521+
struct kvm_msr_entry msr;
4522+
4523+
msr.index = msr_based_features[i];
4524+
if (kvm_x86_ops->get_msr_feature(&msr))
4525+
continue;
4526+
4527+
if (j < i)
4528+
msr_based_features[j] = msr_based_features[i];
4529+
j++;
4530+
}
4531+
num_msr_based_features = j;
44674532
}
44684533

44694534
static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len,

include/uapi/linux/kvm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,7 @@ struct kvm_ppc_resize_hpt {
761761
#define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07
762762
#define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08
763763
#define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2)
764+
#define KVM_GET_MSR_FEATURE_INDEX_LIST _IOWR(KVMIO, 0x0a, struct kvm_msr_list)
764765

765766
/*
766767
* Extension capability list.
@@ -934,6 +935,7 @@ struct kvm_ppc_resize_hpt {
934935
#define KVM_CAP_S390_AIS_MIGRATION 150
935936
#define KVM_CAP_PPC_GET_CPU_CHAR 151
936937
#define KVM_CAP_S390_BPB 152
938+
#define KVM_CAP_GET_MSR_FEATURES 153
937939

938940
#ifdef KVM_CAP_IRQ_ROUTING
939941

0 commit comments

Comments
 (0)