public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
From: Marc Zyngier <marc.zyngier@arm.com>
To: Christoffer Dall <christoffer.dall@linaro.org>,
	kvmarm@lists.cs.columbia.edu, kvm@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
Cc: Andre Przywara <andre.przywara@arm.com>,
	Eric Auger <eric.auger@linaro.org>
Subject: Re: [PATCH v2] KVM: arm/arm64: vgic-new: Synchronize changes to active state
Date: Fri, 20 May 2016 15:07:57 +0100	[thread overview]
Message-ID: <573F1A3D.7050808@arm.com> (raw)
In-Reply-To: <1463752410-3800-1-git-send-email-christoffer.dall@linaro.org>

On 20/05/16 14:53, Christoffer Dall wrote:
> When modifying the active state of an interrupt via the MMIO interface,
> we should ensure that the write has the intended effect.
> 
> If a guest sets an interrupt to active, but that interrupt is already
> flushed into a list register on a running VCPU, then that VCPU will
> write the active state back into the struct vgic_irq upon returning from
> the guest and syncing its state.  This is a non-benign race, because the
> guest can observe that an interrupt is not active, and it can have a
> reasonable expectations that other VCPUs will not ack any IRQs, and then
> set the state to active, and expect it to stay that way.  Currently we
> are not honoring this case.
> 
> Thefore, change both the SACTIVE and CACTIVE mmio handlers to stop the
> world, change the irq state, potentially queue the irq if we're setting
> it to active, and then continue.
> 
> We take this chance to slightly optimize these functions by not stopping
> the world when touching private interrupts where there is inherently no
> possible race.
> 
> Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
> ---
> Changes since v1:
>  - Dont' stop the world for private IRQs
> 
>  virt/kvm/arm/vgic/vgic-mmio.c | 87 ++++++++++++++++++++++++-------------------
>  1 file changed, 48 insertions(+), 39 deletions(-)
> 
> diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
> index 4ef3571..b014c8c 100644
> --- a/virt/kvm/arm/vgic/vgic-mmio.c
> +++ b/virt/kvm/arm/vgic/vgic-mmio.c
> @@ -173,6 +173,36 @@ unsigned long vgic_mmio_read_active(struct kvm_vcpu *vcpu,
>  	return value;
>  }
>  
> +static void vgic_mmio_change_active(struct kvm_vcpu *vcpu, struct vgic_irq *irq,
> +				    bool new_active_state)
> +{
> +	spin_lock(&irq->irq_lock);
> +	/*
> +	 * If this virtual IRQ was written into a list register, we
> +	 * have to make sure the CPU that runs the VCPU thread has
> +	 * synced back LR state to the struct vgic_irq.  We can only
> +	 * know this for sure, when either this irq is not assigned to
> +	 * anyone's AP list anymore, or the VCPU thread is not
> +	 * running on any CPUs.
> +	 *
> +	 * In the opposite case, we know the VCPU thread may be on its
> +	 * way back from the guest and still has to sync back this
> +	 * IRQ, so we release and re-acquire the spin_lock to let the
> +	 * other thread sync back the IRQ.
> +	 */
> +	while (irq->vcpu && /* IRQ may have state in an LR somewhere */
> +	       irq->vcpu->cpu != -1) { /* VCPU thread is running */
> +		BUG_ON(irq->intid < VGIC_NR_PRIVATE_IRQS);
> +		cond_resched_lock(&irq->irq_lock);
> +	}
> +
> +	irq->active = new_active_state;
> +	if (new_active_state)
> +		vgic_queue_irq_unlock(vcpu->kvm, irq);
> +	else
> +		spin_unlock(&irq->irq_lock);
> +}
> +
>  void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
>  			     gpa_t addr, unsigned int len,
>  			     unsigned long val)
> @@ -180,32 +210,18 @@ void vgic_mmio_write_cactive(struct kvm_vcpu *vcpu,
>  	u32 intid = VGIC_ADDR_TO_INTID(addr, 1);
>  	int i;
>  
> -	kvm_arm_halt_guest(vcpu->kvm);
> +	/* Only the VCPU itself can access its active state regs */

I'm afraid this is not true for GICv3 (the private interrupts are
handled by the redistributors, which are not banked).

> +	if (intid >= VGIC_NR_PRIVATE_IRQS)
> +		kvm_arm_halt_guest(vcpu->kvm);
	else {
		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid);
		irq->target_vcpu.arch.pause = true;
		kvm_make_request(irq->target_vcpu, KVM_REQ_VCPU_EXIT);
		/* and then it is a bit complicated... */
	}
> +
>  	for_each_set_bit(i, &val, len * 8) {
>  		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
> -
> -		spin_lock(&irq->irq_lock);
> -		/*
> -		 * If this virtual IRQ was written into a list register, we
> -		 * have to make sure the CPU that runs the VCPU thread has
> -		 * synced back LR state to the struct vgic_irq.  We can only
> -		 * know this for sure, when either this irq is not assigned to
> -		 * anyone's AP list anymore, or the VCPU thread is not
> -		 * running on any CPUs.
> -		 *
> -		 * In the opposite case, we know the VCPU thread may be on its
> -		 * way back from the guest and still has to sync back this
> -		 * IRQ, so we release and re-acquire the spin_lock to let the
> -		 * other thread sync back the IRQ.
> -		 */
> -		while (irq->vcpu && /* IRQ may have state in an LR somewhere */
> -		       irq->vcpu->cpu != -1) /* VCPU thread is running */
> -			cond_resched_lock(&irq->irq_lock);
> -
> -		irq->active = false;
> -		spin_unlock(&irq->irq_lock);
> +		vgic_mmio_change_active(vcpu, irq, false);
>  	}
> -	kvm_arm_resume_guest(vcpu->kvm);
> +
> +	/* Only the VCPU itself can access its active state regs */
> +	if (intid >= VGIC_NR_PRIVATE_IRQS)
> +		kvm_arm_resume_guest(vcpu->kvm);
>  }

I though we had a way to stop a single vcpu without too much hassle,
but I'm not seeing any standard way to do that. Grmbl...

	M.
-- 
Jazz is not dead. It just smells funny...

  reply	other threads:[~2016-05-20 14:08 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-05-20 13:30 [PATCH] KVM: arm/arm64: vgic-new: Synchronize changes to active state Christoffer Dall
2016-05-20 13:53 ` [PATCH v2] " Christoffer Dall
2016-05-20 14:07   ` Marc Zyngier [this message]
2016-05-20 14:14     ` Christoffer Dall
2016-05-20 14:31   ` [PATCH v3] " Christoffer Dall
2016-05-20 14:43     ` Marc Zyngier
2016-05-20 14:47       ` Marc Zyngier
2016-05-20 14:49         ` Christoffer Dall

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=573F1A3D.7050808@arm.com \
    --to=marc.zyngier@arm.com \
    --cc=andre.przywara@arm.com \
    --cc=christoffer.dall@linaro.org \
    --cc=eric.auger@linaro.org \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.cs.columbia.edu \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox