Commit ee14db31 authored by Mark Rutland's avatar Mark Rutland Committed by Marc Zyngier
Browse files

KVM: arm64: Refactor CPTR trap deactivation



For historical reasons, the VHE and nVHE/hVHE implementations of
__activate_cptr_traps() pair with a common implementation of
__kvm_reset_cptr_el2(), which ideally would be named
__deactivate_cptr_traps().

Rename __kvm_reset_cptr_el2() to __deactivate_cptr_traps(), and split it
into separate VHE and nVHE/hVHE variants so that each can be paired with
its corresponding implementation of __activate_cptr_traps().

At the same time, fold kvm_write_cptr_el2() into its callers. This
makes it clear in-context whether a write is made to the CPACR_EL1
encoding or the CPTR_EL2 encoding, and removes the possibility of
confusion as to whether kvm_write_cptr_el2() reformats the sysreg fields
as cpacr_clear_set() does.

In the nVHE/hVHE implementation of __activate_cptr_traps(), placing the
sysreg writes within the if-else blocks requires that the call to
__activate_traps_fpsimd32() is moved earlier, but as this was always
called before writing to CPTR_EL2/CPACR_EL1, this should not result in a
functional change.

Signed-off-by: default avatarMark Rutland <mark.rutland@arm.com>
Reviewed-by: default avatarMark Brown <broonie@kernel.org>
Tested-by: default avatarMark Brown <broonie@kernel.org>
Acked-by: default avatarWill Deacon <will@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Fuad Tabba <tabba@google.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Oliver Upton <oliver.upton@linux.dev>
Reviewed-by: default avatarOliver Upton <oliver.upton@linux.dev>
Link: https://lore.kernel.org/r/20250210195226.1215254-6-mark.rutland@arm.com


Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parent 407a99c4
Loading
Loading
Loading
Loading
+0 −42
Original line number Diff line number Diff line
@@ -605,48 +605,6 @@ static __always_inline void kvm_incr_pc(struct kvm_vcpu *vcpu)
					 __cpacr_to_cptr_set(clr, set));\
	} while (0)

static __always_inline void kvm_write_cptr_el2(u64 val)
{
	if (has_vhe() || has_hvhe())
		write_sysreg(val, cpacr_el1);
	else
		write_sysreg(val, cptr_el2);
}

/* Resets the value of cptr_el2 when returning to the host. */
static __always_inline void __kvm_reset_cptr_el2(struct kvm *kvm)
{
	u64 val;

	if (has_vhe()) {
		val = (CPACR_EL1_FPEN | CPACR_EL1_ZEN_EL1EN);
		if (cpus_have_final_cap(ARM64_SME))
			val |= CPACR_EL1_SMEN_EL1EN;
	} else if (has_hvhe()) {
		val = CPACR_EL1_FPEN;

		if (!kvm_has_sve(kvm) || !guest_owns_fp_regs())
			val |= CPACR_EL1_ZEN;
		if (cpus_have_final_cap(ARM64_SME))
			val |= CPACR_EL1_SMEN;
	} else {
		val = CPTR_NVHE_EL2_RES1;

		if (kvm_has_sve(kvm) && guest_owns_fp_regs())
			val |= CPTR_EL2_TZ;
		if (!cpus_have_final_cap(ARM64_SME))
			val |= CPTR_EL2_TSM;
	}

	kvm_write_cptr_el2(val);
}

#ifdef __KVM_NVHE_HYPERVISOR__
#define kvm_reset_cptr_el2(v)	__kvm_reset_cptr_el2(kern_hyp_va((v)->kvm))
#else
#define kvm_reset_cptr_el2(v)	__kvm_reset_cptr_el2((v)->kvm)
#endif

/*
 * Returns a 'sanitised' view of CPTR_EL2, translating from nVHE to the VHE
 * format if E2H isn't set.
+31 −4
Original line number Diff line number Diff line
@@ -39,6 +39,9 @@ static void __activate_cptr_traps(struct kvm_vcpu *vcpu)
{
	u64 val = CPTR_EL2_TAM;	/* Same bit irrespective of E2H */

	if (!guest_owns_fp_regs())
		__activate_traps_fpsimd32(vcpu);

	if (has_hvhe()) {
		val |= CPACR_EL1_TTA;

@@ -47,6 +50,8 @@ static void __activate_cptr_traps(struct kvm_vcpu *vcpu)
			if (vcpu_has_sve(vcpu))
				val |= CPACR_EL1_ZEN;
		}

		write_sysreg(val, cpacr_el1);
	} else {
		val |= CPTR_EL2_TTA | CPTR_NVHE_EL2_RES1;

@@ -61,12 +66,34 @@ static void __activate_cptr_traps(struct kvm_vcpu *vcpu)

		if (!guest_owns_fp_regs())
			val |= CPTR_EL2_TFP;

		write_sysreg(val, cptr_el2);
	}
}

	if (!guest_owns_fp_regs())
		__activate_traps_fpsimd32(vcpu);
static void __deactivate_cptr_traps(struct kvm_vcpu *vcpu)
{
	struct kvm *kvm = kern_hyp_va(vcpu->kvm);

	kvm_write_cptr_el2(val);
	if (has_hvhe()) {
		u64 val = CPACR_EL1_FPEN;

		if (!kvm_has_sve(kvm) || !guest_owns_fp_regs())
			val |= CPACR_EL1_ZEN;
		if (cpus_have_final_cap(ARM64_SME))
			val |= CPACR_EL1_SMEN;

		write_sysreg(val, cpacr_el1);
	} else {
		u64 val = CPTR_NVHE_EL2_RES1;

		if (kvm_has_sve(kvm) && guest_owns_fp_regs())
			val |= CPTR_EL2_TZ;
		if (!cpus_have_final_cap(ARM64_SME))
			val |= CPTR_EL2_TSM;

		write_sysreg(val, cptr_el2);
	}
}

static void __activate_traps(struct kvm_vcpu *vcpu)
@@ -119,7 +146,7 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)

	write_sysreg(this_cpu_ptr(&kvm_init_params)->hcr_el2, hcr_el2);

	kvm_reset_cptr_el2(vcpu);
	__deactivate_cptr_traps(vcpu);
	write_sysreg(__kvm_hyp_host_vector, vbar_el2);
}

+11 −1
Original line number Diff line number Diff line
@@ -136,6 +136,16 @@ static void __activate_cptr_traps(struct kvm_vcpu *vcpu)
	write_sysreg(val, cpacr_el1);
}

static void __deactivate_cptr_traps(struct kvm_vcpu *vcpu)
{
	u64 val = CPACR_EL1_FPEN | CPACR_EL1_ZEN_EL1EN;

	if (cpus_have_final_cap(ARM64_SME))
		val |= CPACR_EL1_SMEN_EL1EN;

	write_sysreg(val, cpacr_el1);
}

static void __activate_traps(struct kvm_vcpu *vcpu)
{
	u64 val;
@@ -207,7 +217,7 @@ static void __deactivate_traps(struct kvm_vcpu *vcpu)
	 */
	asm(ALTERNATIVE("nop", "isb", ARM64_WORKAROUND_SPECULATIVE_AT));

	kvm_reset_cptr_el2(vcpu);
	__deactivate_cptr_traps(vcpu);

	if (!arm64_kernel_unmapped_at_el0())
		host_vectors = __this_cpu_read(this_cpu_vector);