Commit 7da540e2 authored by James Morse's avatar James Morse Committed by Oliver Upton
Browse files

KVM: arm64: Add a macro for creating filtered sys_reg_descs entries



The sys_reg_descs array holds function pointers and reset value for
managing the user-space and guest view of system registers. These
are mostly created by a set of macro's as only some combinations
of behaviour are needed.

If a register needs special treatment, its sys_reg_descs entry is
open-coded. This is true of some id registers where the value provided
by user-space is validated by some helpers.

Before adding another one of these, add a helper that covers the
existing special cases. 'ID_FILTERED' expects helpers to set the
user-space value, and retrieve the modified reset value.

Like ID_WRITABLE() this uses id_visibility(), which should have no
functional change for the registers converted to use ID_FILTERED().

read_sanitised_id_aa64dfr0_el1() and read_sanitised_id_aa64pfr0_el1()
have been refactored to be called from kvm_read_sanitised_id_reg(), to
try be consistent with ID_WRITABLE().

Signed-off-by: default avatarJames Morse <james.morse@arm.com>
Signed-off-by: default avatarJoey Gouly <joey.gouly@arm.com>
Reviewed-by: default avatarGavin Shan <gshan@redhat.com>
Tested-by: default avatarShameer Kolothum <shameerali.kolothum.thodi@huawei.com>
Reviewed-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20241030160317.2528209-6-joey.gouly@arm.com


Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parent 31ff96c3
Loading
Loading
Loading
Loading
+38 −28
Original line number Diff line number Diff line
@@ -1509,6 +1509,9 @@ static u8 pmuver_to_perfmon(u8 pmuver)
	}
}

static u64 sanitise_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, u64 val);
static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val);

/* Read a sanitised cpufeature ID register by sys_reg_desc */
static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
				       const struct sys_reg_desc *r)
@@ -1522,6 +1525,12 @@ static u64 __kvm_read_sanitised_id_reg(const struct kvm_vcpu *vcpu,
	val = read_sanitised_ftr_reg(id);

	switch (id) {
	case SYS_ID_AA64DFR0_EL1:
		val = sanitise_id_aa64dfr0_el1(vcpu, val);
		break;
	case SYS_ID_AA64PFR0_EL1:
		val = sanitise_id_aa64pfr0_el1(vcpu, val);
		break;
	case SYS_ID_AA64PFR1_EL1:
		if (!kvm_has_mte(vcpu->kvm))
			val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_EL1_MTE);
@@ -1692,11 +1701,8 @@ static unsigned int fp8_visibility(const struct kvm_vcpu *vcpu,
	return REG_HIDDEN;
}

static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
					  const struct sys_reg_desc *rd)
static u64 sanitise_id_aa64pfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
{
	u64 val = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);

	if (!vcpu_has_sve(vcpu))
		val &= ~ID_AA64PFR0_EL1_SVE_MASK;

@@ -1737,11 +1743,8 @@ static u64 read_sanitised_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
	(val);								       \
})

static u64 read_sanitised_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
					  const struct sys_reg_desc *rd)
static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
{
	u64 val = read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1);

	val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8);

	/*
@@ -1834,6 +1837,12 @@ static int set_id_dfr0_el1(struct kvm_vcpu *vcpu,
	return set_id_reg(vcpu, rd, val);
}

static int set_id_aa64pfr0_el1(struct kvm_vcpu *vcpu,
			       const struct sys_reg_desc *rd, u64 val)
{
	return set_id_reg(vcpu, rd, val);
}

/*
 * cpufeature ID register user accessors
 *
@@ -2150,6 +2159,15 @@ static bool bad_redir_trap(struct kvm_vcpu *vcpu,
	.val = mask,				\
}

/* sys_reg_desc initialiser for cpufeature ID registers that need filtering */
#define ID_FILTERED(sysreg, name, mask) {	\
	ID_DESC(sysreg),				\
	.set_user = set_##name,				\
	.visibility = id_visibility,			\
	.reset = kvm_read_sanitised_id_reg,		\
	.val = (mask),					\
}

/*
 * sys_reg_desc initialiser for architecturally unallocated cpufeature ID
 * register with encoding Op0=3, Op1=0, CRn=0, CRm=crm, Op2=op2
@@ -2374,17 +2392,13 @@ static const struct sys_reg_desc sys_reg_descs[] = {

	/* AArch64 ID registers */
	/* CRm=4 */
	{ SYS_DESC(SYS_ID_AA64PFR0_EL1),
	  .access = access_id_reg,
	  .get_user = get_id_reg,
	  .set_user = set_id_reg,
	  .reset = read_sanitised_id_aa64pfr0_el1,
	  .val = ~(ID_AA64PFR0_EL1_AMU |
	ID_FILTERED(ID_AA64PFR0_EL1, id_aa64pfr0_el1,
		    ~(ID_AA64PFR0_EL1_AMU |
		      ID_AA64PFR0_EL1_MPAM |
		      ID_AA64PFR0_EL1_SVE |
		      ID_AA64PFR0_EL1_RAS |
		      ID_AA64PFR0_EL1_AdvSIMD |
		   ID_AA64PFR0_EL1_FP), },
		      ID_AA64PFR0_EL1_FP)),
	ID_WRITABLE(ID_AA64PFR1_EL1, ~(ID_AA64PFR1_EL1_PFAR |
				       ID_AA64PFR1_EL1_DF2 |
				       ID_AA64PFR1_EL1_MTEX |
@@ -2406,11 +2420,6 @@ static const struct sys_reg_desc sys_reg_descs[] = {
	ID_WRITABLE(ID_AA64FPFR0_EL1, ~ID_AA64FPFR0_EL1_RES0),

	/* CRm=5 */
	{ SYS_DESC(SYS_ID_AA64DFR0_EL1),
	  .access = access_id_reg,
	  .get_user = get_id_reg,
	  .set_user = set_id_aa64dfr0_el1,
	  .reset = read_sanitised_id_aa64dfr0_el1,
	/*
	 * Prior to FEAT_Debugv8.9, the architecture defines context-aware
	 * breakpoints (CTX_CMPs) as the highest numbered breakpoints (BRPs).
@@ -2423,10 +2432,11 @@ static const struct sys_reg_desc sys_reg_descs[] = {
	 * See DDI0487K.a, section D2.8.3 Breakpoint types and linking
	 * of breakpoints for more details.
	 */
	  .val = ID_AA64DFR0_EL1_DoubleLock_MASK |
	ID_FILTERED(ID_AA64DFR0_EL1, id_aa64dfr0_el1,
		    ID_AA64DFR0_EL1_DoubleLock_MASK |
		    ID_AA64DFR0_EL1_WRPs_MASK |
		    ID_AA64DFR0_EL1_PMUVer_MASK |
		 ID_AA64DFR0_EL1_DebugVer_MASK, },
		    ID_AA64DFR0_EL1_DebugVer_MASK),
	ID_SANITISED(ID_AA64DFR1_EL1),
	ID_UNALLOCATED(5,2),
	ID_UNALLOCATED(5,3),