]> www.infradead.org Git - users/hch/misc.git/commitdiff
KVM: arm64: Enforce absence of FEAT_FGT on FGT registers
authorMarc Zyngier <maz@kernel.org>
Thu, 18 Sep 2025 15:13:55 +0000 (16:13 +0100)
committerMarc Zyngier <maz@kernel.org>
Fri, 19 Sep 2025 12:43:26 +0000 (13:43 +0100)
As we want to enforce FGT registers behaving as RES0 when FEAT_FGT
is not exposed to the guest, We move a bumch of things that are
so far passed as parameter into a structure that points to the
bit description.

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

index c2bfffe660bcafdf573ca09db52496d1643eb3e2..887e7338fffec9e653247ae3a37bf64780ff5be5 100644 (file)
@@ -458,6 +458,10 @@ static const struct reg_bits_to_feat_map hfgrtr_feat_map[] = {
                        NEVER_FGU, FEAT_AA64EL1),
 };
 
+
+static const DECLARE_FEAT_MAP_FGT(hfgrtr_desc, hfgrtr_masks,
+                                 hfgrtr_feat_map, FEAT_FGT);
+
 static const struct reg_bits_to_feat_map hfgwtr_feat_map[] = {
        NEEDS_FEAT(HFGWTR_EL2_nAMAIR2_EL1       |
                   HFGWTR_EL2_nMAIR2_EL1,
@@ -522,6 +526,9 @@ static const struct reg_bits_to_feat_map hfgwtr_feat_map[] = {
                        NEVER_FGU, FEAT_AA64EL1),
 };
 
+static const DECLARE_FEAT_MAP_FGT(hfgwtr_desc, hfgwtr_masks,
+                                 hfgwtr_feat_map, FEAT_FGT);
+
 static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = {
        NEEDS_FEAT(HDFGRTR_EL2_PMBIDR_EL1       |
                   HDFGRTR_EL2_PMSLATFR_EL1     |
@@ -589,6 +596,9 @@ static const struct reg_bits_to_feat_map hdfgrtr_feat_map[] = {
                        NEVER_FGU, FEAT_AA64EL1)
 };
 
+static const DECLARE_FEAT_MAP_FGT(hdfgrtr_desc, hdfgrtr_masks,
+                                 hdfgrtr_feat_map, FEAT_FGT);
+
 static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = {
        NEEDS_FEAT(HDFGWTR_EL2_PMSLATFR_EL1     |
                   HDFGWTR_EL2_PMSIRR_EL1       |
@@ -649,6 +659,8 @@ static const struct reg_bits_to_feat_map hdfgwtr_feat_map[] = {
        NEEDS_FEAT(HDFGWTR_EL2_TRFCR_EL1, FEAT_TRF),
 };
 
+static const DECLARE_FEAT_MAP_FGT(hdfgwtr_desc, hdfgwtr_masks,
+                                 hdfgwtr_feat_map, FEAT_FGT);
 
 static const struct reg_bits_to_feat_map hfgitr_feat_map[] = {
        NEEDS_FEAT(HFGITR_EL2_PSBCSYNC, FEAT_SPEv1p5),
@@ -723,6 +735,9 @@ static const struct reg_bits_to_feat_map hfgitr_feat_map[] = {
                        NEVER_FGU, FEAT_AA64EL1),
 };
 
+static const DECLARE_FEAT_MAP_FGT(hfgitr_desc, hfgitr_masks,
+                                 hfgitr_feat_map, FEAT_FGT);
+
 static const struct reg_bits_to_feat_map hafgrtr_feat_map[] = {
        NEEDS_FEAT(HAFGRTR_EL2_AMEVTYPER115_EL0 |
                   HAFGRTR_EL2_AMEVTYPER114_EL0 |
@@ -765,6 +780,9 @@ static const struct reg_bits_to_feat_map hafgrtr_feat_map[] = {
                   FEAT_AMUv1),
 };
 
+static const DECLARE_FEAT_MAP_FGT(hafgrtr_desc, hafgrtr_masks,
+                                 hafgrtr_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)
@@ -1122,20 +1140,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_desc(const struct reg_feat_map_desc *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_desc(&hfgrtr_desc);
+       check_reg_desc(&hfgwtr_desc);
+       check_reg_desc(&hfgitr_desc);
+       check_reg_desc(&hdfgrtr_desc);
+       check_reg_desc(&hdfgwtr_desc);
+       check_reg_desc(&hafgrtr_desc);
        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),
@@ -1190,7 +1213,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;
@@ -1206,6 +1229,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_feat_map_desc *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,
@@ -1223,30 +1269,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_desc,
+                                            0, NEVER_FGU);
+               val |= compute_reg_res0_bits(kvm, &hfgwtr_desc,
+                                            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_desc,
+                                            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_desc,
+                                            0, NEVER_FGU);
+               val |= compute_reg_res0_bits(kvm, &hdfgwtr_desc,
+                                            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_desc,
+                                            0, NEVER_FGU);
                break;
        case HFGRTR2_GROUP:
                val |= compute_res0_bits(kvm, hfgrtr2_feat_map,
@@ -1282,39 +1322,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_desc, 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_desc, 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_desc, 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_desc, 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_desc, 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_desc, 0, 0);
                *res1 = HAFGRTR_EL2_RES1;
                break;
        case HFGRTR2_EL2: