Commit add570b3 authored by Marc Zyngier's avatar Marc Zyngier Committed by Oliver Upton
Browse files

KVM: arm64: vgic: Make vgic_get_irq() more robust



vgic_get_irq() has an awkward signature, as it takes both a kvm
*and* a vcpu, where the vcpu is allowed to be NULL if the INTID
being looked up is a global interrupt (SPI or LPI).

This leads to potentially problematic situations where the INTID
passed is a private interrupt, but that there is no vcpu.

In order to make things less ambiguous, let have *two* helpers
instead:

- vgic_get_irq(struct kvm *kvm, u32 intid), which is only concerned
  with *global* interrupts, as indicated by the lack of vcpu.

- vgic_get_vcpu_irq(struct kvm_vcpu *vcpu, u32 intid), which can
  return *any* interrupt class, but must have of course a non-NULL
  vcpu.

Most of the code nicely falls under one or the other situations,
except for a couple of cases (close to the UABI or in the debug code)
where we have to distinguish between the two cases.

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20241117165757.247686-3-maz@kernel.org


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent d561491b
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -287,7 +287,10 @@ static int vgic_debug_show(struct seq_file *s, void *v)
	 * Expect this to succeed, as iter_mark_lpis() takes a reference on
	 * every LPI to be visited.
	 */
	irq = vgic_get_irq(kvm, vcpu, iter->intid);
	if (iter->intid < VGIC_NR_PRIVATE_IRQS)
		irq = vgic_get_vcpu_irq(vcpu, iter->intid);
	else
		irq = vgic_get_irq(kvm, iter->intid);
	if (WARN_ON_ONCE(!irq))
		return -EINVAL;

+1 −1
Original line number Diff line number Diff line
@@ -322,7 +322,7 @@ int vgic_init(struct kvm *kvm)
			goto out;

		for (i = 0; i < VGIC_NR_PRIVATE_IRQS; i++) {
			struct vgic_irq *irq = vgic_get_irq(kvm, vcpu, i);
			struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, i);

			switch (dist->vgic_model) {
			case KVM_DEV_TYPE_ARM_VGIC_V3:
+4 −4
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
				     struct kvm_vcpu *vcpu)
{
	struct vgic_dist *dist = &kvm->arch.vgic;
	struct vgic_irq *irq = vgic_get_irq(kvm, NULL, intid), *oldirq;
	struct vgic_irq *irq = vgic_get_irq(kvm, intid), *oldirq;
	unsigned long flags;
	int ret;

@@ -419,7 +419,7 @@ static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
			last_byte_offset = byte_offset;
		}

		irq = vgic_get_irq(vcpu->kvm, NULL, intid);
		irq = vgic_get_irq(vcpu->kvm, intid);
		if (!irq)
			continue;

@@ -1288,7 +1288,7 @@ int vgic_its_invall(struct kvm_vcpu *vcpu)
	unsigned long intid;

	xa_for_each(&dist->lpi_xa, intid, irq) {
		irq = vgic_get_irq(kvm, NULL, intid);
		irq = vgic_get_irq(kvm, intid);
		if (!irq)
			continue;

@@ -1354,7 +1354,7 @@ static int vgic_its_cmd_handle_movall(struct kvm *kvm, struct vgic_its *its,
		return 0;

	xa_for_each(&dist->lpi_xa, intid, irq) {
		irq = vgic_get_irq(kvm, NULL, intid);
		irq = vgic_get_irq(kvm, intid);
		if (!irq)
			continue;

+6 −6
Original line number Diff line number Diff line
@@ -148,7 +148,7 @@ static void vgic_mmio_write_sgir(struct kvm_vcpu *source_vcpu,
		if (!(targets & (1U << c)))
			continue;

		irq = vgic_get_irq(source_vcpu->kvm, vcpu, intid);
		irq = vgic_get_vcpu_irq(vcpu, intid);

		raw_spin_lock_irqsave(&irq->irq_lock, flags);
		irq->pending_latch = true;
@@ -167,7 +167,7 @@ static unsigned long vgic_mmio_read_target(struct kvm_vcpu *vcpu,
	u64 val = 0;

	for (i = 0; i < len; i++) {
		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
		struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i);

		val |= (u64)irq->targets << (i * 8);

@@ -191,7 +191,7 @@ static void vgic_mmio_write_target(struct kvm_vcpu *vcpu,
		return;

	for (i = 0; i < len; i++) {
		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid + i);
		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, intid + i);
		int target;

		raw_spin_lock_irqsave(&irq->irq_lock, flags);
@@ -213,7 +213,7 @@ static unsigned long vgic_mmio_read_sgipend(struct kvm_vcpu *vcpu,
	u64 val = 0;

	for (i = 0; i < len; i++) {
		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
		struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i);

		val |= (u64)irq->source << (i * 8);

@@ -231,7 +231,7 @@ static void vgic_mmio_write_sgipendc(struct kvm_vcpu *vcpu,
	unsigned long flags;

	for (i = 0; i < len; i++) {
		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
		struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i);

		raw_spin_lock_irqsave(&irq->irq_lock, flags);

@@ -253,7 +253,7 @@ static void vgic_mmio_write_sgipends(struct kvm_vcpu *vcpu,
	unsigned long flags;

	for (i = 0; i < len; i++) {
		struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
		struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, intid + i);

		raw_spin_lock_irqsave(&irq->irq_lock, flags);

+4 −4
Original line number Diff line number Diff line
@@ -194,7 +194,7 @@ static unsigned long vgic_mmio_read_irouter(struct kvm_vcpu *vcpu,
					    gpa_t addr, unsigned int len)
{
	int intid = VGIC_ADDR_TO_INTID(addr, 64);
	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, NULL, intid);
	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, intid);
	unsigned long ret = 0;

	if (!irq)
@@ -220,7 +220,7 @@ static void vgic_mmio_write_irouter(struct kvm_vcpu *vcpu,
	if (addr & 4)
		return;

	irq = vgic_get_irq(vcpu->kvm, NULL, intid);
	irq = vgic_get_irq(vcpu->kvm, intid);

	if (!irq)
		return;
@@ -548,7 +548,7 @@ static void vgic_mmio_write_invlpi(struct kvm_vcpu *vcpu,

	vgic_set_rdist_busy(vcpu, true);

	irq = vgic_get_irq(vcpu->kvm, NULL, intid);
	irq = vgic_get_irq(vcpu->kvm, intid);
	if (irq) {
		vgic_its_inv_lpi(vcpu->kvm, irq);
		vgic_put_irq(vcpu->kvm, irq);
@@ -1025,7 +1025,7 @@ int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr)

static void vgic_v3_queue_sgi(struct kvm_vcpu *vcpu, u32 sgi, bool allow_group1)
{
	struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, sgi);
	struct vgic_irq *irq = vgic_get_vcpu_irq(vcpu, sgi);
	unsigned long flags;

	raw_spin_lock_irqsave(&irq->irq_lock, flags);
Loading