Hi, I've encountered a situation in which I would like to allow userspace to set the MSRs which KVM should not emulate and instead implement these as no-ops. I have not seen any work in this space, furthermore there is an item on the KVM TODO that is very similar to what I'm trying to do. The userspace interface is an extension of kvm_vcpu_ioctl, adding the KVM_SET_MSRS_NOOP flag. It takes a struct kvm_msrs as a list of which MSRs should be no-ops and adds the field noop to struct kvm_msr_entry. This patch only affects vmx, but if the approach is sane, I can extend it to support svm as well. diff -purN linux-2.6.32-rc5/arch/x86/include/asm/kvm.h linux-2.6.32-rc5-kvm-msrs-noop/arch/x86/include/asm/kvm.h --- linux-2.6.32-rc5/arch/x86/include/asm/kvm.h 2009-10-15 20:41:50.000000000 -0400 +++ linux-2.6.32-rc5-kvm-msrs-noop/arch/x86/include/asm/kvm.h 2009-10-27 22:44:58.000000000 -0400 @@ -144,6 +144,7 @@ struct kvm_msr_entry { __u32 index; __u32 reserved; __u64 data; + __u8 noop; }; /* for KVM_GET_MSRS and KVM_SET_MSRS */ diff -purN linux-2.6.32-rc5/arch/x86/include/asm/kvm_host.h linux-2.6.32-rc5-kvm-msrs-noop/arch/x86/include/asm/kvm_host.h --- linux-2.6.32-rc5/arch/x86/include/asm/kvm_host.h 2009-10-15 20:41:50.000000000 -0400 +++ linux-2.6.32-rc5-kvm-msrs-noop/arch/x86/include/asm/kvm_host.h 2009-10-27 22:44:58.000000000 -0400 @@ -481,6 +481,7 @@ struct kvm_x86_ops { struct kvm_guest_debug *dbg); int (*get_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata); int (*set_msr)(struct kvm_vcpu *vcpu, u32 msr_index, u64 data); + int (*set_msr_noop)(struct kvm_vcpu *vcpu, u32 msr_index); u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg); void (*get_segment)(struct kvm_vcpu *vcpu, struct kvm_segment *var, int seg); diff -purN linux-2.6.32-rc5/arch/x86/kvm/vmx.c linux-2.6.32-rc5-kvm-msrs-noop/arch/x86/kvm/vmx.c --- linux-2.6.32-rc5/arch/x86/kvm/vmx.c 2009-10-15 20:41:50.000000000 -0400 +++ linux-2.6.32-rc5-kvm-msrs-noop/arch/x86/kvm/vmx.c 2009-10-27 22:44:58.000000000 -0400 @@ -983,6 +983,13 @@ static int vmx_get_msr(struct kvm_vcpu * return -EINVAL; } + msr = find_msr_entry(to_vmx(vcpu), msr_index); + if (msr) { + if (msr->noop) { + return 0; + } + } + switch (msr_index) { #ifdef CONFIG_X86_64 case MSR_FS_BASE: @@ -1032,6 +1039,13 @@ static int vmx_set_msr(struct kvm_vcpu * u64 host_tsc; int ret = 0; + msr = find_msr_entry(to_vmx(vcpu), msr_index); + if (msr) { + if (msr->noop) { + return ret; + } + } + switch (msr_index) { case MSR_EFER: vmx_load_host_state(vmx); @@ -1078,6 +1092,21 @@ static int vmx_set_msr(struct kvm_vcpu * return ret; } +static int vmx_set_msr_noop(struct kvm_vcpu *vcpu, u32 msr) +{ + struct kvm_msr_entry *m; + + if (!vcpu) + return -1; + + m = find_msr_entry(to_vmx(vcpu), msr); + if (!m) + return -1; + + m->noop = 1; + return 0; +} + static void vmx_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg) { __set_bit(reg, (unsigned long *)&vcpu->arch.regs_avail); @@ -3942,6 +3971,7 @@ static struct kvm_x86_ops vmx_x86_ops = .set_guest_debug = set_guest_debug, .get_msr = vmx_get_msr, .set_msr = vmx_set_msr, + .set_msr_noop = vmx_set_msr_noop, .get_segment_base = vmx_get_segment_base, .get_segment = vmx_get_segment, .set_segment = vmx_set_segment, diff -purN linux-2.6.32-rc5/arch/x86/kvm/x86.c linux-2.6.32-rc5-kvm-msrs-noop/arch/x86/kvm/x86.c --- linux-2.6.32-rc5/arch/x86/kvm/x86.c 2009-10-15 20:41:50.000000000 -0400 +++ linux-2.6.32-rc5-kvm-msrs-noop/arch/x86/kvm/x86.c 2009-10-27 22:44:58.000000000 -0400 @@ -975,6 +975,31 @@ int kvm_get_msr(struct kvm_vcpu *vcpu, u return kvm_x86_ops->get_msr(vcpu, msr_index, pdata); } +static int kvm_set_msrs_noop(struct kvm_vcpu *vcpu, struct kvm_msrs __user *user_msrs) +{ + int i, r; + int size; + struct kvm_msrs msrs; + struct kvm_msr_entry *entries; + + if (copy_from_user(&msrs, user_msrs, sizeof msrs)) + goto out; + + size = sizeof(struct kvm_msr_entry) * msrs.nmsrs; + if (copy_from_user(entries, user_msrs->entries, size)) + goto out; + + for (i = 0; i < msrs.nmsrs; i++) { + r = kvm_x86_ops->set_msr_noop(vcpu, entries[i].index); + if (r) + goto out; + } + + return 0; +out: + return -1; +} + static int get_msr_mtrr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) { u64 *p = (u64 *)&vcpu->arch.mtrr_state.fixed_ranges; @@ -1864,6 +1889,9 @@ long kvm_arch_vcpu_ioctl(struct file *fi case KVM_SET_MSRS: r = msr_io(vcpu, argp, do_set_msr, 0); break; + case KVM_SET_MSRS_NOOP: + r = kvm_set_msrs_noop(vcpu, argp); + break; case KVM_TPR_ACCESS_REPORTING: { struct kvm_tpr_access_ctl tac; diff -purN linux-2.6.32-rc5/include/linux/kvm.h linux-2.6.32-rc5-kvm-msrs-noop/include/linux/kvm.h --- linux-2.6.32-rc5/include/linux/kvm.h 2009-10-15 20:41:50.000000000 -0400 +++ linux-2.6.32-rc5-kvm-msrs-noop/include/linux/kvm.h 2009-10-27 22:46:36.000000000 -0400 @@ -593,6 +593,7 @@ struct kvm_irqfd { #define KVM_X86_SETUP_MCE _IOW(KVMIO, 0x9c, __u64) #define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO, 0x9d, __u64) #define KVM_X86_SET_MCE _IOW(KVMIO, 0x9e, struct kvm_x86_mce) +#define KVM_SET_MSRS_NOOP _IOW(KVMIO, 0x9f, struct kvm_msrs) /* * Deprecated interfaces -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html