diff mbox series

[Xen-devel,MM-PART1,v3,7/8] xen/arm: tlbflush: Rework TLB helpers

Message ID 20190514122136.28215-15-julien.grall@arm.com
State New
Headers show
Series xen/arm: Clean-up & fixes in boot/mm code | expand

Commit Message

Julien Grall May 14, 2019, 12:21 p.m. UTC
All the TLBs helpers invalidate all the TLB entries are using the same
pattern:
    DSB SY
    TLBI ...
    DSB SY
    ISB

This pattern is following pattern recommended by the Arm Arm to ensure
visibility of updates to translation tables (see K11.5.2 in ARM DDI
0487D.b).

We have been a bit too eager in Xen and use system-wide DSBs when this
can be limited to the inner-shareable domain.

Furthermore, the first DSB can be restrict further to only store in the
inner-shareable domain. This is because the DSB is here to ensure
visibility of the update to translation table walks.

Lastly, there are a lack of documentation in most of the TLBs helper.

Rather than trying to update the helpers one by one, this patch
introduce a per-arch macro to generate the TLB helpers. This will be
easier to update the TLBs helper in the future and the documentation.

Signed-off-by: Julien Grall <julien.grall@arm.com>
Reviewed-by: Andrii Anisov <andrii_anisov@epam.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>

---
    Changes in v3:
        - Add Stefano's reviewed-by

    Changes in v2:
        - Update the reference to the Arm Arm to the latest spec
        - Add Andrii's reviewed-by
---
 xen/include/asm-arm/arm32/flushtlb.h | 73 ++++++++++++++--------------------
 xen/include/asm-arm/arm64/flushtlb.h | 76 +++++++++++++++---------------------
 2 files changed, 60 insertions(+), 89 deletions(-)
diff mbox series

Patch

diff --git a/xen/include/asm-arm/arm32/flushtlb.h b/xen/include/asm-arm/arm32/flushtlb.h
index b629db61cb..9085e65011 100644
--- a/xen/include/asm-arm/arm32/flushtlb.h
+++ b/xen/include/asm-arm/arm32/flushtlb.h
@@ -1,59 +1,44 @@ 
 #ifndef __ASM_ARM_ARM32_FLUSHTLB_H__
 #define __ASM_ARM_ARM32_FLUSHTLB_H__
 
-/* Flush local TLBs, current VMID only */
-static inline void flush_guest_tlb_local(void)
-{
-    dsb(sy);
-
-    WRITE_CP32((uint32_t) 0, TLBIALL);
-
-    dsb(sy);
-    isb();
+/*
+ * Every invalidation operation use the following patterns:
+ *
+ * DSB ISHST        // Ensure prior page-tables updates have completed
+ * TLBI...          // Invalidate the TLB
+ * DSB ISH          // Ensure the TLB invalidation has completed
+ * ISB              // See explanation below
+ *
+ * For Xen page-tables the ISB will discard any instructions fetched
+ * from the old mappings.
+ *
+ * For the Stage-2 page-tables the ISB ensures the completion of the DSB
+ * (and therefore the TLB invalidation) before continuing. So we know
+ * the TLBs cannot contain an entry for a mapping we may have removed.
+ */
+#define TLB_HELPER(name, tlbop) \
+static inline void name(void)   \
+{                               \
+    dsb(ishst);                 \
+    WRITE_CP32(0, tlbop);       \
+    dsb(ish);                   \
+    isb();                      \
 }
 
-/* Flush inner shareable TLBs, current VMID only */
-static inline void flush_guest_tlb(void)
-{
-    dsb(sy);
-
-    WRITE_CP32((uint32_t) 0, TLBIALLIS);
+/* Flush local TLBs, current VMID only */
+TLB_HELPER(flush_guest_tlb_local, TLBIALL);
 
-    dsb(sy);
-    isb();
-}
+/* Flush inner shareable TLBs, current VMID only */
+TLB_HELPER(flush_guest_tlb, TLBIALLIS);
 
 /* Flush local TLBs, all VMIDs, non-hypervisor mode */
-static inline void flush_all_guests_tlb_local(void)
-{
-    dsb(sy);
-
-    WRITE_CP32((uint32_t) 0, TLBIALLNSNH);
-
-    dsb(sy);
-    isb();
-}
+TLB_HELPER(flush_all_guests_tlb_local, TLBIALLNSNH);
 
 /* Flush innershareable TLBs, all VMIDs, non-hypervisor mode */
-static inline void flush_all_guests_tlb(void)
-{
-    dsb(sy);
-
-    WRITE_CP32((uint32_t) 0, TLBIALLNSNHIS);
-
-    dsb(sy);
-    isb();
-}
+TLB_HELPER(flush_all_guests_tlb, TLBIALLNSNHIS);
 
 /* Flush all hypervisor mappings from the TLB of the local processor. */
-static inline void flush_xen_tlb_local(void)
-{
-    asm volatile("dsb;" /* Ensure preceding are visible */
-                 CMD_CP32(TLBIALLH)
-                 "dsb;" /* Ensure completion of the TLB flush */
-                 "isb;"
-                 : : : "memory");
-}
+TLB_HELPER(flush_xen_tlb_local, TLBIALLH);
 
 /* Flush TLB of local processor for address va. */
 static inline void __flush_xen_tlb_one_local(vaddr_t va)
diff --git a/xen/include/asm-arm/arm64/flushtlb.h b/xen/include/asm-arm/arm64/flushtlb.h
index 2fed34b2ec..ceec59542e 100644
--- a/xen/include/asm-arm/arm64/flushtlb.h
+++ b/xen/include/asm-arm/arm64/flushtlb.h
@@ -1,60 +1,46 @@ 
 #ifndef __ASM_ARM_ARM64_FLUSHTLB_H__
 #define __ASM_ARM_ARM64_FLUSHTLB_H__
 
-/* Flush local TLBs, current VMID only */
-static inline void flush_guest_tlb_local(void)
-{
-    asm volatile(
-        "dsb sy;"
-        "tlbi vmalls12e1;"
-        "dsb sy;"
-        "isb;"
-        : : : "memory");
+/*
+ * Every invalidation operation use the following patterns:
+ *
+ * DSB ISHST        // Ensure prior page-tables updates have completed
+ * TLBI...          // Invalidate the TLB
+ * DSB ISH          // Ensure the TLB invalidation has completed
+ * ISB              // See explanation below
+ *
+ * For Xen page-tables the ISB will discard any instructions fetched
+ * from the old mappings.
+ *
+ * For the Stage-2 page-tables the ISB ensures the completion of the DSB
+ * (and therefore the TLB invalidation) before continuing. So we know
+ * the TLBs cannot contain an entry for a mapping we may have removed.
+ */
+#define TLB_HELPER(name, tlbop) \
+static inline void name(void)   \
+{                               \
+    asm volatile(               \
+        "dsb  ishst;"           \
+        "tlbi "  # tlbop  ";"   \
+        "dsb  ish;"             \
+        "isb;"                  \
+        : : : "memory");        \
 }
 
+/* Flush local TLBs, current VMID only. */
+TLB_HELPER(flush_guest_tlb_local, vmalls12e1);
+
 /* Flush innershareable TLBs, current VMID only */
-static inline void flush_guest_tlb(void)
-{
-    asm volatile(
-        "dsb sy;"
-        "tlbi vmalls12e1is;"
-        "dsb sy;"
-        "isb;"
-        : : : "memory");
-}
+TLB_HELPER(flush_guest_tlb, vmalls12e1is);
 
 /* Flush local TLBs, all VMIDs, non-hypervisor mode */
-static inline void flush_all_guests_tlb_local(void)
-{
-    asm volatile(
-        "dsb sy;"
-        "tlbi alle1;"
-        "dsb sy;"
-        "isb;"
-        : : : "memory");
-}
+TLB_HELPER(flush_all_guests_tlb_local, alle1);
 
 /* Flush innershareable TLBs, all VMIDs, non-hypervisor mode */
-static inline void flush_all_guests_tlb(void)
-{
-    asm volatile(
-        "dsb sy;"
-        "tlbi alle1is;"
-        "dsb sy;"
-        "isb;"
-        : : : "memory");
-}
+TLB_HELPER(flush_all_guests_tlb, alle1is);
 
 /* Flush all hypervisor mappings from the TLB of the local processor. */
-static inline void flush_xen_tlb_local(void)
-{
-    asm volatile (
-        "dsb    sy;"                    /* Ensure visibility of PTE writes */
-        "tlbi   alle2;"                 /* Flush hypervisor TLB */
-        "dsb    sy;"                    /* Ensure completion of TLB flush */
-        "isb;"
-        : : : "memory");
-}
+TLB_HELPER(flush_xen_tlb_local, alle2);
 
 /* Flush TLB of local processor for address va. */
 static inline void  __flush_xen_tlb_one_local(vaddr_t va)