* [PATCH 0/8] KVM: arm64: Handle effective RES0 behaviour of undefined registers
@ 2025-09-17 16:58 Marc Zyngier
2025-09-17 16:58 ` [PATCH 1/8] KVM: arm64: Enforce absence of FEAT_FGT on FGT registers Marc Zyngier
` (7 more replies)
0 siblings, 8 replies; 11+ messages in thread
From: Marc Zyngier @ 2025-09-17 16:58 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel
Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
Jinqian Yang
When a feature is removed from a guest, we ensure that the trap and
control bits for that particular feature are made RES0.
For example, SCTLR2_EL2 contains a large number of bits. For any
feature FEAT_FOO that is controlled by a bit FOO in SCTLR2_EL2, we
make sure that SCTLR2_EL2.FOO is RES0 if FEAT_FOO is not visible to
the guest.
However, nothing makes SCTLR2_EL2 RES0 if FEAT_SCTLR2 is not visible.
This series aims at solving this sort of situations. It is still quite
incomplete, but aims at bridging a couple of other series:
- 20250911114621.3724469-1-yangjinqian1@huawei.com which wants to
make EL2-related fields writable to allow migration
- 20250912212258.407350-1-oliver.upton@linux.dev which wants to align
the NV support with the rest of the kernel
Hopefully this helps getting to a point where we everything is
sanitised according to the architecture, EL2 on the same footing as
EL1, and everything migrating in every possible case.
And winning the lottery.
Marc Zyngier (8):
KVM: arm64: Enforce absence of FEAT_FGT on FGT registers
KVM: arm64: Enforce absence of FEAT_FGT2 on FGT2 registers
KVM: arm64: Enforce absence of FEAT_HCX on HCRX_EL2
KVM: arm64: Convert HCR_EL2 RES0 handling to compute_reg_res0_bits()
KVM: arm64: Enforce absence of FEAT_SCTLR2 on SCTLR2_EL{1,2}
KVM: arm64: Enforce absence of FEAT_TCR2 on TCR2_EL2
KVM: arm64: Convert SCTLR_EL1 RES0 handling to compute_reg_res0_bits()
KVM: arm64: Convert MDCR_EL2 RES0 handling to compute_reg_res0_bits()
arch/arm64/kvm/config.c | 385 +++++++++++++++++++++++++---------------
1 file changed, 240 insertions(+), 145 deletions(-)
--
2.39.2
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/8] KVM: arm64: Enforce absence of FEAT_FGT on FGT registers
2025-09-17 16:58 [PATCH 0/8] KVM: arm64: Handle effective RES0 behaviour of undefined registers Marc Zyngier
@ 2025-09-17 16:58 ` Marc Zyngier
2025-09-18 6:07 ` Oliver Upton
2025-09-17 16:58 ` [PATCH 2/8] KVM: arm64: Enforce absence of FEAT_FGT2 on FGT2 registers Marc Zyngier
` (6 subsequent siblings)
7 siblings, 1 reply; 11+ messages in thread
From: Marc Zyngier @ 2025-09-17 16:58 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel
Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
Jinqian Yang
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/config.c | 201 +++++++++++++++++++++++++++-------------
1 file changed, 137 insertions(+), 64 deletions(-)
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index da66c4a147752..42b834c82a20d 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -8,11 +8,16 @@
#include <asm/sysreg.h>
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 +33,16 @@ struct reg_bits_to_feat_map {
};
};
-#define __NEEDS_FEAT_3(m, f, id, fld, lim) \
+struct reg_to_feat_map {
+ 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 +51,50 @@ 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__)
#define NEEDS_FEAT(m, ...) NEEDS_FEAT_FLAG(m, 0, __VA_ARGS__)
+#define FEAT_MAP(r, f, m) \
+ { \
+ .name = #r, \
+ .feat_map = NEEDS_FEAT(~r##_RES0, f), \
+ .bit_feat_map = m, \
+ .bit_feat_map_sz = ARRAY_SIZE(m), \
+ }
+
+#define FEAT_MAP_FGT(msk, m, f) \
+ { \
+ .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
@@ -320,7 +354,7 @@ static bool compute_hcr_e2h(struct kvm *kvm, u64 *bits)
return true;
}
-static const struct reg_bits_to_feat_map hfgrtr_feat_map[] = {
+static const struct reg_bits_to_feat_map hfgrtr_bit_feat_map[] = {
NEEDS_FEAT(HFGRTR_EL2_nAMAIR2_EL1 |
HFGRTR_EL2_nMAIR2_EL1,
FEAT_AIE),
@@ -397,7 +431,12 @@ static const struct reg_bits_to_feat_map hfgrtr_feat_map[] = {
NEVER_FGU, FEAT_AA64EL1),
};
-static const struct reg_bits_to_feat_map hfgwtr_feat_map[] = {
+static const
+struct reg_to_feat_map hfgrtr_feat_map = FEAT_MAP_FGT(hfgrtr_masks,
+ hfgrtr_bit_feat_map,
+ FEAT_FGT);
+
+static const struct reg_bits_to_feat_map hfgwtr_bit_feat_map[] = {
NEEDS_FEAT(HFGWTR_EL2_nAMAIR2_EL1 |
HFGWTR_EL2_nMAIR2_EL1,
FEAT_AIE),
@@ -461,7 +500,12 @@ static const struct reg_bits_to_feat_map hfgwtr_feat_map[] = {
NEVER_FGU, FEAT_AA64EL1),
};
-static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = {
+static const
+struct reg_to_feat_map hfgwtr_feat_map = FEAT_MAP_FGT(hfgwtr_masks,
+ hfgwtr_bit_feat_map,
+ FEAT_FGT);
+
+static const struct reg_bits_to_feat_map hdfgrtr_bit_feat_map[] = {
NEEDS_FEAT(HDFGRTR_EL2_PMBIDR_EL1 |
HDFGRTR_EL2_PMSLATFR_EL1 |
HDFGRTR_EL2_PMSIRR_EL1 |
@@ -528,7 +572,12 @@ static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = {
NEVER_FGU, FEAT_AA64EL1)
};
-static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = {
+static const
+struct reg_to_feat_map hdfgrtr_feat_map = FEAT_MAP_FGT(hdfgrtr_masks,
+ hdfgrtr_bit_feat_map,
+ FEAT_FGT);
+
+static const struct reg_bits_to_feat_map hdfgwtr_bit_feat_map[] = {
NEEDS_FEAT(HDFGWTR_EL2_PMSLATFR_EL1 |
HDFGWTR_EL2_PMSIRR_EL1 |
HDFGWTR_EL2_PMSICR_EL1 |
@@ -588,8 +637,12 @@ static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = {
NEEDS_FEAT(HDFGWTR_EL2_TRFCR_EL1, FEAT_TRF),
};
+static const
+struct reg_to_feat_map hdfgwtr_feat_map = FEAT_MAP_FGT(hdfgwtr_masks,
+ hdfgwtr_bit_feat_map,
+ FEAT_FGT);
-static const struct reg_bits_to_feat_map hfgitr_feat_map[] = {
+static const struct reg_bits_to_feat_map hfgitr_bit_feat_map[] = {
NEEDS_FEAT(HFGITR_EL2_PSBCSYNC, FEAT_SPEv1p5),
NEEDS_FEAT(HFGITR_EL2_ATS1E1A, FEAT_ATS1A),
NEEDS_FEAT(HFGITR_EL2_COSPRCTX, FEAT_SPECRES2),
@@ -662,7 +715,12 @@ static const struct reg_bits_to_feat_map hfgitr_feat_map[] = {
NEVER_FGU, FEAT_AA64EL1),
};
-static const struct reg_bits_to_feat_map hafgrtr_feat_map[] = {
+static const
+struct reg_to_feat_map hfgitr_feat_map = FEAT_MAP_FGT(hfgitr_masks,
+ hfgitr_bit_feat_map,
+ FEAT_FGT);
+
+static const struct reg_bits_to_feat_map hafgrtr_bit_feat_map[] = {
NEEDS_FEAT(HAFGRTR_EL2_AMEVTYPER115_EL0 |
HAFGRTR_EL2_AMEVTYPER114_EL0 |
HAFGRTR_EL2_AMEVTYPER113_EL0 |
@@ -704,6 +762,11 @@ static const struct reg_bits_to_feat_map hafgrtr_feat_map[] = {
FEAT_AMUv1),
};
+static const
+struct reg_to_feat_map hafgrtr_feat_map = FEAT_MAP_FGT(hafgrtr_masks,
+ hafgrtr_bit_feat_map,
+ FEAT_FGT);
+
static const struct reg_bits_to_feat_map hfgitr2_feat_map[] = {
NEEDS_FEAT(HFGITR2_EL2_nDCCIVAPS, FEAT_PoPS),
NEEDS_FEAT(HFGITR2_EL2_TSBCSYNC, FEAT_TRBEv1p1)
@@ -1061,20 +1124,25 @@ static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
str, mask ^ ~res0);
}
+static u64 reg_feat_map_bits(const struct reg_bits_to_feat_map *map)
+{
+ return map->flags & RES0_POINTER ? ~(*map->res0p) : map->bits;
+}
+
+static void __init check_reg_feat_map(const struct reg_to_feat_map *r)
+{
+ check_feat_map(r->bit_feat_map, r->bit_feat_map_sz,
+ ~reg_feat_map_bits(&r->feat_map), r->name);
+}
+
void __init check_feature_map(void)
{
- check_feat_map(hfgrtr_feat_map, ARRAY_SIZE(hfgrtr_feat_map),
- hfgrtr_masks.res0, hfgrtr_masks.str);
- check_feat_map(hfgwtr_feat_map, ARRAY_SIZE(hfgwtr_feat_map),
- hfgwtr_masks.res0, hfgwtr_masks.str);
- check_feat_map(hfgitr_feat_map, ARRAY_SIZE(hfgitr_feat_map),
- hfgitr_masks.res0, hfgitr_masks.str);
- check_feat_map(hdfgrtr_feat_map, ARRAY_SIZE(hdfgrtr_feat_map),
- hdfgrtr_masks.res0, hdfgrtr_masks.str);
- check_feat_map(hdfgwtr_feat_map, ARRAY_SIZE(hdfgwtr_feat_map),
- hdfgwtr_masks.res0, hdfgwtr_masks.str);
- check_feat_map(hafgrtr_feat_map, ARRAY_SIZE(hafgrtr_feat_map),
- hafgrtr_masks.res0, hafgrtr_masks.str);
+ check_reg_feat_map(&hfgrtr_feat_map);
+ check_reg_feat_map(&hfgwtr_feat_map);
+ check_reg_feat_map(&hfgitr_feat_map);
+ check_reg_feat_map(&hdfgrtr_feat_map);
+ check_reg_feat_map(&hdfgwtr_feat_map);
+ check_reg_feat_map(&hafgrtr_feat_map);
check_feat_map(hcrx_feat_map, ARRAY_SIZE(hcrx_feat_map),
__HCRX_EL2_RES0, "HCRX_EL2");
check_feat_map(hcr_feat_map, ARRAY_SIZE(hcr_feat_map),
@@ -1129,7 +1197,7 @@ static u64 __compute_fixed_bits(struct kvm *kvm,
match = idreg_feat_match(kvm, &map[i]);
if (!match || (map[i].flags & FIXED_VALUE))
- val |= map[i].bits;
+ val |= reg_feat_map_bits(&map[i]);
}
return val;
@@ -1145,6 +1213,29 @@ static u64 compute_res0_bits(struct kvm *kvm,
require, exclude | FIXED_VALUE);
}
+static u64 compute_reg_res0_bits(struct kvm *kvm,
+ const struct reg_to_feat_map *r,
+ unsigned long require, unsigned long exclude)
+
+{
+ u64 res0;
+
+ res0 = compute_res0_bits(kvm, r->bit_feat_map, r->bit_feat_map_sz,
+ require, exclude);
+
+ /*
+ * If computing FGUs, don't take RES0 or register existence
+ * into account -- we're not computing bits for the register
+ * itself.
+ */
+ if (!(exclude & NEVER_FGU)) {
+ res0 |= compute_res0_bits(kvm, &r->feat_map, 1, require, exclude);
+ res0 |= ~reg_feat_map_bits(&r->feat_map);
+ }
+
+ return res0;
+}
+
static u64 compute_fixed_bits(struct kvm *kvm,
const struct reg_bits_to_feat_map *map,
int map_size,
@@ -1162,30 +1253,24 @@ void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt)
switch (fgt) {
case HFGRTR_GROUP:
- val |= compute_res0_bits(kvm, hfgrtr_feat_map,
- ARRAY_SIZE(hfgrtr_feat_map),
- 0, NEVER_FGU);
- val |= compute_res0_bits(kvm, hfgwtr_feat_map,
- ARRAY_SIZE(hfgwtr_feat_map),
- 0, NEVER_FGU);
+ val |= compute_reg_res0_bits(kvm, &hfgrtr_feat_map,
+ 0, NEVER_FGU);
+ val |= compute_reg_res0_bits(kvm, &hfgwtr_feat_map,
+ 0, NEVER_FGU);
break;
case HFGITR_GROUP:
- val |= compute_res0_bits(kvm, hfgitr_feat_map,
- ARRAY_SIZE(hfgitr_feat_map),
- 0, NEVER_FGU);
+ val |= compute_reg_res0_bits(kvm, &hfgitr_feat_map,
+ 0, NEVER_FGU);
break;
case HDFGRTR_GROUP:
- val |= compute_res0_bits(kvm, hdfgrtr_feat_map,
- ARRAY_SIZE(hdfgrtr_feat_map),
- 0, NEVER_FGU);
- val |= compute_res0_bits(kvm, hdfgwtr_feat_map,
- ARRAY_SIZE(hdfgwtr_feat_map),
- 0, NEVER_FGU);
+ val |= compute_reg_res0_bits(kvm, &hdfgrtr_feat_map,
+ 0, NEVER_FGU);
+ val |= compute_reg_res0_bits(kvm, &hdfgwtr_feat_map,
+ 0, NEVER_FGU);
break;
case HAFGRTR_GROUP:
- val |= compute_res0_bits(kvm, hafgrtr_feat_map,
- ARRAY_SIZE(hafgrtr_feat_map),
- 0, NEVER_FGU);
+ val |= compute_reg_res0_bits(kvm, &hafgrtr_feat_map,
+ 0, NEVER_FGU);
break;
case HFGRTR2_GROUP:
val |= compute_res0_bits(kvm, hfgrtr2_feat_map,
@@ -1221,39 +1306,27 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
switch (reg) {
case HFGRTR_EL2:
- *res0 = compute_res0_bits(kvm, hfgrtr_feat_map,
- ARRAY_SIZE(hfgrtr_feat_map), 0, 0);
- *res0 |= hfgrtr_masks.res0;
+ *res0 = compute_reg_res0_bits(kvm, &hfgrtr_feat_map, 0, 0);
*res1 = HFGRTR_EL2_RES1;
break;
case HFGWTR_EL2:
- *res0 = compute_res0_bits(kvm, hfgwtr_feat_map,
- ARRAY_SIZE(hfgwtr_feat_map), 0, 0);
- *res0 |= hfgwtr_masks.res0;
+ *res0 = compute_reg_res0_bits(kvm, &hfgwtr_feat_map, 0, 0);
*res1 = HFGWTR_EL2_RES1;
break;
case HFGITR_EL2:
- *res0 = compute_res0_bits(kvm, hfgitr_feat_map,
- ARRAY_SIZE(hfgitr_feat_map), 0, 0);
- *res0 |= hfgitr_masks.res0;
+ *res0 = compute_reg_res0_bits(kvm, &hfgitr_feat_map, 0, 0);
*res1 = HFGITR_EL2_RES1;
break;
case HDFGRTR_EL2:
- *res0 = compute_res0_bits(kvm, hdfgrtr_feat_map,
- ARRAY_SIZE(hdfgrtr_feat_map), 0, 0);
- *res0 |= hdfgrtr_masks.res0;
+ *res0 = compute_reg_res0_bits(kvm, &hdfgrtr_feat_map, 0, 0);
*res1 = HDFGRTR_EL2_RES1;
break;
case HDFGWTR_EL2:
- *res0 = compute_res0_bits(kvm, hdfgwtr_feat_map,
- ARRAY_SIZE(hdfgwtr_feat_map), 0, 0);
- *res0 |= hdfgwtr_masks.res0;
+ *res0 = compute_reg_res0_bits(kvm, &hdfgwtr_feat_map, 0, 0);
*res1 = HDFGWTR_EL2_RES1;
break;
case HAFGRTR_EL2:
- *res0 = compute_res0_bits(kvm, hafgrtr_feat_map,
- ARRAY_SIZE(hafgrtr_feat_map), 0, 0);
- *res0 |= hafgrtr_masks.res0;
+ *res0 = compute_reg_res0_bits(kvm, &hafgrtr_feat_map, 0, 0);
*res1 = HAFGRTR_EL2_RES1;
break;
case HFGRTR2_EL2:
--
2.39.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/8] KVM: arm64: Enforce absence of FEAT_FGT2 on FGT2 registers
2025-09-17 16:58 [PATCH 0/8] KVM: arm64: Handle effective RES0 behaviour of undefined registers Marc Zyngier
2025-09-17 16:58 ` [PATCH 1/8] KVM: arm64: Enforce absence of FEAT_FGT on FGT registers Marc Zyngier
@ 2025-09-17 16:58 ` Marc Zyngier
2025-09-17 16:58 ` [PATCH 3/8] KVM: arm64: Enforce absence of FEAT_HCX on HCRX_EL2 Marc Zyngier
` (5 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Marc Zyngier @ 2025-09-17 16:58 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel
Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
Jinqian Yang
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/config.c | 86 ++++++++++++++++++++++++-----------------
1 file changed, 51 insertions(+), 35 deletions(-)
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 42b834c82a20d..05be2b917c8c0 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -185,6 +185,7 @@ struct reg_to_feat_map {
#define FEAT_SSBS ID_AA64PFR1_EL1, SSBS, IMP
#define FEAT_TIDCP1 ID_AA64MMFR1_EL1, TIDCP1, IMP
#define FEAT_FGT ID_AA64MMFR0_EL1, FGT, IMP
+#define FEAT_FGT2 ID_AA64MMFR0_EL1, FGT, FGT2
#define FEAT_MTPMU ID_AA64DFR0_EL1, MTPMU, IMP
static bool not_feat_aa64el3(struct kvm *kvm)
@@ -767,12 +768,17 @@ struct reg_to_feat_map hafgrtr_feat_map = FEAT_MAP_FGT(hafgrtr_masks,
hafgrtr_bit_feat_map,
FEAT_FGT);
-static const struct reg_bits_to_feat_map hfgitr2_feat_map[] = {
+static const struct reg_bits_to_feat_map hfgitr2_bit_feat_map[] = {
NEEDS_FEAT(HFGITR2_EL2_nDCCIVAPS, FEAT_PoPS),
NEEDS_FEAT(HFGITR2_EL2_TSBCSYNC, FEAT_TRBEv1p1)
};
-static const struct reg_bits_to_feat_map hfgrtr2_feat_map[] = {
+static const
+struct reg_to_feat_map hfgitr2_feat_map = FEAT_MAP_FGT(hfgitr2_masks,
+ hfgitr2_bit_feat_map,
+ FEAT_FGT2);
+
+static const struct reg_bits_to_feat_map hfgrtr2_bit_feat_map[] = {
NEEDS_FEAT(HFGRTR2_EL2_nPFAR_EL1, FEAT_PFAR),
NEEDS_FEAT(HFGRTR2_EL2_nERXGSR_EL1, FEAT_RASv2),
NEEDS_FEAT(HFGRTR2_EL2_nACTLRALIAS_EL1 |
@@ -791,7 +797,12 @@ static const struct reg_bits_to_feat_map hfgrtr2_feat_map[] = {
NEEDS_FEAT(HFGRTR2_EL2_nRCWSMASK_EL1, FEAT_THE),
};
-static const struct reg_bits_to_feat_map hfgwtr2_feat_map[] = {
+static const
+struct reg_to_feat_map hfgrtr2_feat_map = FEAT_MAP_FGT(hfgrtr2_masks,
+ hfgrtr2_bit_feat_map,
+ FEAT_FGT2);
+
+static const struct reg_bits_to_feat_map hfgwtr2_bit_feat_map[] = {
NEEDS_FEAT(HFGWTR2_EL2_nPFAR_EL1, FEAT_PFAR),
NEEDS_FEAT(HFGWTR2_EL2_nACTLRALIAS_EL1 |
HFGWTR2_EL2_nACTLRMASK_EL1 |
@@ -809,7 +820,12 @@ static const struct reg_bits_to_feat_map hfgwtr2_feat_map[] = {
NEEDS_FEAT(HFGWTR2_EL2_nRCWSMASK_EL1, FEAT_THE),
};
-static const struct reg_bits_to_feat_map hdfgrtr2_feat_map[] = {
+static const
+struct reg_to_feat_map hfgwtr2_feat_map = FEAT_MAP_FGT(hfgwtr2_masks,
+ hfgwtr2_bit_feat_map,
+ FEAT_FGT2);
+
+static const struct reg_bits_to_feat_map hdfgrtr2_bit_feat_map[] = {
NEEDS_FEAT(HDFGRTR2_EL2_nMDSELR_EL1, FEAT_Debugv8p9),
NEEDS_FEAT(HDFGRTR2_EL2_nPMECR_EL1, feat_ebep_pmuv3_ss),
NEEDS_FEAT(HDFGRTR2_EL2_nTRCITECR_EL1, FEAT_ITE),
@@ -839,7 +855,12 @@ static const struct reg_bits_to_feat_map hdfgrtr2_feat_map[] = {
NEEDS_FEAT(HDFGRTR2_EL2_nTRBMPAM_EL1, feat_trbe_mpam),
};
-static const struct reg_bits_to_feat_map hdfgwtr2_feat_map[] = {
+static const
+struct reg_to_feat_map hdfgrtr2_feat_map = FEAT_MAP_FGT(hdfgrtr2_masks,
+ hdfgrtr2_bit_feat_map,
+ FEAT_FGT2);
+
+static const struct reg_bits_to_feat_map hdfgwtr2_bit_feat_map[] = {
NEEDS_FEAT(HDFGWTR2_EL2_nMDSELR_EL1, FEAT_Debugv8p9),
NEEDS_FEAT(HDFGWTR2_EL2_nPMECR_EL1, feat_ebep_pmuv3_ss),
NEEDS_FEAT(HDFGWTR2_EL2_nTRCITECR_EL1, FEAT_ITE),
@@ -867,6 +888,11 @@ static const struct reg_bits_to_feat_map hdfgwtr2_feat_map[] = {
NEEDS_FEAT(HDFGWTR2_EL2_nTRBMPAM_EL1, feat_trbe_mpam),
};
+static const
+struct reg_to_feat_map hdfgwtr2_feat_map = FEAT_MAP_FGT(hdfgwtr2_masks,
+ hdfgwtr2_bit_feat_map,
+ FEAT_FGT2);
+
static const struct reg_bits_to_feat_map hcrx_feat_map[] = {
NEEDS_FEAT(HCRX_EL2_PACMEn, feat_pauth_lr),
NEEDS_FEAT(HCRX_EL2_EnFPM, FEAT_FPMR),
@@ -1143,6 +1169,11 @@ void __init check_feature_map(void)
check_reg_feat_map(&hdfgrtr_feat_map);
check_reg_feat_map(&hdfgwtr_feat_map);
check_reg_feat_map(&hafgrtr_feat_map);
+ check_reg_feat_map(&hfgrtr2_feat_map);
+ check_reg_feat_map(&hfgwtr2_feat_map);
+ check_reg_feat_map(&hfgitr2_feat_map);
+ check_reg_feat_map(&hdfgrtr2_feat_map);
+ check_reg_feat_map(&hdfgwtr2_feat_map);
check_feat_map(hcrx_feat_map, ARRAY_SIZE(hcrx_feat_map),
__HCRX_EL2_RES0, "HCRX_EL2");
check_feat_map(hcr_feat_map, ARRAY_SIZE(hcr_feat_map),
@@ -1273,25 +1304,20 @@ void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt)
0, NEVER_FGU);
break;
case HFGRTR2_GROUP:
- val |= compute_res0_bits(kvm, hfgrtr2_feat_map,
- ARRAY_SIZE(hfgrtr2_feat_map),
- 0, NEVER_FGU);
- val |= compute_res0_bits(kvm, hfgwtr2_feat_map,
- ARRAY_SIZE(hfgwtr2_feat_map),
- 0, NEVER_FGU);
+ val |= compute_reg_res0_bits(kvm, &hfgrtr2_feat_map,
+ 0, NEVER_FGU);
+ val |= compute_reg_res0_bits(kvm, &hfgwtr2_feat_map,
+ 0, NEVER_FGU);
break;
case HFGITR2_GROUP:
- val |= compute_res0_bits(kvm, hfgitr2_feat_map,
- ARRAY_SIZE(hfgitr2_feat_map),
- 0, NEVER_FGU);
+ val |= compute_reg_res0_bits(kvm, &hfgitr2_feat_map,
+ 0, NEVER_FGU);
break;
case HDFGRTR2_GROUP:
- val |= compute_res0_bits(kvm, hdfgrtr2_feat_map,
- ARRAY_SIZE(hdfgrtr2_feat_map),
- 0, NEVER_FGU);
- val |= compute_res0_bits(kvm, hdfgwtr2_feat_map,
- ARRAY_SIZE(hdfgwtr2_feat_map),
- 0, NEVER_FGU);
+ val |= compute_reg_res0_bits(kvm, &hdfgrtr2_feat_map,
+ 0, NEVER_FGU);
+ val |= compute_reg_res0_bits(kvm, &hdfgwtr2_feat_map,
+ 0, NEVER_FGU);
break;
default:
BUG();
@@ -1330,33 +1356,23 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
*res1 = HAFGRTR_EL2_RES1;
break;
case HFGRTR2_EL2:
- *res0 = compute_res0_bits(kvm, hfgrtr2_feat_map,
- ARRAY_SIZE(hfgrtr2_feat_map), 0, 0);
- *res0 |= hfgrtr2_masks.res0;
+ *res0 = compute_reg_res0_bits(kvm, &hfgrtr2_feat_map, 0, 0);
*res1 = HFGRTR2_EL2_RES1;
break;
case HFGWTR2_EL2:
- *res0 = compute_res0_bits(kvm, hfgwtr2_feat_map,
- ARRAY_SIZE(hfgwtr2_feat_map), 0, 0);
- *res0 |= hfgwtr2_masks.res0;
+ *res0 = compute_reg_res0_bits(kvm, &hfgwtr2_feat_map, 0, 0);
*res1 = HFGWTR2_EL2_RES1;
break;
case HFGITR2_EL2:
- *res0 = compute_res0_bits(kvm, hfgitr2_feat_map,
- ARRAY_SIZE(hfgitr2_feat_map), 0, 0);
- *res0 |= hfgitr2_masks.res0;
+ *res0 = compute_reg_res0_bits(kvm, &hfgitr2_feat_map, 0, 0);
*res1 = HFGITR2_EL2_RES1;
break;
case HDFGRTR2_EL2:
- *res0 = compute_res0_bits(kvm, hdfgrtr2_feat_map,
- ARRAY_SIZE(hdfgrtr2_feat_map), 0, 0);
- *res0 |= hdfgrtr2_masks.res0;
+ *res0 = compute_reg_res0_bits(kvm, &hdfgrtr2_feat_map, 0, 0);
*res1 = HDFGRTR2_EL2_RES1;
break;
case HDFGWTR2_EL2:
- *res0 = compute_res0_bits(kvm, hdfgwtr2_feat_map,
- ARRAY_SIZE(hdfgwtr2_feat_map), 0, 0);
- *res0 |= hdfgwtr2_masks.res0;
+ *res0 = compute_reg_res0_bits(kvm, &hdfgwtr2_feat_map, 0, 0);
*res1 = HDFGWTR2_EL2_RES1;
break;
case HCRX_EL2:
--
2.39.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/8] KVM: arm64: Enforce absence of FEAT_HCX on HCRX_EL2
2025-09-17 16:58 [PATCH 0/8] KVM: arm64: Handle effective RES0 behaviour of undefined registers Marc Zyngier
2025-09-17 16:58 ` [PATCH 1/8] KVM: arm64: Enforce absence of FEAT_FGT on FGT registers Marc Zyngier
2025-09-17 16:58 ` [PATCH 2/8] KVM: arm64: Enforce absence of FEAT_FGT2 on FGT2 registers Marc Zyngier
@ 2025-09-17 16:58 ` Marc Zyngier
2025-09-17 16:58 ` [PATCH 4/8] KVM: arm64: Convert HCR_EL2 RES0 handling to compute_reg_res0_bits() Marc Zyngier
` (4 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Marc Zyngier @ 2025-09-17 16:58 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel
Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
Jinqian Yang
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/config.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 05be2b917c8c0..f8e9cfa844266 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -187,6 +187,7 @@ struct reg_to_feat_map {
#define FEAT_FGT ID_AA64MMFR0_EL1, FGT, IMP
#define FEAT_FGT2 ID_AA64MMFR0_EL1, FGT, FGT2
#define FEAT_MTPMU ID_AA64DFR0_EL1, MTPMU, IMP
+#define FEAT_HCX ID_AA64MMFR1_EL1, HCX, IMP
static bool not_feat_aa64el3(struct kvm *kvm)
{
@@ -893,7 +894,7 @@ struct reg_to_feat_map hdfgwtr2_feat_map = FEAT_MAP_FGT(hdfgwtr2_masks,
hdfgwtr2_bit_feat_map,
FEAT_FGT2);
-static const struct reg_bits_to_feat_map hcrx_feat_map[] = {
+static const struct reg_bits_to_feat_map hcrx_bit_feat_map[] = {
NEEDS_FEAT(HCRX_EL2_PACMEn, feat_pauth_lr),
NEEDS_FEAT(HCRX_EL2_EnFPM, FEAT_FPMR),
NEEDS_FEAT(HCRX_EL2_GCSEn, FEAT_GCS),
@@ -922,6 +923,10 @@ static const struct reg_bits_to_feat_map hcrx_feat_map[] = {
NEEDS_FEAT(HCRX_EL2_EnAS0, FEAT_LS64_ACCDATA),
};
+static const
+struct reg_to_feat_map hcrx_feat_map = FEAT_MAP(__HCRX_EL2, FEAT_HCX,
+ hcrx_bit_feat_map);
+
static const struct reg_bits_to_feat_map hcr_feat_map[] = {
NEEDS_FEAT(HCR_EL2_TID0, FEAT_AA32EL0),
NEEDS_FEAT_FIXED(HCR_EL2_RW, compute_hcr_rw),
@@ -1174,8 +1179,7 @@ void __init check_feature_map(void)
check_reg_feat_map(&hfgitr2_feat_map);
check_reg_feat_map(&hdfgrtr2_feat_map);
check_reg_feat_map(&hdfgwtr2_feat_map);
- check_feat_map(hcrx_feat_map, ARRAY_SIZE(hcrx_feat_map),
- __HCRX_EL2_RES0, "HCRX_EL2");
+ check_reg_feat_map(&hcrx_feat_map);
check_feat_map(hcr_feat_map, ARRAY_SIZE(hcr_feat_map),
HCR_EL2_RES0, "HCR_EL2");
check_feat_map(sctlr2_feat_map, ARRAY_SIZE(sctlr2_feat_map),
@@ -1376,9 +1380,7 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
*res1 = HDFGWTR2_EL2_RES1;
break;
case HCRX_EL2:
- *res0 = compute_res0_bits(kvm, hcrx_feat_map,
- ARRAY_SIZE(hcrx_feat_map), 0, 0);
- *res0 |= __HCRX_EL2_RES0;
+ *res0 = compute_reg_res0_bits(kvm, &hcrx_feat_map, 0, 0);
*res1 = __HCRX_EL2_RES1;
break;
case HCR_EL2:
--
2.39.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 4/8] KVM: arm64: Convert HCR_EL2 RES0 handling to compute_reg_res0_bits()
2025-09-17 16:58 [PATCH 0/8] KVM: arm64: Handle effective RES0 behaviour of undefined registers Marc Zyngier
` (2 preceding siblings ...)
2025-09-17 16:58 ` [PATCH 3/8] KVM: arm64: Enforce absence of FEAT_HCX on HCRX_EL2 Marc Zyngier
@ 2025-09-17 16:58 ` Marc Zyngier
2025-09-17 16:58 ` [PATCH 5/8] KVM: arm64: Enforce absence of FEAT_SCTLR2 on SCTLR2_EL{1,2} Marc Zyngier
` (3 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Marc Zyngier @ 2025-09-17 16:58 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel
Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
Jinqian Yang
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/config.c | 33 ++++++++++++++++-----------------
1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index f8e9cfa844266..c064c31effee9 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -107,6 +107,7 @@ struct reg_to_feat_map {
#define FEAT_AA32EL0 ID_AA64PFR0_EL1, EL0, AARCH32
#define FEAT_AA32EL1 ID_AA64PFR0_EL1, EL1, AARCH32
#define FEAT_AA64EL1 ID_AA64PFR0_EL1, EL1, IMP
+#define FEAT_AA64EL2 ID_AA64PFR0_EL1, EL2, IMP
#define FEAT_AA64EL3 ID_AA64PFR0_EL1, EL3, IMP
#define FEAT_AIE ID_AA64MMFR3_EL1, AIE, IMP
#define FEAT_S2POE ID_AA64MMFR3_EL1, S2POE, IMP
@@ -927,7 +928,7 @@ static const
struct reg_to_feat_map hcrx_feat_map = FEAT_MAP(__HCRX_EL2, FEAT_HCX,
hcrx_bit_feat_map);
-static const struct reg_bits_to_feat_map hcr_feat_map[] = {
+static const struct reg_bits_to_feat_map hcr_bit_feat_map[] = {
NEEDS_FEAT(HCR_EL2_TID0, FEAT_AA32EL0),
NEEDS_FEAT_FIXED(HCR_EL2_RW, compute_hcr_rw),
NEEDS_FEAT(HCR_EL2_HCD, not_feat_aa64el3),
@@ -998,6 +999,10 @@ static const struct reg_bits_to_feat_map hcr_feat_map[] = {
NEEDS_FEAT_FIXED(HCR_EL2_E2H, compute_hcr_e2h),
};
+static const
+struct reg_to_feat_map hcr_feat_map = FEAT_MAP(HCR_EL2, FEAT_AA64EL2,
+ hcr_bit_feat_map);
+
static const struct reg_bits_to_feat_map sctlr2_feat_map[] = {
NEEDS_FEAT(SCTLR2_EL1_NMEA |
SCTLR2_EL1_EASE,
@@ -1180,8 +1185,7 @@ void __init check_feature_map(void)
check_reg_feat_map(&hdfgrtr2_feat_map);
check_reg_feat_map(&hdfgwtr2_feat_map);
check_reg_feat_map(&hcrx_feat_map);
- check_feat_map(hcr_feat_map, ARRAY_SIZE(hcr_feat_map),
- HCR_EL2_RES0, "HCR_EL2");
+ check_reg_feat_map(&hcr_feat_map);
check_feat_map(sctlr2_feat_map, ARRAY_SIZE(sctlr2_feat_map),
SCTLR2_EL1_RES0, "SCTLR2_EL1");
check_feat_map(tcr2_el2_feat_map, ARRAY_SIZE(tcr2_el2_feat_map),
@@ -1271,15 +1275,13 @@ static u64 compute_reg_res0_bits(struct kvm *kvm,
return res0;
}
-static u64 compute_fixed_bits(struct kvm *kvm,
- const struct reg_bits_to_feat_map *map,
- int map_size,
- u64 *fixed_bits,
- unsigned long require,
- unsigned long exclude)
+static u64 compute_reg_fixed_bits(struct kvm *kvm,
+ const struct reg_to_feat_map *r,
+ u64 *fixed_bits, unsigned long require,
+ unsigned long exclude)
{
- return __compute_fixed_bits(kvm, map, map_size, fixed_bits,
- require | FIXED_VALUE, exclude);
+ return __compute_fixed_bits(kvm, r->bit_feat_map, r->bit_feat_map_sz,
+ fixed_bits, require | FIXED_VALUE, exclude);
}
void compute_fgu(struct kvm *kvm, enum fgt_group_id fgt)
@@ -1384,12 +1386,9 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
*res1 = __HCRX_EL2_RES1;
break;
case HCR_EL2:
- mask = compute_fixed_bits(kvm, hcr_feat_map,
- ARRAY_SIZE(hcr_feat_map), &fixed,
- 0, 0);
- *res0 = compute_res0_bits(kvm, hcr_feat_map,
- ARRAY_SIZE(hcr_feat_map), 0, 0);
- *res0 |= HCR_EL2_RES0 | (mask & ~fixed);
+ mask = compute_reg_fixed_bits(kvm, &hcr_feat_map, &fixed, 0, 0);
+ *res0 = compute_reg_res0_bits(kvm, &hcr_feat_map, 0, 0);
+ *res0 |= (mask & ~fixed);
*res1 = HCR_EL2_RES1 | (mask & fixed);
break;
case SCTLR2_EL1:
--
2.39.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 5/8] KVM: arm64: Enforce absence of FEAT_SCTLR2 on SCTLR2_EL{1,2}
2025-09-17 16:58 [PATCH 0/8] KVM: arm64: Handle effective RES0 behaviour of undefined registers Marc Zyngier
` (3 preceding siblings ...)
2025-09-17 16:58 ` [PATCH 4/8] KVM: arm64: Convert HCR_EL2 RES0 handling to compute_reg_res0_bits() Marc Zyngier
@ 2025-09-17 16:58 ` Marc Zyngier
2025-09-17 16:58 ` [PATCH 6/8] KVM: arm64: Enforce absence of FEAT_TCR2 on TCR2_EL2 Marc Zyngier
` (2 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Marc Zyngier @ 2025-09-17 16:58 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel
Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
Jinqian Yang
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/config.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index c064c31effee9..b008551fcf7e9 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -1003,7 +1003,7 @@ static const
struct reg_to_feat_map hcr_feat_map = FEAT_MAP(HCR_EL2, FEAT_AA64EL2,
hcr_bit_feat_map);
-static const struct reg_bits_to_feat_map sctlr2_feat_map[] = {
+static const struct reg_bits_to_feat_map sctlr2_bit_feat_map[] = {
NEEDS_FEAT(SCTLR2_EL1_NMEA |
SCTLR2_EL1_EASE,
FEAT_DoubleFault2),
@@ -1020,6 +1020,10 @@ static const struct reg_bits_to_feat_map sctlr2_feat_map[] = {
FEAT_CPA2),
};
+static const
+struct reg_to_feat_map sctlr2_feat_map = FEAT_MAP(SCTLR2_EL1, FEAT_SCTLR2,
+ sctlr2_bit_feat_map);
+
static const struct reg_bits_to_feat_map tcr2_el2_feat_map[] = {
NEEDS_FEAT(TCR2_EL2_FNG1 |
TCR2_EL2_FNG0 |
@@ -1186,8 +1190,7 @@ void __init check_feature_map(void)
check_reg_feat_map(&hdfgwtr2_feat_map);
check_reg_feat_map(&hcrx_feat_map);
check_reg_feat_map(&hcr_feat_map);
- check_feat_map(sctlr2_feat_map, ARRAY_SIZE(sctlr2_feat_map),
- SCTLR2_EL1_RES0, "SCTLR2_EL1");
+ check_reg_feat_map(&sctlr2_feat_map);
check_feat_map(tcr2_el2_feat_map, ARRAY_SIZE(tcr2_el2_feat_map),
TCR2_EL2_RES0, "TCR2_EL2");
check_feat_map(sctlr_el1_feat_map, ARRAY_SIZE(sctlr_el1_feat_map),
@@ -1393,9 +1396,7 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
break;
case SCTLR2_EL1:
case SCTLR2_EL2:
- *res0 = compute_res0_bits(kvm, sctlr2_feat_map,
- ARRAY_SIZE(sctlr2_feat_map), 0, 0);
- *res0 |= SCTLR2_EL1_RES0;
+ *res0 = compute_reg_res0_bits(kvm, &sctlr2_feat_map, 0, 0);
*res1 = SCTLR2_EL1_RES1;
break;
case TCR2_EL2:
--
2.39.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 6/8] KVM: arm64: Enforce absence of FEAT_TCR2 on TCR2_EL2
2025-09-17 16:58 [PATCH 0/8] KVM: arm64: Handle effective RES0 behaviour of undefined registers Marc Zyngier
` (4 preceding siblings ...)
2025-09-17 16:58 ` [PATCH 5/8] KVM: arm64: Enforce absence of FEAT_SCTLR2 on SCTLR2_EL{1,2} Marc Zyngier
@ 2025-09-17 16:58 ` Marc Zyngier
2025-09-17 16:58 ` [PATCH 7/8] KVM: arm64: Convert SCTLR_EL1 RES0 handling to compute_reg_res0_bits() Marc Zyngier
2025-09-17 16:58 ` [PATCH 8/8] KVM: arm64: Convert MDCR_EL2 " Marc Zyngier
7 siblings, 0 replies; 11+ messages in thread
From: Marc Zyngier @ 2025-09-17 16:58 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel
Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
Jinqian Yang
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/config.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index b008551fcf7e9..0e6723bd75775 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -1024,7 +1024,7 @@ static const
struct reg_to_feat_map sctlr2_feat_map = FEAT_MAP(SCTLR2_EL1, FEAT_SCTLR2,
sctlr2_bit_feat_map);
-static const struct reg_bits_to_feat_map tcr2_el2_feat_map[] = {
+static const struct reg_bits_to_feat_map tcr2_el2_bit_feat_map[] = {
NEEDS_FEAT(TCR2_EL2_FNG1 |
TCR2_EL2_FNG0 |
TCR2_EL2_A2,
@@ -1046,6 +1046,10 @@ static const struct reg_bits_to_feat_map tcr2_el2_feat_map[] = {
NEEDS_FEAT(TCR2_EL2_PIE, FEAT_S1PIE),
};
+static const
+struct reg_to_feat_map tcr2_el2_feat_map = FEAT_MAP(TCR2_EL2, FEAT_TCR2,
+ tcr2_el2_bit_feat_map);
+
static const struct reg_bits_to_feat_map sctlr_el1_feat_map[] = {
NEEDS_FEAT(SCTLR_EL1_CP15BEN |
SCTLR_EL1_ITD |
@@ -1191,8 +1195,7 @@ void __init check_feature_map(void)
check_reg_feat_map(&hcrx_feat_map);
check_reg_feat_map(&hcr_feat_map);
check_reg_feat_map(&sctlr2_feat_map);
- check_feat_map(tcr2_el2_feat_map, ARRAY_SIZE(tcr2_el2_feat_map),
- TCR2_EL2_RES0, "TCR2_EL2");
+ check_reg_feat_map(&tcr2_el2_feat_map);
check_feat_map(sctlr_el1_feat_map, ARRAY_SIZE(sctlr_el1_feat_map),
SCTLR_EL1_RES0, "SCTLR_EL1");
check_feat_map(mdcr_el2_feat_map, ARRAY_SIZE(mdcr_el2_feat_map),
@@ -1400,9 +1403,7 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
*res1 = SCTLR2_EL1_RES1;
break;
case TCR2_EL2:
- *res0 = compute_res0_bits(kvm, tcr2_el2_feat_map,
- ARRAY_SIZE(tcr2_el2_feat_map), 0, 0);
- *res0 |= TCR2_EL2_RES0;
+ *res0 = compute_reg_res0_bits(kvm, &tcr2_el2_feat_map, 0, 0);
*res1 = TCR2_EL2_RES1;
break;
case SCTLR_EL1:
--
2.39.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 7/8] KVM: arm64: Convert SCTLR_EL1 RES0 handling to compute_reg_res0_bits()
2025-09-17 16:58 [PATCH 0/8] KVM: arm64: Handle effective RES0 behaviour of undefined registers Marc Zyngier
` (5 preceding siblings ...)
2025-09-17 16:58 ` [PATCH 6/8] KVM: arm64: Enforce absence of FEAT_TCR2 on TCR2_EL2 Marc Zyngier
@ 2025-09-17 16:58 ` Marc Zyngier
2025-09-17 16:58 ` [PATCH 8/8] KVM: arm64: Convert MDCR_EL2 " Marc Zyngier
7 siblings, 0 replies; 11+ messages in thread
From: Marc Zyngier @ 2025-09-17 16:58 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel
Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
Jinqian Yang
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/config.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 0e6723bd75775..09af46e16ac30 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -1050,7 +1050,7 @@ static const
struct reg_to_feat_map tcr2_el2_feat_map = FEAT_MAP(TCR2_EL2, FEAT_TCR2,
tcr2_el2_bit_feat_map);
-static const struct reg_bits_to_feat_map sctlr_el1_feat_map[] = {
+static const struct reg_bits_to_feat_map sctlr_el1_bit_feat_map[] = {
NEEDS_FEAT(SCTLR_EL1_CP15BEN |
SCTLR_EL1_ITD |
SCTLR_EL1_SED,
@@ -1124,6 +1124,10 @@ static const struct reg_bits_to_feat_map sctlr_el1_feat_map[] = {
FEAT_AA64EL1),
};
+static const
+struct reg_to_feat_map sctlr_el1_feat_map = FEAT_MAP(SCTLR_EL1, FEAT_AA64EL1,
+ sctlr_el1_bit_feat_map);
+
static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
NEEDS_FEAT(MDCR_EL2_EBWE, FEAT_Debugv8p9),
NEEDS_FEAT(MDCR_EL2_TDOSA, FEAT_DoubleLock),
@@ -1196,8 +1200,7 @@ void __init check_feature_map(void)
check_reg_feat_map(&hcr_feat_map);
check_reg_feat_map(&sctlr2_feat_map);
check_reg_feat_map(&tcr2_el2_feat_map);
- check_feat_map(sctlr_el1_feat_map, ARRAY_SIZE(sctlr_el1_feat_map),
- SCTLR_EL1_RES0, "SCTLR_EL1");
+ check_reg_feat_map(&sctlr_el1_feat_map);
check_feat_map(mdcr_el2_feat_map, ARRAY_SIZE(mdcr_el2_feat_map),
MDCR_EL2_RES0, "MDCR_EL2");
}
@@ -1407,9 +1410,7 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
*res1 = TCR2_EL2_RES1;
break;
case SCTLR_EL1:
- *res0 = compute_res0_bits(kvm, sctlr_el1_feat_map,
- ARRAY_SIZE(sctlr_el1_feat_map), 0, 0);
- *res0 |= SCTLR_EL1_RES0;
+ *res0 = compute_reg_res0_bits(kvm, &sctlr_el1_feat_map, 0, 0);
*res1 = SCTLR_EL1_RES1;
break;
case MDCR_EL2:
--
2.39.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 8/8] KVM: arm64: Convert MDCR_EL2 RES0 handling to compute_reg_res0_bits()
2025-09-17 16:58 [PATCH 0/8] KVM: arm64: Handle effective RES0 behaviour of undefined registers Marc Zyngier
` (6 preceding siblings ...)
2025-09-17 16:58 ` [PATCH 7/8] KVM: arm64: Convert SCTLR_EL1 RES0 handling to compute_reg_res0_bits() Marc Zyngier
@ 2025-09-17 16:58 ` Marc Zyngier
7 siblings, 0 replies; 11+ messages in thread
From: Marc Zyngier @ 2025-09-17 16:58 UTC (permalink / raw)
To: kvmarm, linux-arm-kernel
Cc: Joey Gouly, Suzuki K Poulose, Oliver Upton, Zenghui Yu,
Jinqian Yang
Signed-off-by: Marc Zyngier <maz@kernel.org>
---
arch/arm64/kvm/config.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
index 09af46e16ac30..91e235cfdbffd 100644
--- a/arch/arm64/kvm/config.c
+++ b/arch/arm64/kvm/config.c
@@ -1128,7 +1128,7 @@ static const
struct reg_to_feat_map sctlr_el1_feat_map = FEAT_MAP(SCTLR_EL1, FEAT_AA64EL1,
sctlr_el1_bit_feat_map);
-static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
+static const struct reg_bits_to_feat_map mdcr_el2_bit_feat_map[] = {
NEEDS_FEAT(MDCR_EL2_EBWE, FEAT_Debugv8p9),
NEEDS_FEAT(MDCR_EL2_TDOSA, FEAT_DoubleLock),
NEEDS_FEAT(MDCR_EL2_PMEE, FEAT_EBEP),
@@ -1159,6 +1159,10 @@ static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
FEAT_AA64EL1),
};
+static const
+struct reg_to_feat_map mdcr_el2_feat_map = FEAT_MAP(MDCR_EL2, FEAT_AA64EL2,
+ mdcr_el2_bit_feat_map);
+
static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
int map_size, u64 res0, const char *str)
{
@@ -1201,8 +1205,7 @@ void __init check_feature_map(void)
check_reg_feat_map(&sctlr2_feat_map);
check_reg_feat_map(&tcr2_el2_feat_map);
check_reg_feat_map(&sctlr_el1_feat_map);
- check_feat_map(mdcr_el2_feat_map, ARRAY_SIZE(mdcr_el2_feat_map),
- MDCR_EL2_RES0, "MDCR_EL2");
+ check_reg_feat_map(&mdcr_el2_feat_map);
}
static bool idreg_feat_match(struct kvm *kvm, const struct reg_bits_to_feat_map *map)
@@ -1414,8 +1417,7 @@ void get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg, u64 *res0, u64 *r
*res1 = SCTLR_EL1_RES1;
break;
case MDCR_EL2:
- *res0 = compute_res0_bits(kvm, mdcr_el2_feat_map,
- ARRAY_SIZE(mdcr_el2_feat_map), 0, 0);
+ *res0 = compute_reg_res0_bits(kvm, &mdcr_el2_feat_map, 0, 0);
*res0 |= MDCR_EL2_RES0;
*res1 = MDCR_EL2_RES1;
break;
--
2.39.2
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 1/8] KVM: arm64: Enforce absence of FEAT_FGT on FGT registers
2025-09-17 16:58 ` [PATCH 1/8] KVM: arm64: Enforce absence of FEAT_FGT on FGT registers Marc Zyngier
@ 2025-09-18 6:07 ` Oliver Upton
2025-09-18 9:53 ` Marc Zyngier
0 siblings, 1 reply; 11+ messages in thread
From: Oliver Upton @ 2025-09-18 6:07 UTC (permalink / raw)
To: Marc Zyngier
Cc: kvmarm, linux-arm-kernel, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Jinqian Yang
Hey,
On Wed, Sep 17, 2025 at 05:58:33PM +0100, Marc Zyngier wrote:
Did you mean to add changelogs to these patches?
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> ---
> arch/arm64/kvm/config.c | 201 +++++++++++++++++++++++++++-------------
> 1 file changed, 137 insertions(+), 64 deletions(-)
>
> diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> index da66c4a147752..42b834c82a20d 100644
> --- a/arch/arm64/kvm/config.c
> +++ b/arch/arm64/kvm/config.c
> @@ -8,11 +8,16 @@
> #include <asm/sysreg.h>
>
> 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 +33,16 @@ struct reg_bits_to_feat_map {
> };
> };
>
> -#define __NEEDS_FEAT_3(m, f, id, fld, lim) \
> +struct reg_to_feat_map {
> + const char *name;
> + const struct reg_bits_to_feat_map feat_map;
Some documentation might help with confusion between this and
bit_feat_map. IIUC you're using a single NEEDS_FEAT() expression to RES0
the whole sucker based on whether or not the FEAT_XXX for the EL2
register is present?
> + const struct reg_bits_to_feat_map *bit_feat_map;
> + const unsigned int bit_feat_map_sz;
> +};
Ok, differentiating "reg_to_feat_map" and "reg_bits_to_feat_map" is a
bit hard on the reader... Could this maybe be called "reg_feat_map_desc"
or similar?
This refactoring could also be done as a separate patch.
Thanks,
Oliver
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/8] KVM: arm64: Enforce absence of FEAT_FGT on FGT registers
2025-09-18 6:07 ` Oliver Upton
@ 2025-09-18 9:53 ` Marc Zyngier
0 siblings, 0 replies; 11+ messages in thread
From: Marc Zyngier @ 2025-09-18 9:53 UTC (permalink / raw)
To: Oliver Upton
Cc: kvmarm, linux-arm-kernel, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Jinqian Yang
On Thu, 18 Sep 2025 07:07:26 +0100,
Oliver Upton <oliver.upton@linux.dev> wrote:
>
> Hey,
>
> On Wed, Sep 17, 2025 at 05:58:33PM +0100, Marc Zyngier wrote:
>
> Did you mean to add changelogs to these patches?
I actually meant to send a *different* series. Pushed out the wrong
branch and sent crap. Apologies for the noise.
>
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> > ---
> > arch/arm64/kvm/config.c | 201 +++++++++++++++++++++++++++-------------
> > 1 file changed, 137 insertions(+), 64 deletions(-)
> >
> > diff --git a/arch/arm64/kvm/config.c b/arch/arm64/kvm/config.c
> > index da66c4a147752..42b834c82a20d 100644
> > --- a/arch/arm64/kvm/config.c
> > +++ b/arch/arm64/kvm/config.c
> > @@ -8,11 +8,16 @@
> > #include <asm/sysreg.h>
> >
> > 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 +33,16 @@ struct reg_bits_to_feat_map {
> > };
> > };
> >
> > -#define __NEEDS_FEAT_3(m, f, id, fld, lim) \
> > +struct reg_to_feat_map {
> > + const char *name;
> > + const struct reg_bits_to_feat_map feat_map;
>
> Some documentation might help with confusion between this and
> bit_feat_map. IIUC you're using a single NEEDS_FEAT() expression to RES0
> the whole sucker based on whether or not the FEAT_XXX for the EL2
> register is present?
>
> > + const struct reg_bits_to_feat_map *bit_feat_map;
> > + const unsigned int bit_feat_map_sz;
> > +};
>
> Ok, differentiating "reg_to_feat_map" and "reg_bits_to_feat_map" is a
> bit hard on the reader... Could this maybe be called "reg_feat_map_desc"
> or similar?
Sure thing. Things will be a bit noisier, but hey...
> This refactoring could also be done as a separate patch.
Yup, that's what I already have in the series I was suppose to send...
I'll respin this shortly.
Thanks,
M.
--
Without deviation from the norm, progress is not possible.
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-09-18 9:53 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-17 16:58 [PATCH 0/8] KVM: arm64: Handle effective RES0 behaviour of undefined registers Marc Zyngier
2025-09-17 16:58 ` [PATCH 1/8] KVM: arm64: Enforce absence of FEAT_FGT on FGT registers Marc Zyngier
2025-09-18 6:07 ` Oliver Upton
2025-09-18 9:53 ` Marc Zyngier
2025-09-17 16:58 ` [PATCH 2/8] KVM: arm64: Enforce absence of FEAT_FGT2 on FGT2 registers Marc Zyngier
2025-09-17 16:58 ` [PATCH 3/8] KVM: arm64: Enforce absence of FEAT_HCX on HCRX_EL2 Marc Zyngier
2025-09-17 16:58 ` [PATCH 4/8] KVM: arm64: Convert HCR_EL2 RES0 handling to compute_reg_res0_bits() Marc Zyngier
2025-09-17 16:58 ` [PATCH 5/8] KVM: arm64: Enforce absence of FEAT_SCTLR2 on SCTLR2_EL{1,2} Marc Zyngier
2025-09-17 16:58 ` [PATCH 6/8] KVM: arm64: Enforce absence of FEAT_TCR2 on TCR2_EL2 Marc Zyngier
2025-09-17 16:58 ` [PATCH 7/8] KVM: arm64: Convert SCTLR_EL1 RES0 handling to compute_reg_res0_bits() Marc Zyngier
2025-09-17 16:58 ` [PATCH 8/8] KVM: arm64: Convert MDCR_EL2 " Marc Zyngier
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).