diff options
author | Tom Lendacky <thomas.lendacky@amd.com> | 2018-02-21 14:39:51 -0500 |
---|---|---|
committer | Radim Krčmář <rkrcmar@redhat.com> | 2018-03-01 13:00:28 -0500 |
commit | 801e459a6f3a63af9d447e6249088c76ae16efc4 (patch) | |
tree | b23a56566b4ace273ae07cd150acec275e3cd669 | |
parent | d4858aaf6bd8a90e2dacc0dfec2077e334dcedbf (diff) |
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>
-rw-r--r-- | Documentation/virtual/kvm/api.txt | 40 | ||||
-rw-r--r-- | arch/x86/include/asm/kvm_host.h | 2 | ||||
-rw-r--r-- | arch/x86/kvm/svm.c | 6 | ||||
-rw-r--r-- | arch/x86/kvm/vmx.c | 6 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 75 | ||||
-rw-r--r-- | include/uapi/linux/kvm.h | 2 |
6 files changed, 114 insertions, 17 deletions
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 792fa8717d13..d6b3ff51a14f 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt | |||
@@ -123,14 +123,15 @@ memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the | |||
123 | flag KVM_VM_MIPS_VZ. | 123 | flag KVM_VM_MIPS_VZ. |
124 | 124 | ||
125 | 125 | ||
126 | 4.3 KVM_GET_MSR_INDEX_LIST | 126 | 4.3 KVM_GET_MSR_INDEX_LIST, KVM_GET_MSR_FEATURE_INDEX_LIST |
127 | 127 | ||
128 | Capability: basic | 128 | Capability: basic, KVM_CAP_GET_MSR_FEATURES for KVM_GET_MSR_FEATURE_INDEX_LIST |
129 | Architectures: x86 | 129 | Architectures: x86 |
130 | Type: system | 130 | Type: system ioctl |
131 | Parameters: struct kvm_msr_list (in/out) | 131 | Parameters: struct kvm_msr_list (in/out) |
132 | Returns: 0 on success; -1 on error | 132 | Returns: 0 on success; -1 on error |
133 | Errors: | 133 | Errors: |
134 | EFAULT: the msr index list cannot be read from or written to | ||
134 | E2BIG: the msr index list is to be to fit in the array specified by | 135 | E2BIG: the msr index list is to be to fit in the array specified by |
135 | the user. | 136 | the user. |
136 | 137 | ||
@@ -139,16 +140,23 @@ struct kvm_msr_list { | |||
139 | __u32 indices[0]; | 140 | __u32 indices[0]; |
140 | }; | 141 | }; |
141 | 142 | ||
142 | This ioctl returns the guest msrs that are supported. The list varies | 143 | The user fills in the size of the indices array in nmsrs, and in return |
143 | by kvm version and host processor, but does not change otherwise. The | 144 | kvm adjusts nmsrs to reflect the actual number of msrs and fills in the |
144 | user fills in the size of the indices array in nmsrs, and in return | 145 | indices array with their numbers. |
145 | kvm adjusts nmsrs to reflect the actual number of msrs and fills in | 146 | |
146 | the indices array with their numbers. | 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. | ||
147 | 149 | ||
148 | Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are | 150 | Note: if kvm indicates supports MCE (KVM_CAP_MCE), then the MCE bank MSRs are |
149 | not returned in the MSR list, as different vcpus can have a different number | 151 | not returned in the MSR list, as different vcpus can have a different number |
150 | of banks, as set via the KVM_X86_SETUP_MCE ioctl. | 152 | of banks, as set via the KVM_X86_SETUP_MCE ioctl. |
151 | 153 | ||
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 | |||
152 | 160 | ||
153 | 4.4 KVM_CHECK_EXTENSION | 161 | 4.4 KVM_CHECK_EXTENSION |
154 | 162 | ||
@@ -475,14 +483,22 @@ Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead. | |||
475 | 483 | ||
476 | 4.18 KVM_GET_MSRS | 484 | 4.18 KVM_GET_MSRS |
477 | 485 | ||
478 | Capability: basic | 486 | Capability: basic (vcpu), KVM_CAP_GET_MSR_FEATURES (system) |
479 | Architectures: x86 | 487 | Architectures: x86 |
480 | Type: vcpu ioctl | 488 | Type: system ioctl, vcpu ioctl |
481 | Parameters: struct kvm_msrs (in/out) | 489 | 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. | ||
483 | 498 | ||
499 | When used as a vcpu ioctl: | ||
484 | Reads model-specific registers from the vcpu. Supported msr indices can | 500 | 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. |
486 | 502 | ||
487 | struct kvm_msrs { | 503 | struct kvm_msrs { |
488 | __u32 nmsrs; /* number of msrs in entries */ | 504 | __u32 nmsrs; /* number of msrs in entries */ |
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 0a9e330b34f0..bab0694b35c3 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
@@ -1095,6 +1095,8 @@ struct kvm_x86_ops { | |||
1095 | int (*mem_enc_op)(struct kvm *kvm, void __user *argp); | 1095 | int (*mem_enc_op)(struct kvm *kvm, void __user *argp); |
1096 | int (*mem_enc_reg_region)(struct kvm *kvm, struct kvm_enc_region *argp); | 1096 | int (*mem_enc_reg_region)(struct kvm *kvm, struct kvm_enc_region *argp); |
1097 | int (*mem_enc_unreg_region)(struct kvm *kvm, struct kvm_enc_region *argp); | 1097 | int (*mem_enc_unreg_region)(struct kvm *kvm, struct kvm_enc_region *argp); |
1098 | |||
1099 | int (*get_msr_feature)(struct kvm_msr_entry *entry); | ||
1098 | }; | 1100 | }; |
1099 | 1101 | ||
1100 | struct kvm_arch_async_pf { | 1102 | struct kvm_arch_async_pf { |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 3d8377f75eda..d8db947acf70 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -3869,6 +3869,11 @@ static int cr8_write_interception(struct vcpu_svm *svm) | |||
3869 | return 0; | 3869 | return 0; |
3870 | } | 3870 | } |
3871 | 3871 | ||
3872 | static int svm_get_msr_feature(struct kvm_msr_entry *msr) | ||
3873 | { | ||
3874 | return 1; | ||
3875 | } | ||
3876 | |||
3872 | static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) | 3877 | static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) |
3873 | { | 3878 | { |
3874 | struct vcpu_svm *svm = to_svm(vcpu); | 3879 | struct vcpu_svm *svm = to_svm(vcpu); |
@@ -6832,6 +6837,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = { | |||
6832 | .vcpu_unblocking = svm_vcpu_unblocking, | 6837 | .vcpu_unblocking = svm_vcpu_unblocking, |
6833 | 6838 | ||
6834 | .update_bp_intercept = update_bp_intercept, | 6839 | .update_bp_intercept = update_bp_intercept, |
6840 | .get_msr_feature = svm_get_msr_feature, | ||
6835 | .get_msr = svm_get_msr, | 6841 | .get_msr = svm_get_msr, |
6836 | .set_msr = svm_set_msr, | 6842 | .set_msr = svm_set_msr, |
6837 | .get_segment_base = svm_get_segment_base, | 6843 | .get_segment_base = svm_get_segment_base, |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index ec14f2319a87..fafc1f6d8987 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
@@ -3226,6 +3226,11 @@ static inline bool vmx_feature_control_msr_valid(struct kvm_vcpu *vcpu, | |||
3226 | return !(val & ~valid_bits); | 3226 | return !(val & ~valid_bits); |
3227 | } | 3227 | } |
3228 | 3228 | ||
3229 | static int vmx_get_msr_feature(struct kvm_msr_entry *msr) | ||
3230 | { | ||
3231 | return 1; | ||
3232 | } | ||
3233 | |||
3229 | /* | 3234 | /* |
3230 | * Reads an msr value (of 'msr_index') into 'pdata'. | 3235 | * Reads an msr value (of 'msr_index') into 'pdata'. |
3231 | * Returns 0 on success, non-0 otherwise. | 3236 | * Returns 0 on success, non-0 otherwise. |
@@ -12296,6 +12301,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = { | |||
12296 | .vcpu_put = vmx_vcpu_put, | 12301 | .vcpu_put = vmx_vcpu_put, |
12297 | 12302 | ||
12298 | .update_bp_intercept = update_exception_bitmap, | 12303 | .update_bp_intercept = update_exception_bitmap, |
12304 | .get_msr_feature = vmx_get_msr_feature, | ||
12299 | .get_msr = vmx_get_msr, | 12305 | .get_msr = vmx_get_msr, |
12300 | .set_msr = vmx_set_msr, | 12306 | .set_msr = vmx_set_msr, |
12301 | .get_segment_base = vmx_get_segment_base, | 12307 | .get_segment_base = vmx_get_segment_base, |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 96edda878dbf..239fc1fd7845 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -1049,6 +1049,28 @@ static u32 emulated_msrs[] = { | |||
1049 | 1049 | ||
1050 | static unsigned num_emulated_msrs; | 1050 | static unsigned num_emulated_msrs; |
1051 | 1051 | ||
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 | |||
1052 | bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer) | 1074 | bool kvm_valid_efer(struct kvm_vcpu *vcpu, u64 efer) |
1053 | { | 1075 | { |
1054 | if (efer & efer_reserved_bits) | 1076 | if (efer & efer_reserved_bits) |
@@ -2680,13 +2702,11 @@ static int __msr_io(struct kvm_vcpu *vcpu, struct kvm_msrs *msrs, | |||
2680 | int (*do_msr)(struct kvm_vcpu *vcpu, | 2702 | int (*do_msr)(struct kvm_vcpu *vcpu, |
2681 | unsigned index, u64 *data)) | 2703 | unsigned index, u64 *data)) |
2682 | { | 2704 | { |
2683 | int i, idx; | 2705 | int i; |
2684 | 2706 | ||
2685 | idx = srcu_read_lock(&vcpu->kvm->srcu); | ||
2686 | for (i = 0; i < msrs->nmsrs; ++i) | 2707 | for (i = 0; i < msrs->nmsrs; ++i) |
2687 | if (do_msr(vcpu, entries[i].index, &entries[i].data)) | 2708 | if (do_msr(vcpu, entries[i].index, &entries[i].data)) |
2688 | break; | 2709 | break; |
2689 | srcu_read_unlock(&vcpu->kvm->srcu, idx); | ||
2690 | 2710 | ||
2691 | return i; | 2711 | return i; |
2692 | } | 2712 | } |
@@ -2785,6 +2805,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) | |||
2785 | case KVM_CAP_SET_BOOT_CPU_ID: | 2805 | case KVM_CAP_SET_BOOT_CPU_ID: |
2786 | case KVM_CAP_SPLIT_IRQCHIP: | 2806 | case KVM_CAP_SPLIT_IRQCHIP: |
2787 | case KVM_CAP_IMMEDIATE_EXIT: | 2807 | case KVM_CAP_IMMEDIATE_EXIT: |
2808 | case KVM_CAP_GET_MSR_FEATURES: | ||
2788 | r = 1; | 2809 | r = 1; |
2789 | break; | 2810 | break; |
2790 | case KVM_CAP_ADJUST_CLOCK: | 2811 | case KVM_CAP_ADJUST_CLOCK: |
@@ -2899,6 +2920,31 @@ long kvm_arch_dev_ioctl(struct file *filp, | |||
2899 | goto out; | 2920 | goto out; |
2900 | r = 0; | 2921 | r = 0; |
2901 | break; | 2922 | 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; | ||
2902 | } | 2948 | } |
2903 | default: | 2949 | default: |
2904 | r = -EINVAL; | 2950 | r = -EINVAL; |
@@ -3636,12 +3682,18 @@ long kvm_arch_vcpu_ioctl(struct file *filp, | |||
3636 | r = 0; | 3682 | r = 0; |
3637 | break; | 3683 | break; |
3638 | } | 3684 | } |
3639 | case KVM_GET_MSRS: | 3685 | case KVM_GET_MSRS: { |
3686 | int idx = srcu_read_lock(&vcpu->kvm->srcu); | ||
3640 | r = msr_io(vcpu, argp, do_get_msr, 1); | 3687 | r = msr_io(vcpu, argp, do_get_msr, 1); |
3688 | srcu_read_unlock(&vcpu->kvm->srcu, idx); | ||
3641 | break; | 3689 | break; |
3642 | case KVM_SET_MSRS: | 3690 | } |
3691 | case KVM_SET_MSRS: { | ||
3692 | int idx = srcu_read_lock(&vcpu->kvm->srcu); | ||
3643 | r = msr_io(vcpu, argp, do_set_msr, 0); | 3693 | r = msr_io(vcpu, argp, do_set_msr, 0); |
3694 | srcu_read_unlock(&vcpu->kvm->srcu, idx); | ||
3644 | break; | 3695 | break; |
3696 | } | ||
3645 | case KVM_TPR_ACCESS_REPORTING: { | 3697 | case KVM_TPR_ACCESS_REPORTING: { |
3646 | struct kvm_tpr_access_ctl tac; | 3698 | struct kvm_tpr_access_ctl tac; |
3647 | 3699 | ||
@@ -4464,6 +4516,19 @@ static void kvm_init_msr_list(void) | |||
4464 | j++; | 4516 | j++; |
4465 | } | 4517 | } |
4466 | num_emulated_msrs = j; | 4518 | 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; | ||
4467 | } | 4532 | } |
4468 | 4533 | ||
4469 | static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len, | 4534 | static int vcpu_mmio_write(struct kvm_vcpu *vcpu, gpa_t addr, int len, |
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 0fb5ef939732..7b26d4b0b052 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h | |||
@@ -761,6 +761,7 @@ struct kvm_ppc_resize_hpt { | |||
761 | #define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07 | 761 | #define KVM_TRACE_PAUSE __KVM_DEPRECATED_MAIN_0x07 |
762 | #define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08 | 762 | #define KVM_TRACE_DISABLE __KVM_DEPRECATED_MAIN_0x08 |
763 | #define KVM_GET_EMULATED_CPUID _IOWR(KVMIO, 0x09, struct kvm_cpuid2) | 763 | #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) | ||
764 | 765 | ||
765 | /* | 766 | /* |
766 | * Extension capability list. | 767 | * Extension capability list. |
@@ -934,6 +935,7 @@ struct kvm_ppc_resize_hpt { | |||
934 | #define KVM_CAP_S390_AIS_MIGRATION 150 | 935 | #define KVM_CAP_S390_AIS_MIGRATION 150 |
935 | #define KVM_CAP_PPC_GET_CPU_CHAR 151 | 936 | #define KVM_CAP_PPC_GET_CPU_CHAR 151 |
936 | #define KVM_CAP_S390_BPB 152 | 937 | #define KVM_CAP_S390_BPB 152 |
938 | #define KVM_CAP_GET_MSR_FEATURES 153 | ||
937 | 939 | ||
938 | #ifdef KVM_CAP_IRQ_ROUTING | 940 | #ifdef KVM_CAP_IRQ_ROUTING |
939 | 941 | ||