Commit 46bd74ef authored by Marc Zyngier's avatar Marc Zyngier
Browse files

Merge branch kvm-arm64/el2-feature-control into kvmarm-master/next



* kvm-arm64/el2-feature-control: (23 commits)
  : .
  : General rework of EL2 features that can be disabled to satisfy
  : the requirement of migration between heterogeneous hosts:
  :
  : - Handle effective RES0 behaviour of undefined registers, making sure
  :   that disabling a feature affects full registeres, and not just
  :   individual control bits. (20250918151402.1665315-1-maz@kernel.org)
  :
  : - Allow ID_AA64MMFR1_EL1.{TWED,HCX} to be disabled from userspace.
  :   (20250911114621.3724469-1-yangjinqian1@huawei.com)
  :
  : - Turn the NV feature management into a deny-list, and expose
  :   missing features to EL2 guests.
  :   (20250912212258.407350-1-oliver.upton@linux.dev)
  : .
  KVM: arm64: nv: Expose up to FEAT_Debugv8p8 to NV-enabled VMs
  KVM: arm64: nv: Advertise FEAT_TIDCP1 to NV-enabled VMs
  KVM: arm64: nv: Advertise FEAT_SpecSEI to NV-enabled VMs
  KVM: arm64: nv: Expose FEAT_TWED to NV-enabled VMs
  KVM: arm64: nv: Exclude guest's TWED configuration when TWE isn't set
  KVM: arm64: nv: Expose FEAT_AFP to NV-enabled VMs
  KVM: arm64: nv: Expose FEAT_ECBHB to NV-enabled VMs
  KVM: arm64: nv: Expose FEAT_RASv1p1 via RAS_frac
  KVM: arm64: nv: Expose FEAT_DF2 to NV-enabled VMs
  KVM: arm64: nv: Don't erroneously claim FEAT_DoubleLock for NV VMs
  KVM: arm64: nv: Convert masks to denylists in limit_nv_id_reg()
  KVM: arm64: selftests: Test writes to ID_AA64MMFR1_EL1.{HCX, TWED}
  KVM: arm64: Make ID_AA64MMFR1_EL1.{HCX, TWED} writable from userspace
  KVM: arm64: Convert MDCR_EL2 RES0 handling to compute_reg_res0_bits()
  KVM: arm64: Convert SCTLR_EL1 RES0 handling to compute_reg_res0_bits()
  KVM: arm64: Enforce absence of FEAT_TCR2 on TCR2_EL2
  KVM: arm64: Enforce absence of FEAT_SCTLR2 on SCTLR2_EL{1,2}
  KVM: arm64: Convert HCR_EL2 RES0 handling to compute_reg_res0_bits()
  KVM: arm64: Enforce absence of FEAT_HCX on HCRX_EL2
  KVM: arm64: Enforce absence of FEAT_FGT2 on FGT2 registers
  ...

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parents f01c7baa b8b1d62f
Loading
Loading
Loading
Loading
+227 −131
Original line number Diff line number Diff line
@@ -7,12 +7,22 @@
#include <linux/kvm_host.h>
#include <asm/sysreg.h>

/*
 * Describes the dependencies between a set of bits (or the negation
 * of a set of RES0 bits) and a feature. The flags indicate how the
 * data is interpreted.
 */
struct reg_bits_to_feat_map {
	union {
		u64	bits;
		u64	*res0p;
	};

#define	NEVER_FGU	BIT(0)	/* Can trap, but never UNDEF */
#define	CALL_FUNC	BIT(1)	/* Needs to evaluate tons of crap */
#define	FIXED_VALUE	BIT(2)	/* RAZ/WI or RAO/WI in KVM */
#define	RES0_POINTER	BIT(3)	/* Pointer to RES0 value instead of bits */

	unsigned long	flags;

	union {
@@ -28,9 +38,27 @@ struct reg_bits_to_feat_map {
	};
};

#define __NEEDS_FEAT_3(m, f, id, fld, lim)		\
/*
 * Describes the dependencies for a given register:
 *
 * @feat_map describes the dependency for the whole register. If the
 * features the register depends on are not present, the whole
 * register is effectively RES0.
 *
 * @bit_feat_map describes the dependencies for a set of bits in that
 * register. If the features these bits depend on are not present, the
 * bits are effectively RES0.
 */
struct reg_feat_map_desc {
	const char			  *name;
	const struct reg_bits_to_feat_map feat_map;
	const struct reg_bits_to_feat_map *bit_feat_map;
	const unsigned int		  bit_feat_map_sz;
};

#define __NEEDS_FEAT_3(m, f, w, id, fld, lim)		\
	{						\
		.bits	= (m),				\
		.w	= (m),				\
		.flags = (f),				\
		.regidx	= IDREG_IDX(SYS_ ## id),	\
		.shift	= id ##_## fld ## _SHIFT,	\
@@ -39,28 +67,63 @@ struct reg_bits_to_feat_map {
		.lo_lim	= id ##_## fld ##_## lim	\
	}

#define __NEEDS_FEAT_2(m, f, fun, dummy)		\
#define __NEEDS_FEAT_2(m, f, w, fun, dummy)		\
	{						\
		.bits	= (m),				\
		.w	= (m),				\
		.flags = (f) | CALL_FUNC,		\
		.fval = (fun),				\
	}

#define __NEEDS_FEAT_1(m, f, fun)			\
#define __NEEDS_FEAT_1(m, f, w, fun)			\
	{						\
		.bits	= (m),				\
		.w	= (m),				\
		.flags = (f) | CALL_FUNC,		\
		.match = (fun),				\
	}

#define __NEEDS_FEAT_FLAG(m, f, w, ...)			\
	CONCATENATE(__NEEDS_FEAT_, COUNT_ARGS(__VA_ARGS__))(m, f, w, __VA_ARGS__)

#define NEEDS_FEAT_FLAG(m, f, ...)			\
	CONCATENATE(__NEEDS_FEAT_, COUNT_ARGS(__VA_ARGS__))(m, f, __VA_ARGS__)
	__NEEDS_FEAT_FLAG(m, f, bits, __VA_ARGS__)

#define NEEDS_FEAT_FIXED(m, ...)			\
	NEEDS_FEAT_FLAG(m, FIXED_VALUE, __VA_ARGS__, 0)
	__NEEDS_FEAT_FLAG(m, FIXED_VALUE, bits, __VA_ARGS__, 0)

#define NEEDS_FEAT_RES0(p, ...)				\
	__NEEDS_FEAT_FLAG(p, RES0_POINTER, res0p, __VA_ARGS__)

/*
 * Declare the dependency between a set of bits and a set of features,
 * generating a struct reg_bit_to_feat_map.
 */
#define NEEDS_FEAT(m, ...)	NEEDS_FEAT_FLAG(m, 0, __VA_ARGS__)

/*
 * Declare the dependency between a non-FGT register, a set of
 * feature, and the set of individual bits it contains. This generates
 * a struct reg_feat_map_desc.
 */
#define DECLARE_FEAT_MAP(n, r, m, f)					\
	struct reg_feat_map_desc n = {					\
		.name			= #r,				\
		.feat_map		= NEEDS_FEAT(~r##_RES0, f), 	\
		.bit_feat_map		= m,				\
		.bit_feat_map_sz	= ARRAY_SIZE(m),		\
	}

/*
 * Specialised version of the above for FGT registers that have their
 * RES0 masks described as struct fgt_masks.
 */
#define DECLARE_FEAT_MAP_FGT(n, msk, m, f)				\
	struct reg_feat_map_desc n = {					\
		.name			= #msk,				\
		.feat_map		= NEEDS_FEAT_RES0(&msk.res0, f),\
		.bit_feat_map		= m,				\
		.bit_feat_map_sz	= ARRAY_SIZE(m),		\
	}

#define FEAT_SPE		ID_AA64DFR0_EL1, PMSVer, IMP
#define FEAT_SPE_FnE		ID_AA64DFR0_EL1, PMSVer, V1P2
#define FEAT_BRBE		ID_AA64DFR0_EL1, BRBE, IMP
@@ -73,6 +136,7 @@ struct reg_bits_to_feat_map {
#define FEAT_AA32EL0		ID_AA64PFR0_EL1, EL0, AARCH32
#define FEAT_AA32EL1		ID_AA64PFR0_EL1, EL1, AARCH32
#define FEAT_AA64EL1		ID_AA64PFR0_EL1, EL1, IMP
#define FEAT_AA64EL2		ID_AA64PFR0_EL1, EL2, IMP
#define FEAT_AA64EL3		ID_AA64PFR0_EL1, EL3, IMP
#define FEAT_AIE		ID_AA64MMFR3_EL1, AIE, IMP
#define FEAT_S2POE		ID_AA64MMFR3_EL1, S2POE, IMP
@@ -131,7 +195,6 @@ struct reg_bits_to_feat_map {
#define FEAT_SPMU		ID_AA64DFR1_EL1, SPMU, IMP
#define FEAT_SPE_nVM		ID_AA64DFR2_EL1, SPE_nVM, IMP
#define FEAT_STEP2		ID_AA64DFR2_EL1, STEP, IMP
#define FEAT_SYSREG128		ID_AA64ISAR2_EL1, SYSREG_128, IMP
#define FEAT_CPA2		ID_AA64ISAR3_EL1, CPA, CPA2
#define FEAT_ASID2		ID_AA64MMFR4_EL1, ASID2, IMP
#define FEAT_MEC		ID_AA64MMFR3_EL1, MEC, IMP
@@ -143,7 +206,6 @@ struct reg_bits_to_feat_map {
#define FEAT_LSMAOC		ID_AA64MMFR2_EL1, LSM, IMP
#define FEAT_MixedEnd		ID_AA64MMFR0_EL1, BIGEND, IMP
#define FEAT_MixedEndEL0	ID_AA64MMFR0_EL1, BIGENDEL0, IMP
#define FEAT_MTE2		ID_AA64PFR1_EL1, MTE, MTE2
#define FEAT_MTE_ASYNC		ID_AA64PFR1_EL1, MTE_frac, ASYNC
#define FEAT_MTE_STORE_ONLY	ID_AA64PFR2_EL1, MTESTOREONLY, IMP
#define FEAT_PAN		ID_AA64MMFR1_EL1, PAN, IMP
@@ -151,7 +213,9 @@ struct reg_bits_to_feat_map {
#define FEAT_SSBS		ID_AA64PFR1_EL1, SSBS, IMP
#define FEAT_TIDCP1		ID_AA64MMFR1_EL1, TIDCP1, IMP
#define FEAT_FGT		ID_AA64MMFR0_EL1, FGT, IMP
#define FEAT_FGT2		ID_AA64MMFR0_EL1, FGT, FGT2
#define FEAT_MTPMU		ID_AA64DFR0_EL1, MTPMU, IMP
#define FEAT_HCX		ID_AA64MMFR1_EL1, HCX, IMP

static bool not_feat_aa64el3(struct kvm *kvm)
{
@@ -397,6 +461,10 @@ static const struct reg_bits_to_feat_map hfgrtr_feat_map[] = {
			NEVER_FGU, FEAT_AA64EL1),
};


static const DECLARE_FEAT_MAP_FGT(hfgrtr_desc, hfgrtr_masks,
				  hfgrtr_feat_map, FEAT_FGT);

static const struct reg_bits_to_feat_map hfgwtr_feat_map[] = {
	NEEDS_FEAT(HFGWTR_EL2_nAMAIR2_EL1	|
		   HFGWTR_EL2_nMAIR2_EL1,
@@ -461,6 +529,9 @@ static const struct reg_bits_to_feat_map hfgwtr_feat_map[] = {
			NEVER_FGU, FEAT_AA64EL1),
};

static const DECLARE_FEAT_MAP_FGT(hfgwtr_desc, hfgwtr_masks,
				  hfgwtr_feat_map, FEAT_FGT);

static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = {
	NEEDS_FEAT(HDFGRTR_EL2_PMBIDR_EL1	|
		   HDFGRTR_EL2_PMSLATFR_EL1	|
@@ -528,6 +599,9 @@ static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = {
			NEVER_FGU, FEAT_AA64EL1)
};

static const DECLARE_FEAT_MAP_FGT(hdfgrtr_desc, hdfgrtr_masks,
				  hdfgrtr_feat_map, FEAT_FGT);

static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = {
	NEEDS_FEAT(HDFGWTR_EL2_PMSLATFR_EL1	|
		   HDFGWTR_EL2_PMSIRR_EL1	|
@@ -588,6 +662,8 @@ static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = {
	NEEDS_FEAT(HDFGWTR_EL2_TRFCR_EL1, FEAT_TRF),
};

static const DECLARE_FEAT_MAP_FGT(hdfgwtr_desc, hdfgwtr_masks,
				  hdfgwtr_feat_map, FEAT_FGT);

static const struct reg_bits_to_feat_map hfgitr_feat_map[] = {
	NEEDS_FEAT(HFGITR_EL2_PSBCSYNC, FEAT_SPEv1p5),
@@ -662,6 +738,9 @@ static const struct reg_bits_to_feat_map hfgitr_feat_map[] = {
			NEVER_FGU, FEAT_AA64EL1),
};

static const DECLARE_FEAT_MAP_FGT(hfgitr_desc, hfgitr_masks,
				  hfgitr_feat_map, FEAT_FGT);

static const struct reg_bits_to_feat_map hafgrtr_feat_map[] = {
	NEEDS_FEAT(HAFGRTR_EL2_AMEVTYPER115_EL0	|
		   HAFGRTR_EL2_AMEVTYPER114_EL0	|
@@ -704,11 +783,17 @@ static const struct reg_bits_to_feat_map hafgrtr_feat_map[] = {
		   FEAT_AMUv1),
};

static const DECLARE_FEAT_MAP_FGT(hafgrtr_desc, hafgrtr_masks,
				  hafgrtr_feat_map, FEAT_FGT);

static const struct reg_bits_to_feat_map hfgitr2_feat_map[] = {
	NEEDS_FEAT(HFGITR2_EL2_nDCCIVAPS, FEAT_PoPS),
	NEEDS_FEAT(HFGITR2_EL2_TSBCSYNC, FEAT_TRBEv1p1)
};

static const DECLARE_FEAT_MAP_FGT(hfgitr2_desc, hfgitr2_masks,
				  hfgitr2_feat_map, FEAT_FGT2);

static const struct reg_bits_to_feat_map hfgrtr2_feat_map[] = {
	NEEDS_FEAT(HFGRTR2_EL2_nPFAR_EL1, FEAT_PFAR),
	NEEDS_FEAT(HFGRTR2_EL2_nERXGSR_EL1, FEAT_RASv2),
@@ -728,6 +813,9 @@ static const struct reg_bits_to_feat_map hfgrtr2_feat_map[] = {
	NEEDS_FEAT(HFGRTR2_EL2_nRCWSMASK_EL1, FEAT_THE),
};

static const DECLARE_FEAT_MAP_FGT(hfgrtr2_desc, hfgrtr2_masks,
				  hfgrtr2_feat_map, FEAT_FGT2);

static const struct reg_bits_to_feat_map hfgwtr2_feat_map[] = {
	NEEDS_FEAT(HFGWTR2_EL2_nPFAR_EL1, FEAT_PFAR),
	NEEDS_FEAT(HFGWTR2_EL2_nACTLRALIAS_EL1	|
@@ -746,6 +834,9 @@ static const struct reg_bits_to_feat_map hfgwtr2_feat_map[] = {
	NEEDS_FEAT(HFGWTR2_EL2_nRCWSMASK_EL1, FEAT_THE),
};

static const DECLARE_FEAT_MAP_FGT(hfgwtr2_desc, hfgwtr2_masks,
				  hfgwtr2_feat_map, FEAT_FGT2);

static const struct reg_bits_to_feat_map hdfgrtr2_feat_map[] = {
	NEEDS_FEAT(HDFGRTR2_EL2_nMDSELR_EL1, FEAT_Debugv8p9),
	NEEDS_FEAT(HDFGRTR2_EL2_nPMECR_EL1, feat_ebep_pmuv3_ss),
@@ -776,6 +867,9 @@ static const struct reg_bits_to_feat_map hdfgrtr2_feat_map[] = {
	NEEDS_FEAT(HDFGRTR2_EL2_nTRBMPAM_EL1, feat_trbe_mpam),
};

static const DECLARE_FEAT_MAP_FGT(hdfgrtr2_desc, hdfgrtr2_masks,
				  hdfgrtr2_feat_map, FEAT_FGT2);

static const struct reg_bits_to_feat_map hdfgwtr2_feat_map[] = {
	NEEDS_FEAT(HDFGWTR2_EL2_nMDSELR_EL1, FEAT_Debugv8p9),
	NEEDS_FEAT(HDFGWTR2_EL2_nPMECR_EL1, feat_ebep_pmuv3_ss),
@@ -804,6 +898,10 @@ static const struct reg_bits_to_feat_map hdfgwtr2_feat_map[] = {
	NEEDS_FEAT(HDFGWTR2_EL2_nTRBMPAM_EL1, feat_trbe_mpam),
};

static const DECLARE_FEAT_MAP_FGT(hdfgwtr2_desc, hdfgwtr2_masks,
				  hdfgwtr2_feat_map, FEAT_FGT2);


static const struct reg_bits_to_feat_map hcrx_feat_map[] = {
	NEEDS_FEAT(HCRX_EL2_PACMEn, feat_pauth_lr),
	NEEDS_FEAT(HCRX_EL2_EnFPM, FEAT_FPMR),
@@ -833,6 +931,10 @@ static const struct reg_bits_to_feat_map hcrx_feat_map[] = {
	NEEDS_FEAT(HCRX_EL2_EnAS0, FEAT_LS64_ACCDATA),
};


static const DECLARE_FEAT_MAP(hcrx_desc, __HCRX_EL2,
			      hcrx_feat_map, FEAT_HCX);

static const struct reg_bits_to_feat_map hcr_feat_map[] = {
	NEEDS_FEAT(HCR_EL2_TID0, FEAT_AA32EL0),
	NEEDS_FEAT_FIXED(HCR_EL2_RW, compute_hcr_rw),
@@ -904,6 +1006,9 @@ static const struct reg_bits_to_feat_map hcr_feat_map[] = {
	NEEDS_FEAT_FIXED(HCR_EL2_E2H, compute_hcr_e2h),
};

static const DECLARE_FEAT_MAP(hcr_desc, HCR_EL2,
			      hcr_feat_map, FEAT_AA64EL2);

static const struct reg_bits_to_feat_map sctlr2_feat_map[] = {
	NEEDS_FEAT(SCTLR2_EL1_NMEA	|
		   SCTLR2_EL1_EASE,
@@ -921,6 +1026,9 @@ static const struct reg_bits_to_feat_map sctlr2_feat_map[] = {
		   FEAT_CPA2),
};

static const DECLARE_FEAT_MAP(sctlr2_desc, SCTLR2_EL1,
			      sctlr2_feat_map, FEAT_SCTLR2);

static const struct reg_bits_to_feat_map tcr2_el2_feat_map[] = {
	NEEDS_FEAT(TCR2_EL2_FNG1	|
		   TCR2_EL2_FNG0	|
@@ -943,6 +1051,9 @@ static const struct reg_bits_to_feat_map tcr2_el2_feat_map[] = {
	NEEDS_FEAT(TCR2_EL2_PIE, FEAT_S1PIE),
};

static const DECLARE_FEAT_MAP(tcr2_el2_desc, TCR2_EL2,
			      tcr2_el2_feat_map, FEAT_TCR2);

static const struct reg_bits_to_feat_map sctlr_el1_feat_map[] = {
	NEEDS_FEAT(SCTLR_EL1_CP15BEN	|
		   SCTLR_EL1_ITD	|
@@ -1017,6 +1128,9 @@ static const struct reg_bits_to_feat_map sctlr_el1_feat_map[] = {
		   FEAT_AA64EL1),
};

static const DECLARE_FEAT_MAP(sctlr_el1_desc, SCTLR_EL1,
			      sctlr_el1_feat_map, FEAT_AA64EL1);

static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
	NEEDS_FEAT(MDCR_EL2_EBWE, FEAT_Debugv8p9),
	NEEDS_FEAT(MDCR_EL2_TDOSA, FEAT_DoubleLock),
@@ -1048,6 +1162,9 @@ static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
		   FEAT_AA64EL1),
};

static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
			      mdcr_el2_feat_map, FEAT_AA64EL2);

static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
				  int map_size, u64 res0, const char *str)
{
@@ -1061,32 +1178,36 @@ static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
			str, mask ^ ~res0);
}

static u64 reg_feat_map_bits(const struct reg_bits_to_feat_map *map)
{
	return map->flags & RES0_POINTER ? ~(*map->res0p) : map->bits;
}

static void __init check_reg_desc(const struct reg_feat_map_desc *r)
{
	check_feat_map(r->bit_feat_map, r->bit_feat_map_sz,
		       ~reg_feat_map_bits(&r->feat_map), r->name);
}

void __init check_feature_map(void)
{
	check_feat_map(hfgrtr_feat_map, ARRAY_SIZE(hfgrtr_feat_map),
		       hfgrtr_masks.res0, hfgrtr_masks.str);
	check_feat_map(hfgwtr_feat_map, ARRAY_SIZE(hfgwtr_feat_map),
		       hfgwtr_masks.res0, hfgwtr_masks.str);
	check_feat_map(hfgitr_feat_map, ARRAY_SIZE(hfgitr_feat_map),
		       hfgitr_masks.res0, hfgitr_masks.str);
	check_feat_map(hdfgrtr_feat_map, ARRAY_SIZE(hdfgrtr_feat_map),
		       hdfgrtr_masks.res0, hdfgrtr_masks.str);
	check_feat_map(hdfgwtr_feat_map, ARRAY_SIZE(hdfgwtr_feat_map),
		       hdfgwtr_masks.res0, hdfgwtr_masks.str);
	check_feat_map(hafgrtr_feat_map, ARRAY_SIZE(hafgrtr_feat_map),
		       hafgrtr_masks.res0, hafgrtr_masks.str);
	check_feat_map(hcrx_feat_map, ARRAY_SIZE(hcrx_feat_map),
		       __HCRX_EL2_RES0, "HCRX_EL2");
	check_feat_map(hcr_feat_map, ARRAY_SIZE(hcr_feat_map),
		       HCR_EL2_RES0, "HCR_EL2");
	check_feat_map(sctlr2_feat_map, ARRAY_SIZE(sctlr2_feat_map),
		       SCTLR2_EL1_RES0, "SCTLR2_EL1");
	check_feat_map(tcr2_el2_feat_map, ARRAY_SIZE(tcr2_el2_feat_map),
		       TCR2_EL2_RES0, "TCR2_EL2");
	check_feat_map(sctlr_el1_feat_map, ARRAY_SIZE(sctlr_el1_feat_map),
		       SCTLR_EL1_RES0, "SCTLR_EL1");
	check_feat_map(mdcr_el2_feat_map, ARRAY_SIZE(mdcr_el2_feat_map),
		       MDCR_EL2_RES0, "MDCR_EL2");
	check_reg_desc(&hfgrtr_desc);
	check_reg_desc(&hfgwtr_desc);
	check_reg_desc(&hfgitr_desc);
	check_reg_desc(&hdfgrtr_desc);
	check_reg_desc(&hdfgwtr_desc);
	check_reg_desc(&hafgrtr_desc);
	check_reg_desc(&hfgrtr2_desc);
	check_reg_desc(&hfgwtr2_desc);
	check_reg_desc(&hfgitr2_desc);
	check_reg_desc(&hdfgrtr2_desc);
	check_reg_desc(&hdfgwtr2_desc);
	check_reg_desc(&hcrx_desc);
	check_reg_desc(&hcr_desc);
	check_reg_desc(&sctlr2_desc);
	check_reg_desc(&tcr2_el2_desc);
	check_reg_desc(&sctlr_el1_desc);
	check_reg_desc(&mdcr_el2_desc);
}

static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
@@ -1129,7 +1250,7 @@ static u64 __compute_fixed_bits(struct kvm *kvm,
			match = idreg_feat_match(kvm, &map[i]);

		if (!match || (map[i].flags & FIXED_VALUE))
			val |= map[i].bits;
			val |= reg_feat_map_bits(&map[i]);
	}

	return val;
@@ -1145,15 +1266,36 @@ static u64 compute_res0_bits(struct kvm *kvm,
				    require, exclude | FIXED_VALUE);
}

static u64 compute_fixed_bits(struct kvm *kvm,
			      const struct reg_bits_to_feat_map *map,
			      int map_size,
			      u64 *fixed_bits,
			      unsigned long require,
static u64 compute_reg_res0_bits(struct kvm *kvm,
				 const struct reg_feat_map_desc *r,
				 unsigned long require, unsigned long exclude)

{
	u64 res0;

	res0 = compute_res0_bits(kvm, r->bit_feat_map, r->bit_feat_map_sz,
				 require, exclude);

	/*
	 * If computing FGUs, don't take RES0 or register existence
	 * into account -- we're not computing bits for the register
	 * itself.
	 */
	if (!(exclude & NEVER_FGU)) {
		res0 |= compute_res0_bits(kvm, &r->feat_map, 1, require, exclude);
		res0 |= ~reg_feat_map_bits(&r->feat_map);
	}

	return res0;
}

static u64 compute_reg_fixed_bits(struct kvm *kvm,
				  const struct reg_feat_map_desc *r,
				  u64 *fixed_bits, unsigned long require,
				  unsigned long exclude)
{
	return __compute_fixed_bits(kvm, map, map_size, fixed_bits,
				    require | FIXED_VALUE, exclude);
	return __compute_fixed_bits(kvm, r->bit_feat_map, r->bit_feat_map_sz,
				    fixed_bits, require | FIXED_VALUE, exclude);
}

void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt)
@@ -1162,50 +1304,39 @@ void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt)

	switch (fgt) {
	case HFGRTR_GROUP:
		val |= compute_res0_bits(kvm, hfgrtr_feat_map,
					 ARRAY_SIZE(hfgrtr_feat_map),
		val |= compute_reg_res0_bits(kvm, &hfgrtr_desc,
					     0, NEVER_FGU);
		val |= compute_res0_bits(kvm, hfgwtr_feat_map,
					 ARRAY_SIZE(hfgwtr_feat_map),
		val |= compute_reg_res0_bits(kvm, &hfgwtr_desc,
					     0, NEVER_FGU);
		break;
	case HFGITR_GROUP:
		val |= compute_res0_bits(kvm, hfgitr_feat_map,
					 ARRAY_SIZE(hfgitr_feat_map),
		val |= compute_reg_res0_bits(kvm, &hfgitr_desc,
					     0, NEVER_FGU);
		break;
	case HDFGRTR_GROUP:
		val |= compute_res0_bits(kvm, hdfgrtr_feat_map,
					 ARRAY_SIZE(hdfgrtr_feat_map),
		val |= compute_reg_res0_bits(kvm, &hdfgrtr_desc,
					     0, NEVER_FGU);
		val |= compute_res0_bits(kvm, hdfgwtr_feat_map,
					 ARRAY_SIZE(hdfgwtr_feat_map),
		val |= compute_reg_res0_bits(kvm, &hdfgwtr_desc,
					     0, NEVER_FGU);
		break;
	case HAFGRTR_GROUP:
		val |= compute_res0_bits(kvm, hafgrtr_feat_map,
					 ARRAY_SIZE(hafgrtr_feat_map),
		val |= compute_reg_res0_bits(kvm, &hafgrtr_desc,
					     0, NEVER_FGU);
		break;
	case HFGRTR2_GROUP:
		val |= compute_res0_bits(kvm, hfgrtr2_feat_map,
					 ARRAY_SIZE(hfgrtr2_feat_map),
		val |= compute_reg_res0_bits(kvm, &hfgrtr2_desc,
					     0, NEVER_FGU);
		val |= compute_res0_bits(kvm, hfgwtr2_feat_map,
					 ARRAY_SIZE(hfgwtr2_feat_map),
		val |= compute_reg_res0_bits(kvm, &hfgwtr2_desc,
					     0, NEVER_FGU);
		break;
	case HFGITR2_GROUP:
		val |= compute_res0_bits(kvm, hfgitr2_feat_map,
					 ARRAY_SIZE(hfgitr2_feat_map),
		val |= compute_reg_res0_bits(kvm, &hfgitr2_desc,
					     0, NEVER_FGU);
		break;
	case HDFGRTR2_GROUP:
		val |= compute_res0_bits(kvm, hdfgrtr2_feat_map,
					 ARRAY_SIZE(hdfgrtr2_feat_map),
		val |= compute_reg_res0_bits(kvm, &hdfgrtr2_desc,
					     0, NEVER_FGU);
		val |= compute_res0_bits(kvm, hdfgwtr2_feat_map,
					 ARRAY_SIZE(hdfgwtr2_feat_map),
		val |= compute_reg_res0_bits(kvm, &hdfgwtr2_desc,
					     0, NEVER_FGU);
		break;
	default:
@@ -1221,109 +1352,74 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r

	switch (reg) {
	case HFGRTR_EL2:
		*res0 = compute_res0_bits(kvm, hfgrtr_feat_map,
					  ARRAY_SIZE(hfgrtr_feat_map), 0, 0);
		*res0 |= hfgrtr_masks.res0;
		*res0 = compute_reg_res0_bits(kvm, &hfgrtr_desc, 0, 0);
		*res1 = HFGRTR_EL2_RES1;
		break;
	case HFGWTR_EL2:
		*res0 = compute_res0_bits(kvm, hfgwtr_feat_map,
					  ARRAY_SIZE(hfgwtr_feat_map), 0, 0);
		*res0 |= hfgwtr_masks.res0;
		*res0 = compute_reg_res0_bits(kvm, &hfgwtr_desc, 0, 0);
		*res1 = HFGWTR_EL2_RES1;
		break;
	case HFGITR_EL2:
		*res0 = compute_res0_bits(kvm, hfgitr_feat_map,
					  ARRAY_SIZE(hfgitr_feat_map), 0, 0);
		*res0 |= hfgitr_masks.res0;
		*res0 = compute_reg_res0_bits(kvm, &hfgitr_desc, 0, 0);
		*res1 = HFGITR_EL2_RES1;
		break;
	case HDFGRTR_EL2:
		*res0 = compute_res0_bits(kvm, hdfgrtr_feat_map,
					  ARRAY_SIZE(hdfgrtr_feat_map), 0, 0);
		*res0 |= hdfgrtr_masks.res0;
		*res0 = compute_reg_res0_bits(kvm, &hdfgrtr_desc, 0, 0);
		*res1 = HDFGRTR_EL2_RES1;
		break;
	case HDFGWTR_EL2:
		*res0 = compute_res0_bits(kvm, hdfgwtr_feat_map,
					  ARRAY_SIZE(hdfgwtr_feat_map), 0, 0);
		*res0 |= hdfgwtr_masks.res0;
		*res0 = compute_reg_res0_bits(kvm, &hdfgwtr_desc, 0, 0);
		*res1 = HDFGWTR_EL2_RES1;
		break;
	case HAFGRTR_EL2:
		*res0 = compute_res0_bits(kvm, hafgrtr_feat_map,
					  ARRAY_SIZE(hafgrtr_feat_map), 0, 0);
		*res0 |= hafgrtr_masks.res0;
		*res0 = compute_reg_res0_bits(kvm, &hafgrtr_desc, 0, 0);
		*res1 = HAFGRTR_EL2_RES1;
		break;
	case HFGRTR2_EL2:
		*res0 = compute_res0_bits(kvm, hfgrtr2_feat_map,
					  ARRAY_SIZE(hfgrtr2_feat_map), 0, 0);
		*res0 |= hfgrtr2_masks.res0;
		*res0 = compute_reg_res0_bits(kvm, &hfgrtr2_desc, 0, 0);
		*res1 = HFGRTR2_EL2_RES1;
		break;
	case HFGWTR2_EL2:
		*res0 = compute_res0_bits(kvm, hfgwtr2_feat_map,
					  ARRAY_SIZE(hfgwtr2_feat_map), 0, 0);
		*res0 |= hfgwtr2_masks.res0;
		*res0 = compute_reg_res0_bits(kvm, &hfgwtr2_desc, 0, 0);
		*res1 = HFGWTR2_EL2_RES1;
		break;
	case HFGITR2_EL2:
		*res0 = compute_res0_bits(kvm, hfgitr2_feat_map,
					  ARRAY_SIZE(hfgitr2_feat_map), 0, 0);
		*res0 |= hfgitr2_masks.res0;
		*res0 = compute_reg_res0_bits(kvm, &hfgitr2_desc, 0, 0);
		*res1 = HFGITR2_EL2_RES1;
		break;
	case HDFGRTR2_EL2:
		*res0 = compute_res0_bits(kvm, hdfgrtr2_feat_map,
					  ARRAY_SIZE(hdfgrtr2_feat_map), 0, 0);
		*res0 |= hdfgrtr2_masks.res0;
		*res0 = compute_reg_res0_bits(kvm, &hdfgrtr2_desc, 0, 0);
		*res1 = HDFGRTR2_EL2_RES1;
		break;
	case HDFGWTR2_EL2:
		*res0 = compute_res0_bits(kvm, hdfgwtr2_feat_map,
					  ARRAY_SIZE(hdfgwtr2_feat_map), 0, 0);
		*res0 |= hdfgwtr2_masks.res0;
		*res0 = compute_reg_res0_bits(kvm, &hdfgwtr2_desc, 0, 0);
		*res1 = HDFGWTR2_EL2_RES1;
		break;
	case HCRX_EL2:
		*res0 = compute_res0_bits(kvm, hcrx_feat_map,
					  ARRAY_SIZE(hcrx_feat_map), 0, 0);
		*res0 |= __HCRX_EL2_RES0;
		*res0 = compute_reg_res0_bits(kvm, &hcrx_desc, 0, 0);
		*res1 = __HCRX_EL2_RES1;
		break;
	case HCR_EL2:
		mask = compute_fixed_bits(kvm, hcr_feat_map,
					  ARRAY_SIZE(hcr_feat_map), &fixed,
					  0, 0);
		*res0 = compute_res0_bits(kvm, hcr_feat_map,
					  ARRAY_SIZE(hcr_feat_map), 0, 0);
		*res0 |= HCR_EL2_RES0 | (mask & ~fixed);
		mask = compute_reg_fixed_bits(kvm, &hcr_desc, &fixed, 0, 0);
		*res0 = compute_reg_res0_bits(kvm, &hcr_desc, 0, 0);
		*res0 |= (mask & ~fixed);
		*res1 = HCR_EL2_RES1 | (mask & fixed);
		break;
	case SCTLR2_EL1:
	case SCTLR2_EL2:
		*res0 = compute_res0_bits(kvm, sctlr2_feat_map,
					  ARRAY_SIZE(sctlr2_feat_map), 0, 0);
		*res0 |= SCTLR2_EL1_RES0;
		*res0 = compute_reg_res0_bits(kvm, &sctlr2_desc, 0, 0);
		*res1 = SCTLR2_EL1_RES1;
		break;
	case TCR2_EL2:
		*res0 = compute_res0_bits(kvm, tcr2_el2_feat_map,
					  ARRAY_SIZE(tcr2_el2_feat_map), 0, 0);
		*res0 |= TCR2_EL2_RES0;
		*res0 = compute_reg_res0_bits(kvm, &tcr2_el2_desc, 0, 0);
		*res1 = TCR2_EL2_RES1;
		break;
	case SCTLR_EL1:
		*res0 = compute_res0_bits(kvm, sctlr_el1_feat_map,
					  ARRAY_SIZE(sctlr_el1_feat_map), 0, 0);
		*res0 |= SCTLR_EL1_RES0;
		*res0 = compute_reg_res0_bits(kvm, &sctlr_el1_desc, 0, 0);
		*res1 = SCTLR_EL1_RES1;
		break;
	case MDCR_EL2:
		*res0 = compute_res0_bits(kvm, mdcr_el2_feat_map,
					  ARRAY_SIZE(mdcr_el2_feat_map), 0, 0);
		*res0 |= MDCR_EL2_RES0;
		*res0 = compute_reg_res0_bits(kvm, &mdcr_el2_desc, 0, 0);
		*res1 = MDCR_EL2_RES1;
		break;
	default:
+7 −0
Original line number Diff line number Diff line
@@ -95,6 +95,13 @@ static u64 __compute_hcr(struct kvm_vcpu *vcpu)
			/* Force NV2 in case the guest is forgetful... */
			guest_hcr |= HCR_NV2;
		}

		/*
		 * Exclude the guest's TWED configuration if it hasn't set TWE
		 * to avoid potentially delaying traps for the host.
		 */
		if (!(guest_hcr & HCR_TWE))
			guest_hcr &= ~(HCR_EL2_TWEDEn | HCR_EL2_TWEDEL);
	}

	BUG_ON(host_data_test_flag(VCPU_IN_HYP_CONTEXT) &&
+31 −17
Original line number Diff line number Diff line
@@ -1462,9 +1462,16 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val)

	case SYS_ID_AA64PFR1_EL1:
		/* Only support BTI, SSBS, CSV2_frac */
		val &= (ID_AA64PFR1_EL1_BT	|
			ID_AA64PFR1_EL1_SSBS	|
			ID_AA64PFR1_EL1_CSV2_frac);
		val &= ~(ID_AA64PFR1_EL1_PFAR		|
			 ID_AA64PFR1_EL1_MTEX		|
			 ID_AA64PFR1_EL1_THE		|
			 ID_AA64PFR1_EL1_GCS		|
			 ID_AA64PFR1_EL1_MTE_frac	|
			 ID_AA64PFR1_EL1_NMI		|
			 ID_AA64PFR1_EL1_SME		|
			 ID_AA64PFR1_EL1_RES0		|
			 ID_AA64PFR1_EL1_MPAM_frac	|
			 ID_AA64PFR1_EL1_MTE);
		break;

	case SYS_ID_AA64MMFR0_EL1:
@@ -1517,12 +1524,11 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val)
		break;

	case SYS_ID_AA64MMFR1_EL1:
		val &= (ID_AA64MMFR1_EL1_HCX	|
			ID_AA64MMFR1_EL1_PAN	|
			ID_AA64MMFR1_EL1_LO	|
			ID_AA64MMFR1_EL1_HPDS	|
			ID_AA64MMFR1_EL1_VH	|
			ID_AA64MMFR1_EL1_VMIDBits);
		val &= ~(ID_AA64MMFR1_EL1_CMOW		|
			 ID_AA64MMFR1_EL1_nTLBPA	|
			 ID_AA64MMFR1_EL1_ETS		|
			 ID_AA64MMFR1_EL1_XNX		|
			 ID_AA64MMFR1_EL1_HAFDBS);
		/* FEAT_E2H0 implies no VHE */
		if (test_bit(KVM_ARM_VCPU_HAS_EL2_E2H0, kvm->arch.vcpu_features))
			val &= ~ID_AA64MMFR1_EL1_VH;
@@ -1564,14 +1570,22 @@ u64 limit_nv_id_reg(struct kvm *kvm, u32 reg, u64 val)

	case SYS_ID_AA64DFR0_EL1:
		/* Only limited support for PMU, Debug, BPs, WPs, and HPMN0 */
		val &= (ID_AA64DFR0_EL1_PMUVer	|
			ID_AA64DFR0_EL1_WRPs	|
			ID_AA64DFR0_EL1_BRPs	|
			ID_AA64DFR0_EL1_DebugVer|
			ID_AA64DFR0_EL1_HPMN0);

		/* Cap Debug to ARMv8.1 */
		val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, VHE);
		val &= ~(ID_AA64DFR0_EL1_ExtTrcBuff	|
			 ID_AA64DFR0_EL1_BRBE		|
			 ID_AA64DFR0_EL1_MTPMU		|
			 ID_AA64DFR0_EL1_TraceBuffer	|
			 ID_AA64DFR0_EL1_TraceFilt	|
			 ID_AA64DFR0_EL1_PMSVer		|
			 ID_AA64DFR0_EL1_CTX_CMPs	|
			 ID_AA64DFR0_EL1_SEBEP		|
			 ID_AA64DFR0_EL1_PMSS		|
			 ID_AA64DFR0_EL1_TraceVer);

		/*
		 * FEAT_Debugv8p9 requires support for extended breakpoints /
		 * watchpoints.
		 */
		val = ID_REG_LIMIT_FIELD_ENUM(val, ID_AA64DFR0_EL1, DebugVer, V8P8);
		break;
	}

+25 −2
Original line number Diff line number Diff line
@@ -1997,6 +1997,26 @@ static u64 sanitise_id_aa64dfr0_el1(const struct kvm_vcpu *vcpu, u64 val)
	return val;
}

/*
 * Older versions of KVM erroneously claim support for FEAT_DoubleLock with
 * NV-enabled VMs on unsupporting hardware. Silently ignore the incorrect
 * value if it is consistent with the bug.
 */
static bool ignore_feat_doublelock(struct kvm_vcpu *vcpu, u64 val)
{
	u8 host, user;

	if (!vcpu_has_nv(vcpu))
		return false;

	host = SYS_FIELD_GET(ID_AA64DFR0_EL1, DoubleLock,
			     read_sanitised_ftr_reg(SYS_ID_AA64DFR0_EL1));
	user = SYS_FIELD_GET(ID_AA64DFR0_EL1, DoubleLock, val);

	return host == ID_AA64DFR0_EL1_DoubleLock_NI &&
	       user == ID_AA64DFR0_EL1_DoubleLock_IMP;
}

static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
			       const struct sys_reg_desc *rd,
			       u64 val)
@@ -2028,6 +2048,11 @@ static int set_id_aa64dfr0_el1(struct kvm_vcpu *vcpu,
	if (debugver < ID_AA64DFR0_EL1_DebugVer_IMP)
		return -EINVAL;

	if (ignore_feat_doublelock(vcpu, val)) {
		val &= ~ID_AA64DFR0_EL1_DoubleLock;
		val |= SYS_FIELD_PREP_ENUM(ID_AA64DFR0_EL1, DoubleLock, NI);
	}

	return set_id_reg(vcpu, rd, val);
}

@@ -3152,8 +3177,6 @@ static const struct sys_reg_desc sys_reg_descs[] = {
				      ~(ID_AA64MMFR0_EL1_RES0 |
					ID_AA64MMFR0_EL1_ASIDBITS)),
	ID_WRITABLE(ID_AA64MMFR1_EL1, ~(ID_AA64MMFR1_EL1_RES0 |
					ID_AA64MMFR1_EL1_HCX |
					ID_AA64MMFR1_EL1_TWED |
					ID_AA64MMFR1_EL1_XNX |
					ID_AA64MMFR1_EL1_VH |
					ID_AA64MMFR1_EL1_VMIDBits)),
+2 −0
Original line number Diff line number Diff line
@@ -165,7 +165,9 @@ static const struct reg_ftr_bits ftr_id_aa64mmfr0_el1[] = {
static const struct reg_ftr_bits ftr_id_aa64mmfr1_el1[] = {
	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, TIDCP1, 0),
	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, AFP, 0),
	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, HCX, 0),
	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, ETS, 0),
	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, TWED, 0),
	REG_FTR_BITS(FTR_HIGHER_SAFE, ID_AA64MMFR1_EL1, SpecSEI, 0),
	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, PAN, 0),
	REG_FTR_BITS(FTR_LOWER_SAFE, ID_AA64MMFR1_EL1, LO, 0),