]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: arm64: Account for RES1 bits in DECLARE_FEAT_MAP() and co
authorMarc Zyngier <maz@kernel.org>
Wed, 10 Dec 2025 17:30:22 +0000 (17:30 +0000)
committerMarc Zyngier <maz@kernel.org>
Thu, 15 Jan 2026 10:58:20 +0000 (10:58 +0000)
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.

Reviewed-by: Fuad Tabba <tabba@google.com>
Tested-by: Sascha Bischoff <sascha.bischoff@arm.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Tested-by: Fuad Tabba <tabba@google.com>
Link: https://patch.msgid.link/20251210173024.561160-5-maz@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/include/asm/kvm_host.h
arch/arm64/kvm/config.c
arch/arm64/kvm/emulate-nested.c

index ac7f970c788302531b2e4275ddbf0de0da4c8514..b552a1e03848cdbdb19d1ab22d885cbf630dfc9e 100644 (file)
@@ -638,6 +638,7 @@ struct fgt_masks {
        u64             mask;
        u64             nmask;
        u64             res0;
+       u64             res1;
 };
 
 extern struct fgt_masks hfgrtr_masks;
index 24bb3f36e9d59d479cd1efa73487131e7a69a4b5..3845b188551b60bbc052ace58cde1eadc827ee3c 100644 (file)
  */
 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)
index 834f13fb1fb7d4f8801be52fe70b00c851346525..75d49f83342a5a1ae96acfdeb4e7113ff473ae11 100644 (file)
@@ -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;
 }