[PATCH v4 31/43] KVM: arm64: Switch to table-driven FGU configuration

Joey Gouly joey.gouly at arm.com
Thu May 8 08:58:28 PDT 2025


On Tue, May 06, 2025 at 05:43:36PM +0100, Marc Zyngier wrote:
> Defining the FGU behaviour is extremely tedious. It relies on matching
> each set of bits from FGT registers with am architectural feature, and
> adding them to the FGU list if the corresponding feature isn't advertised
> to the guest.
> 
> It is however relatively easy to dump most of that information from
> the architecture JSON description, and use that to control the FGU bits.
> 
> Let's introduce a new set of tables descripbing the mapping between
> FGT bits and features. Most of the time, this is only a lookup in
> an idreg field, with a few more complex exceptions.
> 
> While this is obviously many more lines in a new file, this is
> mostly generated, and is pretty easy to maintain.

I didn't review every single value in the maps (autogenerated as you said), but
I did take a look at a few.

__compute_fixed_bits() is pretty confusing, it's doing multiple things:
  - It returns a mask of bits that didn't match (aka RES0)
  - or it returns a mask of bits that may have a fixed value and fills out a
    pointer with what the fixed values are.

It has the __ prefix, so it's an implemetation-detail kinda function, not
asking you to change anything, just pointing out the most confusing part of the
patch!

Just one small whitespace nit below.

Reviewed-by: Joey Gouly <joey.gouly at arm.com>

> 
> Signed-off-by: Marc Zyngier <maz at kernel.org>
> ---
>  arch/arm64/include/asm/kvm_host.h |   2 +
>  arch/arm64/kvm/Makefile           |   2 +-
>  arch/arm64/kvm/config.c           | 589 ++++++++++++++++++++++++++++++
>  arch/arm64/kvm/sys_regs.c         |  73 +---
>  4 files changed, 596 insertions(+), 70 deletions(-)
>  create mode 100644 arch/arm64/kvm/config.c
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index 9e5164fad0dbc..9386f15cdc252 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -1610,4 +1610,6 @@ void kvm_set_vm_id_reg(struct kvm *kvm, u32 reg, u64 val);
>  #define kvm_has_s1poe(k)				\
>  	(kvm_has_feat((k), ID_AA64MMFR3_EL1, S1POE, IMP))
>  
> +void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt);
> +
>  #endif /* __ARM64_KVM_HOST_H__ */
> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
> index 209bc76263f10..7c329e01c557a 100644
> --- a/arch/arm64/kvm/Makefile
> +++ b/arch/arm64/kvm/Makefile
> @@ -14,7 +14,7 @@ CFLAGS_sys_regs.o += -Wno-override-init
>  CFLAGS_handle_exit.o += -Wno-override-init
>  
>  kvm-y += arm.o mmu.o mmio.o psci.o hypercalls.o pvtime.o \
> -	 inject_fault.o va_layout.o handle_exit.o \
> +	 inject_fault.o va_layout.o handle_exit.o config.o \
>  	 guest.o debug.o reset.o sys_regs.o stacktrace.o \
>  	 vgic-sys-reg-v3.o fpsimd.o pkvm.o \
>  	 arch_timer.o trng.o vmid.o emulate-nested.o nested.o at.o \
> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> new file mode 100644
> index 0000000000000..85350b883abf7
> --- /dev/null
> +++ b/arch/arm64/kvm/config.c
> @@ -0,0 +1,589 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2025 Google LLC
> + * Author: Marc Zyngier <maz at kernel.org>
> + */
> +
> +#include <linux/kvm_host.h>
> +#include <asm/sysreg.h>
> +
> +struct reg_bits_to_feat_map {
> +	u64		bits;
> +
> +#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 */
> +	unsigned long	flags;
> +
> +	union {
> +		struct {
> +			u8	regidx;
> +			u8	shift;
> +			u8	width;
> +			bool	sign;
> +			s8	lo_lim;
> +		};
> +		bool	(*match)(struct kvm *);
> +		bool	(*fval)(struct kvm *, u64 *);
> +	};
> +};
> +
> +#define __NEEDS_FEAT_3(m, f, id, fld, lim)		\
> +	{						\
> +		.bits	= (m),				\
> +		.flags = (f),				\
> +		.regidx	= IDREG_IDX(SYS_ ## id),	\
> +		.shift	= id ##_## fld ## _SHIFT,	\
> +		.width	= id ##_## fld ## _WIDTH,	\
> +		.sign	= id ##_## fld ## _SIGNED,	\
> +		.lo_lim	= id ##_## fld ##_## lim	\
> +	}
> +
> +#define __NEEDS_FEAT_2(m, f, fun, dummy)		\
> +	{						\
> +		.bits	= (m),				\
> +		.flags = (f) | CALL_FUNC,		\
> +		.fval = (fun),				\
> +	}
> +
> +#define __NEEDS_FEAT_1(m, f, fun)			\
> +	{						\
> +		.bits	= (m),				\
> +		.flags = (f) | CALL_FUNC,		\
> +		.match = (fun),				\
> +	}
> +
> +#define NEEDS_FEAT_FLAG(m, f, ...)			\
> +	CONCATENATE(__NEEDS_FEAT_, COUNT_ARGS(__VA_ARGS__))(m, f, __VA_ARGS__)
> +
> +#define NEEDS_FEAT_FIXED(m, ...)			\
> +	NEEDS_FEAT_FLAG(m, FIXED_VALUE, __VA_ARGS__, 0)
> +
> +#define NEEDS_FEAT(m, ...)	NEEDS_FEAT_FLAG(m, 0, __VA_ARGS__)
> +
> +#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
> +#define FEAT_TRC_SR		ID_AA64DFR0_EL1, TraceVer, IMP
> +#define FEAT_PMUv3		ID_AA64DFR0_EL1, PMUVer, IMP
> +#define FEAT_TRBE		ID_AA64DFR0_EL1, TraceBuffer, IMP
> +#define FEAT_DoubleLock		ID_AA64DFR0_EL1, DoubleLock, IMP
> +#define FEAT_TRF		ID_AA64DFR0_EL1, TraceFilt, IMP
> +#define FEAT_AA64EL1		ID_AA64PFR0_EL1, EL1, IMP
> +#define FEAT_AIE		ID_AA64MMFR3_EL1, AIE, IMP
> +#define FEAT_S2POE		ID_AA64MMFR3_EL1, S2POE, IMP
> +#define FEAT_S1POE		ID_AA64MMFR3_EL1, S1POE, IMP
> +#define FEAT_S1PIE		ID_AA64MMFR3_EL1, S1PIE, IMP
> +#define FEAT_THE		ID_AA64PFR1_EL1, THE, IMP
> +#define FEAT_SME		ID_AA64PFR1_EL1, SME, IMP
> +#define FEAT_GCS		ID_AA64PFR1_EL1, GCS, IMP
> +#define FEAT_LS64_ACCDATA	ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA
> +#define FEAT_RAS		ID_AA64PFR0_EL1, RAS, IMP
> +#define FEAT_GICv3		ID_AA64PFR0_EL1, GIC, IMP
> +#define FEAT_LOR		ID_AA64MMFR1_EL1, LO, IMP
> +#define FEAT_SPEv1p5		ID_AA64DFR0_EL1, PMSVer, V1P5
> +#define FEAT_ATS1A		ID_AA64ISAR2_EL1, ATS1A, IMP
> +#define FEAT_SPECRES2		ID_AA64ISAR1_EL1, SPECRES, COSP_RCTX
> +#define FEAT_SPECRES		ID_AA64ISAR1_EL1, SPECRES, IMP
> +#define FEAT_TLBIRANGE		ID_AA64ISAR0_EL1, TLB, RANGE
> +#define FEAT_TLBIOS		ID_AA64ISAR0_EL1, TLB, OS
> +#define FEAT_PAN2		ID_AA64MMFR1_EL1, PAN, PAN2
> +#define FEAT_DPB2		ID_AA64ISAR1_EL1, DPB, DPB2
> +#define FEAT_AMUv1		ID_AA64PFR0_EL1, AMU, IMP
> +
> +static bool feat_rasv1p1(struct kvm *kvm)
> +{
> +	return (kvm_has_feat(kvm, ID_AA64PFR0_EL1, RAS, V1P1) ||
> +		(kvm_has_feat_enum(kvm, ID_AA64PFR0_EL1, RAS, IMP) &&
> +		 kvm_has_feat(kvm, ID_AA64PFR1_EL1, RAS_frac, RASv1p1)));
> +}
> +
> +static bool feat_csv2_2_csv2_1p2(struct kvm *kvm)
> +{
> +	return (kvm_has_feat(kvm,  ID_AA64PFR0_EL1, CSV2, CSV2_2) ||
> +		(kvm_has_feat(kvm, ID_AA64PFR1_EL1, CSV2_frac, CSV2_1p2) &&
> +		 kvm_has_feat_enum(kvm,  ID_AA64PFR0_EL1, CSV2, IMP)));
> +}
> +
> +static bool feat_pauth(struct kvm *kvm)
> +{
> +	return kvm_has_pauth(kvm, PAuth);
> +}
> +
> +static const struct reg_bits_to_feat_map hfgrtr_feat_map[] = {
> +	NEEDS_FEAT(HFGRTR_EL2_nAMAIR2_EL1	|
> +		   HFGRTR_EL2_nMAIR2_EL1,
> +		   FEAT_AIE),
> +	NEEDS_FEAT(HFGRTR_EL2_nS2POR_EL1, FEAT_S2POE),
> +	NEEDS_FEAT(HFGRTR_EL2_nPOR_EL1		|
> +		   HFGRTR_EL2_nPOR_EL0,
> +		   FEAT_S1POE),
> +	NEEDS_FEAT(HFGRTR_EL2_nPIR_EL1		|
> +		   HFGRTR_EL2_nPIRE0_EL1,
> +		   FEAT_S1PIE),
> +	NEEDS_FEAT(HFGRTR_EL2_nRCWMASK_EL1, FEAT_THE),
> +	NEEDS_FEAT(HFGRTR_EL2_nTPIDR2_EL0	|
> +		   HFGRTR_EL2_nSMPRI_EL1,
> +		   FEAT_SME),
> +	NEEDS_FEAT(HFGRTR_EL2_nGCS_EL1		|
> +		   HFGRTR_EL2_nGCS_EL0,
> +		   FEAT_GCS),
> +	NEEDS_FEAT(HFGRTR_EL2_nACCDATA_EL1, FEAT_LS64_ACCDATA),
> +	NEEDS_FEAT(HFGRTR_EL2_ERXADDR_EL1	|
> +		   HFGRTR_EL2_ERXMISCn_EL1	|
> +		   HFGRTR_EL2_ERXSTATUS_EL1	|
> +		   HFGRTR_EL2_ERXCTLR_EL1	|
> +		   HFGRTR_EL2_ERXFR_EL1		|
> +		   HFGRTR_EL2_ERRSELR_EL1	|
> +		   HFGRTR_EL2_ERRIDR_EL1,
> +		   FEAT_RAS),
> +	NEEDS_FEAT(HFGRTR_EL2_ERXPFGCDN_EL1|
> +		   HFGRTR_EL2_ERXPFGCTL_EL1|

Inconsistent |.

> +		   HFGRTR_EL2_ERXPFGF_EL1,
> +		   feat_rasv1p1),
> +	NEEDS_FEAT(HFGRTR_EL2_ICC_IGRPENn_EL1, FEAT_GICv3),
> +	NEEDS_FEAT(HFGRTR_EL2_SCXTNUM_EL0	|
> +		   HFGRTR_EL2_SCXTNUM_EL1,
> +		   feat_csv2_2_csv2_1p2),
> +	NEEDS_FEAT(HFGRTR_EL2_LORSA_EL1		|
> +		   HFGRTR_EL2_LORN_EL1		|
> +		   HFGRTR_EL2_LORID_EL1		|
> +		   HFGRTR_EL2_LOREA_EL1		|
> +		   HFGRTR_EL2_LORC_EL1,
> +		   FEAT_LOR),
> +	NEEDS_FEAT(HFGRTR_EL2_APIBKey		|
> +		   HFGRTR_EL2_APIAKey		|
> +		   HFGRTR_EL2_APGAKey		|
> +		   HFGRTR_EL2_APDBKey		|
> +		   HFGRTR_EL2_APDAKey,
> +		   feat_pauth),
> +	NEEDS_FEAT_FLAG(HFGRTR_EL2_VBAR_EL1	|
> +			HFGRTR_EL2_TTBR1_EL1	|
> +			HFGRTR_EL2_TTBR0_EL1	|
> +			HFGRTR_EL2_TPIDR_EL0	|
> +			HFGRTR_EL2_TPIDRRO_EL0	|
> +			HFGRTR_EL2_TPIDR_EL1	|
> +			HFGRTR_EL2_TCR_EL1	|
> +			HFGRTR_EL2_SCTLR_EL1	|
> +			HFGRTR_EL2_REVIDR_EL1	|
> +			HFGRTR_EL2_PAR_EL1	|
> +			HFGRTR_EL2_MPIDR_EL1	|
> +			HFGRTR_EL2_MIDR_EL1	|
> +			HFGRTR_EL2_MAIR_EL1	|
> +			HFGRTR_EL2_ISR_EL1	|
> +			HFGRTR_EL2_FAR_EL1	|
> +			HFGRTR_EL2_ESR_EL1	|
> +			HFGRTR_EL2_DCZID_EL0	|
> +			HFGRTR_EL2_CTR_EL0	|
> +			HFGRTR_EL2_CSSELR_EL1	|
> +			HFGRTR_EL2_CPACR_EL1	|
> +			HFGRTR_EL2_CONTEXTIDR_EL1|
> +			HFGRTR_EL2_CLIDR_EL1	|
> +			HFGRTR_EL2_CCSIDR_EL1	|
> +			HFGRTR_EL2_AMAIR_EL1	|
> +			HFGRTR_EL2_AIDR_EL1	|
> +			HFGRTR_EL2_AFSR1_EL1	|
> +			HFGRTR_EL2_AFSR0_EL1,
> +			NEVER_FGU, FEAT_AA64EL1),
> +};
> +
> +static const struct reg_bits_to_feat_map hfgwtr_feat_map[] = {
> +	NEEDS_FEAT(HFGWTR_EL2_nAMAIR2_EL1	|
> +		   HFGWTR_EL2_nMAIR2_EL1,
> +		   FEAT_AIE),
> +	NEEDS_FEAT(HFGWTR_EL2_nS2POR_EL1, FEAT_S2POE),
> +	NEEDS_FEAT(HFGWTR_EL2_nPOR_EL1		|
> +		   HFGWTR_EL2_nPOR_EL0,
> +		   FEAT_S1POE),
> +	NEEDS_FEAT(HFGWTR_EL2_nPIR_EL1		|
> +		   HFGWTR_EL2_nPIRE0_EL1,
> +		   FEAT_S1PIE),
> +	NEEDS_FEAT(HFGWTR_EL2_nRCWMASK_EL1, FEAT_THE),
> +	NEEDS_FEAT(HFGWTR_EL2_nTPIDR2_EL0	|
> +		   HFGWTR_EL2_nSMPRI_EL1,
> +		   FEAT_SME),
> +	NEEDS_FEAT(HFGWTR_EL2_nGCS_EL1		|
> +		   HFGWTR_EL2_nGCS_EL0,
> +		   FEAT_GCS),
> +	NEEDS_FEAT(HFGWTR_EL2_nACCDATA_EL1, FEAT_LS64_ACCDATA),
> +	NEEDS_FEAT(HFGWTR_EL2_ERXADDR_EL1	|
> +		   HFGWTR_EL2_ERXMISCn_EL1	|
> +		   HFGWTR_EL2_ERXSTATUS_EL1	|
> +		   HFGWTR_EL2_ERXCTLR_EL1	|
> +		   HFGWTR_EL2_ERRSELR_EL1,
> +		   FEAT_RAS),
> +	NEEDS_FEAT(HFGWTR_EL2_ERXPFGCDN_EL1	|
> +		   HFGWTR_EL2_ERXPFGCTL_EL1,
> +		   feat_rasv1p1),
> +	NEEDS_FEAT(HFGWTR_EL2_ICC_IGRPENn_EL1, FEAT_GICv3),
> +	NEEDS_FEAT(HFGWTR_EL2_SCXTNUM_EL0	|
> +		   HFGWTR_EL2_SCXTNUM_EL1,
> +		   feat_csv2_2_csv2_1p2),
> +	NEEDS_FEAT(HFGWTR_EL2_LORSA_EL1		|
> +		   HFGWTR_EL2_LORN_EL1		|
> +		   HFGWTR_EL2_LOREA_EL1		|
> +		   HFGWTR_EL2_LORC_EL1,
> +		   FEAT_LOR),
> +	NEEDS_FEAT(HFGWTR_EL2_APIBKey		|
> +		   HFGWTR_EL2_APIAKey		|
> +		   HFGWTR_EL2_APGAKey		|
> +		   HFGWTR_EL2_APDBKey		|
> +		   HFGWTR_EL2_APDAKey,
> +		   feat_pauth),
> +	NEEDS_FEAT_FLAG(HFGWTR_EL2_VBAR_EL1	|
> +			HFGWTR_EL2_TTBR1_EL1	|
> +			HFGWTR_EL2_TTBR0_EL1	|
> +			HFGWTR_EL2_TPIDR_EL0	|
> +			HFGWTR_EL2_TPIDRRO_EL0	|
> +			HFGWTR_EL2_TPIDR_EL1	|
> +			HFGWTR_EL2_TCR_EL1	|
> +			HFGWTR_EL2_SCTLR_EL1	|
> +			HFGWTR_EL2_PAR_EL1	|
> +			HFGWTR_EL2_MAIR_EL1	|
> +			HFGWTR_EL2_FAR_EL1	|
> +			HFGWTR_EL2_ESR_EL1	|
> +			HFGWTR_EL2_CSSELR_EL1	|
> +			HFGWTR_EL2_CPACR_EL1	|
> +			HFGWTR_EL2_CONTEXTIDR_EL1|
> +			HFGWTR_EL2_AMAIR_EL1	|
> +			HFGWTR_EL2_AFSR1_EL1	|
> +			HFGWTR_EL2_AFSR0_EL1,
> +			NEVER_FGU, FEAT_AA64EL1),
> +};
> +
> +static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = {
> +	NEEDS_FEAT(HDFGRTR_EL2_PMBIDR_EL1	|
> +		   HDFGRTR_EL2_PMSLATFR_EL1	|
> +		   HDFGRTR_EL2_PMSIRR_EL1	|
> +		   HDFGRTR_EL2_PMSIDR_EL1	|
> +		   HDFGRTR_EL2_PMSICR_EL1	|
> +		   HDFGRTR_EL2_PMSFCR_EL1	|
> +		   HDFGRTR_EL2_PMSEVFR_EL1	|
> +		   HDFGRTR_EL2_PMSCR_EL1	|
> +		   HDFGRTR_EL2_PMBSR_EL1	|
> +		   HDFGRTR_EL2_PMBPTR_EL1	|
> +		   HDFGRTR_EL2_PMBLIMITR_EL1,
> +		   FEAT_SPE),
> +	NEEDS_FEAT(HDFGRTR_EL2_nPMSNEVFR_EL1, FEAT_SPE_FnE),
> +	NEEDS_FEAT(HDFGRTR_EL2_nBRBDATA		|
> +		   HDFGRTR_EL2_nBRBCTL		|
> +		   HDFGRTR_EL2_nBRBIDR,
> +		   FEAT_BRBE),
> +	NEEDS_FEAT(HDFGRTR_EL2_TRCVICTLR	|
> +		   HDFGRTR_EL2_TRCSTATR		|
> +		   HDFGRTR_EL2_TRCSSCSRn	|
> +		   HDFGRTR_EL2_TRCSEQSTR	|
> +		   HDFGRTR_EL2_TRCPRGCTLR	|
> +		   HDFGRTR_EL2_TRCOSLSR		|
> +		   HDFGRTR_EL2_TRCIMSPECn	|
> +		   HDFGRTR_EL2_TRCID		|
> +		   HDFGRTR_EL2_TRCCNTVRn	|
> +		   HDFGRTR_EL2_TRCCLAIM		|
> +		   HDFGRTR_EL2_TRCAUXCTLR	|
> +		   HDFGRTR_EL2_TRCAUTHSTATUS	|
> +		   HDFGRTR_EL2_TRC,
> +		   FEAT_TRC_SR),
> +	NEEDS_FEAT(HDFGRTR_EL2_PMCEIDn_EL0	|
> +		   HDFGRTR_EL2_PMUSERENR_EL0	|
> +		   HDFGRTR_EL2_PMMIR_EL1	|
> +		   HDFGRTR_EL2_PMSELR_EL0	|
> +		   HDFGRTR_EL2_PMOVS		|
> +		   HDFGRTR_EL2_PMINTEN		|
> +		   HDFGRTR_EL2_PMCNTEN		|
> +		   HDFGRTR_EL2_PMCCNTR_EL0	|
> +		   HDFGRTR_EL2_PMCCFILTR_EL0	|
> +		   HDFGRTR_EL2_PMEVTYPERn_EL0	|
> +		   HDFGRTR_EL2_PMEVCNTRn_EL0,
> +		   FEAT_PMUv3),
> +	NEEDS_FEAT(HDFGRTR_EL2_TRBTRG_EL1	|
> +		   HDFGRTR_EL2_TRBSR_EL1	|
> +		   HDFGRTR_EL2_TRBPTR_EL1	|
> +		   HDFGRTR_EL2_TRBMAR_EL1	|
> +		   HDFGRTR_EL2_TRBLIMITR_EL1	|
> +		   HDFGRTR_EL2_TRBIDR_EL1	|
> +		   HDFGRTR_EL2_TRBBASER_EL1,
> +		   FEAT_TRBE),
> +	NEEDS_FEAT_FLAG(HDFGRTR_EL2_OSDLR_EL1, NEVER_FGU,
> +			FEAT_DoubleLock),

This confused me at first, but it's because OSDLR_EL1 is always accessible
(with FEAT_AA64EL1), but can only be trapped with FEAT_DoubleLock.

> +	NEEDS_FEAT_FLAG(HDFGRTR_EL2_OSECCR_EL1	|
> +			HDFGRTR_EL2_OSLSR_EL1	|
> +			HDFGRTR_EL2_DBGPRCR_EL1	|
> +			HDFGRTR_EL2_DBGAUTHSTATUS_EL1|
> +			HDFGRTR_EL2_DBGCLAIM	|
> +			HDFGRTR_EL2_MDSCR_EL1	|
> +			HDFGRTR_EL2_DBGWVRn_EL1	|
> +			HDFGRTR_EL2_DBGWCRn_EL1	|
> +			HDFGRTR_EL2_DBGBVRn_EL1	|
> +			HDFGRTR_EL2_DBGBCRn_EL1,
> +			NEVER_FGU, FEAT_AA64EL1)
> +};
> +
> +static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = {
> +	NEEDS_FEAT(HDFGWTR_EL2_PMSLATFR_EL1	|
> +		   HDFGWTR_EL2_PMSIRR_EL1	|
> +		   HDFGWTR_EL2_PMSICR_EL1	|
> +		   HDFGWTR_EL2_PMSFCR_EL1	|
> +		   HDFGWTR_EL2_PMSEVFR_EL1	|
> +		   HDFGWTR_EL2_PMSCR_EL1	|
> +		   HDFGWTR_EL2_PMBSR_EL1	|
> +		   HDFGWTR_EL2_PMBPTR_EL1	|
> +		   HDFGWTR_EL2_PMBLIMITR_EL1,
> +		   FEAT_SPE),
> +	NEEDS_FEAT(HDFGWTR_EL2_nPMSNEVFR_EL1, FEAT_SPE_FnE),
> +	NEEDS_FEAT(HDFGWTR_EL2_nBRBDATA		|
> +		   HDFGWTR_EL2_nBRBCTL,
> +		   FEAT_BRBE),
> +	NEEDS_FEAT(HDFGWTR_EL2_TRCVICTLR	|
> +		   HDFGWTR_EL2_TRCSSCSRn	|
> +		   HDFGWTR_EL2_TRCSEQSTR	|
> +		   HDFGWTR_EL2_TRCPRGCTLR	|
> +		   HDFGWTR_EL2_TRCOSLAR		|
> +		   HDFGWTR_EL2_TRCIMSPECn	|
> +		   HDFGWTR_EL2_TRCCNTVRn	|
> +		   HDFGWTR_EL2_TRCCLAIM		|
> +		   HDFGWTR_EL2_TRCAUXCTLR	|
> +		   HDFGWTR_EL2_TRC,
> +		   FEAT_TRC_SR),
> +	NEEDS_FEAT(HDFGWTR_EL2_PMUSERENR_EL0	|
> +		   HDFGWTR_EL2_PMCR_EL0		|
> +		   HDFGWTR_EL2_PMSWINC_EL0	|
> +		   HDFGWTR_EL2_PMSELR_EL0	|
> +		   HDFGWTR_EL2_PMOVS		|
> +		   HDFGWTR_EL2_PMINTEN		|
> +		   HDFGWTR_EL2_PMCNTEN		|
> +		   HDFGWTR_EL2_PMCCNTR_EL0	|
> +		   HDFGWTR_EL2_PMCCFILTR_EL0	|
> +		   HDFGWTR_EL2_PMEVTYPERn_EL0	|
> +		   HDFGWTR_EL2_PMEVCNTRn_EL0,
> +		   FEAT_PMUv3),
> +	NEEDS_FEAT(HDFGWTR_EL2_TRBTRG_EL1	|
> +		   HDFGWTR_EL2_TRBSR_EL1	|
> +		   HDFGWTR_EL2_TRBPTR_EL1	|
> +		   HDFGWTR_EL2_TRBMAR_EL1	|
> +		   HDFGWTR_EL2_TRBLIMITR_EL1	|
> +		   HDFGWTR_EL2_TRBBASER_EL1,
> +		   FEAT_TRBE),
> +	NEEDS_FEAT_FLAG(HDFGWTR_EL2_OSDLR_EL1,
> +			NEVER_FGU, FEAT_DoubleLock),
> +	NEEDS_FEAT_FLAG(HDFGWTR_EL2_OSECCR_EL1	|
> +			HDFGWTR_EL2_OSLAR_EL1	|
> +			HDFGWTR_EL2_DBGPRCR_EL1	|
> +			HDFGWTR_EL2_DBGCLAIM	|
> +			HDFGWTR_EL2_MDSCR_EL1	|
> +			HDFGWTR_EL2_DBGWVRn_EL1	|
> +			HDFGWTR_EL2_DBGWCRn_EL1	|
> +			HDFGWTR_EL2_DBGBVRn_EL1	|
> +			HDFGWTR_EL2_DBGBCRn_EL1,
> +			NEVER_FGU, FEAT_AA64EL1),
> +	NEEDS_FEAT(HDFGWTR_EL2_TRFCR_EL1, FEAT_TRF),
> +};
> +
> +
> +static const struct reg_bits_to_feat_map hfgitr_feat_map[] = {
> +	NEEDS_FEAT(HFGITR_EL2_PSBCSYNC, FEAT_SPEv1p5),
> +	NEEDS_FEAT(HFGITR_EL2_ATS1E1A, FEAT_ATS1A),
> +	NEEDS_FEAT(HFGITR_EL2_COSPRCTX, FEAT_SPECRES2),
> +	NEEDS_FEAT(HFGITR_EL2_nGCSEPP		|
> +		   HFGITR_EL2_nGCSSTR_EL1	|
> +		   HFGITR_EL2_nGCSPUSHM_EL1,
> +		   FEAT_GCS),
> +	NEEDS_FEAT(HFGITR_EL2_nBRBIALL		|
> +		   HFGITR_EL2_nBRBINJ,
> +		   FEAT_BRBE),
> +	NEEDS_FEAT(HFGITR_EL2_CPPRCTX		|
> +		   HFGITR_EL2_DVPRCTX		|
> +		   HFGITR_EL2_CFPRCTX,
> +		   FEAT_SPECRES),
> +	NEEDS_FEAT(HFGITR_EL2_TLBIRVAALE1	|
> +		   HFGITR_EL2_TLBIRVALE1	|
> +		   HFGITR_EL2_TLBIRVAAE1	|
> +		   HFGITR_EL2_TLBIRVAE1		|
> +		   HFGITR_EL2_TLBIRVAALE1IS	|
> +		   HFGITR_EL2_TLBIRVALE1IS	|
> +		   HFGITR_EL2_TLBIRVAAE1IS	|
> +		   HFGITR_EL2_TLBIRVAE1IS	|
> +		   HFGITR_EL2_TLBIRVAALE1OS	|
> +		   HFGITR_EL2_TLBIRVALE1OS	|
> +		   HFGITR_EL2_TLBIRVAAE1OS	|
> +		   HFGITR_EL2_TLBIRVAE1OS,
> +		   FEAT_TLBIRANGE),
> +	NEEDS_FEAT(HFGITR_EL2_TLBIVAALE1OS	|
> +		   HFGITR_EL2_TLBIVALE1OS	|
> +		   HFGITR_EL2_TLBIVAAE1OS	|
> +		   HFGITR_EL2_TLBIASIDE1OS	|
> +		   HFGITR_EL2_TLBIVAE1OS	|
> +		   HFGITR_EL2_TLBIVMALLE1OS,
> +		   FEAT_TLBIOS),
> +	NEEDS_FEAT(HFGITR_EL2_ATS1E1WP		|
> +		   HFGITR_EL2_ATS1E1RP,
> +		   FEAT_PAN2),
> +	NEEDS_FEAT(HFGITR_EL2_DCCVADP, FEAT_DPB2),
> +	NEEDS_FEAT_FLAG(HFGITR_EL2_DCCVAC	|
> +			HFGITR_EL2_SVC_EL1	|
> +			HFGITR_EL2_SVC_EL0	|
> +			HFGITR_EL2_ERET		|
> +			HFGITR_EL2_TLBIVAALE1	|
> +			HFGITR_EL2_TLBIVALE1	|
> +			HFGITR_EL2_TLBIVAAE1	|
> +			HFGITR_EL2_TLBIASIDE1	|
> +			HFGITR_EL2_TLBIVAE1	|
> +			HFGITR_EL2_TLBIVMALLE1	|
> +			HFGITR_EL2_TLBIVAALE1IS	|
> +			HFGITR_EL2_TLBIVALE1IS	|
> +			HFGITR_EL2_TLBIVAAE1IS	|
> +			HFGITR_EL2_TLBIASIDE1IS	|
> +			HFGITR_EL2_TLBIVAE1IS	|
> +			HFGITR_EL2_TLBIVMALLE1IS|
> +			HFGITR_EL2_ATS1E0W	|
> +			HFGITR_EL2_ATS1E0R	|
> +			HFGITR_EL2_ATS1E1W	|
> +			HFGITR_EL2_ATS1E1R	|
> +			HFGITR_EL2_DCZVA	|
> +			HFGITR_EL2_DCCIVAC	|
> +			HFGITR_EL2_DCCVAP	|
> +			HFGITR_EL2_DCCVAU	|
> +			HFGITR_EL2_DCCISW	|
> +			HFGITR_EL2_DCCSW	|
> +			HFGITR_EL2_DCISW	|
> +			HFGITR_EL2_DCIVAC	|
> +			HFGITR_EL2_ICIVAU	|
> +			HFGITR_EL2_ICIALLU	|
> +			HFGITR_EL2_ICIALLUIS,
> +			NEVER_FGU, FEAT_AA64EL1),
> +};
> +
> +static const struct reg_bits_to_feat_map hafgrtr_feat_map[] = {
> +	NEEDS_FEAT(HAFGRTR_EL2_AMEVTYPER115_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER114_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER113_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER112_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER111_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER110_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER19_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER18_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER17_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER16_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER15_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER14_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER13_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER12_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER11_EL0	|
> +		   HAFGRTR_EL2_AMEVTYPER10_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR115_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR114_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR113_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR112_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR111_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR110_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR19_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR18_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR17_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR16_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR15_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR14_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR13_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR12_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR11_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR10_EL0	|
> +		   HAFGRTR_EL2_AMCNTEN1		|
> +		   HAFGRTR_EL2_AMCNTEN0		|
> +		   HAFGRTR_EL2_AMEVCNTR03_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR02_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR01_EL0	|
> +		   HAFGRTR_EL2_AMEVCNTR00_EL0,
> +		   FEAT_AMUv1),
> +};
> +
> +static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
> +{
> +	u64 regval = kvm->arch.id_regs[map->regidx];
> +	u64 regfld = (regval >> map->shift) & GENMASK(map->width - 1, 0);
> +
> +	if (map->sign) {
> +		s64 sfld = sign_extend64(regfld, map->width - 1);
> +		s64 slim = sign_extend64(map->lo_lim, map->width - 1);
> +		return sfld >= slim;
> +	} else {
> +		return regfld >= map->lo_lim;
> +	}
> +}
> +
> +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,
> +				unsigned long exclude)
> +{
> +	u64 val = 0;
> +
> +	for (int i = 0; i < map_size; i++) {
> +		bool match;
> +
> +		if ((map[i].flags & require) != require)
> +			continue;
> +
> +		if (map[i].flags & exclude)
> +			continue;
> +
> +		if (map[i].flags & CALL_FUNC)
> +			match = (map[i].flags & FIXED_VALUE) ?
> +				map[i].fval(kvm, fixed_bits) :
> +				map[i].match(kvm);
> +		else
> +			match = idreg_feat_match(kvm, &map[i]);
> +
> +		if (!match || (map[i].flags & FIXED_VALUE))
> +			val |= map[i].bits;
> +	}
> +
> +	return val;
> +}
> +
> +static u64 compute_res0_bits(struct kvm *kvm,
> +			     const struct reg_bits_to_feat_map *map,
> +			     int map_size,
> +			     unsigned long require,
> +			     unsigned long exclude)
> +{
> +	return __compute_fixed_bits(kvm, map, map_size, NULL,
> +				    require, exclude | FIXED_VALUE);
> +}
> +
> +void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt)
> +{
> +	u64 val = 0;
> +
> +	switch (fgt) {
> +	case HFGRTR_GROUP:
> +		val |= compute_res0_bits(kvm, hfgrtr_feat_map,
> +					 ARRAY_SIZE(hfgrtr_feat_map),
> +					 0, NEVER_FGU);
> +		val |= compute_res0_bits(kvm, hfgwtr_feat_map,
> +					 ARRAY_SIZE(hfgwtr_feat_map),
> +					 0, NEVER_FGU);
> +		break;
> +	case HFGITR_GROUP:
> +		val |= compute_res0_bits(kvm, hfgitr_feat_map,
> +					 ARRAY_SIZE(hfgitr_feat_map),
> +					 0, NEVER_FGU);
> +		break;
> +	case HDFGRTR_GROUP:
> +		val |= compute_res0_bits(kvm, hdfgrtr_feat_map,
> +					 ARRAY_SIZE(hdfgrtr_feat_map),
> +					 0, NEVER_FGU);
> +		val |= compute_res0_bits(kvm, hdfgwtr_feat_map,
> +					 ARRAY_SIZE(hdfgwtr_feat_map),
> +					 0, NEVER_FGU);
> +		break;
> +	case HAFGRTR_GROUP:
> +		val |= compute_res0_bits(kvm, hafgrtr_feat_map,
> +					 ARRAY_SIZE(hafgrtr_feat_map),
> +					 0, NEVER_FGU);
> +		break;
> +	default:
> +		BUG();
> +	}
> +
> +	kvm->arch.fgu[fgt] = val;
> +}
> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
> index a9ecca4b2fa74..b3e53a899c1fe 100644
> --- a/arch/arm64/kvm/sys_regs.c
> +++ b/arch/arm64/kvm/sys_regs.c
> @@ -5147,75 +5147,10 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu)
>  	if (test_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags))
>  		goto out;
>  
> -	kvm->arch.fgu[HFGRTR_GROUP] = (HFGRTR_EL2_nAMAIR2_EL1		|
> -				       HFGRTR_EL2_nMAIR2_EL1		|
> -				       HFGRTR_EL2_nS2POR_EL1		|
> -				       HFGRTR_EL2_nSMPRI_EL1_MASK	|
> -				       HFGRTR_EL2_nTPIDR2_EL0_MASK);
> -
> -	if (!kvm_has_feat(kvm, ID_AA64ISAR1_EL1, LS64, LS64_ACCDATA))
> -		kvm->arch.fgu[HFGRTR_GROUP] |= HFGRTR_EL2_nACCDATA_EL1;
> -
> -	if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, OS))
> -		kvm->arch.fgu[HFGITR_GROUP] |= (HFGITR_EL2_TLBIRVAALE1OS|
> -						HFGITR_EL2_TLBIRVALE1OS	|
> -						HFGITR_EL2_TLBIRVAAE1OS	|
> -						HFGITR_EL2_TLBIRVAE1OS	|
> -						HFGITR_EL2_TLBIVAALE1OS	|
> -						HFGITR_EL2_TLBIVALE1OS	|
> -						HFGITR_EL2_TLBIVAAE1OS	|
> -						HFGITR_EL2_TLBIASIDE1OS	|
> -						HFGITR_EL2_TLBIVAE1OS	|
> -						HFGITR_EL2_TLBIVMALLE1OS);
> -
> -	if (!kvm_has_feat(kvm, ID_AA64ISAR0_EL1, TLB, RANGE))
> -		kvm->arch.fgu[HFGITR_GROUP] |= (HFGITR_EL2_TLBIRVAALE1	|
> -						HFGITR_EL2_TLBIRVALE1	|
> -						HFGITR_EL2_TLBIRVAAE1	|
> -						HFGITR_EL2_TLBIRVAE1	|
> -						HFGITR_EL2_TLBIRVAALE1IS|
> -						HFGITR_EL2_TLBIRVALE1IS	|
> -						HFGITR_EL2_TLBIRVAAE1IS	|
> -						HFGITR_EL2_TLBIRVAE1IS	|
> -						HFGITR_EL2_TLBIRVAALE1OS|
> -						HFGITR_EL2_TLBIRVALE1OS	|
> -						HFGITR_EL2_TLBIRVAAE1OS	|
> -						HFGITR_EL2_TLBIRVAE1OS);
> -
> -	if (!kvm_has_feat(kvm, ID_AA64ISAR2_EL1, ATS1A, IMP))
> -		kvm->arch.fgu[HFGITR_GROUP] |= HFGITR_EL2_ATS1E1A;
> -
> -	if (!kvm_has_feat(kvm, ID_AA64MMFR1_EL1, PAN, PAN2))
> -		kvm->arch.fgu[HFGITR_GROUP] |= (HFGITR_EL2_ATS1E1RP |
> -						HFGITR_EL2_ATS1E1WP);
> -
> -	if (!kvm_has_s1pie(kvm))
> -		kvm->arch.fgu[HFGRTR_GROUP] |= (HFGRTR_EL2_nPIRE0_EL1 |
> -						HFGRTR_EL2_nPIR_EL1);
> -
> -	if (!kvm_has_s1poe(kvm))
> -		kvm->arch.fgu[HFGRTR_GROUP] |= (HFGRTR_EL2_nPOR_EL1 |
> -						HFGRTR_EL2_nPOR_EL0);
> -
> -	if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, AMU, IMP))
> -		kvm->arch.fgu[HAFGRTR_GROUP] |= ~(HAFGRTR_EL2_RES0 |
> -						  HAFGRTR_EL2_RES1);
> -
> -	if (!kvm_has_feat(kvm, ID_AA64DFR0_EL1, BRBE, IMP)) {
> -		kvm->arch.fgu[HDFGRTR_GROUP] |= (HDFGRTR_EL2_nBRBDATA  |
> -						 HDFGRTR_EL2_nBRBCTL   |
> -						 HDFGRTR_EL2_nBRBIDR);
> -		kvm->arch.fgu[HFGITR_GROUP] |= (HFGITR_EL2_nBRBINJ |
> -						HFGITR_EL2_nBRBIALL);
> -	}
> -
> -	if (!kvm_has_feat(kvm, ID_AA64PFR1_EL1, GCS, IMP)) {
> -		kvm->arch.fgu[HFGRTR_GROUP] |= (HFGRTR_EL2_nGCS_EL0 |
> -						HFGRTR_EL2_nGCS_EL1);
> -		kvm->arch.fgu[HFGITR_GROUP] |= (HFGITR_EL2_nGCSPUSHM_EL1 |
> -						HFGITR_EL2_nGCSSTR_EL1 |
> -						HFGITR_EL2_nGCSEPP);
> -	}
> +	compute_fgu(kvm, HFGRTR_GROUP);
> +	compute_fgu(kvm, HFGITR_GROUP);
> +	compute_fgu(kvm, HDFGRTR_GROUP);
> +	compute_fgu(kvm, HAFGRTR_GROUP);
>  
>  	set_bit(KVM_ARCH_FLAG_FGU_INITIALIZED, &kvm->arch.flags);
>  out:
> -- 
> 2.39.2
> 



More information about the linux-arm-kernel mailing list