The patch titled KVM: Expose MSRs to userspace (v2) has been added to the -mm tree. Its filename is kvm-expose-msrs-to-userspace-v2.patch See http://www.zip.com.au/~akpm/linux/patches/stuff/added-to-mm.txt to find out what to do about this ------------------------------------------------------ Subject: KVM: Expose MSRs to userspace (v2) From: Avi Kivity <avi@xxxxxxxxxxxx> Changes from v1: - get msrs and set msrs are now symmetric: both accept a list of msrs. it is now possible to retrieve a single msr. - a new KVM_GET_MSR_INDEX_LIST allows discovering which msrs are supported by kvm (previously this was integrated into KVM_GET_MSRS) - error handling is simpler and correcter - the implementation is collapsed into a single msr_io() function - avoid pointers in ioctl structs, instead use zero length arrays Signed-off-by: Uri Lublin <uril@xxxxxxxxxxxx> Signed-off-by: Avi Kivity <avi@xxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxx> --- drivers/kvm/kvm_main.c | 177 +++++++++++++++++---------------------- include/linux/kvm.h | 14 +-- 2 files changed, 89 insertions(+), 102 deletions(-) diff -puN drivers/kvm/kvm_main.c~kvm-expose-msrs-to-userspace-v2 drivers/kvm/kvm_main.c --- a/drivers/kvm/kvm_main.c~kvm-expose-msrs-to-userspace-v2 +++ a/drivers/kvm/kvm_main.c @@ -126,6 +126,8 @@ static const u32 vmx_msr_index[] = { #define MSR_IA32_VMX_EXIT_CTLS_MSR 0x483 #define MSR_IA32_VMX_ENTRY_CTLS_MSR 0x484 +#define MAX_IO_MSRS 256 + #define CR0_RESEVED_BITS 0xffffffff1ffaffc0ULL #define LMSW_GUEST_MASK 0x0eULL #define CR4_RESEVED_BITS (~((1ULL << 11) - 1)) @@ -3147,7 +3149,7 @@ static int kvm_dev_ioctl_set_sregs(struc /* * List of msr numbers which we expose to userspace through KVM_GET_MSRS - * and KVM_SET_MSRS. + * and KVM_SET_MSRS, and KVM_GET_MSR_INDEX_LIST. */ static u32 msrs_to_save[] = { MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP, @@ -3158,110 +3160,91 @@ static u32 msrs_to_save[] = { MSR_IA32_TIME_STAMP_COUNTER, }; -static int kvm_dev_ioctl_get_msrs(struct kvm *kvm, struct kvm_msrs *msrs) + +/* + * Adapt set_msr() to msr_io()'s calling convention + */ +static int do_set_msr(struct kvm_vcpu *vcpu, unsigned index, u64 *data) +{ + return set_msr(vcpu, index, *data); +} + +/* + * Read or write a bunch of msrs. All parameters are kernel addresses. + * + * @return number of msrs set successfully. + */ +static int __msr_io(struct kvm *kvm, struct kvm_msrs *msrs, + struct kvm_msr_entry *entries, + int (*do_msr)(struct kvm_vcpu *vcpu, + unsigned index, u64 *data)) { struct kvm_vcpu *vcpu; - struct kvm_msr_entry *entry, *entries; - int rc; - u32 size, num_entries, i; + int i; if (msrs->vcpu < 0 || msrs->vcpu >= KVM_MAX_VCPUS) return -EINVAL; - num_entries = ARRAY_SIZE(msrs_to_save); - if (msrs->nmsrs < num_entries) { - /* inform actual number of entries */ - msrs->nmsrs = num_entries; - return -EINVAL; - } - vcpu = vcpu_load(kvm, msrs->vcpu); if (!vcpu) return -ENOENT; - msrs->nmsrs = num_entries; /* update to actual number of entries */ - size = msrs->nmsrs * sizeof(struct kvm_msr_entry); - rc = -E2BIG; - if (size > 4096) - goto out_vcpu; - - rc = -ENOMEM; - entries = vmalloc(size); - if (entries == NULL) - goto out_vcpu; - - memset(entries, 0, size); - rc = -EINVAL; - for (i=0; i<num_entries; i++) { - entry = &entries[i]; - entry->index = msrs_to_save[i]; - if (get_msr(vcpu, entry->index, &entry->data)) - goto out_free; - } - - rc = -EFAULT; - if (copy_to_user(msrs->entries, entries, size)) - goto out_free; - - rc = 0; -out_free: - vfree(entries); + for (i = 0; i < msrs->nmsrs; ++i) + if (do_msr(vcpu, entries[i].index, &entries[i].data)) + break; -out_vcpu: vcpu_put(vcpu); - return rc; + return i; } -static int kvm_dev_ioctl_set_msrs(struct kvm *kvm, struct kvm_msrs *msrs) -{ - struct kvm_vcpu *vcpu; - struct kvm_msr_entry *entry, *entries; - int rc; - u32 size, num_entries, i; +/* + * Read or write a bunch of msrs. Parameters are user addresses. + * + * @return number of msrs set successfully. + */ +static int msr_io(struct kvm *kvm, struct kvm_msrs __user *user_msrs, + int (*do_msr)(struct kvm_vcpu *vcpu, + unsigned index, u64 *data), + int writeback) +{ + struct kvm_msrs msrs; + struct kvm_msr_entry *entries; + int r, n; + unsigned size; - if (msrs->vcpu < 0 || msrs->vcpu >= KVM_MAX_VCPUS) - return -EINVAL; + r = -EFAULT; + if (copy_from_user(&msrs, user_msrs, sizeof msrs)) + goto out; - num_entries = ARRAY_SIZE(msrs_to_save); - if (msrs->nmsrs < num_entries) { - msrs->nmsrs = num_entries; /* inform actual size */ - return -EINVAL; - } + r = -E2BIG; + if (msrs.nmsrs >= MAX_IO_MSRS) + goto out; - vcpu = vcpu_load(kvm, msrs->vcpu); - if (!vcpu) - return -ENOENT; + r = -ENOMEM; + size = sizeof(struct kvm_msr_entry) * msrs.nmsrs; + entries = vmalloc(size); + if (!entries) + goto out; - size = msrs->nmsrs * sizeof(struct kvm_msr_entry); - rc = -E2BIG; - if (size > 4096) - goto out_vcpu; + r = -EFAULT; + if (copy_from_user(entries, user_msrs->entries, size)) + goto out_free; - rc = -ENOMEM; - entries = vmalloc(size); - if (entries == NULL) - goto out_vcpu; + r = n = __msr_io(kvm, &msrs, entries, do_msr); + if (r < 0) + goto out_free; - rc = -EFAULT; - if (copy_from_user(entries, msrs->entries, size)) + r = -EFAULT; + if (writeback && copy_to_user(user_msrs->entries, entries, size)) goto out_free; - rc = -EINVAL; - for (i=0; i<num_entries; i++) { - entry = &entries[i]; - if (set_msr(vcpu, entry->index, entry->data)) - goto out_free; - } + r = n; - rc = 0; out_free: vfree(entries); - -out_vcpu: - vcpu_put(vcpu); - - return rc; +out: + return r; } /* @@ -3505,32 +3488,32 @@ static long kvm_dev_ioctl(struct file *f goto out; break; } - case KVM_GET_MSRS: { - struct kvm_msrs kvm_msrs; + case KVM_GET_MSRS: + r = msr_io(kvm, (void __user *)arg, get_msr, 1); + break; + case KVM_SET_MSRS: + r = msr_io(kvm, (void __user *)arg, do_set_msr, 0); + break; + case KVM_GET_MSR_INDEX_LIST: { + struct kvm_msr_list __user *user_msr_list = (void __user *)arg; + struct kvm_msr_list msr_list; + unsigned n; r = -EFAULT; - if (copy_from_user(&kvm_msrs, (void *)arg, sizeof kvm_msrs)) + if (copy_from_user(&msr_list, user_msr_list, sizeof msr_list)) goto out; - r = kvm_dev_ioctl_get_msrs(kvm, &kvm_msrs); - if (r) + n = msr_list.nmsrs; + msr_list.nmsrs = ARRAY_SIZE(msrs_to_save); + if (copy_to_user(user_msr_list, &msr_list, sizeof msr_list)) goto out; - r = -EFAULT; - if (copy_to_user((void *)arg, &kvm_msrs, sizeof kvm_msrs)) + r = -E2BIG; + if (n < ARRAY_SIZE(msrs_to_save)) goto out; - r = 0; - break; - } - case KVM_SET_MSRS: { - struct kvm_msrs kvm_msrs; - r = -EFAULT; - if (copy_from_user(&kvm_msrs, (void *)arg, sizeof kvm_msrs)) - goto out; - r = kvm_dev_ioctl_set_msrs(kvm, &kvm_msrs); - if (r) + if (copy_to_user(user_msr_list->indices, &msrs_to_save, + sizeof msrs_to_save)) goto out; r = 0; - break; } default: ; diff -puN include/linux/kvm.h~kvm-expose-msrs-to-userspace-v2 include/linux/kvm.h --- a/include/linux/kvm.h~kvm-expose-msrs-to-userspace-v2 +++ a/include/linux/kvm.h @@ -152,10 +152,13 @@ struct kvm_msrs { __u32 vcpu; __u32 nmsrs; /* number of msrs in entries */ - union { - struct kvm_msr_entry __user *entries; - __u64 padding; - }; + struct kvm_msr_entry entries[0]; +}; + +/* for KVM_GET_MSR_INDEX_LIST */ +struct kvm_msr_list { + __u32 nmsrs; /* number of msrs in entries */ + __u32 indices[0]; }; /* for KVM_TRANSLATE */ @@ -218,6 +221,7 @@ struct kvm_dirty_log { #define KVM_CREATE_VCPU _IOW(KVMIO, 11, int /* vcpu_slot */) #define KVM_GET_DIRTY_LOG _IOW(KVMIO, 12, struct kvm_dirty_log) #define KVM_GET_MSRS _IOWR(KVMIO, 13, struct kvm_msrs) -#define KVM_SET_MSRS _IOW(KVMIO, 14, struct kvm_msrs) +#define KVM_SET_MSRS _IOWR(KVMIO, 14, struct kvm_msrs) +#define KVM_GET_MSR_INDEX_LIST _IOWR(KVMIO, 15, struct kvm_msr_list) #endif _ Patches currently in -mm which might be from avi@xxxxxxxxxxxx are kvm-userspace-interface.patch kvm-intel-virtual-mode-extensions-definitions.patch kvm-kvm-data-structures.patch kvm-random-accessors-and-constants.patch kvm-virtualization-infrastructure.patch kvm-virtualization-infrastructure-kvm-fix-guest-cr4-corruption.patch kvm-virtualization-infrastructure-include-desch.patch kvm-virtualization-infrastructure-fix-segment-state-changes-across-processor-mode-switches.patch kvm-virtualization-infrastructure-fix-asm-constraints-for-segment-loads.patch kvm-virtualization-infrastructure-fix-mmu-reset-locking-when-setting-cr0.patch kvm-memory-slot-management.patch kvm-vcpu-creation-and-maintenance.patch kvm-vcpu-creation-and-maintenance-segment-access-cleanup.patch kvm-workaround-cr0cd-cache-disable-bit-leak-from-guest-to.patch kvm-vcpu-execution-loop.patch kvm-define-exit-handlers.patch kvm-define-exit-handlers-pass-fs-gs-segment-bases-to-x86-emulator.patch kvm-less-common-exit-handlers.patch kvm-less-common-exit-handlers-handle-rdmsrmsr_efer.patch kvm-mmu.patch kvm-x86-emulator.patch kvm-x86-emulator-fix-emulator-mov-cr-decoding.patch kvm-plumbing.patch kvm-dynamically-determine-which-msrs-to-load-and-save.patch kvm-fix-calculation-of-initial-value-of-rdx-register.patch kvm-avoid-using-vmx-instruction-directly.patch kvm-avoid-using-vmx-instruction-directly-fix-asm-constraints.patch kvm-expose-interrupt-bitmap.patch kvm-add-time-stamp-counter-msr-and-accessors.patch kvm-expose-msrs-to-userspace.patch kvm-expose-msrs-to-userspace-v2.patch - To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html