arch/arm64/kvm/vgic/vgic-v2.c

Source file repositories/reference/linux-study-clean/arch/arm64/kvm/vgic/vgic-v2.c

File Facts

System
Linux kernel
Corpus path
arch/arm64/kvm/vgic/vgic-v2.c
Extension
.c
Size
16614 bytes
Lines
623
Domain
Architecture Layer
Bucket
arch/arm64
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!eoicount) {
			break;
		} else {
			guard(raw_spinlock)(&irq->irq_lock);

			if (!(likely(vgic_target_oracle(irq) == vcpu) &&
			      irq->active))
				continue;

			lr = vgic_v2_compute_lr(vcpu, irq) & ~GICH_LR_ACTIVE_BIT;
		}

		if (lr & GICH_LR_HW)
			writel_relaxed(FIELD_GET(GICH_LR_PHYSID_CPUID, lr),
				       kvm_vgic_global_state.gicc_base + GIC_CPU_DEACTIVATE);
		vgic_v2_fold_lr(vcpu, lr);
		eoicount--;
	}

	cpuif->used_lrs = 0;
}

void vgic_v2_deactivate(struct kvm_vcpu *vcpu, u32 val)
{
	struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
	struct vgic_v2_cpu_if *cpuif = &vgic_cpu->vgic_v2;
	struct kvm_vcpu *target_vcpu = NULL;
	bool mmio = false;
	struct vgic_irq *irq;
	unsigned long flags;
	u64 lr = 0;
	u8 cpuid;

	/* Snapshot CPUID, and remove it from the INTID */
	cpuid = FIELD_GET(GENMASK_ULL(12, 10), val);
	val &= ~GENMASK_ULL(12, 10);

	/* We only deal with DIR when EOIMode==1 */
	if (!(cpuif->vgic_vmcr & GICH_VMCR_EOI_MODE_MASK))
		return;

	/* Make sure we're in the same context as LR handling */
	local_irq_save(flags);

	irq = vgic_get_vcpu_irq(vcpu, val);
	if (WARN_ON_ONCE(!irq))
		goto out;

	/* See the corresponding v3 code for the rationale */
	scoped_guard(raw_spinlock, &irq->irq_lock) {
		target_vcpu = irq->vcpu;

		/* Not on any ap_list? */
		if (!target_vcpu)
			goto put;

		/*
		 * Urgh. We're deactivating something that we cannot
		 * observe yet... Big hammer time.
		 */
		if (irq->on_lr) {
			mmio = true;
			goto put;
		}

		/* SGI: check that the cpuid matches */
		if (val < VGIC_NR_SGIS && irq->active_source != cpuid) {
			target_vcpu = NULL;
			goto put;
		}

		/* (with a Dalek voice) DEACTIVATE!!!! */
		lr = vgic_v2_compute_lr(vcpu, irq) & ~GICH_LR_ACTIVE_BIT;
	}

	if (lr & GICH_LR_HW)
		writel_relaxed(FIELD_GET(GICH_LR_PHYSID_CPUID, lr),
			       kvm_vgic_global_state.gicc_base + GIC_CPU_DEACTIVATE);

	vgic_v2_fold_lr(vcpu, lr);

put:
	vgic_put_irq(vcpu->kvm, irq);

out:
	local_irq_restore(flags);

	if (mmio)
		vgic_mmio_write_cactive(vcpu, (val / 32) * 4, 4, BIT(val % 32));

Annotation

Implementation Notes