diff options
Diffstat (limited to '')
| -rw-r--r-- | arch/x86/kvm/lapic.c | 56 | 
1 files changed, 41 insertions, 15 deletions
| diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 006911858174..08e8a899e005 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -352,25 +352,46 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic)  static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)  { -	apic->irr_pending = false; +	struct kvm_vcpu *vcpu; + +	vcpu = apic->vcpu; +  	apic_clear_vector(vec, apic->regs + APIC_IRR); -	if (apic_search_irr(apic) != -1) -		apic->irr_pending = true; +	if (unlikely(kvm_apic_vid_enabled(vcpu->kvm))) +		/* try to update RVI */ +		kvm_make_request(KVM_REQ_EVENT, vcpu); +	else { +		vec = apic_search_irr(apic); +		apic->irr_pending = (vec != -1); +	}  }  static inline void apic_set_isr(int vec, struct kvm_lapic *apic)  { -	/* Note that we never get here with APIC virtualization enabled.  */ +	struct kvm_vcpu *vcpu; + +	if (__apic_test_and_set_vector(vec, apic->regs + APIC_ISR)) +		return; + +	vcpu = apic->vcpu; -	if (!__apic_test_and_set_vector(vec, apic->regs + APIC_ISR)) -		++apic->isr_count; -	BUG_ON(apic->isr_count > MAX_APIC_VECTOR);  	/* -	 * ISR (in service register) bit is set when injecting an interrupt. -	 * The highest vector is injected. Thus the latest bit set matches -	 * the highest bit in ISR. +	 * With APIC virtualization enabled, all caching is disabled +	 * because the processor can modify ISR under the hood.  Instead +	 * just set SVI.  	 */ -	apic->highest_isr_cache = vec; +	if (unlikely(kvm_apic_vid_enabled(vcpu->kvm))) +		kvm_x86_ops->hwapic_isr_update(vcpu->kvm, vec); +	else { +		++apic->isr_count; +		BUG_ON(apic->isr_count > MAX_APIC_VECTOR); +		/* +		 * ISR (in service register) bit is set when injecting an interrupt. +		 * The highest vector is injected. Thus the latest bit set matches +		 * the highest bit in ISR. +		 */ +		apic->highest_isr_cache = vec; +	}  }  static inline int apic_find_highest_isr(struct kvm_lapic *apic) @@ -1451,7 +1472,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)  	vcpu->arch.apic_arb_prio = 0;  	vcpu->arch.apic_attention = 0; -	apic_debug(KERN_INFO "%s: vcpu=%p, id=%d, base_msr=" +	apic_debug("%s: vcpu=%p, id=%d, base_msr="  		   "0x%016" PRIx64 ", base_address=0x%0lx.\n", __func__,  		   vcpu, kvm_apic_id(apic),  		   vcpu->arch.apic_base, apic->base_address); @@ -1627,11 +1648,16 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)  	int vector = kvm_apic_has_interrupt(vcpu);  	struct kvm_lapic *apic = vcpu->arch.apic; -	/* Note that we never get here with APIC virtualization enabled.  */ -  	if (vector == -1)  		return -1; +	/* +	 * We get here even with APIC virtualization enabled, if doing +	 * nested virtualization and L1 runs with the "acknowledge interrupt +	 * on exit" mode.  Then we cannot inject the interrupt via RVI, +	 * because the process would deliver it through the IDT. +	 */ +  	apic_set_isr(vector, apic);  	apic_update_ppr(apic);  	apic_clear_irr(vector, apic); @@ -1895,7 +1921,7 @@ void kvm_apic_accept_events(struct kvm_vcpu *vcpu)  		/* evaluate pending_events before reading the vector */  		smp_rmb();  		sipi_vector = apic->sipi_vector; -		pr_debug("vcpu %d received sipi with vector # %x\n", +		apic_debug("vcpu %d received sipi with vector # %x\n",  			 vcpu->vcpu_id, sipi_vector);  		kvm_vcpu_deliver_sipi_vector(vcpu, sipi_vector);  		vcpu->arch.mp_state = KVM_MP_STATE_RUNNABLE; | 
