]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: arm64: Move RESx into individual register descriptors
authorMarc Zyngier <maz@kernel.org>
Mon, 2 Feb 2026 18:43:22 +0000 (18:43 +0000)
committerMarc Zyngier <maz@kernel.org>
Thu, 5 Feb 2026 09:02:13 +0000 (09:02 +0000)
Instead of hacking the RES1 bits at runtime, move them into the
register descriptors. This makes it significantly nicer.

Reviewed-by: Fuad Tabba <tabba@google.com>
Tested-by: Fuad Tabba <tabba@google.com>
Link: https://patch.msgid.link/20260202184329.2724080-14-maz@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/kvm/config.c

index 7e8e42c1cee4a28f02ab5771ea6bf2a0e164a757..474d5c8038c2434386bd7f8c5be1877694bb187a 100644 (file)
@@ -28,6 +28,7 @@ struct reg_bits_to_feat_map {
 #define        REQUIRES_E2H1   BIT(5)  /* Add HCR_EL2.E2H RES1 as a pre-condition */
 #define        RES1_WHEN_E2H0  BIT(6)  /* RES1 when E2H=0 and not supported */
 #define        RES1_WHEN_E2H1  BIT(7)  /* RES1 when E2H=1 and not supported */
+#define        FORCE_RESx      BIT(8)  /* Unconditional RESx */
 
        unsigned long   flags;
 
@@ -87,6 +88,12 @@ struct reg_feat_map_desc {
                .match = (fun),                         \
        }
 
+#define __NEEDS_FEAT_0(m, f, w, ...)                   \
+       {                                               \
+               .w      = (m),                          \
+               .flags = (f),                           \
+       }
+
 #define __NEEDS_FEAT_FLAG(m, f, w, ...)                        \
        CONCATENATE(__NEEDS_FEAT_, COUNT_ARGS(__VA_ARGS__))(m, f, w, __VA_ARGS__)
 
@@ -105,10 +112,14 @@ struct reg_feat_map_desc {
  */
 #define NEEDS_FEAT(m, ...)     NEEDS_FEAT_FLAG(m, 0, __VA_ARGS__)
 
+/* Declare fixed RESx bits */
+#define FORCE_RES0(m)          NEEDS_FEAT_FLAG(m, FORCE_RESx)
+#define FORCE_RES1(m)          NEEDS_FEAT_FLAG(m, FORCE_RESx | AS_RES1)
+
 /*
- * 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.
+ * Declare the dependency between a non-FGT register, a set of features,
+ * 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 = {                                  \
@@ -1007,6 +1018,8 @@ static const struct reg_bits_to_feat_map hcr_feat_map[] = {
                   HCR_EL2_TWEDEn,
                   FEAT_TWED),
        NEEDS_FEAT_FIXED(HCR_EL2_E2H, compute_hcr_e2h),
+       FORCE_RES0(HCR_EL2_RES0),
+       FORCE_RES1(HCR_EL2_RES1),
 };
 
 static const DECLARE_FEAT_MAP(hcr_desc, HCR_EL2,
@@ -1027,6 +1040,8 @@ static const struct reg_bits_to_feat_map sctlr2_feat_map[] = {
                   SCTLR2_EL1_CPTM      |
                   SCTLR2_EL1_CPTM0,
                   FEAT_CPA2),
+       FORCE_RES0(SCTLR2_EL1_RES0),
+       FORCE_RES1(SCTLR2_EL1_RES1),
 };
 
 static const DECLARE_FEAT_MAP(sctlr2_desc, SCTLR2_EL1,
@@ -1052,6 +1067,8 @@ static const struct reg_bits_to_feat_map tcr2_el2_feat_map[] = {
                   TCR2_EL2_E0POE,
                   FEAT_S1POE),
        NEEDS_FEAT(TCR2_EL2_PIE, FEAT_S1PIE),
+       FORCE_RES0(TCR2_EL2_RES0),
+       FORCE_RES1(TCR2_EL2_RES1),
 };
 
 static const DECLARE_FEAT_MAP(tcr2_el2_desc, TCR2_EL2,
@@ -1129,6 +1146,8 @@ static const struct reg_bits_to_feat_map sctlr_el1_feat_map[] = {
                   SCTLR_EL1_A          |
                   SCTLR_EL1_M,
                   FEAT_AA64EL1),
+       FORCE_RES0(SCTLR_EL1_RES0),
+       FORCE_RES1(SCTLR_EL1_RES1),
 };
 
 static const DECLARE_FEAT_MAP(sctlr_el1_desc, SCTLR_EL1,
@@ -1163,6 +1182,8 @@ static const struct reg_bits_to_feat_map mdcr_el2_feat_map[] = {
                   MDCR_EL2_TDE         |
                   MDCR_EL2_TDRA,
                   FEAT_AA64EL1),
+       FORCE_RES0(MDCR_EL2_RES0),
+       FORCE_RES1(MDCR_EL2_RES1),
 };
 
 static const DECLARE_FEAT_MAP(mdcr_el2_desc, MDCR_EL2,
@@ -1201,6 +1222,8 @@ static const struct reg_bits_to_feat_map vtcr_el2_feat_map[] = {
                   VTCR_EL2_SL0         |
                   VTCR_EL2_T0SZ,
                   FEAT_AA64EL1),
+       FORCE_RES0(VTCR_EL2_RES0),
+       FORCE_RES1(VTCR_EL2_RES1),
 };
 
 static const DECLARE_FEAT_MAP(vtcr_el2_desc, VTCR_EL2,
@@ -1211,8 +1234,14 @@ static void __init check_feat_map(const struct reg_bits_to_feat_map *map,
 {
        u64 mask = 0;
 
+       /*
+        * Don't account for FORCE_RESx that are architectural, and
+        * therefore part of the resx parameter. Other FORCE_RESx bits
+        * are implementation choices, and therefore accounted for.
+        */
        for (int i = 0; i < map_size; i++)
-               mask |= map[i].bits;
+               if (!((map[i].flags & FORCE_RESx) && (map[i].bits & resx)))
+                       mask |= map[i].bits;
 
        if (mask != ~resx)
                kvm_err("Undefined %s behaviour, bits %016llx\n",
@@ -1284,13 +1313,16 @@ static struct resx compute_resx_bits(struct kvm *kvm,
                if (map[i].flags & exclude)
                        continue;
 
-               switch (map[i].flags & (CALL_FUNC | FIXED_VALUE)) {
+               switch (map[i].flags & (FORCE_RESx | CALL_FUNC | FIXED_VALUE)) {
                case CALL_FUNC | FIXED_VALUE:
                        map[i].fval(kvm, &resx);
                        continue;
                case CALL_FUNC:
                        match = map[i].match(kvm);
                        break;
+               case FORCE_RESx:
+                       match = false;
+                       break;
                default:
                        match = idreg_feat_match(kvm, &map[i]);
                }
@@ -1434,28 +1466,22 @@ struct resx get_reg_fixed_bits(struct kvm *kvm, enum vcpu_sysreg reg)
                break;
        case HCR_EL2:
                resx = compute_reg_resx_bits(kvm, &hcr_desc, 0, 0);
-               resx.res1 |= HCR_EL2_RES1;
                break;
        case SCTLR2_EL1:
        case SCTLR2_EL2:
                resx = compute_reg_resx_bits(kvm, &sctlr2_desc, 0, 0);
-               resx.res1 |= SCTLR2_EL1_RES1;
                break;
        case TCR2_EL2:
                resx = compute_reg_resx_bits(kvm, &tcr2_el2_desc, 0, 0);
-               resx.res1 |= TCR2_EL2_RES1;
                break;
        case SCTLR_EL1:
                resx = compute_reg_resx_bits(kvm, &sctlr_el1_desc, 0, 0);
-               resx.res1 |= SCTLR_EL1_RES1;
                break;
        case MDCR_EL2:
                resx = compute_reg_resx_bits(kvm, &mdcr_el2_desc, 0, 0);
-               resx.res1 |= MDCR_EL2_RES1;
                break;
        case VTCR_EL2:
                resx = compute_reg_resx_bits(kvm, &vtcr_el2_desc, 0, 0);
-               resx.res1 |= VTCR_EL2_RES1;
                break;
        default:
                WARN_ON_ONCE(1);