[PATCH v2 4/6] KVM: arm64: Account for RES1 bits in DECLARE_FEAT_MAP() and co

Sascha Bischoff Sascha.Bischoff at arm.com
Thu Dec 11 09:23:17 PST 2025


On Wed, 2025-12-10 at 17:30 +0000, Marc Zyngier wrote:
> None of the registers we manage in the feature dependency
> infrastructure
> so far has any RES1 bit. This is about to change, as VTCR_EL2 has
> its bit 31 being RES1.
> 
> In order to not fail the consistency checks by not describing a bit,
> add RES1 bits to the set of immutable bits. This requires some extra
> surgery for the FGT handling, as we now need to track RES1 bits there
> as well.
> 
> There are no RES1 FGT bits *yet*. Watch this space.
> 
> Signed-off-by: Marc Zyngier <maz at kernel.org>

I've tested this change with my WIP vgic_v5 support, which indeed
introduces a RES1 FGT bit. I can confirm that the FGT support is now
working as I'd expect it to. Thanks for this change!

Tested-by: Sascha Bischoff <sascha.bischoff at arm.com>

Thanks,
Sascha

> ---
>  arch/arm64/include/asm/kvm_host.h |  1 +
>  arch/arm64/kvm/config.c           | 25 +++++++-------
>  arch/arm64/kvm/emulate-nested.c   | 55 +++++++++++++++++------------
> --
>  3 files changed, 45 insertions(+), 36 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h
> b/arch/arm64/include/asm/kvm_host.h
> index ac7f970c78830..b552a1e03848c 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -638,6 +638,7 @@ struct fgt_masks {
>  	u64		mask;
>  	u64		nmask;
>  	u64		res0;
> +	u64		res1;
>  };
>  
>  extern struct fgt_masks hfgrtr_masks;
> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> index 24bb3f36e9d59..3845b188551b6 100644
> --- a/arch/arm64/kvm/config.c
> +++ b/arch/arm64/kvm/config.c
> @@ -16,14 +16,14 @@
>   */
>  struct reg_bits_to_feat_map {
>  	union {
> -		u64	bits;
> -		u64	*res0p;
> +		u64		 bits;
> +		struct fgt_masks *masks;
>  	};
>  
>  #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 */
> +#define	MASKS_POINTER	BIT(3)	/* Pointer to fgt_masks
> struct instead of bits */
>  
>  	unsigned long	flags;
>  
> @@ -92,8 +92,8 @@ struct reg_feat_map_desc {
>  #define NEEDS_FEAT_FIXED(m, ...)			\
>  	__NEEDS_FEAT_FLAG(m, FIXED_VALUE, bits, __VA_ARGS__, 0)
>  
> -#define NEEDS_FEAT_RES0(p, ...)				\
> -	__NEEDS_FEAT_FLAG(p, RES0_POINTER, res0p, __VA_ARGS__)
> +#define NEEDS_FEAT_MASKS(p, ...)				\
> +	__NEEDS_FEAT_FLAG(p, MASKS_POINTER, masks, __VA_ARGS__)
>  
>  /*
>   * Declare the dependency between a set of bits and a set of
> features,
> @@ -109,19 +109,20 @@ 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), 	\
> +		.feat_map		= NEEDS_FEAT(~(r##_RES0
> |	\
> +						       r##_RES1),
> 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.
> + * RESx 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),\
> +		.feat_map		= NEEDS_FEAT_MASKS(&msk,
> f),	\
>  		.bit_feat_map		=
> m,				\
>  		.bit_feat_map_sz	=
> ARRAY_SIZE(m),		\
>  	}
> @@ -1168,21 +1169,21 @@ 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)
> +				  int map_size, u64 resx, const char
> *str)
>  {
>  	u64 mask = 0;
>  
>  	for (int i = 0; i < map_size; i++)
>  		mask |= map[i].bits;
>  
> -	if (mask != ~res0)
> +	if (mask != ~resx)
>  		kvm_err("Undefined %s behaviour, bits %016llx\n",
> -			str, mask ^ ~res0);
> +			str, mask ^ ~resx);
>  }
>  
>  static u64 reg_feat_map_bits(const struct reg_bits_to_feat_map *map)
>  {
> -	return map->flags & RES0_POINTER ? ~(*map->res0p) : map-
> >bits;
> +	return map->flags & MASKS_POINTER ? (map->masks->mask | map-
> >masks->nmask) : map->bits;
>  }
>  
>  static void __init check_reg_desc(const struct reg_feat_map_desc *r)
> diff --git a/arch/arm64/kvm/emulate-nested.c
> b/arch/arm64/kvm/emulate-nested.c
> index 834f13fb1fb7d..75d49f83342a5 100644
> --- a/arch/arm64/kvm/emulate-nested.c
> +++ b/arch/arm64/kvm/emulate-nested.c
> @@ -2105,23 +2105,24 @@ static u32 encoding_next(u32 encoding)
>  }
>  
>  #define FGT_MASKS(__n,
> __m)						\
> -	struct fgt_masks __n = { .str = #__m, .res0 = __m, }
> -
> -FGT_MASKS(hfgrtr_masks, HFGRTR_EL2_RES0);
> -FGT_MASKS(hfgwtr_masks, HFGWTR_EL2_RES0);
> -FGT_MASKS(hfgitr_masks, HFGITR_EL2_RES0);
> -FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2_RES0);
> -FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2_RES0);
> -FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2_RES0);
> -FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2_RES0);
> -FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2_RES0);
> -FGT_MASKS(hfgitr2_masks, HFGITR2_EL2_RES0);
> -FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2_RES0);
> -FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2_RES0);
> +	struct fgt_masks __n = { .str = #__m, .res0 = __m ## _RES0,
> .res1 = __m ## _RES1 }
> +
> +FGT_MASKS(hfgrtr_masks, HFGRTR_EL2);
> +FGT_MASKS(hfgwtr_masks, HFGWTR_EL2);
> +FGT_MASKS(hfgitr_masks, HFGITR_EL2);
> +FGT_MASKS(hdfgrtr_masks, HDFGRTR_EL2);
> +FGT_MASKS(hdfgwtr_masks, HDFGWTR_EL2);
> +FGT_MASKS(hafgrtr_masks, HAFGRTR_EL2);
> +FGT_MASKS(hfgrtr2_masks, HFGRTR2_EL2);
> +FGT_MASKS(hfgwtr2_masks, HFGWTR2_EL2);
> +FGT_MASKS(hfgitr2_masks, HFGITR2_EL2);
> +FGT_MASKS(hdfgrtr2_masks, HDFGRTR2_EL2);
> +FGT_MASKS(hdfgwtr2_masks, HDFGWTR2_EL2);
>  
>  static __init bool aggregate_fgt(union trap_config tc)
>  {
>  	struct fgt_masks *rmasks, *wmasks;
> +	u64 rresx, wresx;
>  
>  	switch (tc.fgt) {
>  	case HFGRTR_GROUP:
> @@ -2154,24 +2155,27 @@ static __init bool aggregate_fgt(union
> trap_config tc)
>  		break;
>  	}
>  
> +	rresx = rmasks->res0 | rmasks->res1;
> +	if (wmasks)
> +		wresx = wmasks->res0 | wmasks->res1;
> +
>  	/*
>  	 * A bit can be reserved in either the R or W register, but
>  	 * not both.
>  	 */
> -	if ((BIT(tc.bit) & rmasks->res0) &&
> -	    (!wmasks || (BIT(tc.bit) & wmasks->res0)))
> +	if ((BIT(tc.bit) & rresx) && (!wmasks || (BIT(tc.bit) &
> wresx)))
>  		return false;
>  
>  	if (tc.pol)
> -		rmasks->mask |= BIT(tc.bit) & ~rmasks->res0;
> +		rmasks->mask |= BIT(tc.bit) & ~rresx;
>  	else
> -		rmasks->nmask |= BIT(tc.bit) & ~rmasks->res0;
> +		rmasks->nmask |= BIT(tc.bit) & ~rresx;
>  
>  	if (wmasks) {
>  		if (tc.pol)
> -			wmasks->mask |= BIT(tc.bit) & ~wmasks->res0;
> +			wmasks->mask |= BIT(tc.bit) & ~wresx;
>  		else
> -			wmasks->nmask |= BIT(tc.bit) & ~wmasks-
> >res0;
> +			wmasks->nmask |= BIT(tc.bit) & ~wresx;
>  	}
>  
>  	return true;
> @@ -2180,7 +2184,6 @@ static __init bool aggregate_fgt(union
> trap_config tc)
>  static __init int check_fgt_masks(struct fgt_masks *masks)
>  {
>  	unsigned long duplicate = masks->mask & masks->nmask;
> -	u64 res0 = masks->res0;
>  	int ret = 0;
>  
>  	if (duplicate) {
> @@ -2194,10 +2197,14 @@ static __init int check_fgt_masks(struct
> fgt_masks *masks)
>  		ret = -EINVAL;
>  	}
>  
> -	masks->res0 = ~(masks->mask | masks->nmask);
> -	if (masks->res0 != res0)
> -		kvm_info("Implicit %s = %016llx, expecting
> %016llx\n",
> -			 masks->str, masks->res0, res0);
> +	if ((masks->res0 | masks->res1 | masks->mask | masks->nmask)
> != GENMASK(63, 0) ||
> +	    (masks->res0 & masks->res1)  || (masks->res0 & masks-
> >mask) ||
> +	    (masks->res0 & masks->nmask) || (masks->res1 & masks-
> >mask)  ||
> +	    (masks->res1 & masks->nmask) || (masks->mask & masks-
> >nmask)) {
> +		kvm_info("Inconsistent masks for %s (%016llx,
> %016llx, %016llx, %016llx)\n",
> +			 masks->str, masks->res0, masks->res1,
> masks->mask, masks->nmask);
> +		masks->res0 = ~(masks->res1 | masks->mask | masks-
> >nmask);
> +	}
>  
>  	return ret;
>  }



More information about the linux-arm-kernel mailing list