KVM: arm64: Add reg_feat_map_desc to describe full register dependency

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>
This commit is contained in:
Marc Zyngier 2025-09-18 16:13:54 +01:00
parent c3b3bbd160
commit 559442afea

View 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