diff options
Diffstat (limited to 'arch/x86/kvm/x86.c')
| -rw-r--r-- | arch/x86/kvm/x86.c | 59 | 
1 files changed, 47 insertions, 12 deletions
| diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ed31c31b2485..ea306adbbc13 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -702,8 +702,9 @@ EXPORT_SYMBOL_GPL(kvm_set_xcr);  int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)  {  	unsigned long old_cr4 = kvm_read_cr4(vcpu); -	unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | -				   X86_CR4_PAE | X86_CR4_SMEP; +	unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE | +				   X86_CR4_SMEP | X86_CR4_SMAP; +  	if (cr4 & CR4_RESERVED_BITS)  		return 1; @@ -744,9 +745,6 @@ int kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)  	    (!(cr4 & X86_CR4_PCIDE) && (old_cr4 & X86_CR4_PCIDE)))  		kvm_mmu_reset_context(vcpu); -	if ((cr4 ^ old_cr4) & X86_CR4_SMAP) -		update_permission_bitmask(vcpu, vcpu->arch.walk_mmu, false); -  	if ((cr4 ^ old_cr4) & X86_CR4_OSXSAVE)  		kvm_update_cpuid(vcpu); @@ -1669,12 +1667,28 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)  		&guest_hv_clock, sizeof(guest_hv_clock))))  		return 0; -	/* -	 * The interface expects us to write an even number signaling that the -	 * update is finished. Since the guest won't see the intermediate -	 * state, we just increase by 2 at the end. +	/* This VCPU is paused, but it's legal for a guest to read another +	 * VCPU's kvmclock, so we really have to follow the specification where +	 * it says that version is odd if data is being modified, and even after +	 * it is consistent. +	 * +	 * Version field updates must be kept separate.  This is because +	 * kvm_write_guest_cached might use a "rep movs" instruction, and +	 * writes within a string instruction are weakly ordered.  So there +	 * are three writes overall. +	 * +	 * As a small optimization, only write the version field in the first +	 * and third write.  The vcpu->pv_time cache is still valid, because the +	 * version field is the first in the struct.  	 */ -	vcpu->hv_clock.version = guest_hv_clock.version + 2; +	BUILD_BUG_ON(offsetof(struct pvclock_vcpu_time_info, version) != 0); + +	vcpu->hv_clock.version = guest_hv_clock.version + 1; +	kvm_write_guest_cached(v->kvm, &vcpu->pv_time, +				&vcpu->hv_clock, +				sizeof(vcpu->hv_clock.version)); + +	smp_wmb();  	/* retain PVCLOCK_GUEST_STOPPED if set in guest copy */  	pvclock_flags = (guest_hv_clock.flags & PVCLOCK_GUEST_STOPPED); @@ -1695,6 +1709,13 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)  	kvm_write_guest_cached(v->kvm, &vcpu->pv_time,  				&vcpu->hv_clock,  				sizeof(vcpu->hv_clock)); + +	smp_wmb(); + +	vcpu->hv_clock.version++; +	kvm_write_guest_cached(v->kvm, &vcpu->pv_time, +				&vcpu->hv_clock, +				sizeof(vcpu->hv_clock.version));  	return 0;  } @@ -6174,6 +6195,8 @@ void kvm_vcpu_reload_apic_access_page(struct kvm_vcpu *vcpu)  		return;  	page = gfn_to_page(vcpu->kvm, APIC_DEFAULT_PHYS_BASE >> PAGE_SHIFT); +	if (is_error_page(page)) +		return;  	kvm_x86_ops->set_apic_access_page_addr(vcpu, page_to_phys(page));  	/* @@ -7037,7 +7060,9 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu)  	fpu_save_init(&vcpu->arch.guest_fpu);  	__kernel_fpu_end();  	++vcpu->stat.fpu_reload; -	kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu); +	if (!vcpu->arch.eager_fpu) +		kvm_make_request(KVM_REQ_DEACTIVATE_FPU, vcpu); +  	trace_kvm_fpu(0);  } @@ -7053,11 +7078,21 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)  struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,  						unsigned int id)  { +	struct kvm_vcpu *vcpu; +  	if (check_tsc_unstable() && atomic_read(&kvm->online_vcpus) != 0)  		printk_once(KERN_WARNING  		"kvm: SMP vm created on host with unstable TSC; "  		"guest TSC will not be reliable\n"); -	return kvm_x86_ops->vcpu_create(kvm, id); + +	vcpu = kvm_x86_ops->vcpu_create(kvm, id); + +	/* +	 * Activate fpu unconditionally in case the guest needs eager FPU.  It will be +	 * deactivated soon if it doesn't. +	 */ +	kvm_x86_ops->fpu_activate(vcpu); +	return vcpu;  }  int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) |