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

Fuad Tabba tabba at google.com
Thu Dec 11 06:30:03 PST 2025


On Wed, 10 Dec 2025 at 17:30, Marc Zyngier <maz at kernel.org> 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>


Reviewed-by: Fuad Tabba <tabba at google.com>

/fuad

> ---
>  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;
>  }
> --
> 2.47.3
>



More information about the linux-arm-kernel mailing list