linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14
@ 2025-02-06 15:20 Marc Zyngier
  2025-02-06 15:20 ` [PATCH 1/3] KVM: arm64: timer: Drop warning on failed interrupt signalling Marc Zyngier
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Marc Zyngier @ 2025-02-06 15:20 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Alexander Potapenko, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu

Alexander, while fuzzing KVM/arm64, found an annoying set of problems,
all stemming from the fact that the vgic can be destroyed in parallel
with the rest of the guest still being live.

Yes, this is annoying.

Fixing this is not going to happen overnight (though I have some
ideas), but we can make what we have today a bit more robust.

This is what patch #2 is doing. Patch #1 is just removing a loud
WARN_ON() that serves little purpose, and patch #3 fixes the actual
bug that Alex reported.

Hopefully, none of that is controversial...

Marc Zyngier (3):
  KVM: arm64: timer: Drop warning on failed interrupt signalling
  KVM: arm64: vgic: Check for unallocated PPI/SPI arrays
  KVM: arm64: vgic: Gracefully handle resetting an unallocated interrupt

 arch/arm64/kvm/arch_timer.c | 16 +++++++---------
 arch/arm64/kvm/vgic/vgic.c  |  7 +++++++
 2 files changed, 14 insertions(+), 9 deletions(-)

-- 
2.39.2



^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/3] KVM: arm64: timer: Drop warning on failed interrupt signalling
  2025-02-06 15:20 [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14 Marc Zyngier
@ 2025-02-06 15:20 ` Marc Zyngier
  2025-02-06 15:50   ` Alexander Potapenko
  2025-02-06 15:20 ` [PATCH 2/3] KVM: arm64: vgic: Check for unallocated PPI/SPI arrays Marc Zyngier
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: Marc Zyngier @ 2025-02-06 15:20 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Alexander Potapenko, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu

We currently spit out a warning if making a timer interrupt pending
fails. But not only this is loud and easy to trigger from userspace,
we also fail to do anything useful with that information.

Dropping the warning is the easiest thing to do for now. We can
always add error reporting if we really want in the future.

Reported-by: Alexander Potapenko <glider@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/arch_timer.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/kvm/arch_timer.c b/arch/arm64/kvm/arch_timer.c
index 231c0cd9c7b4b..70802e4c91cf5 100644
--- a/arch/arm64/kvm/arch_timer.c
+++ b/arch/arm64/kvm/arch_timer.c
@@ -447,21 +447,19 @@ static void kvm_timer_update_status(struct arch_timer_context *ctx, bool level)
 static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level,
 				 struct arch_timer_context *timer_ctx)
 {
-	int ret;
-
 	kvm_timer_update_status(timer_ctx, new_level);
 
 	timer_ctx->irq.level = new_level;
 	trace_kvm_timer_update_irq(vcpu->vcpu_id, timer_irq(timer_ctx),
 				   timer_ctx->irq.level);
 
-	if (!userspace_irqchip(vcpu->kvm)) {
-		ret = kvm_vgic_inject_irq(vcpu->kvm, vcpu,
-					  timer_irq(timer_ctx),
-					  timer_ctx->irq.level,
-					  timer_ctx);
-		WARN_ON(ret);
-	}
+	if (userspace_irqchip(vcpu->kvm))
+		return;
+
+	kvm_vgic_inject_irq(vcpu->kvm, vcpu,
+			    timer_irq(timer_ctx),
+			    timer_ctx->irq.level,
+			    timer_ctx);
 }
 
 /* Only called for a fully emulated timer */
-- 
2.39.2



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 2/3] KVM: arm64: vgic: Check for unallocated PPI/SPI arrays
  2025-02-06 15:20 [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14 Marc Zyngier
  2025-02-06 15:20 ` [PATCH 1/3] KVM: arm64: timer: Drop warning on failed interrupt signalling Marc Zyngier
@ 2025-02-06 15:20 ` Marc Zyngier
  2025-02-06 15:50   ` Alexander Potapenko
  2025-02-06 15:21 ` [PATCH 3/3] KVM: arm64: vgic: Gracefully handle resetting an unallocated interrupt Marc Zyngier
  2025-02-07 18:03 ` [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14 Oliver Upton
  3 siblings, 1 reply; 11+ messages in thread
From: Marc Zyngier @ 2025-02-06 15:20 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Alexander Potapenko, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu

Alexander's fuzzing has exhibited a large variety of races that
all end-up with taking the address of a PPI or SPI structure while
the vgic was torn down (because nuking it is only an ioctl() away,
and syzkaller is amazing at finding holes).

In order to preserve some sanity, always evaluate whether the array
containing the PPI/SPI is allocated.

Suggested-by: Alexander Potapenko <glider@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/vgic/vgic.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index cc8c6b9b5dd8b..f454cef59e24b 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -89,6 +89,8 @@ struct vgic_irq *vgic_get_irq(struct kvm *kvm, u32 intid)
 	/* SPIs */
 	if (intid >= VGIC_NR_PRIVATE_IRQS &&
 	    intid < (kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS)) {
+		if (unlikely(!kvm->arch.vgic.spis))
+			return NULL;
 		intid = array_index_nospec(intid, kvm->arch.vgic.nr_spis + VGIC_NR_PRIVATE_IRQS);
 		return &kvm->arch.vgic.spis[intid - VGIC_NR_PRIVATE_IRQS];
 	}
@@ -107,6 +109,8 @@ struct vgic_irq *vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid)
 
 	/* SGIs and PPIs */
 	if (intid < VGIC_NR_PRIVATE_IRQS) {
+		if (unlikely(!vcpu->arch.vgic_cpu.private_irqs))
+			return NULL;
 		intid = array_index_nospec(intid, VGIC_NR_PRIVATE_IRQS);
 		return &vcpu->arch.vgic_cpu.private_irqs[intid];
 	}
-- 
2.39.2



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH 3/3] KVM: arm64: vgic: Gracefully handle resetting an unallocated interrupt
  2025-02-06 15:20 [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14 Marc Zyngier
  2025-02-06 15:20 ` [PATCH 1/3] KVM: arm64: timer: Drop warning on failed interrupt signalling Marc Zyngier
  2025-02-06 15:20 ` [PATCH 2/3] KVM: arm64: vgic: Check for unallocated PPI/SPI arrays Marc Zyngier
@ 2025-02-06 15:21 ` Marc Zyngier
  2025-02-06 15:50   ` Alexander Potapenko
  2025-02-07 18:03 ` [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14 Oliver Upton
  3 siblings, 1 reply; 11+ messages in thread
From: Marc Zyngier @ 2025-02-06 15:21 UTC (permalink / raw)
  To: kvmarm, linux-arm-kernel
  Cc: Alexander Potapenko, Joey Gouly, Suzuki K Poulose, Oliver Upton,
	Zenghui Yu

Playing with racing vcpu reset and vgic teardown makes it relatively
easy to trigger a case where, by the time we try to reset a mapped
interrupt such as a timer's, the vgic is gone and there is no
interrupt to play with.

Check for NULL upfront to avoid further embarassement.

Reported-by: Alexander Potapenko <glider@google.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/vgic/vgic.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c
index f454cef59e24b..2ea6d1d1d3091 100644
--- a/arch/arm64/kvm/vgic/vgic.c
+++ b/arch/arm64/kvm/vgic/vgic.c
@@ -542,6 +542,9 @@ void kvm_vgic_reset_mapped_irq(struct kvm_vcpu *vcpu, u32 vintid)
 	struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, vintid);
 	unsigned long flags;
 
+	if (!irq)
+		return;
+
 	if (!irq->hw)
 		goto out;
 
-- 
2.39.2



^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/3] KVM: arm64: timer: Drop warning on failed interrupt signalling
  2025-02-06 15:20 ` [PATCH 1/3] KVM: arm64: timer: Drop warning on failed interrupt signalling Marc Zyngier
@ 2025-02-06 15:50   ` Alexander Potapenko
  0 siblings, 0 replies; 11+ messages in thread
From: Alexander Potapenko @ 2025-02-06 15:50 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, Joey Gouly, Suzuki K Poulose,
	Oliver Upton, Zenghui Yu

On Thu, Feb 6, 2025 at 4:21 PM Marc Zyngier <maz@kernel.org> wrote:
>
> We currently spit out a warning if making a timer interrupt pending
> fails. But not only this is loud and easy to trigger from userspace,
> we also fail to do anything useful with that information.
>
> Dropping the warning is the easiest thing to do for now. We can
> always add error reporting if we really want in the future.
>
> Reported-by: Alexander Potapenko <glider@google.com>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
Tested-by: Alexander Potapenko <glider@google.com>

Thanks!


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/3] KVM: arm64: vgic: Check for unallocated PPI/SPI arrays
  2025-02-06 15:20 ` [PATCH 2/3] KVM: arm64: vgic: Check for unallocated PPI/SPI arrays Marc Zyngier
@ 2025-02-06 15:50   ` Alexander Potapenko
  0 siblings, 0 replies; 11+ messages in thread
From: Alexander Potapenko @ 2025-02-06 15:50 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, Joey Gouly, Suzuki K Poulose,
	Oliver Upton, Zenghui Yu

On Thu, Feb 6, 2025 at 4:21 PM Marc Zyngier <maz@kernel.org> wrote:
>
> Alexander's fuzzing has exhibited a large variety of races that
> all end-up with taking the address of a PPI or SPI structure while
> the vgic was torn down (because nuking it is only an ioctl() away,
> and syzkaller is amazing at finding holes).
>
> In order to preserve some sanity, always evaluate whether the array
> containing the PPI/SPI is allocated.
>
> Suggested-by: Alexander Potapenko <glider@google.com>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
Tested-by: Alexander Potapenko <glider@google.com>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/3] KVM: arm64: vgic: Gracefully handle resetting an unallocated interrupt
  2025-02-06 15:21 ` [PATCH 3/3] KVM: arm64: vgic: Gracefully handle resetting an unallocated interrupt Marc Zyngier
@ 2025-02-06 15:50   ` Alexander Potapenko
  0 siblings, 0 replies; 11+ messages in thread
From: Alexander Potapenko @ 2025-02-06 15:50 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, Joey Gouly, Suzuki K Poulose,
	Oliver Upton, Zenghui Yu

On Thu, Feb 6, 2025 at 4:21 PM Marc Zyngier <maz@kernel.org> wrote:
>
> Playing with racing vcpu reset and vgic teardown makes it relatively
> easy to trigger a case where, by the time we try to reset a mapped
> interrupt such as a timer's, the vgic is gone and there is no
> interrupt to play with.
>
> Check for NULL upfront to avoid further embarassement.
>
> Reported-by: Alexander Potapenko <glider@google.com>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
Tested-by: Alexander Potapenko <glider@google.com>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14
  2025-02-06 15:20 [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14 Marc Zyngier
                   ` (2 preceding siblings ...)
  2025-02-06 15:21 ` [PATCH 3/3] KVM: arm64: vgic: Gracefully handle resetting an unallocated interrupt Marc Zyngier
@ 2025-02-07 18:03 ` Oliver Upton
  2025-02-07 18:10   ` Marc Zyngier
  3 siblings, 1 reply; 11+ messages in thread
From: Oliver Upton @ 2025-02-07 18:03 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, Alexander Potapenko, Joey Gouly,
	Suzuki K Poulose, Zenghui Yu

On Thu, Feb 06, 2025 at 03:20:57PM +0000, Marc Zyngier wrote:
> Alexander, while fuzzing KVM/arm64, found an annoying set of problems,
> all stemming from the fact that the vgic can be destroyed in parallel
> with the rest of the guest still being live.
> 
> Yes, this is annoying.
> 
> Fixing this is not going to happen overnight (though I have some
> ideas), but we can make what we have today a bit more robust.
> 
> This is what patch #2 is doing. Patch #1 is just removing a loud
> WARN_ON() that serves little purpose, and patch #3 fixes the actual
> bug that Alex reported.
> 
> Hopefully, none of that is controversial...

I'm a bit grumbly about slapping bandaids on the problem, but given the
fact that glider reported all of this a while ago and we still haven't
fixed it is enough to justify these patches. So:

Reviewed-by: Oliver Upton <oliver.upton@linux.dev>

-- 
Thanks,
Oliver


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14
  2025-02-07 18:03 ` [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14 Oliver Upton
@ 2025-02-07 18:10   ` Marc Zyngier
  2025-02-07 18:50     ` Oliver Upton
  0 siblings, 1 reply; 11+ messages in thread
From: Marc Zyngier @ 2025-02-07 18:10 UTC (permalink / raw)
  To: Oliver Upton
  Cc: kvmarm, linux-arm-kernel, Alexander Potapenko, Joey Gouly,
	Suzuki K Poulose, Zenghui Yu

On Fri, 07 Feb 2025 18:03:55 +0000,
Oliver Upton <oliver.upton@linux.dev> wrote:
> 
> On Thu, Feb 06, 2025 at 03:20:57PM +0000, Marc Zyngier wrote:
> > Alexander, while fuzzing KVM/arm64, found an annoying set of problems,
> > all stemming from the fact that the vgic can be destroyed in parallel
> > with the rest of the guest still being live.
> > 
> > Yes, this is annoying.
> > 
> > Fixing this is not going to happen overnight (though I have some
> > ideas), but we can make what we have today a bit more robust.
> > 
> > This is what patch #2 is doing. Patch #1 is just removing a loud
> > WARN_ON() that serves little purpose, and patch #3 fixes the actual
> > bug that Alex reported.
> > 
> > Hopefully, none of that is controversial...
> 
> I'm a bit grumbly about slapping bandaids on the problem, but given the
> fact that glider reported all of this a while ago and we still haven't
> fixed it is enough to justify these patches. So:

Yeah, same here. I'm starting to think that we need to either prevent
the vgic from being asynchronously destroyed, or start refcounting all
IRQs just like LPIs. Which is very annoying since we don't have a
global namespace for SGIs and PPIs.

But maybe simply refcounting the vgic itself would be enough.
Thoughts?

> Reviewed-by: Oliver Upton <oliver.upton@linux.dev>

Thanks,

	M.

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


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14
  2025-02-07 18:10   ` Marc Zyngier
@ 2025-02-07 18:50     ` Oliver Upton
  2025-02-08 15:15       ` Marc Zyngier
  0 siblings, 1 reply; 11+ messages in thread
From: Oliver Upton @ 2025-02-07 18:50 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: kvmarm, linux-arm-kernel, Alexander Potapenko, Joey Gouly,
	Suzuki K Poulose, Zenghui Yu

On Fri, Feb 07, 2025 at 06:10:49PM +0000, Marc Zyngier wrote:
> On Fri, 07 Feb 2025 18:03:55 +0000,
> Oliver Upton <oliver.upton@linux.dev> wrote:
> > 
> > On Thu, Feb 06, 2025 at 03:20:57PM +0000, Marc Zyngier wrote:
> > > Alexander, while fuzzing KVM/arm64, found an annoying set of problems,
> > > all stemming from the fact that the vgic can be destroyed in parallel
> > > with the rest of the guest still being live.
> > > 
> > > Yes, this is annoying.
> > > 
> > > Fixing this is not going to happen overnight (though I have some
> > > ideas), but we can make what we have today a bit more robust.
> > > 
> > > This is what patch #2 is doing. Patch #1 is just removing a loud
> > > WARN_ON() that serves little purpose, and patch #3 fixes the actual
> > > bug that Alex reported.
> > > 
> > > Hopefully, none of that is controversial...
> > 
> > I'm a bit grumbly about slapping bandaids on the problem, but given the
> > fact that glider reported all of this a while ago and we still haven't
> > fixed it is enough to justify these patches. So:
> 
> Yeah, same here. I'm starting to think that we need to either prevent
> the vgic from being asynchronously destroyed, or start refcounting all
> IRQs just like LPIs. Which is very annoying since we don't have a
> global namespace for SGIs and PPIs.
> 
> But maybe simply refcounting the vgic itself would be enough.
> Thoughts?

So would we refcount on the owning structure for a particular IRQ? i.e.
private IRQs are counted against the owning vCPU and SPIs against the
distributor?

Adding a vgic_put_vcpu_irq() could help disambiguate private IRQs too.

-- 
Thanks,
Oliver


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14
  2025-02-07 18:50     ` Oliver Upton
@ 2025-02-08 15:15       ` Marc Zyngier
  0 siblings, 0 replies; 11+ messages in thread
From: Marc Zyngier @ 2025-02-08 15:15 UTC (permalink / raw)
  To: Oliver Upton
  Cc: kvmarm, linux-arm-kernel, Alexander Potapenko, Joey Gouly,
	Suzuki K Poulose, Zenghui Yu

On Fri, 07 Feb 2025 18:50:32 +0000,
Oliver Upton <oliver.upton@linux.dev> wrote:
> 
> On Fri, Feb 07, 2025 at 06:10:49PM +0000, Marc Zyngier wrote:
> > On Fri, 07 Feb 2025 18:03:55 +0000,
> > Oliver Upton <oliver.upton@linux.dev> wrote:
> > > 
> > > On Thu, Feb 06, 2025 at 03:20:57PM +0000, Marc Zyngier wrote:
> > > > Alexander, while fuzzing KVM/arm64, found an annoying set of problems,
> > > > all stemming from the fact that the vgic can be destroyed in parallel
> > > > with the rest of the guest still being live.
> > > > 
> > > > Yes, this is annoying.
> > > > 
> > > > Fixing this is not going to happen overnight (though I have some
> > > > ideas), but we can make what we have today a bit more robust.
> > > > 
> > > > This is what patch #2 is doing. Patch #1 is just removing a loud
> > > > WARN_ON() that serves little purpose, and patch #3 fixes the actual
> > > > bug that Alex reported.
> > > > 
> > > > Hopefully, none of that is controversial...
> > > 
> > > I'm a bit grumbly about slapping bandaids on the problem, but given the
> > > fact that glider reported all of this a while ago and we still haven't
> > > fixed it is enough to justify these patches. So:
> > 
> > Yeah, same here. I'm starting to think that we need to either prevent
> > the vgic from being asynchronously destroyed, or start refcounting all
> > IRQs just like LPIs. Which is very annoying since we don't have a
> > global namespace for SGIs and PPIs.
> > 
> > But maybe simply refcounting the vgic itself would be enough.
> > Thoughts?
> 
> So would we refcount on the owning structure for a particular IRQ? i.e.
> private IRQs are counted against the owning vCPU and SPIs against the
> distributor?
> 
> Adding a vgic_put_vcpu_irq() could help disambiguate private IRQs too.

Having slept (yay!) on it, I don't think this is enough.

The observation is that a lot of the issues we have are triggered by
the private interrupt array being allocated on demand on VGIC
creation. We had way fewer problems when the private interrupts were
directly part of struct vcpu, which really was hiding the basic
problem.

We have an annoying discrepancy between knowing that a GIC is present
(VM-wide state) and the interrupts for a vcpu being allocated (vcpu
state). This is what Alexander's fuzzing is all about (create a vcpu,
init it, and while this is happening, create/destroy a vgic).

So it isn't just destruction, but also creation that is problematic,
and I'm not sure that refcounting is the correct solution anymore.

Now, for the issue that this series is trying to fix, I came up with
an alternative approach, based on the above epiphany. We currently
allocate private interrupts in two locations:

- at vcpu creation time *if* a vgic has already been created

- from vgic_init(), which is itself called on:

  - KVM_DEV_ARM_VGIC_CTRL_INIT for the modern stuff,

  - or lazily for anything old and specific to GICv2 (huh).

Crucially, there is a gaping window between the creation of a vgic
*after* a vcpu has been created, and its initialisation. Anything that
checks for irqchip_in_kernel() during that interval may assume that
private interrupts are allocated, because this is what it used to be.
Waiting for vgic_init() to mop-up the "early" vcpus is what creates
the issue.

Given that, the solution is obvious: hoist the early vcpu mop-up from
vgic_init() into kvm_vgic_create(). This guarantees that any vcpu
observing irqchip_in_kernel() being true will also see its private
interrupts.

The patch below fixes it for me (tested with kvmtool, qemu, and Alex's
tickling reproducer).

Thoughts?

	M.

From c150c2300d5b8918909ad46a769aae864a58025f Mon Sep 17 00:00:00 2001
From: Marc Zyngier <maz@kernel.org>
Date: Sat, 8 Feb 2025 14:58:43 +0000
Subject: [PATCH] KVM: arm64: vgic: Hoist SGI/PPI alloc from vgic_init() to
 kvm_create_vgic()

If userspace creates vcpus, then a vgic, we end-up in a situation
where irqchip_in_kernel() will return true, but no private interrupt
has been allocated for these vcpus. This situation will continue
until userspace initialises the vgic, at which point we fix the
early vcpus. Should a vcpu run or be initialised in the interval,
bad things may happen.

An obvious solution is to move this fix-up phase to the point where
the vgic is created. This ensures that from that point onwards,
all vcpus have their private interrupts, as new vcpus will directly
allocate them.

With that, we have the invariant that when irqchip_in_kernel() is
true, all vcpus have their private interrupts.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 arch/arm64/kvm/vgic/vgic-init.c | 74 ++++++++++++++++-----------------
 1 file changed, 37 insertions(+), 37 deletions(-)

diff --git a/arch/arm64/kvm/vgic/vgic-init.c b/arch/arm64/kvm/vgic/vgic-init.c
index c7a82bd0c276d..1f33e71c2a731 100644
--- a/arch/arm64/kvm/vgic/vgic-init.c
+++ b/arch/arm64/kvm/vgic/vgic-init.c
@@ -34,9 +34,9 @@
  *
  * CPU Interface:
  *
- * - kvm_vgic_vcpu_init(): initialization of static data that
- *   doesn't depend on any sizing information or emulation type. No
- *   allocation is allowed there.
+ * - kvm_vgic_vcpu_init(): initialization of static data that doesn't depend
+ *   on any sizing information. Private interrupts are allocated if not
+ *   already allocated at vgic-creation time.
  */
 
 /* EARLY INIT */
@@ -58,6 +58,8 @@ void kvm_vgic_early_init(struct kvm *kvm)
 
 /* CREATION */
 
+static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type);
+
 /**
  * kvm_vgic_create: triggered by the instantiation of the VGIC device by
  * user space, either through the legacy KVM_CREATE_IRQCHIP ioctl (v2 only)
@@ -112,6 +114,22 @@ int kvm_vgic_create(struct kvm *kvm, u32 type)
 		goto out_unlock;
 	}
 
+	kvm_for_each_vcpu(i, vcpu, kvm) {
+		ret = vgic_allocate_private_irqs_locked(vcpu, type);
+		if (ret)
+			break;
+	}
+
+	if (ret) {
+		kvm_for_each_vcpu(i, vcpu, kvm) {
+			struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
+			kfree(vgic_cpu->private_irqs);
+			vgic_cpu->private_irqs = NULL;
+		}
+
+		goto out_unlock;
+	}
+
 	kvm->arch.vgic.in_kernel = true;
 	kvm->arch.vgic.vgic_model = type;
 
@@ -201,7 +219,7 @@ int kvm_vgic_vcpu_nv_init(struct kvm_vcpu *vcpu)
 	return ret;
 }
 
-static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu)
+static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu, u32 type)
 {
 	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
 	int i;
@@ -239,17 +257,28 @@ static int vgic_allocate_private_irqs_locked(struct kvm_vcpu *vcpu)
 			/* PPIs */
 			irq->config = VGIC_CONFIG_LEVEL;
 		}
+
+		switch (type) {
+		case KVM_DEV_TYPE_ARM_VGIC_V3:
+			irq->group = 1;
+			irq->mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
+			break;
+		case KVM_DEV_TYPE_ARM_VGIC_V2:
+			irq->group = 0;
+			irq->targets = BIT(vcpu->vcpu_id);
+			break;
+		}
 	}
 
 	return 0;
 }
 
-static int vgic_allocate_private_irqs(struct kvm_vcpu *vcpu)
+static int vgic_allocate_private_irqs(struct kvm_vcpu *vcpu, u32 type)
 {
 	int ret;
 
 	mutex_lock(&vcpu->kvm->arch.config_lock);
-	ret = vgic_allocate_private_irqs_locked(vcpu);
+	ret = vgic_allocate_private_irqs_locked(vcpu, type);
 	mutex_unlock(&vcpu->kvm->arch.config_lock);
 
 	return ret;
@@ -279,7 +308,7 @@ int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu)
 	if (!irqchip_in_kernel(vcpu->kvm))
 		return 0;
 
-	ret = vgic_allocate_private_irqs(vcpu);
+	ret = vgic_allocate_private_irqs(vcpu, dist->vgic_model);
 	if (ret)
 		return ret;
 
@@ -316,7 +345,7 @@ int vgic_init(struct kvm *kvm)
 {
 	struct vgic_dist *dist = &kvm->arch.vgic;
 	struct kvm_vcpu *vcpu;
-	int ret = 0, i;
+	int ret = 0;
 	unsigned long idx;
 
 	lockdep_assert_held(&kvm->arch.config_lock);
@@ -336,35 +365,6 @@ int vgic_init(struct kvm *kvm)
 	if (ret)
 		goto out;
 
-	/* Initialize groups on CPUs created before the VGIC type was known */
-	kvm_for_each_vcpu(idx, vcpu, kvm) {
-		ret = vgic_allocate_private_irqs_locked(vcpu);
-		if (ret)
-			goto out;
-
-		for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
-			struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, i);
-
-			switch (dist->vgic_model) {
-			case KVM_DEV_TYPE_ARM_VGIC_V3:
-				irq->group = 1;
-				irq->mpidr = kvm_vcpu_get_mpidr_aff(vcpu);
-				break;
-			case KVM_DEV_TYPE_ARM_VGIC_V2:
-				irq->group = 0;
-				irq->targets = 1U << idx;
-				break;
-			default:
-				ret = -EINVAL;
-			}
-
-			vgic_put_irq(kvm, irq);
-
-			if (ret)
-				goto out;
-		}
-	}
-
 	/*
 	 * If we have GICv4.1 enabled, unconditionally request enable the
 	 * v4 support so that we get HW-accelerated vSGIs. Otherwise, only
-- 
2.39.2


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


^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2025-02-08 15:17 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-06 15:20 [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14 Marc Zyngier
2025-02-06 15:20 ` [PATCH 1/3] KVM: arm64: timer: Drop warning on failed interrupt signalling Marc Zyngier
2025-02-06 15:50   ` Alexander Potapenko
2025-02-06 15:20 ` [PATCH 2/3] KVM: arm64: vgic: Check for unallocated PPI/SPI arrays Marc Zyngier
2025-02-06 15:50   ` Alexander Potapenko
2025-02-06 15:21 ` [PATCH 3/3] KVM: arm64: vgic: Gracefully handle resetting an unallocated interrupt Marc Zyngier
2025-02-06 15:50   ` Alexander Potapenko
2025-02-07 18:03 ` [PATCH 0/3] KVM: arm64: Assorted vgic fixes for 6.14 Oliver Upton
2025-02-07 18:10   ` Marc Zyngier
2025-02-07 18:50     ` Oliver Upton
2025-02-08 15:15       ` Marc Zyngier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).