aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Turner <andrew@FreeBSD.org>2025-01-24 11:36:18 +0000
committerAndrew Turner <andrew@FreeBSD.org>2025-01-24 12:09:27 +0000
commit3041b636463d521e3c2bbea7673da6afceec34e5 (patch)
treea4f2daff71d7dd42a46c8fa9f1e463a17a6df333
parent3bf6554017b78f03bb779a5a3115034243e5c6c7 (diff)
arm64: Support mapping a 52-bit physical adddress
When FEAT_LPA2 is enabled the physical address space increases from 48-bits to 52-bits. The top two address bits are moved to the now unused shareability field. Update the kernel to support this new larger address space. Reviewed by: alc, kib Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D46624
-rw-r--r--sys/arm64/arm64/pmap.c2
-rw-r--r--sys/arm64/include/armreg.h2
-rw-r--r--sys/arm64/include/hypervisor.h1
-rw-r--r--sys/arm64/include/pmap.h2
-rw-r--r--sys/arm64/include/pte.h52
-rw-r--r--sys/arm64/vmm/vmm_arm64.c10
6 files changed, 57 insertions, 12 deletions
diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index 23eedff2e7cd..5c1e5bb63e4d 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -355,7 +355,7 @@ static u_int physmap_idx;
static SYSCTL_NODE(_vm, OID_AUTO, pmap, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
"VM/pmap parameters");
-static bool pmap_lpa_enabled __read_mostly = false;
+bool pmap_lpa_enabled __read_mostly = false;
pt_entry_t pmap_sh_attr __read_mostly = ATTR_SH(ATTR_SH_IS);
#if PAGE_SIZE == PAGE_SIZE_4K
diff --git a/sys/arm64/include/armreg.h b/sys/arm64/include/armreg.h
index d586d3568bd7..2a2c8b23e0a4 100644
--- a/sys/arm64/include/armreg.h
+++ b/sys/arm64/include/armreg.h
@@ -2066,7 +2066,7 @@
#define PAR_NS_SHIFT 9
#define PAR_NS_MASK (0x3 << PAR_NS_SHIFT)
#define PAR_PA_SHIFT 12
-#define PAR_PA_MASK 0x0000fffffffff000
+#define PAR_PA_MASK 0x000ffffffffff000
#define PAR_ATTR_SHIFT 56
#define PAR_ATTR_MASK (0xff << PAR_ATTR_SHIFT)
/* When PAR_F == 1 (aborted) */
diff --git a/sys/arm64/include/hypervisor.h b/sys/arm64/include/hypervisor.h
index 15fc36014626..a32e1000d911 100644
--- a/sys/arm64/include/hypervisor.h
+++ b/sys/arm64/include/hypervisor.h
@@ -281,6 +281,7 @@
#define VTCR_EL2_PS_42BIT (0x3UL << VTCR_EL2_PS_SHIFT)
#define VTCR_EL2_PS_44BIT (0x4UL << VTCR_EL2_PS_SHIFT)
#define VTCR_EL2_PS_48BIT (0x5UL << VTCR_EL2_PS_SHIFT)
+#define VTCR_EL2_PS_52BIT (0x6UL << VTCR_EL2_PS_SHIFT)
#define VTCR_EL2_DS_SHIFT 32
#define VTCR_EL2_DS (0x1UL << VTCR_EL2_DS_SHIFT)
diff --git a/sys/arm64/include/pmap.h b/sys/arm64/include/pmap.h
index d92069ee42fd..75de9e342c72 100644
--- a/sys/arm64/include/pmap.h
+++ b/sys/arm64/include/pmap.h
@@ -101,6 +101,8 @@ extern struct pmap kernel_pmap_store;
#define kernel_pmap (&kernel_pmap_store)
#define pmap_kernel() kernel_pmap
+extern bool pmap_lpa_enabled;
+
#define PMAP_ASSERT_LOCKED(pmap) \
mtx_assert(&(pmap)->pm_mtx, MA_OWNED)
#define PMAP_LOCK(pmap) mtx_lock(&(pmap)->pm_mtx)
diff --git a/sys/arm64/include/pte.h b/sys/arm64/include/pte.h
index 02eba21448ba..ae6a8694f6c4 100644
--- a/sys/arm64/include/pte.h
+++ b/sys/arm64/include/pte.h
@@ -54,13 +54,6 @@ typedef uint64_t pt_entry_t; /* page table entry */
#define ATTR_MASK_L UINT64_C(0x0000000000000fff)
#define ATTR_MASK (ATTR_MASK_H | ATTR_MASK_L)
-#define BASE_MASK ~ATTR_MASK
-#define BASE_ADDR(x) ((x) & BASE_MASK)
-
-#define PTE_TO_PHYS(pte) BASE_ADDR(pte)
-/* Convert a phys addr to the output address field of a PTE */
-#define PHYS_TO_PTE(pa) (pa)
-
/* Bits 58:55 are reserved for software */
#define ATTR_SW_UNUSED1 (1UL << 58)
#define ATTR_SW_NO_PROMOTE (1UL << 57)
@@ -81,13 +74,35 @@ typedef uint64_t pt_entry_t; /* page table entry */
#define ATTR_CONTIGUOUS (1UL << 52)
#define ATTR_DBM (1UL << 51)
#define ATTR_S1_GP (1UL << 50)
+
+/*
+ * Largest possible output address field for a level 3 page. Block
+ * entries will use fewer low address bits, but these are res0 so
+ * should be safe to include.
+ *
+ * This is also safe to use for the next-level table address for
+ * table entries as they encode a physical address in the same way.
+ */
+#if PAGE_SIZE == PAGE_SIZE_4K
+#define ATTR_ADDR UINT64_C(0x0003fffffffff000)
+#elif PAGE_SIZE == PAGE_SIZE_16K
+#define ATTR_ADDR UINT64_C(0x0003ffffffffc000)
+#else
+#error Unsupported page size
+#endif
+
#define ATTR_S1_nG (1 << 11)
#define ATTR_AF (1 << 10)
+/* When TCR_EL1.DS == 0 */
#define ATTR_SH(x) ((x) << 8)
#define ATTR_SH_MASK ATTR_SH(3)
#define ATTR_SH_NS 0 /* Non-shareable */
#define ATTR_SH_OS 2 /* Outer-shareable */
#define ATTR_SH_IS 3 /* Inner-shareable */
+/* When TCR_EL1.DS == 1 */
+#define ATTR_OA_51_50_SHIFT 8
+#define ATTR_OA_51_50_MASK (3 << ATTR_OA_51_50_SHIFT)
+#define ATTR_OA_51_50_DELTA (50 - 8) /* Delta from address to pte */
#define ATTR_S1_AP_RW_BIT (1 << 7)
#define ATTR_S1_AP(x) ((x) << 6)
@@ -124,6 +139,29 @@ typedef uint64_t pt_entry_t; /* page table entry */
*/
#define ATTR_PROMOTE (ATTR_MASK & ~(ATTR_CONTIGUOUS | ATTR_AF))
+/* Read the output address or next-level table address from a PTE */
+#define PTE_TO_PHYS(x) ({ \
+ pt_entry_t _pte = (x); \
+ vm_paddr_t _pa; \
+ _pa = _pte & ATTR_ADDR; \
+ if (pmap_lpa_enabled) \
+ _pa |= (_pte & ATTR_OA_51_50_MASK) << ATTR_OA_51_50_DELTA; \
+ _pa; \
+})
+
+/*
+ * Convert a physical address to an output address or next-level
+ * table address in a PTE
+ */
+#define PHYS_TO_PTE(x) ({ \
+ vm_paddr_t _pa = (x); \
+ pt_entry_t _pte; \
+ _pte = _pa & ATTR_ADDR; \
+ if (pmap_lpa_enabled) \
+ _pte |= (_pa >> ATTR_OA_51_50_DELTA) & ATTR_OA_51_50_MASK; \
+ _pte; \
+})
+
#if PAGE_SIZE == PAGE_SIZE_4K
#define L0_SHIFT 39
#define L1_SHIFT 30
diff --git a/sys/arm64/vmm/vmm_arm64.c b/sys/arm64/vmm/vmm_arm64.c
index 80d985241c69..43b2ba7802d7 100644
--- a/sys/arm64/vmm/vmm_arm64.c
+++ b/sys/arm64/vmm/vmm_arm64.c
@@ -381,8 +381,6 @@ vmmops_modinit(int ipinum)
* shareable
*/
el2_regs.vtcr_el2 = VTCR_EL2_RES1;
- el2_regs.vtcr_el2 |=
- min(pa_range_bits << VTCR_EL2_PS_SHIFT, VTCR_EL2_PS_48BIT);
el2_regs.vtcr_el2 |= VTCR_EL2_IRGN0_WBWA | VTCR_EL2_ORGN0_WBWA;
el2_regs.vtcr_el2 |= VTCR_EL2_T0SZ(64 - vmm_virt_bits);
el2_regs.vtcr_el2 |= vmm_vtcr_el2_sl(vmm_pmap_levels);
@@ -402,8 +400,14 @@ vmmops_modinit(int ipinum)
* the shareability field changes to become address bits when this
* is set.
*/
- if ((READ_SPECIALREG(tcr_el1) & TCR_DS) != 0)
+ if ((READ_SPECIALREG(tcr_el1) & TCR_DS) != 0) {
el2_regs.vtcr_el2 |= VTCR_EL2_DS;
+ el2_regs.vtcr_el2 |=
+ min(pa_range_bits << VTCR_EL2_PS_SHIFT, VTCR_EL2_PS_52BIT);
+ } else {
+ el2_regs.vtcr_el2 |=
+ min(pa_range_bits << VTCR_EL2_PS_SHIFT, VTCR_EL2_PS_48BIT);
+ }
smp_rendezvous(NULL, arm_setup_vectors, NULL, &el2_regs);