]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
arm64: Convert VTCR_EL2 to sysreg infratructure
authorMarc Zyngier <maz@kernel.org>
Wed, 10 Dec 2025 17:30:21 +0000 (17:30 +0000)
committerMarc Zyngier <maz@kernel.org>
Thu, 15 Jan 2026 10:58:20 +0000 (10:58 +0000)
Our definition of VTCR_EL2 is both partial (tons of fields are
missing) and totally inconsistent (some constants are shifted,
some are not). They are also expressed in terms of TCR, which is
rather inconvenient.

Replace the ad-hoc definitions with the the generated version.
This results in a bunch of additional changes to make the code
with the unshifted nature of generated enumerations.

The register data was extracted from the BSD licenced AARCHMRS
(AARCHMRS_OPENSOURCE_A_profile_FAT-2025-09_ASL0).

Reviewed-by: Alexandru Elisei <alexandru.elisei@arm.com>
Reviewed-by: Fuad Tabba <tabba@google.com>
Tested-by: Fuad Tabba <tabba@google.com>
Link: https://patch.msgid.link/20251210173024.561160-4-maz@kernel.org
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/include/asm/kvm_arm.h
arch/arm64/include/asm/sysreg.h
arch/arm64/kvm/hyp/pgtable.c
arch/arm64/kvm/nested.c
arch/arm64/tools/sysreg

index e500600e4b9b8cf555a5b555db21b935dc6f83c1..dfdbd2b65db9e273e6bca8ba1b27b14d9f94e4af 100644 (file)
 #define TCR_EL2_MASK   (TCR_EL2_TG0_MASK | TCR_EL2_SH0_MASK | \
                         TCR_EL2_ORGN0_MASK | TCR_EL2_IRGN0_MASK)
 
-/* VTCR_EL2 Registers bits */
-#define VTCR_EL2_DS            TCR_EL2_DS
-#define VTCR_EL2_RES1          (1U << 31)
-#define VTCR_EL2_HD            (1 << 22)
-#define VTCR_EL2_HA            (1 << 21)
-#define VTCR_EL2_PS_SHIFT      TCR_EL2_PS_SHIFT
-#define VTCR_EL2_PS_MASK       TCR_EL2_PS_MASK
-#define VTCR_EL2_TG0_MASK      TCR_TG0_MASK
-#define VTCR_EL2_TG0_4K                TCR_TG0_4K
-#define VTCR_EL2_TG0_16K       TCR_TG0_16K
-#define VTCR_EL2_TG0_64K       TCR_TG0_64K
-#define VTCR_EL2_SH0_MASK      TCR_SH0_MASK
-#define VTCR_EL2_SH0_INNER     TCR_SH0_INNER
-#define VTCR_EL2_ORGN0_MASK    TCR_ORGN0_MASK
-#define VTCR_EL2_ORGN0_WBWA    TCR_ORGN0_WBWA
-#define VTCR_EL2_IRGN0_MASK    TCR_IRGN0_MASK
-#define VTCR_EL2_IRGN0_WBWA    TCR_IRGN0_WBWA
-#define VTCR_EL2_SL0_SHIFT     6
-#define VTCR_EL2_SL0_MASK      (3 << VTCR_EL2_SL0_SHIFT)
-#define VTCR_EL2_T0SZ_MASK     0x3f
-#define VTCR_EL2_VS_SHIFT      19
-#define VTCR_EL2_VS_8BIT       (0 << VTCR_EL2_VS_SHIFT)
-#define VTCR_EL2_VS_16BIT      (1 << VTCR_EL2_VS_SHIFT)
-
-#define VTCR_EL2_T0SZ(x)       TCR_T0SZ(x)
-
 /*
- * We configure the Stage-2 page tables to always restrict the IPA space to be
- * 40 bits wide (T0SZ = 24).  Systems with a PARange smaller than 40 bits are
- * not known to exist and will break with this configuration.
- *
  * The VTCR_EL2 is configured per VM and is initialised in kvm_init_stage2_mmu.
  *
  * Note that when using 4K pages, we concatenate two first level page tables
  *
  */
 
-#define VTCR_EL2_COMMON_BITS   (VTCR_EL2_SH0_INNER | VTCR_EL2_ORGN0_WBWA | \
-                                VTCR_EL2_IRGN0_WBWA | VTCR_EL2_RES1)
-
 /*
  * VTCR_EL2:SL0 indicates the entry level for Stage2 translation.
  * Interestingly, it depends on the page size.
  */
 #ifdef CONFIG_ARM64_64K_PAGES
 
-#define VTCR_EL2_TGRAN                 VTCR_EL2_TG0_64K
+#define VTCR_EL2_TGRAN                 64K
 #define VTCR_EL2_TGRAN_SL0_BASE                3UL
 
 #elif defined(CONFIG_ARM64_16K_PAGES)
 
-#define VTCR_EL2_TGRAN                 VTCR_EL2_TG0_16K
+#define VTCR_EL2_TGRAN                 16K
 #define VTCR_EL2_TGRAN_SL0_BASE                3UL
 
 #else  /* 4K */
 
-#define VTCR_EL2_TGRAN                 VTCR_EL2_TG0_4K
+#define VTCR_EL2_TGRAN                 4K
 #define VTCR_EL2_TGRAN_SL0_BASE                2UL
 
 #endif
 
 #define VTCR_EL2_LVLS_TO_SL0(levels)   \
-       ((VTCR_EL2_TGRAN_SL0_BASE - (4 - (levels))) << VTCR_EL2_SL0_SHIFT)
+       FIELD_PREP(VTCR_EL2_SL0, (VTCR_EL2_TGRAN_SL0_BASE - (4 - (levels))))
 #define VTCR_EL2_SL0_TO_LVLS(sl0)      \
        ((sl0) + 4 - VTCR_EL2_TGRAN_SL0_BASE)
 #define VTCR_EL2_LVLS(vtcr)            \
-       VTCR_EL2_SL0_TO_LVLS(((vtcr) & VTCR_EL2_SL0_MASK) >> VTCR_EL2_SL0_SHIFT)
+       VTCR_EL2_SL0_TO_LVLS(FIELD_GET(VTCR_EL2_SL0, (vtcr)))
+
+#define VTCR_EL2_FLAGS (SYS_FIELD_PREP_ENUM(VTCR_EL2, SH0, INNER)          | \
+                        SYS_FIELD_PREP_ENUM(VTCR_EL2, ORGN0, WBWA)         | \
+                        SYS_FIELD_PREP_ENUM(VTCR_EL2, IRGN0, WBWA)         | \
+                        SYS_FIELD_PREP_ENUM(VTCR_EL2, TG0, VTCR_EL2_TGRAN) | \
+                        VTCR_EL2_RES1)
 
-#define VTCR_EL2_FLAGS                 (VTCR_EL2_COMMON_BITS | VTCR_EL2_TGRAN)
-#define VTCR_EL2_IPA(vtcr)             (64 - ((vtcr) & VTCR_EL2_T0SZ_MASK))
+#define VTCR_EL2_IPA(vtcr)             (64 - FIELD_GET(VTCR_EL2_T0SZ, (vtcr)))
 
 /*
  * ARM VMSAv8-64 defines an algorithm for finding the translation table
index 106b15eb232a46eee9aa95a216cfe064dd74d83d..939f9c5bbae670405079cb12b069be965f1e16a2 100644 (file)
 #define SYS_TTBR1_EL2                  sys_reg(3, 4, 2, 0, 1)
 #define SYS_TCR_EL2                    sys_reg(3, 4, 2, 0, 2)
 #define SYS_VTTBR_EL2                  sys_reg(3, 4, 2, 1, 0)
-#define SYS_VTCR_EL2                   sys_reg(3, 4, 2, 1, 2)
 
 #define SYS_HAFGRTR_EL2                        sys_reg(3, 4, 3, 1, 6)
 #define SYS_SPSR_EL2                   sys_reg(3, 4, 4, 0, 0)
index 9abc0a6cf448109aba081022bbed15aa9889db7d..a99a7d6e7d0c83135626c7bac3785567acea4e01 100644 (file)
@@ -583,8 +583,8 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
        u64 vtcr = VTCR_EL2_FLAGS;
        s8 lvls;
 
-       vtcr |= kvm_get_parange(mmfr0) << VTCR_EL2_PS_SHIFT;
-       vtcr |= VTCR_EL2_T0SZ(phys_shift);
+       vtcr |= FIELD_PREP(VTCR_EL2_PS, kvm_get_parange(mmfr0));
+       vtcr |= FIELD_PREP(VTCR_EL2_T0SZ, (UL(64) - phys_shift));
        /*
         * Use a minimum 2 level page table to prevent splitting
         * host PMD huge pages at stage2.
@@ -624,9 +624,7 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
                vtcr |= VTCR_EL2_DS;
 
        /* Set the vmid bits */
-       vtcr |= (get_vmid_bits(mmfr1) == 16) ?
-               VTCR_EL2_VS_16BIT :
-               VTCR_EL2_VS_8BIT;
+       vtcr |= (get_vmid_bits(mmfr1) == 16) ? VTCR_EL2_VS : 0;
 
        return vtcr;
 }
index cdeeb8f09e722532538c90a798367ce86ce2be6c..522fa3cc95783094acb674158266938c04a0b223 100644 (file)
@@ -377,7 +377,7 @@ static void vtcr_to_walk_info(u64 vtcr, struct s2_walk_info *wi)
 {
        wi->t0sz = vtcr & TCR_EL2_T0SZ_MASK;
 
-       switch (vtcr & VTCR_EL2_TG0_MASK) {
+       switch (FIELD_GET(VTCR_EL2_TG0_MASK, vtcr)) {
        case VTCR_EL2_TG0_4K:
                wi->pgshift = 12;        break;
        case VTCR_EL2_TG0_16K:
@@ -513,7 +513,7 @@ static u8 get_guest_mapping_ttl(struct kvm_s2_mmu *mmu, u64 addr)
 
        lockdep_assert_held_write(&kvm_s2_mmu_to_kvm(mmu)->mmu_lock);
 
-       switch (vtcr & VTCR_EL2_TG0_MASK) {
+       switch (FIELD_GET(VTCR_EL2_TG0_MASK, vtcr)) {
        case VTCR_EL2_TG0_4K:
                ttl = (TLBI_TTL_TG_4K << 2);
                break;
@@ -530,7 +530,7 @@ static u8 get_guest_mapping_ttl(struct kvm_s2_mmu *mmu, u64 addr)
 
 again:
        /* Iteratively compute the block sizes for a particular granule size */
-       switch (vtcr & VTCR_EL2_TG0_MASK) {
+       switch (FIELD_GET(VTCR_EL2_TG0_MASK, vtcr)) {
        case VTCR_EL2_TG0_4K:
                if      (sz < SZ_4K)    sz = SZ_4K;
                else if (sz < SZ_2M)    sz = SZ_2M;
@@ -593,7 +593,7 @@ unsigned long compute_tlb_inval_range(struct kvm_s2_mmu *mmu, u64 val)
 
        if (!max_size) {
                /* Compute the maximum extent of the invalidation */
-               switch (mmu->tlb_vtcr & VTCR_EL2_TG0_MASK) {
+               switch (FIELD_GET(VTCR_EL2_TG0_MASK, mmu->tlb_vtcr)) {
                case VTCR_EL2_TG0_4K:
                        max_size = SZ_1G;
                        break;
index 063b13b7c7319fea6fed24566d5bf9b4f0f2b078..a0f6249bd4f98c66265ea844f5a70b05b856f7d3 100644 (file)
@@ -4400,6 +4400,63 @@ Field    56:12   BADDR
 Res0   11:0
 EndSysreg
 
+Sysreg VTCR_EL2        3       4       2       1       2
+Res0   63:46
+Field  45      HDBSS
+Field  44      HAFT
+Res0   43:42
+Field  41      TL0
+Field  40      GCSH
+Res0   39
+Field  38      D128
+Field  37      S2POE
+Field  36      S2PIE
+Field  35      TL1
+Field  34      AssuredOnly
+Field  33      SL2
+Field  32      DS
+Res1   31
+Field  30      NSA
+Field  29      NSW
+Field  28      HWU62
+Field  27      HWU61
+Field  26      HWU60
+Field  25      HWU59
+Res0   24:23
+Field  22      HD
+Field  21      HA
+Res0   20
+Enum   19      VS
+       0b0     8BIT
+       0b1     16BIT
+EndEnum
+Field  18:16   PS
+Enum   15:14   TG0
+       0b00    4K
+       0b01    64K
+       0b10    16K
+EndEnum
+Enum   13:12   SH0
+       0b00    NONE
+       0b01    OUTER
+       0b11    INNER
+EndEnum
+Enum   11:10   ORGN0
+       0b00    NC
+       0b01    WBWA
+       0b10    WT
+       0b11    WBnWA
+EndEnum
+Enum   9:8     IRGN0
+       0b00    NC
+       0b01    WBWA
+       0b10    WT
+       0b11    WBnWA
+EndEnum
+Field  7:6     SL0
+Field  5:0     T0SZ
+EndSysreg
+
 Sysreg GCSCR_EL2       3       4       2       5       0
 Fields GCSCR_ELx
 EndSysreg