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

KVM: arm64: nv: Handle L2->L1 transition on interrupt injection



An interrupt being delivered to L1 while running L2 must result
in the correct exception being delivered to L1.

This means that if, on entry to L2, we found ourselves with pending
interrupts in the L1 distributor, we need to take immediate action.
This is done by posting a request which will prevent the entry in
L2, and deliver an IRQ exception to L1, forcing the switch.

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


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent 146a050f
Loading
Loading
Loading
Loading
+9 −8
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@
#define KVM_REQ_SUSPEND			KVM_ARCH_REQ(6)
#define KVM_REQ_RESYNC_PMU_EL0		KVM_ARCH_REQ(7)
#define KVM_REQ_NESTED_S2_UNMAP		KVM_ARCH_REQ(8)
#define KVM_REQ_GUEST_HYP_IRQ_PENDING	KVM_ARCH_REQ(9)

#define KVM_DIRTY_LOG_MANUAL_CAPS   (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | \
				     KVM_DIRTY_LOG_INITIALLY_SET)
+5 −0
Original line number Diff line number Diff line
@@ -1148,6 +1148,11 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
		 * preserved on VMID roll-over if the task was preempted,
		 * making a thread's VMID inactive. So we need to call
		 * kvm_arm_vmid_update() in non-premptible context.
		 *
		 * Note that this must happen after the check_vcpu_request()
		 * call to pick the correct s2_mmu structure, as a pending
		 * nested exception (IRQ, for example) can trigger a change
		 * in translation regime.
		 */
		if (kvm_arm_vmid_update(&vcpu->arch.hw_mmu->vmid) &&
		    has_vhe())
+4 −0
Original line number Diff line number Diff line
@@ -1318,4 +1318,8 @@ void check_nested_vcpu_requests(struct kvm_vcpu *vcpu)
		}
		write_unlock(&vcpu->kvm->mmu_lock);
	}

	/* Must be last, as may switch context! */
	if (kvm_check_request(KVM_REQ_GUEST_HYP_IRQ_PENDING, vcpu))
		kvm_inject_nested_irq(vcpu);
}
+23 −0
Original line number Diff line number Diff line
@@ -906,6 +906,29 @@ static inline void vgic_restore_state(struct kvm_vcpu *vcpu)
/* Flush our emulation state into the GIC hardware before entering the guest. */
void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
{
	/*
	 * If in a nested state, we must return early. Two possibilities:
	 *
	 * - If we have any pending IRQ for the guest and the guest
	 *   expects IRQs to be handled in its virtual EL2 mode (the
	 *   virtual IMO bit is set) and it is not already running in
	 *   virtual EL2 mode, then we have to emulate an IRQ
	 *   exception to virtual EL2.
	 *
	 *   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.
	 *
	 * - Otherwise, do exactly *NOTHING*. The guest state is
	 *   already loaded, and we can carry on with running it.
	 */
	if (vgic_state_is_nested(vcpu)) {
		if (kvm_vgic_vcpu_pending_irq(vcpu))
			kvm_make_request(KVM_REQ_GUEST_HYP_IRQ_PENDING, vcpu);

		return;
	}

	/*
	 * If there are no virtual interrupts active or pending for this
	 * VCPU, then there is no work to do and we can bail out without