Commit 59af011d authored by Marc Zyngier's avatar Marc Zyngier
Browse files

KVM: arm64: Honor guest requested traps in GICv3 emulation



On platforms that require emulation of the CPU interface, we still
need to honor the traps requested by the guest (ICH_HCR_EL2 as well
as the FGTs for ICC_IGRPEN{0,1}_EL1.

Check for these bits early and lail out if any trap applies.

Reviewed-by: default avatarOliver Upton <oliver.upton@linux.dev>
Link: https://lore.kernel.org/r/20240827152517.3909653-9-maz@kernel.org


Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parent 15a1ba8d
Loading
Loading
Loading
Loading
+72 −0
Original line number Diff line number Diff line
@@ -1042,6 +1042,75 @@ static void __vgic_v3_write_ctlr(struct kvm_vcpu *vcpu, u32 vmcr, int rt)
	write_gicreg(vmcr, ICH_VMCR_EL2);
}

static bool __vgic_v3_check_trap_forwarding(struct kvm_vcpu *vcpu,
					    u32 sysreg, bool is_read)
{
	u64 ich_hcr;

	if (!vcpu_has_nv(vcpu) || is_hyp_ctxt(vcpu))
		return false;

	ich_hcr = __vcpu_sys_reg(vcpu, ICH_HCR_EL2);

	switch (sysreg) {
	case SYS_ICC_IGRPEN0_EL1:
		if (is_read &&
		    (__vcpu_sys_reg(vcpu, HFGRTR_EL2) & HFGxTR_EL2_ICC_IGRPENn_EL1))
			return true;

		if (!is_read &&
		    (__vcpu_sys_reg(vcpu, HFGWTR_EL2) & HFGxTR_EL2_ICC_IGRPENn_EL1))
			return true;

		fallthrough;

	case SYS_ICC_AP0Rn_EL1(0):
	case SYS_ICC_AP0Rn_EL1(1):
	case SYS_ICC_AP0Rn_EL1(2):
	case SYS_ICC_AP0Rn_EL1(3):
	case SYS_ICC_BPR0_EL1:
	case SYS_ICC_EOIR0_EL1:
	case SYS_ICC_HPPIR0_EL1:
	case SYS_ICC_IAR0_EL1:
		return ich_hcr & ICH_HCR_TALL0;

	case SYS_ICC_IGRPEN1_EL1:
		if (is_read &&
		    (__vcpu_sys_reg(vcpu, HFGRTR_EL2) & HFGxTR_EL2_ICC_IGRPENn_EL1))
			return true;

		if (!is_read &&
		    (__vcpu_sys_reg(vcpu, HFGWTR_EL2) & HFGxTR_EL2_ICC_IGRPENn_EL1))
			return true;

		fallthrough;

	case SYS_ICC_AP1Rn_EL1(0):
	case SYS_ICC_AP1Rn_EL1(1):
	case SYS_ICC_AP1Rn_EL1(2):
	case SYS_ICC_AP1Rn_EL1(3):
	case SYS_ICC_BPR1_EL1:
	case SYS_ICC_EOIR1_EL1:
	case SYS_ICC_HPPIR1_EL1:
	case SYS_ICC_IAR1_EL1:
		return ich_hcr & ICH_HCR_TALL1;

	case SYS_ICC_DIR_EL1:
		if (ich_hcr & ICH_HCR_TDIR)
			return true;

		fallthrough;

	case SYS_ICC_RPR_EL1:
	case SYS_ICC_CTLR_EL1:
	case SYS_ICC_PMR_EL1:
		return ich_hcr & ICH_HCR_TC;

	default:
		return false;
	}
}

int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)
{
	int rt;
@@ -1065,6 +1134,9 @@ int __vgic_v3_perform_cpuif_access(struct kvm_vcpu *vcpu)

	is_read = (esr & ESR_ELx_SYS64_ISS_DIR_MASK) == ESR_ELx_SYS64_ISS_DIR_READ;

	if (__vgic_v3_check_trap_forwarding(vcpu, sysreg, is_read))
		return 0;

	switch (sysreg) {
	case SYS_ICC_IAR0_EL1:
	case SYS_ICC_IAR1_EL1: