| From foo@baz Tue Aug 14 16:14:56 CEST 2018 |
| From: Tom Lendacky <thomas.lendacky@amd.com> |
| Date: Wed, 21 Feb 2018 13:39:51 -0600 |
| Subject: KVM: x86: Add a framework for supporting MSR-based features |
| |
| From: Tom Lendacky <thomas.lendacky@amd.com> |
| |
| commit 801e459a6f3a63af9d447e6249088c76ae16efc4 upstream |
| |
| 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> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| Documentation/virtual/kvm/api.txt | 40 ++++++++++++++------ |
| arch/x86/include/asm/kvm_host.h | 2 + |
| arch/x86/kvm/svm.c | 6 +++ |
| arch/x86/kvm/vmx.c | 6 +++ |
| arch/x86/kvm/x86.c | 75 +++++++++++++++++++++++++++++++++++--- |
| include/uapi/linux/kvm.h | 2 + |
| 6 files changed, 114 insertions(+), 17 deletions(-) |
| |
| --- a/Documentation/virtual/kvm/api.txt |
| +++ b/Documentation/virtual/kvm/api.txt |
| @@ -122,14 +122,15 @@ KVM_CAP_S390_UCONTROL and use the flag K |
| privileged user (CAP_SYS_ADMIN). |
| |
| |
| -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. |
| |
| @@ -138,16 +139,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 |
| |
| @@ -474,14 +482,22 @@ Support for this has been removed. Use |
| |
| 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 */ |
| --- a/arch/x86/include/asm/kvm_host.h |
| +++ b/arch/x86/include/asm/kvm_host.h |
| @@ -1025,6 +1025,8 @@ struct kvm_x86_ops { |
| void (*cancel_hv_timer)(struct kvm_vcpu *vcpu); |
| |
| void (*setup_mce)(struct kvm_vcpu *vcpu); |
| + |
| + int (*get_msr_feature)(struct kvm_msr_entry *entry); |
| }; |
| |
| struct kvm_arch_async_pf { |
| --- a/arch/x86/kvm/svm.c |
| +++ b/arch/x86/kvm/svm.c |
| @@ -3485,6 +3485,11 @@ static int cr8_write_interception(struct |
| 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); |
| @@ -5504,6 +5509,7 @@ static struct kvm_x86_ops svm_x86_ops __ |
| .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, |
| --- a/arch/x86/kvm/vmx.c |
| +++ b/arch/x86/kvm/vmx.c |
| @@ -3153,6 +3153,11 @@ static inline bool vmx_feature_control_m |
| 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. |
| @@ -11659,6 +11664,7 @@ static struct kvm_x86_ops vmx_x86_ops __ |
| .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, |
| --- a/arch/x86/kvm/x86.c |
| +++ b/arch/x86/kvm/x86.c |
| @@ -1008,6 +1008,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) |
| @@ -2546,13 +2568,11 @@ static int __msr_io(struct kvm_vcpu *vcp |
| 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; |
| } |
| @@ -2652,6 +2672,7 @@ int kvm_vm_ioctl_check_extension(struct |
| case KVM_CAP_ASSIGN_DEV_IRQ: |
| case KVM_CAP_PCI_2_3: |
| #endif |
| + case KVM_CAP_GET_MSR_FEATURES: |
| r = 1; |
| break; |
| case KVM_CAP_ADJUST_CLOCK: |
| @@ -2771,6 +2792,31 @@ long kvm_arch_dev_ioctl(struct file *fil |
| 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; |
| @@ -3452,12 +3498,18 @@ long kvm_arch_vcpu_ioctl(struct file *fi |
| 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; |
| |
| @@ -4237,6 +4289,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, |
| --- a/include/uapi/linux/kvm.h |
| +++ b/include/uapi/linux/kvm.h |
| @@ -717,6 +717,7 @@ struct kvm_ppc_smmu_info { |
| #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. |
| @@ -871,6 +872,7 @@ struct kvm_ppc_smmu_info { |
| #define KVM_CAP_MSI_DEVID 131 |
| #define KVM_CAP_PPC_HTM 132 |
| #define KVM_CAP_S390_BPB 152 |
| +#define KVM_CAP_GET_MSR_FEATURES 153 |
| |
| #ifdef KVM_CAP_IRQ_ROUTING |
| |