]> www.infradead.org Git - users/hch/misc.git/commitdiff
KVM: arm64: Add reg_feat_map_desc to describe full register dependency
authorMarc Zyngier <maz@kernel.org>
Thu, 18 Sep 2025 15:13:54 +0000 (16:13 +0100)
committerMarc Zyngier <maz@kernel.org>
Fri, 19 Sep 2025 12:43:25 +0000 (13:43 +0100)
struct reg_bits_to_feat_map is great to describe bit-to-feature
dependency, but not so much to describe register-to-feature
dependency. Yet both need to exist.

Add a new reg_feat_map_desc structure to describe this.

Extra complexity is added by the need to source the RES0 bits from
the runtime-computed FGT masks, for which we need an extra flag
and extra complexity. Oh well.

Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/config.c

index d85dd05c00b0e9d33b66a5b3490063248b317347..c2bfffe660bcafdf573ca09db52496d1643eb3e2 100644 (file)
@@ -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 {
-       u64             bits;
+       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