*/
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;
#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,
#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), \
}
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)
}
#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:
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;
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) {
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;
}