Commit e880bd33 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

KVM: arm64: nv: Add trap forwarding for CNTHCTL_EL2



Describe the CNTHCTL_EL2 register, and associate it with all the sysregs
it allows to trap.

Reviewed-by: default avatarEric Auger <eric.auger@redhat.com>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Reviewed-by: default avatarJing Zhang <jingzhangos@google.com>
Link: https://lore.kernel.org/r/20230815183903.2735724-19-maz@kernel.org
parent cb31632c
Loading
Loading
Loading
Loading
+49 −1
Original line number Diff line number Diff line
@@ -100,9 +100,11 @@ enum cgt_group_id {

	/*
	 * Anything after this point requires a callback evaluating a
	 * complex trap condition. Hopefully we'll never need this...
	 * complex trap condition. Ugly stuff.
	 */
	__COMPLEX_CONDITIONS__,
	CGT_CNTHCTL_EL1PCTEN = __COMPLEX_CONDITIONS__,
	CGT_CNTHCTL_EL1PTEN,

	/* Must be last */
	__NR_CGT_GROUP_IDS__
@@ -369,10 +371,51 @@ static const enum cgt_group_id *coarse_control_combo[] = {

typedef enum trap_behaviour (*complex_condition_check)(struct kvm_vcpu *);

/*
 * Warning, maximum confusion ahead.
 *
 * When E2H=0, CNTHCTL_EL2[1:0] are defined as EL1PCEN:EL1PCTEN
 * When E2H=1, CNTHCTL_EL2[11:10] are defined as EL1PTEN:EL1PCTEN
 *
 * Note the single letter difference? Yet, the bits have the same
 * function despite a different layout and a different name.
 *
 * We don't try to reconcile this mess. We just use the E2H=0 bits
 * to generate something that is in the E2H=1 format, and live with
 * it. You're welcome.
 */
static u64 get_sanitized_cnthctl(struct kvm_vcpu *vcpu)
{
	u64 val = __vcpu_sys_reg(vcpu, CNTHCTL_EL2);

	if (!vcpu_el2_e2h_is_set(vcpu))
		val = (val & (CNTHCTL_EL1PCEN | CNTHCTL_EL1PCTEN)) << 10;

	return val & ((CNTHCTL_EL1PCEN | CNTHCTL_EL1PCTEN) << 10);
}

static enum trap_behaviour check_cnthctl_el1pcten(struct kvm_vcpu *vcpu)
{
	if (get_sanitized_cnthctl(vcpu) & (CNTHCTL_EL1PCTEN << 10))
		return BEHAVE_HANDLE_LOCALLY;

	return BEHAVE_FORWARD_ANY;
}

static enum trap_behaviour check_cnthctl_el1pten(struct kvm_vcpu *vcpu)
{
	if (get_sanitized_cnthctl(vcpu) & (CNTHCTL_EL1PCEN << 10))
		return BEHAVE_HANDLE_LOCALLY;

	return BEHAVE_FORWARD_ANY;
}

#define CCC(id, fn)				\
	[id - __COMPLEX_CONDITIONS__] = fn

static const complex_condition_check ccc[] = {
	CCC(CGT_CNTHCTL_EL1PCTEN, check_cnthctl_el1pcten),
	CCC(CGT_CNTHCTL_EL1PTEN, check_cnthctl_el1pten),
};

/*
@@ -877,6 +920,11 @@ static const struct encoding_to_trap_config encoding_to_cgt[] __initconst = {
	SR_TRAP(SYS_TRBPTR_EL1, 	CGT_MDCR_E2TB),
	SR_TRAP(SYS_TRBSR_EL1, 		CGT_MDCR_E2TB),
	SR_TRAP(SYS_TRBTRG_EL1,		CGT_MDCR_E2TB),
	SR_TRAP(SYS_CNTP_TVAL_EL0,	CGT_CNTHCTL_EL1PTEN),
	SR_TRAP(SYS_CNTP_CVAL_EL0,	CGT_CNTHCTL_EL1PTEN),
	SR_TRAP(SYS_CNTP_CTL_EL0,	CGT_CNTHCTL_EL1PTEN),
	SR_TRAP(SYS_CNTPCT_EL0,		CGT_CNTHCTL_EL1PCTEN),
	SR_TRAP(SYS_CNTPCTSS_EL0,	CGT_CNTHCTL_EL1PCTEN),
};

static DEFINE_XARRAY(sr_forward_xa);