Commit f76f89e2 authored by Fuad Tabba's avatar Fuad Tabba Committed by Marc Zyngier
Browse files

KVM: arm64: Refactor sys_regs.h,c for nVHE reuse



Refactor sys_regs.h and sys_regs.c to make it easier to reuse
common code. It will be used in nVHE in a later patch.

Note that the refactored code uses __inline_bsearch for find_reg
instead of bsearch to avoid copying the bsearch code for nVHE.

No functional change intended.

Acked-by: default avatarWill Deacon <will@kernel.org>
Signed-off-by: default avatarFuad Tabba <tabba@google.com>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20210817081134.2918285-6-tabba@google.com
parent dabb1667
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -1153,6 +1153,11 @@
#define ICH_VTR_A3V_SHIFT	21
#define ICH_VTR_A3V_MASK	(1 << ICH_VTR_A3V_SHIFT)

#define ARM64_FEATURE_FIELD_BITS	4

/* Create a mask for the feature bits of the specified feature. */
#define ARM64_FEATURE_MASK(x)	(GENMASK_ULL(x##_SHIFT + ARM64_FEATURE_FIELD_BITS - 1, x##_SHIFT))

#ifdef __ASSEMBLY__

	.irp	num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
+16 −44
Original line number Diff line number Diff line
@@ -44,10 +44,6 @@
 * 64bit interface.
 */

#define reg_to_encoding(x)						\
	sys_reg((u32)(x)->Op0, (u32)(x)->Op1,				\
		(u32)(x)->CRn, (u32)(x)->CRm, (u32)(x)->Op2)

static bool read_from_write_only(struct kvm_vcpu *vcpu,
				 struct sys_reg_params *params,
				 const struct sys_reg_desc *r)
@@ -1026,8 +1022,6 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu,
	return true;
}

#define FEATURE(x)	(GENMASK_ULL(x##_SHIFT + 3, x##_SHIFT))

/* Read a sanitised cpufeature ID register by sys_reg_desc */
static u64 read_id_reg(const struct kvm_vcpu *vcpu,
		struct sys_reg_desc const *r, bool raz)
@@ -1038,40 +1032,40 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
	switch (id) {
	case SYS_ID_AA64PFR0_EL1:
		if (!vcpu_has_sve(vcpu))
			val &= ~FEATURE(ID_AA64PFR0_SVE);
		val &= ~FEATURE(ID_AA64PFR0_AMU);
		val &= ~FEATURE(ID_AA64PFR0_CSV2);
		val |= FIELD_PREP(FEATURE(ID_AA64PFR0_CSV2), (u64)vcpu->kvm->arch.pfr0_csv2);
		val &= ~FEATURE(ID_AA64PFR0_CSV3);
		val |= FIELD_PREP(FEATURE(ID_AA64PFR0_CSV3), (u64)vcpu->kvm->arch.pfr0_csv3);
			val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_SVE);
		val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_AMU);
		val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_CSV2);
		val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_CSV2), (u64)vcpu->kvm->arch.pfr0_csv2);
		val &= ~ARM64_FEATURE_MASK(ID_AA64PFR0_CSV3);
		val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR0_CSV3), (u64)vcpu->kvm->arch.pfr0_csv3);
		break;
	case SYS_ID_AA64PFR1_EL1:
		val &= ~FEATURE(ID_AA64PFR1_MTE);
		val &= ~ARM64_FEATURE_MASK(ID_AA64PFR1_MTE);
		if (kvm_has_mte(vcpu->kvm)) {
			u64 pfr, mte;

			pfr = read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1);
			mte = cpuid_feature_extract_unsigned_field(pfr, ID_AA64PFR1_MTE_SHIFT);
			val |= FIELD_PREP(FEATURE(ID_AA64PFR1_MTE), mte);
			val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64PFR1_MTE), mte);
		}
		break;
	case SYS_ID_AA64ISAR1_EL1:
		if (!vcpu_has_ptrauth(vcpu))
			val &= ~(FEATURE(ID_AA64ISAR1_APA) |
				 FEATURE(ID_AA64ISAR1_API) |
				 FEATURE(ID_AA64ISAR1_GPA) |
				 FEATURE(ID_AA64ISAR1_GPI));
			val &= ~(ARM64_FEATURE_MASK(ID_AA64ISAR1_APA) |
				 ARM64_FEATURE_MASK(ID_AA64ISAR1_API) |
				 ARM64_FEATURE_MASK(ID_AA64ISAR1_GPA) |
				 ARM64_FEATURE_MASK(ID_AA64ISAR1_GPI));
		break;
	case SYS_ID_AA64DFR0_EL1:
		/* Limit debug to ARMv8.0 */
		val &= ~FEATURE(ID_AA64DFR0_DEBUGVER);
		val |= FIELD_PREP(FEATURE(ID_AA64DFR0_DEBUGVER), 6);
		val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_DEBUGVER);
		val |= FIELD_PREP(ARM64_FEATURE_MASK(ID_AA64DFR0_DEBUGVER), 6);
		/* Limit guests to PMUv3 for ARMv8.4 */
		val = cpuid_feature_cap_perfmon_field(val,
						      ID_AA64DFR0_PMUVER_SHIFT,
						      kvm_vcpu_has_pmu(vcpu) ? ID_AA64DFR0_PMUVER_8_4 : 0);
		/* Hide SPE from guests */
		val &= ~FEATURE(ID_AA64DFR0_PMSVER);
		val &= ~ARM64_FEATURE_MASK(ID_AA64DFR0_PMSVER);
		break;
	case SYS_ID_DFR0_EL1:
		/* Limit guests to PMUv3 for ARMv8.4 */
@@ -2106,23 +2100,6 @@ static int check_sysreg_table(const struct sys_reg_desc *table, unsigned int n,
	return 0;
}

static int match_sys_reg(const void *key, const void *elt)
{
	const unsigned long pval = (unsigned long)key;
	const struct sys_reg_desc *r = elt;

	return pval - reg_to_encoding(r);
}

static const struct sys_reg_desc *find_reg(const struct sys_reg_params *params,
					 const struct sys_reg_desc table[],
					 unsigned int num)
{
	unsigned long pval = reg_to_encoding(params);

	return bsearch((void *)pval, table, num, sizeof(table[0]), match_sys_reg);
}

int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu)
{
	kvm_inject_undefined(vcpu);
@@ -2365,13 +2342,8 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu)

	trace_kvm_handle_sys_reg(esr);

	params.Op0 = (esr >> 20) & 3;
	params.Op1 = (esr >> 14) & 0x7;
	params.CRn = (esr >> 10) & 0xf;
	params.CRm = (esr >> 1) & 0xf;
	params.Op2 = (esr >> 17) & 0x7;
	params = esr_sys64_to_params(esr);
	params.regval = vcpu_get_reg(vcpu, Rt);
	params.is_write = !(esr & 1);

	ret = emulate_sys_reg(vcpu, &params);

+31 −0
Original line number Diff line number Diff line
@@ -11,6 +11,12 @@
#ifndef __ARM64_KVM_SYS_REGS_LOCAL_H__
#define __ARM64_KVM_SYS_REGS_LOCAL_H__

#include <linux/bsearch.h>

#define reg_to_encoding(x)						\
	sys_reg((u32)(x)->Op0, (u32)(x)->Op1,				\
		(u32)(x)->CRn, (u32)(x)->CRm, (u32)(x)->Op2)

struct sys_reg_params {
	u8	Op0;
	u8	Op1;
@@ -21,6 +27,14 @@ struct sys_reg_params {
	bool	is_write;
};

#define esr_sys64_to_params(esr)                                               \
	((struct sys_reg_params){ .Op0 = ((esr) >> 20) & 3,                    \
				  .Op1 = ((esr) >> 14) & 0x7,                  \
				  .CRn = ((esr) >> 10) & 0xf,                  \
				  .CRm = ((esr) >> 1) & 0xf,                   \
				  .Op2 = ((esr) >> 17) & 0x7,                  \
				  .is_write = !((esr) & 1) })

struct sys_reg_desc {
	/* Sysreg string for debug */
	const char *name;
@@ -152,6 +166,23 @@ static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
	return i1->Op2 - i2->Op2;
}

static inline int match_sys_reg(const void *key, const void *elt)
{
	const unsigned long pval = (unsigned long)key;
	const struct sys_reg_desc *r = elt;

	return pval - reg_to_encoding(r);
}

static inline const struct sys_reg_desc *
find_reg(const struct sys_reg_params *params, const struct sys_reg_desc table[],
	 unsigned int num)
{
	unsigned long pval = reg_to_encoding(params);

	return __inline_bsearch((void *)pval, table, num, sizeof(table[0]), match_sys_reg);
}

const struct sys_reg_desc *find_reg_by_id(u64 id,
					  struct sys_reg_params *params,
					  const struct sys_reg_desc table[],