diff options
Diffstat (limited to 'arch/x86/kvm/x86.c')
| -rw-r--r-- | arch/x86/kvm/x86.c | 47 | 
1 files changed, 34 insertions, 13 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 3017de0431bd..04c5d96b1d67 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -210,7 +210,18 @@ static void kvm_on_user_return(struct user_return_notifier *urn)  	struct kvm_shared_msrs *locals  		= container_of(urn, struct kvm_shared_msrs, urn);  	struct kvm_shared_msr_values *values; +	unsigned long flags; +	/* +	 * Disabling irqs at this point since the following code could be +	 * interrupted and executed through kvm_arch_hardware_disable() +	 */ +	local_irq_save(flags); +	if (locals->registered) { +		locals->registered = false; +		user_return_notifier_unregister(urn); +	} +	local_irq_restore(flags);  	for (slot = 0; slot < shared_msrs_global.nr; ++slot) {  		values = &locals->values[slot];  		if (values->host != values->curr) { @@ -218,8 +229,6 @@ static void kvm_on_user_return(struct user_return_notifier *urn)  			values->curr = values->host;  		}  	} -	locals->registered = false; -	user_return_notifier_unregister(urn);  }  static void shared_msr_update(unsigned slot, u32 msr) @@ -1724,18 +1733,23 @@ static void kvm_gen_update_masterclock(struct kvm *kvm)  static u64 __get_kvmclock_ns(struct kvm *kvm)  { -	struct kvm_vcpu *vcpu = kvm_get_vcpu(kvm, 0);  	struct kvm_arch *ka = &kvm->arch; -	s64 ns; +	struct pvclock_vcpu_time_info hv_clock; -	if (vcpu->arch.hv_clock.flags & PVCLOCK_TSC_STABLE_BIT) { -		u64 tsc = kvm_read_l1_tsc(vcpu, rdtsc()); -		ns = __pvclock_read_cycles(&vcpu->arch.hv_clock, tsc); -	} else { -		ns = ktime_get_boot_ns() + ka->kvmclock_offset; +	spin_lock(&ka->pvclock_gtod_sync_lock); +	if (!ka->use_master_clock) { +		spin_unlock(&ka->pvclock_gtod_sync_lock); +		return ktime_get_boot_ns() + ka->kvmclock_offset;  	} -	return ns; +	hv_clock.tsc_timestamp = ka->master_cycle_now; +	hv_clock.system_time = ka->master_kernel_ns + ka->kvmclock_offset; +	spin_unlock(&ka->pvclock_gtod_sync_lock); + +	kvm_get_time_scale(NSEC_PER_SEC, __this_cpu_read(cpu_tsc_khz) * 1000LL, +			   &hv_clock.tsc_shift, +			   &hv_clock.tsc_to_system_mul); +	return __pvclock_read_cycles(&hv_clock, rdtsc());  }  u64 get_kvmclock_ns(struct kvm *kvm) @@ -2596,7 +2610,6 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)  	case KVM_CAP_PIT_STATE2:  	case KVM_CAP_SET_IDENTITY_MAP_ADDR:  	case KVM_CAP_XEN_HVM: -	case KVM_CAP_ADJUST_CLOCK:  	case KVM_CAP_VCPU_EVENTS:  	case KVM_CAP_HYPERV:  	case KVM_CAP_HYPERV_VAPIC: @@ -2623,6 +2636,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)  #endif  		r = 1;  		break; +	case KVM_CAP_ADJUST_CLOCK: +		r = KVM_CLOCK_TSC_STABLE; +		break;  	case KVM_CAP_X86_SMM:  		/* SMBASE is usually relocated above 1M on modern chipsets,  		 * and SMM handlers might indeed rely on 4G segment limits, @@ -3415,6 +3431,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,  	};  	case KVM_SET_VAPIC_ADDR: {  		struct kvm_vapic_addr va; +		int idx;  		r = -EINVAL;  		if (!lapic_in_kernel(vcpu)) @@ -3422,7 +3439,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp,  		r = -EFAULT;  		if (copy_from_user(&va, argp, sizeof va))  			goto out; +		idx = srcu_read_lock(&vcpu->kvm->srcu);  		r = kvm_lapic_set_vapic_addr(vcpu, va.vapic_addr); +		srcu_read_unlock(&vcpu->kvm->srcu, idx);  		break;  	}  	case KVM_X86_SETUP_MCE: { @@ -4103,9 +4122,11 @@ long kvm_arch_vm_ioctl(struct file *filp,  		struct kvm_clock_data user_ns;  		u64 now_ns; -		now_ns = get_kvmclock_ns(kvm); +		local_irq_disable(); +		now_ns = __get_kvmclock_ns(kvm);  		user_ns.clock = now_ns; -		user_ns.flags = 0; +		user_ns.flags = kvm->arch.use_master_clock ? KVM_CLOCK_TSC_STABLE : 0; +		local_irq_enable();  		memset(&user_ns.pad, 0, sizeof(user_ns.pad));  		r = -EFAULT;  | 
