[PATCH 19/22] x86/mm: introduce a per-CPU fixmap area

Roger Pau Monne posted 22 patches 1 month, 3 weeks ago
[PATCH 19/22] x86/mm: introduce a per-CPU fixmap area
Posted by Roger Pau Monne 1 month, 3 weeks ago
Introduce the logic to manage a per-CPU fixmap area.  This includes adding a
new set of headers that are capable of creating mappings in the per-CPU
page-table regions by making use of the map_pages_to_xen_cpu().

This per-CPU fixmap area is currently set to use one L3 slot: 1GiB of linear
address space.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
 xen/arch/x86/include/asm/fixmap.h | 44 +++++++++++++++++++++++++++++++
 xen/arch/x86/mm.c                 | 16 ++++++++++-
 2 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/xen/arch/x86/include/asm/fixmap.h b/xen/arch/x86/include/asm/fixmap.h
index 516ec3fa6c95..a456c65072d8 100644
--- a/xen/arch/x86/include/asm/fixmap.h
+++ b/xen/arch/x86/include/asm/fixmap.h
@@ -118,6 +118,50 @@ extern void __set_fixmap_x(
 #define __fix_x_to_virt(x) (FIXADDR_X_TOP - ((x) << PAGE_SHIFT))
 #define fix_x_to_virt(x)   ((void *)__fix_x_to_virt(x))
 
+/* per-CPU fixmap area. */
+enum percpu_fixed_addresses {
+    __end_of_percpu_fixed_addresses
+};
+
+#define PERCPU_FIXADDR_SIZE (__end_of_percpu_fixed_addresses << PAGE_SHIFT)
+#define PERCPU_FIXADDR PERCPU_VIRT_SLOT(0)
+
+static inline void *percpu_fix_to_virt(enum percpu_fixed_addresses idx)
+{
+    BUG_ON(idx >=__end_of_percpu_fixed_addresses);
+    return (void *)PERCPU_FIXADDR + (idx << PAGE_SHIFT);
+}
+
+static inline void percpu_set_fixmap_remote(
+    unsigned int cpu, enum percpu_fixed_addresses idx, mfn_t mfn,
+    unsigned long flags)
+{
+    map_pages_to_xen_cpu((unsigned long)percpu_fix_to_virt(idx), mfn, 1, flags,
+                         cpu);
+}
+
+static inline void percpu_clear_fixmap_remote(
+    unsigned int cpu, enum percpu_fixed_addresses idx)
+{
+    /*
+     * Use map_pages_to_xen_cpu() instead of destroy_xen_mappings_cpu() to
+     * avoid tearing down the intermediate page-tables if empty.
+     */
+    map_pages_to_xen_cpu((unsigned long)percpu_fix_to_virt(idx), INVALID_MFN, 1,
+                         0, cpu);
+}
+
+static inline void percpu_set_fixmap(enum percpu_fixed_addresses idx, mfn_t mfn,
+                                     unsigned long flags)
+{
+    percpu_set_fixmap_remote(smp_processor_id(), idx, mfn, flags);
+}
+
+static inline void percpu_clear_fixmap(enum percpu_fixed_addresses idx)
+{
+    percpu_clear_fixmap_remote(smp_processor_id(), idx);
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index faf2d42745d1..937089d203cc 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -6467,7 +6467,17 @@ int allocate_perdomain_local_l3(unsigned int cpu)
 
     per_cpu(local_l3, cpu) = l3;
 
-    return 0;
+    /*
+     * Pre-allocate the page-table structures for the per-cpu fixmap.  Some of
+     * the per-cpu fixmap calls might happen in contexts where memory
+     * allocation is not possible.
+     *
+     * Only one L3 slot is currently reserved for the per-CPU fixmap.
+     */
+    BUILD_BUG_ON(PERCPU_FIXADDR_SIZE > (1 << L3_PAGETABLE_SHIFT));
+    return map_pages_to_xen_cpu(PERCPU_VIRT_START, INVALID_MFN,
+                                PFN_DOWN(PERCPU_FIXADDR_SIZE), MAP_SMALL_PAGES,
+                                cpu);
 }
 
 void free_perdomain_local_l3(unsigned int cpu)
@@ -6478,6 +6488,10 @@ void free_perdomain_local_l3(unsigned int cpu)
         return;
 
     per_cpu(local_l3, cpu) = NULL;
+
+    destroy_xen_mappings_cpu(PERCPU_VIRT_START,
+                             PERCPU_VIRT_START + PERCPU_FIXADDR_SIZE, cpu);
+
     free_xenheap_page(l3);
 }
 
-- 
2.45.2