All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marc Zyngier <maz@kernel.org>
To: Fuad Tabba <fuad.tabba@linux.dev>
Cc: Oliver Upton <oupton@kernel.org>, Joey Gouly <joey.gouly@arm.com>,
	Steffen Eiden <seiden@linux.ibm.com>,
	Suzuki K Poulose <suzuki.poulose@arm.com>,
	Zenghui Yu <yuzenghui@huawei.com>,
	Catalin Marinas <catalin.marinas@arm.com>,
	Will Deacon <will@kernel.org>,
	Mark Rutland <mark.rutland@arm.com>,
	Andre Przywara <andre.przywara@arm.com>,
	linux-arm-kernel@lists.infradead.org, kvmarm@lists.linux.dev,
	linux-kernel@vger.kernel.org, Fuad Tabba <tabba@google.com>
Subject: Re: [PATCH v2 0/2] KVM: arm64: vgic-its: Fix LPI double mapping and DISCARD
Date: Wed, 14 Oct 2026 14:34:09 +0100	[thread overview]
Message-ID: <86se281k4u.wl-maz@kernel.org> (raw)
In-Reply-To: <20261013143338.815377-1-fuad.tabba@linux.dev>

On Tue, 13 Oct 2026 15:33:38 +0100,
Fuad Tabba <fuad.tabba@linux.dev> wrote:
> 
>
> [...]
> > Is the hack below what you are asking for? I can't tell. If it isn't,
> > please post your own version.
> 
> Almost: it's missing a request check between the IN_GUEST_MODE store and
> the flush. Without it, a halt that reads OUTSIDE_GUEST_MODE just before
> the store doesn't wait for the vCPU, which then loads the LPI into an
> LR, takes the early exit on KVM_REQ_SLEEP and folds the LPI back after
> DISCARD has cleared it. That's the outcome in the first litmus test's
> exists clause. With the debug hooks forcing it on QEMU, the guest takes
> the discarded LPI in every run with your diff, and in none with this on
> top:
> 
> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
> index f1449b0..896bc76 100644
> --- a/arch/arm64/kvm/arm.c
> +++ b/arch/arm64/kvm/arm.c
> @@ -1329,11 +1329,29 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
>  		 */
>  		smp_store_mb(vcpu->mode, IN_GUEST_MODE);
>  
> +		/*
> +		 * Don't load the LRs with a request pending:
> +		 * kvm_arm_halt_guest() doesn't wait for a vCPU it reads
> +		 * as OUTSIDE_GUEST_MODE.
> +		 */
> +		if (ret <= 0 || kvm_vcpu_exit_request(vcpu, &ret)) {
> +			isb(); /* Ensure work in x_flush_hwstate is committed */
> +			if (kvm_vcpu_has_pmu(vcpu))
> +				kvm_pmu_sync_hwstate(vcpu);
> +			if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
> +				kvm_timer_sync_user(vcpu);
> +			smp_store_release(&vcpu->mode, OUTSIDE_GUEST_MODE);
> +			local_irq_enable();
> +			preempt_enable();
> +			continue;
> +		}
> +
>  		kvm_vgic_flush_hwstate(vcpu);
>  
>  		kvm_pmu_update_vcpu_events(vcpu);
>  
> -		if (ret <= 0 || kvm_vcpu_exit_request(vcpu, &ret)) {
> +		/* kvm_vgic_flush_hwstate() can make a request when nested */
> +		if (kvm_vcpu_exit_request(vcpu, &ret)) {
>  			isb(); /* Ensure work in x_flush_hwstate is committed */
>  			if (kvm_vcpu_has_pmu(vcpu))
>  				kvm_pmu_sync_hwstate(vcpu);
> 

I don't think this is right. Yes, it probably does enough request
checks that we end-up with not getting it completely wrong, but the
issues are that:

- we have state change before we evaluate the requests

- we mix request generation and state change in a single helper

and we should be able to fix that so that there is only a single
request checking point in the whole entry sequence.

I ended-up with a much bigger change, which really needs to be split
in two:

- untangle state generation and requests: this means that the
  maintenance interrupt generation and the request. The request
  generating stuff must happen before being IN_GUEST_MODE and request
  checking.

- the flushing must happen later on, once we don't look back anymore
  and have committed to entering the guest.

This, in turn, simplifies the "shit, I must rollback all the previous
changes as I can't enter the guest and must handle a request instead"
horror.

Another bug fix is that we now generate the maintenance interrupt
before deciding whether to generate a request switching from L2 to L1
as we have a pending interrupt.

Thoughts?

	M.

diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c
index 0576c2022ef57..3fa9e158f0be1 100644
--- a/arch/arm64/kvm/arm.c
+++ b/arch/arm64/kvm/arm.c
@@ -1321,10 +1321,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 
 		local_irq_disable();
 
-		kvm_vgic_flush_hwstate(vcpu);
-
-		kvm_pmu_update_vcpu_events(vcpu);
-
 		/*
 		 * Ensure we set mode to IN_GUEST_MODE after we disable
 		 * interrupts and before the final VCPU requests check.
@@ -1334,18 +1330,19 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 		smp_store_mb(vcpu->mode, IN_GUEST_MODE);
 
 		if (ret <= 0 || kvm_vcpu_exit_request(vcpu, &ret)) {
-			vcpu->mode = OUTSIDE_GUEST_MODE;
 			isb(); /* Ensure work in x_flush_hwstate is committed */
-			if (kvm_vcpu_has_pmu(vcpu))
-				kvm_pmu_sync_hwstate(vcpu);
 			if (unlikely(!irqchip_in_kernel(vcpu->kvm)))
 				kvm_timer_sync_user(vcpu);
-			kvm_vgic_sync_hwstate(vcpu);
+			smp_store_release(&vcpu->mode, OUTSIDE_GUEST_MODE);
 			local_irq_enable();
 			preempt_enable();
 			continue;
 		}
 
+		kvm_vgic_flush_hwstate(vcpu);
+
+		kvm_pmu_update_vcpu_events(vcpu);
+
 		kvm_arch_vcpu_ctxflush_fp(vcpu);
 
 		/**************************************************************
@@ -1356,7 +1353,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 
 		ret = kvm_arm_vcpu_enter_exit(vcpu);
 
-		vcpu->mode = OUTSIDE_GUEST_MODE;
 		vcpu->stat.exits++;
 		/*
 		 * Back from guest
@@ -1390,6 +1386,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
 
 		kvm_arch_vcpu_ctxsync_fp(vcpu);
 
+		/*
+		 * All the state has been synchronised, let advertise
+		 * we're outside of the guest.
+		 */
+		smp_store_release(&vcpu->mode, OUTSIDE_GUEST_MODE);
+
 		/*
 		 * We must ensure that any pending interrupts are taken before
 		 * we exit guest timing so that timer ticks are accounted as
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index b191365d97cc2..41f3def0eecae 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -2046,6 +2046,9 @@ void check_nested_vcpu_requests(struct kvm_vcpu *vcpu)
  *
  * What follows is some slop to (1) react to exception routing / masking and (2)
  * preserve the pending SError state across translation regimes.
+ *
+ * Also look generate the maintenance interrupt state, and finally check
+ * that if we need to take an interrupt targetting the guest hypervisor.
  */
 void kvm_nested_flush_hwstate(struct kvm_vcpu *vcpu)
 {
@@ -2054,6 +2057,11 @@ void kvm_nested_flush_hwstate(struct kvm_vcpu *vcpu)
 
 	if (unlikely(vcpu_test_and_clear_flag(vcpu, NESTED_SERROR_PENDING)))
 		kvm_inject_serror_esr(vcpu, vcpu_get_vsesr(vcpu));
+
+	vgic_v3_nested_update_mi(vcpu);
+
+	if (vgic_state_is_nested(vcpu) && kvm_vgic_vcpu_pending_irq(vcpu))
+		kvm_make_request(KVM_REQ_GUEST_HYP_IRQ_PENDING, vcpu);
 }
 
 void kvm_nested_sync_hwstate(struct kvm_vcpu *vcpu)
diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index 5cf5a1ef86cdd..7061b4ab206c9 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -1152,7 +1152,7 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	 *
 	 *   We do that by placing a request to ourselves which will
 	 *   abort the entry procedure and inject the exception at the
-	 *   beginning of the run loop.
+	 *   beginning of the run loop (see kvm_nested_flush_hwstate()).
 	 *
 	 * - Otherwise, do exactly *NOTHING* apart from enabling the virtual
 	 *   CPU interface. The guest state is already loaded, and we can
@@ -1162,16 +1162,10 @@ void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
 	 * maintenance interrupt state, as it may fire.
 	 */
 	if (vgic_state_is_nested(vcpu)) {
-		if (kvm_vgic_vcpu_pending_irq(vcpu))
-			kvm_make_request(KVM_REQ_GUEST_HYP_IRQ_PENDING, vcpu);
-
 		vgic_v3_flush_nested(vcpu);
 		return;
 	}
 
-	if (vcpu_has_nv(vcpu))
-		vgic_v3_nested_update_mi(vcpu);
-
 	DEBUG_SPINLOCK_BUG_ON(!irqs_disabled());
 
 	vgic_flush_state(vcpu);
-- 
2.47.3


-- 
Without deviation from the norm, progress is not possible.


  reply	other threads:[~2026-10-14 13:34 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-13  8:16 [PATCH v2 0/2] KVM: arm64: vgic-its: Fix LPI double mapping and DISCARD Fuad Tabba
2026-10-13  8:16 ` [PATCH v2 1/2] KVM: arm64: vgic-its: Don't map an LPI from more than one event Fuad Tabba
2026-10-13  8:16 ` [PATCH v2 2/2] KVM: arm64: vgic-its: Remove the pending state of a discarded LPI Fuad Tabba
2026-10-13  8:50   ` sashiko-bot
2026-10-13  9:49     ` Oliver Upton
2026-10-13  9:51 ` [PATCH v2 0/2] KVM: arm64: vgic-its: Fix LPI double mapping and DISCARD Oliver Upton
2026-10-13 10:01   ` Marc Zyngier
2026-10-13 10:50     ` Fuad Tabba
2026-10-13 11:16       ` Marc Zyngier
2026-10-13 12:59         ` Fuad Tabba
2026-10-13 13:25           ` Marc Zyngier
2026-10-13 14:33             ` Fuad Tabba
2026-10-14 13:34               ` Marc Zyngier [this message]
2026-10-14 15:20                 ` Fuad Tabba

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=86se281k4u.wl-maz@kernel.org \
    --to=maz@kernel.org \
    --cc=andre.przywara@arm.com \
    --cc=catalin.marinas@arm.com \
    --cc=fuad.tabba@linux.dev \
    --cc=joey.gouly@arm.com \
    --cc=kvmarm@lists.linux.dev \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=oupton@kernel.org \
    --cc=seiden@linux.ibm.com \
    --cc=suzuki.poulose@arm.com \
    --cc=tabba@google.com \
    --cc=will@kernel.org \
    --cc=yuzenghui@huawei.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.