Commit fff97df2 authored by Oliver Upton's avatar Oliver Upton
Browse files

KVM: arm64: Route SEAs to the SError vector when EASE is set



One of the finest additions of FEAT_DoubleFault2 is the ability for
software to request *synchronous* external aborts be taken to the
SError vector, which of coure are *asynchronous* in nature.

Opinions be damned, implement the architecture and send SEAs to the
SError vector if EASE is set for the target context.

Reviewed-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20250708172532.1699409-18-oliver.upton@linux.dev


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent 178ec0ae
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -2834,6 +2834,10 @@ int kvm_inject_nested_sea(struct kvm_vcpu *vcpu, bool iabt, u64 addr)
	esr |= ESR_ELx_FSC_EXTABT | ESR_ELx_IL;

	vcpu_write_sys_reg(vcpu, FAR_EL2, addr);

	if (__vcpu_sys_reg(vcpu, SCTLR2_EL2) & SCTLR2_EL1_EASE)
		return kvm_inject_nested(vcpu, esr, except_type_serror);

	return kvm_inject_nested_sync(vcpu, esr);
}

+5 −1
Original line number Diff line number Diff line
@@ -339,6 +339,10 @@ static void kvm_inject_exception(struct kvm_vcpu *vcpu)
			enter_exception64(vcpu, PSR_MODE_EL1h, except_type_sync);
			break;

		case unpack_vcpu_flag(EXCEPT_AA64_EL1_SERR):
			enter_exception64(vcpu, PSR_MODE_EL1h, except_type_serror);
			break;

		case unpack_vcpu_flag(EXCEPT_AA64_EL2_SYNC):
			enter_exception64(vcpu, PSR_MODE_EL2h, except_type_sync);
			break;
@@ -353,7 +357,7 @@ static void kvm_inject_exception(struct kvm_vcpu *vcpu)

		default:
			/*
			 * Only EL1_SYNC and EL2_{SYNC,IRQ,SERR} makes
			 * Only EL1_{SYNC,SERR} and EL2_{SYNC,IRQ,SERR} makes
			 * sense so far. Everything else gets silently
			 * ignored.
			 */
+37 −1
Original line number Diff line number Diff line
@@ -65,12 +65,48 @@ static void pend_sync_exception(struct kvm_vcpu *vcpu)
		kvm_pend_exception(vcpu, EXCEPT_AA64_EL2_SYNC);
}

static void pend_serror_exception(struct kvm_vcpu *vcpu)
{
	if (exception_target_el(vcpu) == PSR_MODE_EL1h)
		kvm_pend_exception(vcpu, EXCEPT_AA64_EL1_SERR);
	else
		kvm_pend_exception(vcpu, EXCEPT_AA64_EL2_SERR);
}

static bool __effective_sctlr2_bit(struct kvm_vcpu *vcpu, unsigned int idx)
{
	u64 sctlr2;

	if (!kvm_has_sctlr2(vcpu->kvm))
		return false;

	if (is_nested_ctxt(vcpu) &&
	    !(__vcpu_sys_reg(vcpu, HCRX_EL2) & HCRX_EL2_SCTLR2En))
		return false;

	if (exception_target_el(vcpu) == PSR_MODE_EL1h)
		sctlr2 = vcpu_read_sys_reg(vcpu, SCTLR2_EL1);
	else
		sctlr2 = vcpu_read_sys_reg(vcpu, SCTLR2_EL2);

	return sctlr2 & BIT(idx);
}

static bool effective_sctlr2_ease(struct kvm_vcpu *vcpu)
{
	return __effective_sctlr2_bit(vcpu, SCTLR2_EL1_EASE_SHIFT);
}

static void inject_abt64(struct kvm_vcpu *vcpu, bool is_iabt, unsigned long addr)
{
	unsigned long cpsr = *vcpu_cpsr(vcpu);
	bool is_aarch32 = vcpu_mode_is_32bit(vcpu);
	u64 esr = 0;

	/* This delight is brought to you by FEAT_DoubleFault2. */
	if (effective_sctlr2_ease(vcpu))
		pend_serror_exception(vcpu);
	else
		pend_sync_exception(vcpu);

	/*