All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings
@ 2022-02-21 10:21 Julien Grall
  2022-02-21 10:22 ` [PATCH v3 01/19] xen/arm: lpae: Rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS Julien Grall
                   ` (19 more replies)
  0 siblings, 20 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:21 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Jan Beulich,
	Wei Liu, Roger Pau Monné

From: Julien Grall <jgrall@amazon.com>

Hi all,

This series was originally sent as "xen/arm: mm: Add limited support
for superpages" [1] and finally has grown enough to remove most of
the open-coding mappings in the boot code.

This will help to:
    1) Get better compliance with the Arm memory model
    2) Pave the way to support other page size (64KB, 16KB)

The previous version was spent a few months ago. So I have decided
to remove all the acked-by/reviewed-by tags.

Cheers,

[1] <20201119190751.22345-1-julien@xen.org>
[2] <PA4PR08MB6253F49C13ED56811BA5B64E92479@PA4PR08MB6253.eurprd08.prod.outlook.com>

Julien Grall (18):
  xen/arm: lpae: Rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS
  xen/arm: lpae: Use the generic helpers to defined the Xen PT helpers
  xen/arm: p2m: Replace level_{orders, masks} arrays with
    XEN_PT_LEVEL_{ORDER, MASK}
  xen/arm: mm: Allow other mapping size in xen_pt_update_entry()
  xen/arm: mm: Add support for the contiguous bit
  xen/arm: mm: Avoid flushing the TLBs when mapping are inserted
  xen/arm: mm: Don't open-code Xen PT update in remove_early_mappings()
  xen/arm: mm: Re-implement early_fdt_map() using map_pages_to_xen()
  xen/arm32: mm: Check if the virtual address is shared before updating
    it
  xen/arm32: mm: Re-implement setup_xenheap_mappings() using
    map_pages_to_xen()
  xen/arm: mm: Allocate xen page tables in domheap rather than xenheap
  xen/arm: mm: Allow page-table allocation from the boot allocator
  xen/arm: Move fixmap definitions in a separate header
  xen/arm: mm: Clean-up the includes and order them
  xen/arm: mm: Use the PMAP helpers in xen_{,un}map_table()
  xen/arm64: mm: Add memory to the boot allocator first
  xen/arm: mm: Rework setup_xenheap_mappings()
  xen/arm: mm: Re-implement setup_frame_table_mappings() with
    map_pages_to_xen()

Wei Liu (1):
  xen/arm: add Persistent Map (PMAP) infrastructure

 xen/arch/arm/Kconfig                    |   1 +
 xen/arch/arm/acpi/lib.c                 |   2 +
 xen/arch/arm/arm32/head.S               |  14 +-
 xen/arch/arm/arm64/head.S               |  14 +-
 xen/arch/arm/include/asm/config.h       |  10 +-
 xen/arch/arm/include/asm/early_printk.h |   1 +
 xen/arch/arm/include/asm/fixmap.h       |  41 ++
 xen/arch/arm/include/asm/lpae.h         |  85 ++--
 xen/arch/arm/include/asm/mm.h           |   4 -
 xen/arch/arm/include/asm/page.h         |   8 +
 xen/arch/arm/include/asm/pmap.h         |  33 ++
 xen/arch/arm/kernel.c                   |   1 +
 xen/arch/arm/mm.c                       | 530 +++++++++++++-----------
 xen/arch/arm/p2m.c                      |  28 +-
 xen/arch/arm/setup.c                    |  63 ++-
 xen/common/Kconfig                      |   3 +
 xen/common/Makefile                     |   1 +
 xen/common/pmap.c                       |  79 ++++
 xen/include/xen/acpi.h                  |  18 +-
 xen/include/xen/pmap.h                  |  16 +
 20 files changed, 613 insertions(+), 339 deletions(-)
 create mode 100644 xen/arch/arm/include/asm/fixmap.h
 create mode 100644 xen/arch/arm/include/asm/pmap.h
 create mode 100644 xen/common/pmap.c
 create mode 100644 xen/include/xen/pmap.h

-- 
2.32.0



^ permalink raw reply	[flat|nested] 79+ messages in thread

* [PATCH v3 01/19] xen/arm: lpae: Rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-02-22 13:30   ` Michal Orzel
  2022-02-22 15:21   ` Bertrand Marquis
  2022-02-21 10:22 ` [PATCH v3 02/19] xen/arm: lpae: Use the generic helpers to defined the Xen PT helpers Julien Grall
                   ` (18 subsequent siblings)
  19 siblings, 2 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

From: Julien Grall <jgrall@amazon.com>

Commit 05031fa87357 "xen/arm: guest_walk: Only generate necessary
offsets/masks" introduced LPAE_ENTRIES_MASK_GS. In a follow-up patch,
we will use it for to define LPAE_ENTRY_MASK.

This will lead to inconsistent naming. As LPAE_ENTRY_MASK is used in
many places, it is better to rename LPAE_ENTRIES_MASK_GS and avoid
some churn.

So rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS.

Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v2:
        - New patch
---
 xen/arch/arm/include/asm/lpae.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/include/asm/lpae.h b/xen/arch/arm/include/asm/lpae.h
index e94de2e7d8e8..4fb9a40a4ca9 100644
--- a/xen/arch/arm/include/asm/lpae.h
+++ b/xen/arch/arm/include/asm/lpae.h
@@ -180,7 +180,7 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
  */
 #define LPAE_SHIFT_GS(gs)         ((gs) - 3)
 #define LPAE_ENTRIES_GS(gs)       (_AC(1, U) << LPAE_SHIFT_GS(gs))
-#define LPAE_ENTRIES_MASK_GS(gs)  (LPAE_ENTRIES_GS(gs) - 1)
+#define LPAE_ENTRY_MASK_GS(gs)  (LPAE_ENTRIES_GS(gs) - 1)
 
 #define LEVEL_ORDER_GS(gs, lvl)   ((3 - (lvl)) * LPAE_SHIFT_GS(gs))
 #define LEVEL_SHIFT_GS(gs, lvl)   (LEVEL_ORDER_GS(gs, lvl) + (gs))
@@ -188,7 +188,7 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
 
 /* Offset in the table at level 'lvl' */
 #define LPAE_TABLE_INDEX_GS(gs, lvl, addr)   \
-    (((addr) >> LEVEL_SHIFT_GS(gs, lvl)) & LPAE_ENTRIES_MASK_GS(gs))
+    (((addr) >> LEVEL_SHIFT_GS(gs, lvl)) & LPAE_ENTRY_MASK_GS(gs))
 
 /* Generate an array @var containing the offset for each level from @addr */
 #define DECLARE_OFFSETS(var, addr)          \
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 02/19] xen/arm: lpae: Use the generic helpers to defined the Xen PT helpers
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
  2022-02-21 10:22 ` [PATCH v3 01/19] xen/arm: lpae: Rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-02-22 14:26   ` Michal Orzel
  2022-02-22 15:38   ` Bertrand Marquis
  2022-02-21 10:22 ` [PATCH v3 03/19] xen/arm: p2m: Replace level_{orders, masks} arrays with XEN_PT_LEVEL_{ORDER, MASK} Julien Grall
                   ` (17 subsequent siblings)
  19 siblings, 2 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

From: Julien Grall <jgrall@amazon.com>

Currently, Xen PT helpers are only working with 4KB page granularity
and open-code the generic helpers. To allow more flexibility, we can
re-use the generic helpers and pass Xen's page granularity
(PAGE_SHIFT).

As Xen PT helpers are used in both C and assembly, we need to move
the generic helpers definition outside of the !__ASSEMBLY__ section.

Take the opportunity to prefix LPAE_ENTRIES, LPAE_ENTRIES and
LPAE_ENTRIES_MASK with XEN_PT_.

Note the aliases for each level are still kept for the time being so we
can avoid a massive patch to change all the callers.

Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v3:
      - Prefix the new define with XEN_PT_

    Changes in v2:
        - New patch
---
 xen/arch/arm/arm32/head.S       | 14 +++----
 xen/arch/arm/arm64/head.S       | 14 +++----
 xen/arch/arm/include/asm/lpae.h | 73 ++++++++++++++++++---------------
 xen/arch/arm/mm.c               | 33 ++++++++-------
 xen/arch/arm/p2m.c              | 13 +++---
 5 files changed, 80 insertions(+), 67 deletions(-)

diff --git a/xen/arch/arm/arm32/head.S b/xen/arch/arm/arm32/head.S
index b5912d381b98..b1d209ea2842 100644
--- a/xen/arch/arm/arm32/head.S
+++ b/xen/arch/arm/arm32/head.S
@@ -375,7 +375,7 @@ ENDPROC(cpu_init)
  */
 .macro create_table_entry, ptbl, tbl, virt, shift, mmu=0
         lsr   r1, \virt, #\shift
-        mov_w r2, LPAE_ENTRY_MASK
+        mov_w r2, XEN_PT_LPAE_ENTRY_MASK
         and   r1, r1, r2             /* r1 := slot in \tlb */
         lsl   r1, r1, #3             /* r1 := slot offset in \tlb */
 
@@ -410,7 +410,7 @@ ENDPROC(cpu_init)
  * and be distinct.
  */
 .macro create_mapping_entry, ptbl, virt, phys, type=PT_MEM_L3, mmu=0
-        mov_w r2, LPAE_ENTRY_MASK
+        mov_w r2, XEN_PT_LPAE_ENTRY_MASK
         lsr   r1, \virt, #THIRD_SHIFT
         and   r1, r1, r2             /* r1 := slot in \tlb */
         lsl   r1, r1, #3             /* r1 := slot offset in \tlb */
@@ -465,7 +465,7 @@ create_page_tables:
 1:      strd  r2, r3, [r4, r1]       /* Map vaddr(start) */
         add   r2, r2, #PAGE_SIZE     /* Next page */
         add   r1, r1, #8             /* Next slot */
-        cmp   r1, #(LPAE_ENTRIES<<3) /* 512*8-byte entries per page */
+        cmp   r1, #(XEN_PT_LPAE_ENTRIES<<3) /* 512*8-byte entries per page */
         blo   1b
 
         /*
@@ -487,7 +487,7 @@ create_page_tables:
          * the second level.
          */
         lsr   r1, r9, #FIRST_SHIFT
-        mov_w r0, LPAE_ENTRY_MASK
+        mov_w r0, XEN_PT_LPAE_ENTRY_MASK
         and   r1, r1, r0              /* r1 := first slot */
         cmp   r1, #XEN_FIRST_SLOT
         beq   1f
@@ -502,7 +502,7 @@ create_page_tables:
          * it.
          */
         lsr   r1, r9, #SECOND_SHIFT
-        mov_w r0, LPAE_ENTRY_MASK
+        mov_w r0, XEN_PT_LPAE_ENTRY_MASK
         and   r1, r1, r0             /* r1 := second slot */
         cmp   r1, #XEN_SECOND_SLOT
         beq   virtphys_clash
@@ -573,7 +573,7 @@ remove_identity_mapping:
          * table if the slot is not XEN_FIRST_SLOT.
          */
         lsr   r1, r9, #FIRST_SHIFT
-        mov_w r0, LPAE_ENTRY_MASK
+        mov_w r0, XEN_PT_LPAE_ENTRY_MASK
         and   r1, r1, r0              /* r1 := first slot */
         cmp   r1, #XEN_FIRST_SLOT
         beq   1f
@@ -589,7 +589,7 @@ remove_identity_mapping:
          * table if the slot is not XEN_SECOND_SLOT.
          */
         lsr   r1, r9, #SECOND_SHIFT
-        mov_w r0, LPAE_ENTRY_MASK
+        mov_w r0, XEN_PT_LPAE_ENTRY_MASK
         and   r1, r1, r0             /* r1 := second slot */
         cmp   r1, #XEN_SECOND_SLOT
         beq   identity_mapping_removed
diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
index 51b00ab0bea6..314b800b3f8e 100644
--- a/xen/arch/arm/arm64/head.S
+++ b/xen/arch/arm/arm64/head.S
@@ -509,7 +509,7 @@ ENDPROC(cpu_init)
  */
 .macro create_table_entry, ptbl, tbl, virt, shift, tmp1, tmp2, tmp3
         lsr   \tmp1, \virt, #\shift
-        and   \tmp1, \tmp1, #LPAE_ENTRY_MASK/* \tmp1 := slot in \tlb */
+        and   \tmp1, \tmp1, #XEN_PT_LPAE_ENTRY_MASK/* \tmp1 := slot in \tlb */
 
         load_paddr \tmp2, \tbl
         mov   \tmp3, #PT_PT                 /* \tmp3 := right for linear PT */
@@ -541,7 +541,7 @@ ENDPROC(cpu_init)
         and   \tmp3, \phys, #THIRD_MASK     /* \tmp3 := PAGE_ALIGNED(phys) */
 
         lsr   \tmp1, \virt, #THIRD_SHIFT
-        and   \tmp1, \tmp1, #LPAE_ENTRY_MASK/* \tmp1 := slot in \tlb */
+        and   \tmp1, \tmp1, #XEN_PT_LPAE_ENTRY_MASK/* \tmp1 := slot in \tlb */
 
         mov   \tmp2, #\type                 /* \tmp2 := right for section PT */
         orr   \tmp2, \tmp2, \tmp3           /*          + PAGE_ALIGNED(phys) */
@@ -586,7 +586,7 @@ create_page_tables:
 1:      str   x2, [x4, x1]           /* Map vaddr(start) */
         add   x2, x2, #PAGE_SIZE     /* Next page */
         add   x1, x1, #8             /* Next slot */
-        cmp   x1, #(LPAE_ENTRIES<<3) /* 512 entries per page */
+        cmp   x1, #(XEN_PT_LPAE_ENTRIES<<3) /* 512 entries per page */
         b.lt  1b
 
         /*
@@ -621,7 +621,7 @@ create_page_tables:
          * the second level.
          */
         lsr   x0, x19, #FIRST_SHIFT
-        and   x0, x0, #LPAE_ENTRY_MASK  /* x0 := first slot */
+        and   x0, x0, #XEN_PT_LPAE_ENTRY_MASK  /* x0 := first slot */
         cmp   x0, #XEN_FIRST_SLOT
         beq   1f
         create_table_entry boot_first, boot_second_id, x19, FIRST_SHIFT, x0, x1, x2
@@ -635,7 +635,7 @@ create_page_tables:
          * it.
          */
         lsr   x0, x19, #SECOND_SHIFT
-        and   x0, x0, #LPAE_ENTRY_MASK  /* x0 := first slot */
+        and   x0, x0, #XEN_PT_LPAE_ENTRY_MASK  /* x0 := first slot */
         cmp   x0, #XEN_SECOND_SLOT
         beq   virtphys_clash
         create_table_entry boot_second, boot_third_id, x19, SECOND_SHIFT, x0, x1, x2
@@ -715,7 +715,7 @@ remove_identity_mapping:
          * table if the slot is not XEN_FIRST_SLOT.
          */
         lsr   x1, x19, #FIRST_SHIFT
-        and   x1, x1, #LPAE_ENTRY_MASK  /* x1 := first slot */
+        and   x1, x1, #XEN_PT_LPAE_ENTRY_MASK  /* x1 := first slot */
         cmp   x1, #XEN_FIRST_SLOT
         beq   1f
         /* It is not in slot XEN_FIRST_SLOT, remove the entry. */
@@ -729,7 +729,7 @@ remove_identity_mapping:
          * table if the slot is not XEN_SECOND_SLOT.
          */
         lsr   x1, x19, #SECOND_SHIFT
-        and   x1, x1, #LPAE_ENTRY_MASK  /* x1 := first slot */
+        and   x1, x1, #XEN_PT_LPAE_ENTRY_MASK  /* x1 := first slot */
         cmp   x1, #XEN_SECOND_SLOT
         beq   identity_mapping_removed
         /* It is not in slot 1, remove the entry */
diff --git a/xen/arch/arm/include/asm/lpae.h b/xen/arch/arm/include/asm/lpae.h
index 4fb9a40a4ca9..8cf932b5c947 100644
--- a/xen/arch/arm/include/asm/lpae.h
+++ b/xen/arch/arm/include/asm/lpae.h
@@ -159,6 +159,17 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
 #define lpae_get_mfn(pte)    (_mfn((pte).walk.base))
 #define lpae_set_mfn(pte, mfn)  ((pte).walk.base = mfn_x(mfn))
 
+/* Generate an array @var containing the offset for each level from @addr */
+#define DECLARE_OFFSETS(var, addr)          \
+    const unsigned int var[4] = {           \
+        zeroeth_table_offset(addr),         \
+        first_table_offset(addr),           \
+        second_table_offset(addr),          \
+        third_table_offset(addr)            \
+    }
+
+#endif /* __ASSEMBLY__ */
+
 /*
  * AArch64 supports pages with different sizes (4K, 16K, and 64K).
  * Provide a set of generic helpers that will compute various
@@ -190,17 +201,6 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
 #define LPAE_TABLE_INDEX_GS(gs, lvl, addr)   \
     (((addr) >> LEVEL_SHIFT_GS(gs, lvl)) & LPAE_ENTRY_MASK_GS(gs))
 
-/* Generate an array @var containing the offset for each level from @addr */
-#define DECLARE_OFFSETS(var, addr)          \
-    const unsigned int var[4] = {           \
-        zeroeth_table_offset(addr),         \
-        first_table_offset(addr),           \
-        second_table_offset(addr),          \
-        third_table_offset(addr)            \
-    }
-
-#endif /* __ASSEMBLY__ */
-
 /*
  * These numbers add up to a 48-bit input address space.
  *
@@ -211,26 +211,35 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
  * therefore 39-bits are sufficient.
  */
 
-#define LPAE_SHIFT      9
-#define LPAE_ENTRIES    (_AC(1,U) << LPAE_SHIFT)
-#define LPAE_ENTRY_MASK (LPAE_ENTRIES - 1)
-
-#define THIRD_SHIFT    (PAGE_SHIFT)
-#define THIRD_ORDER    (THIRD_SHIFT - PAGE_SHIFT)
-#define THIRD_SIZE     (_AT(paddr_t, 1) << THIRD_SHIFT)
-#define THIRD_MASK     (~(THIRD_SIZE - 1))
-#define SECOND_SHIFT   (THIRD_SHIFT + LPAE_SHIFT)
-#define SECOND_ORDER   (SECOND_SHIFT - PAGE_SHIFT)
-#define SECOND_SIZE    (_AT(paddr_t, 1) << SECOND_SHIFT)
-#define SECOND_MASK    (~(SECOND_SIZE - 1))
-#define FIRST_SHIFT    (SECOND_SHIFT + LPAE_SHIFT)
-#define FIRST_ORDER    (FIRST_SHIFT - PAGE_SHIFT)
-#define FIRST_SIZE     (_AT(paddr_t, 1) << FIRST_SHIFT)
-#define FIRST_MASK     (~(FIRST_SIZE - 1))
-#define ZEROETH_SHIFT  (FIRST_SHIFT + LPAE_SHIFT)
-#define ZEROETH_ORDER  (ZEROETH_SHIFT - PAGE_SHIFT)
-#define ZEROETH_SIZE   (_AT(paddr_t, 1) << ZEROETH_SHIFT)
-#define ZEROETH_MASK   (~(ZEROETH_SIZE - 1))
+#define XEN_PT_LPAE_SHIFT         LPAE_SHIFT_GS(PAGE_SHIFT)
+#define XEN_PT_LPAE_ENTRIES       LPAE_ENTRIES_GS(PAGE_SHIFT)
+#define XEN_PT_LPAE_ENTRY_MASK    LPAE_ENTRY_MASK_GS(PAGE_SHIFT)
+
+#define XEN_PT_LEVEL_SHIFT(lvl)   LEVEL_SHIFT_GS(PAGE_SHIFT, lvl)
+#define XEN_PT_LEVEL_ORDER(lvl)   LEVEL_ORDER_GS(PAGE_SHIFT, lvl)
+#define XEN_PT_LEVEL_SIZE(lvl)    LEVEL_SIZE_GS(PAGE_SHIFT, lvl)
+#define XEN_PT_LEVEL_MASK(lvl)    (~(XEN_PT_LEVEL_SIZE(lvl) - 1))
+
+/* Convenience aliases */
+#define THIRD_SHIFT         XEN_PT_LEVEL_SHIFT(3)
+#define THIRD_ORDER         XEN_PT_LEVEL_ORDER(3)
+#define THIRD_SIZE          XEN_PT_LEVEL_SIZE(3)
+#define THIRD_MASK          XEN_PT_LEVEL_MASK(3)
+
+#define SECOND_SHIFT        XEN_PT_LEVEL_SHIFT(2)
+#define SECOND_ORDER        XEN_PT_LEVEL_ORDER(2)
+#define SECOND_SIZE         XEN_PT_LEVEL_SIZE(2)
+#define SECOND_MASK         XEN_PT_LEVEL_MASK(2)
+
+#define FIRST_SHIFT         XEN_PT_LEVEL_SHIFT(1)
+#define FIRST_ORDER         XEN_PT_LEVEL_ORDER(1)
+#define FIRST_SIZE          XEN_PT_LEVEL_SIZE(1)
+#define FIRST_MASK          XEN_PT_LEVEL_MASK(1)
+
+#define ZEROETH_SHIFT       XEN_PT_LEVEL_SHIFT(0)
+#define ZEROETH_ORDER       XEN_PT_LEVEL_ORDER(0)
+#define ZEROETH_SIZE        XEN_PT_LEVEL_SIZE(0)
+#define ZEROETH_MASK        XEN_PT_LEVEL_MASK(0)
 
 /* Calculate the offsets into the pagetables for a given VA */
 #define zeroeth_linear_offset(va) ((va) >> ZEROETH_SHIFT)
@@ -238,7 +247,7 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
 #define second_linear_offset(va) ((va) >> SECOND_SHIFT)
 #define third_linear_offset(va) ((va) >> THIRD_SHIFT)
 
-#define TABLE_OFFSET(offs) (_AT(unsigned int, offs) & LPAE_ENTRY_MASK)
+#define TABLE_OFFSET(offs) (_AT(unsigned int, offs) & XEN_PT_LPAE_ENTRY_MASK)
 #define first_table_offset(va)  TABLE_OFFSET(first_linear_offset(va))
 #define second_table_offset(va) TABLE_OFFSET(second_linear_offset(va))
 #define third_table_offset(va)  TABLE_OFFSET(third_linear_offset(va))
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index b1eae767c27c..515d0906f85b 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -71,10 +71,11 @@ mm_printk(const char *fmt, ...) {}
  *  in C).
  */
 #define DEFINE_BOOT_PAGE_TABLE(name)                                          \
-lpae_t __aligned(PAGE_SIZE) __section(".data.page_aligned") name[LPAE_ENTRIES]
+lpae_t __aligned(PAGE_SIZE) __section(".data.page_aligned")                   \
+    name[XEN_PT_LPAE_ENTRIES]
 
 #define DEFINE_PAGE_TABLES(name, nr)                    \
-lpae_t __aligned(PAGE_SIZE) name[LPAE_ENTRIES * (nr)]
+lpae_t __aligned(PAGE_SIZE) name[XEN_PT_LPAE_ENTRIES * (nr)]
 
 #define DEFINE_PAGE_TABLE(name) DEFINE_PAGE_TABLES(name, 1)
 
@@ -207,7 +208,7 @@ static void __init __maybe_unused build_assertions(void)
     BUILD_BUG_ON(zeroeth_table_offset(XEN_VIRT_START));
 #endif
     BUILD_BUG_ON(first_table_offset(XEN_VIRT_START));
-    BUILD_BUG_ON(second_linear_offset(XEN_VIRT_START) >= LPAE_ENTRIES);
+    BUILD_BUG_ON(second_linear_offset(XEN_VIRT_START) >= XEN_PT_LPAE_ENTRIES);
 #ifdef CONFIG_DOMAIN_PAGE
     BUILD_BUG_ON(DOMHEAP_VIRT_START & ~FIRST_MASK);
 #endif
@@ -256,7 +257,7 @@ void dump_pt_walk(paddr_t ttbr, paddr_t addr,
 
     for ( level = root_level; ; level++ )
     {
-        if ( offsets[level] > LPAE_ENTRIES )
+        if ( offsets[level] > XEN_PT_LPAE_ENTRIES )
             break;
 
         pte = mapping[offsets[level]];
@@ -395,15 +396,15 @@ static void __init create_mappings(lpae_t *second,
     ASSERT(!(base_mfn % granularity));
     ASSERT(!(nr_mfns % granularity));
 
-    count = nr_mfns / LPAE_ENTRIES;
+    count = nr_mfns / XEN_PT_LPAE_ENTRIES;
     p = second + second_linear_offset(virt_offset);
     pte = mfn_to_xen_entry(_mfn(base_mfn), MT_NORMAL);
-    if ( granularity == 16 * LPAE_ENTRIES )
+    if ( granularity == 16 * XEN_PT_LPAE_ENTRIES )
         pte.pt.contig = 1;  /* These maps are in 16-entry contiguous chunks. */
     for ( i = 0; i < count; i++ )
     {
         write_pte(p + i, pte);
-        pte.pt.base += 1 << LPAE_SHIFT;
+        pte.pt.base += 1 << XEN_PT_LPAE_SHIFT;
     }
     flush_xen_tlb_local();
 }
@@ -424,7 +425,7 @@ void *map_domain_page(mfn_t mfn)
 {
     unsigned long flags;
     lpae_t *map = this_cpu(xen_dommap);
-    unsigned long slot_mfn = mfn_x(mfn) & ~LPAE_ENTRY_MASK;
+    unsigned long slot_mfn = mfn_x(mfn) & ~XEN_PT_LPAE_ENTRY_MASK;
     vaddr_t va;
     lpae_t pte;
     int i, slot;
@@ -435,7 +436,7 @@ void *map_domain_page(mfn_t mfn)
      * entry is a 2MB superpage pte.  We use the available bits of each
      * PTE as a reference count; when the refcount is zero the slot can
      * be reused. */
-    for ( slot = (slot_mfn >> LPAE_SHIFT) % DOMHEAP_ENTRIES, i = 0;
+    for ( slot = (slot_mfn >> XEN_PT_LPAE_SHIFT) % DOMHEAP_ENTRIES, i = 0;
           i < DOMHEAP_ENTRIES;
           slot = (slot + 1) % DOMHEAP_ENTRIES, i++ )
     {
@@ -477,7 +478,7 @@ void *map_domain_page(mfn_t mfn)
 
     va = (DOMHEAP_VIRT_START
           + (slot << SECOND_SHIFT)
-          + ((mfn_x(mfn) & LPAE_ENTRY_MASK) << THIRD_SHIFT));
+          + ((mfn_x(mfn) & XEN_PT_LPAE_ENTRY_MASK) << THIRD_SHIFT));
 
     /*
      * We may not have flushed this specific subpage at map time,
@@ -513,7 +514,7 @@ mfn_t domain_page_map_to_mfn(const void *ptr)
     unsigned long va = (unsigned long)ptr;
     lpae_t *map = this_cpu(xen_dommap);
     int slot = (va - DOMHEAP_VIRT_START) >> SECOND_SHIFT;
-    unsigned long offset = (va>>THIRD_SHIFT) & LPAE_ENTRY_MASK;
+    unsigned long offset = (va>>THIRD_SHIFT) & XEN_PT_LPAE_ENTRY_MASK;
 
     if ( va >= VMAP_VIRT_START && va < VMAP_VIRT_END )
         return virt_to_mfn(va);
@@ -654,7 +655,8 @@ void __init setup_pagetables(unsigned long boot_phys_offset)
     /* Initialise first level entries, to point to second level entries */
     for ( i = 0; i < 2; i++)
     {
-        p[i] = pte_of_xenaddr((uintptr_t)(xen_second+i*LPAE_ENTRIES));
+        p[i] = pte_of_xenaddr((uintptr_t)(xen_second +
+                                          i * XEN_PT_LPAE_ENTRIES));
         p[i].pt.table = 1;
         p[i].pt.xn = 0;
     }
@@ -663,13 +665,14 @@ void __init setup_pagetables(unsigned long boot_phys_offset)
     for ( i = 0; i < DOMHEAP_SECOND_PAGES; i++ )
     {
         p[first_table_offset(DOMHEAP_VIRT_START+i*FIRST_SIZE)]
-            = pte_of_xenaddr((uintptr_t)(cpu0_dommap+i*LPAE_ENTRIES));
+            = pte_of_xenaddr((uintptr_t)(cpu0_dommap +
+                                         i * XEN_PT_LPAE_ENTRIES));
         p[first_table_offset(DOMHEAP_VIRT_START+i*FIRST_SIZE)].pt.table = 1;
     }
 #endif
 
     /* Break up the Xen mapping into 4k pages and protect them separately. */
-    for ( i = 0; i < LPAE_ENTRIES; i++ )
+    for ( i = 0; i < XEN_PT_LPAE_ENTRIES; i++ )
     {
         vaddr_t va = XEN_VIRT_START + (i << PAGE_SHIFT);
 
@@ -768,7 +771,7 @@ int init_secondary_pagetables(int cpu)
      * domheap mapping pages. */
     for ( i = 0; i < DOMHEAP_SECOND_PAGES; i++ )
     {
-        pte = mfn_to_xen_entry(virt_to_mfn(domheap+i*LPAE_ENTRIES),
+        pte = mfn_to_xen_entry(virt_to_mfn(domheap + i * XEN_PT_LPAE_ENTRIES),
                                MT_NORMAL);
         pte.pt.table = 1;
         write_pte(&first[first_table_offset(DOMHEAP_VIRT_START+i*FIRST_SIZE)], pte);
diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index 02cf852d4cf1..493a1e25879a 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -233,7 +233,8 @@ static lpae_t *p2m_get_root_pointer(struct p2m_domain *p2m,
      * we can't use (P2M_ROOT_LEVEL - 1) because the root level might be
      * 0. Yet we still want to check if all the unused bits are zeroed.
      */
-    root_table = gfn_x(gfn) >> (level_orders[P2M_ROOT_LEVEL] + LPAE_SHIFT);
+    root_table = gfn_x(gfn) >> (level_orders[P2M_ROOT_LEVEL] +
+                                XEN_PT_LPAE_SHIFT);
     if ( root_table >= P2M_ROOT_PAGES )
         return NULL;
 
@@ -773,7 +774,7 @@ static void p2m_free_entry(struct p2m_domain *p2m,
     }
 
     table = map_domain_page(lpae_get_mfn(entry));
-    for ( i = 0; i < LPAE_ENTRIES; i++ )
+    for ( i = 0; i < XEN_PT_LPAE_ENTRIES; i++ )
         p2m_free_entry(p2m, *(table + i), level + 1);
 
     unmap_domain_page(table);
@@ -827,7 +828,7 @@ static bool p2m_split_superpage(struct p2m_domain *p2m, lpae_t *entry,
      * We are either splitting a first level 1G page into 512 second level
      * 2M pages, or a second level 2M page into 512 third level 4K pages.
      */
-    for ( i = 0; i < LPAE_ENTRIES; i++ )
+    for ( i = 0; i < XEN_PT_LPAE_ENTRIES; i++ )
     {
         lpae_t *new_entry = table + i;
 
@@ -850,7 +851,7 @@ static bool p2m_split_superpage(struct p2m_domain *p2m, lpae_t *entry,
     /* Update stats */
     p2m->stats.shattered[level]++;
     p2m->stats.mappings[level]--;
-    p2m->stats.mappings[next_level] += LPAE_ENTRIES;
+    p2m->stats.mappings[next_level] += XEN_PT_LPAE_ENTRIES;
 
     /*
      * Shatter superpage in the page to the level we want to make the
@@ -888,7 +889,7 @@ static int __p2m_set_entry(struct p2m_domain *p2m,
                            p2m_access_t a)
 {
     unsigned int level = 0;
-    unsigned int target = 3 - (page_order / LPAE_SHIFT);
+    unsigned int target = 3 - (page_order / XEN_PT_LPAE_SHIFT);
     lpae_t *entry, *table, orig_pte;
     int rc;
     /* A mapping is removed if the MFN is invalid. */
@@ -1142,7 +1143,7 @@ static void p2m_invalidate_table(struct p2m_domain *p2m, mfn_t mfn)
 
     table = map_domain_page(mfn);
 
-    for ( i = 0; i < LPAE_ENTRIES; i++ )
+    for ( i = 0; i < XEN_PT_LPAE_ENTRIES; i++ )
     {
         lpae_t pte = table[i];
 
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 03/19] xen/arm: p2m: Replace level_{orders, masks} arrays with XEN_PT_LEVEL_{ORDER, MASK}
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
  2022-02-21 10:22 ` [PATCH v3 01/19] xen/arm: lpae: Rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS Julien Grall
  2022-02-21 10:22 ` [PATCH v3 02/19] xen/arm: lpae: Use the generic helpers to defined the Xen PT helpers Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-02-22 15:55   ` Bertrand Marquis
  2022-02-21 10:22 ` [PATCH v3 04/19] xen/arm: mm: Allow other mapping size in xen_pt_update_entry() Julien Grall
                   ` (16 subsequent siblings)
  19 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

From: Julien Grall <jgrall@amazon.com>

The array level_orders and level_masks can be replaced with the
recently introduced macros LEVEL_ORDER and LEVEL_MASK.

Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v3:
        - Fix clashes after prefixing the PT macros with XEN_PT_

    Changes in v2:
        - New patch

    The goal is to remove completely the static arrays so they
    don't need to be global (or duplicated) when adding superpage
    support for Xen PT.

    This also has the added benefits to replace a couple of loads
    with only a few instructions working on immediate.
---
 xen/arch/arm/p2m.c | 17 ++++++-----------
 1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index 493a1e25879a..1d1059f7d2bd 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -37,12 +37,6 @@ static unsigned int __read_mostly max_vmid = MAX_VMID_8_BIT;
  */
 unsigned int __read_mostly p2m_ipa_bits = 64;
 
-/* Helpers to lookup the properties of each level */
-static const paddr_t level_masks[] =
-    { ZEROETH_MASK, FIRST_MASK, SECOND_MASK, THIRD_MASK };
-static const uint8_t level_orders[] =
-    { ZEROETH_ORDER, FIRST_ORDER, SECOND_ORDER, THIRD_ORDER };
-
 static mfn_t __read_mostly empty_root_mfn;
 
 static uint64_t generate_vttbr(uint16_t vmid, mfn_t root_mfn)
@@ -233,7 +227,7 @@ static lpae_t *p2m_get_root_pointer(struct p2m_domain *p2m,
      * we can't use (P2M_ROOT_LEVEL - 1) because the root level might be
      * 0. Yet we still want to check if all the unused bits are zeroed.
      */
-    root_table = gfn_x(gfn) >> (level_orders[P2M_ROOT_LEVEL] +
+    root_table = gfn_x(gfn) >> (XEN_PT_LEVEL_ORDER(P2M_ROOT_LEVEL) +
                                 XEN_PT_LPAE_SHIFT);
     if ( root_table >= P2M_ROOT_PAGES )
         return NULL;
@@ -380,7 +374,7 @@ mfn_t p2m_get_entry(struct p2m_domain *p2m, gfn_t gfn,
     if ( gfn_x(gfn) > gfn_x(p2m->max_mapped_gfn) )
     {
         for ( level = P2M_ROOT_LEVEL; level < 3; level++ )
-            if ( (gfn_x(gfn) & (level_masks[level] >> PAGE_SHIFT)) >
+            if ( (gfn_x(gfn) & (XEN_PT_LEVEL_MASK(level) >> PAGE_SHIFT)) >
                  gfn_x(p2m->max_mapped_gfn) )
                 break;
 
@@ -423,7 +417,8 @@ mfn_t p2m_get_entry(struct p2m_domain *p2m, gfn_t gfn,
          * The entry may point to a superpage. Find the MFN associated
          * to the GFN.
          */
-        mfn = mfn_add(mfn, gfn_x(gfn) & ((1UL << level_orders[level]) - 1));
+        mfn = mfn_add(mfn,
+                      gfn_x(gfn) & ((1UL << XEN_PT_LEVEL_ORDER(level)) - 1));
 
         if ( valid )
             *valid = lpae_is_valid(entry);
@@ -434,7 +429,7 @@ out_unmap:
 
 out:
     if ( page_order )
-        *page_order = level_orders[level];
+        *page_order = XEN_PT_LEVEL_ORDER(level);
 
     return mfn;
 }
@@ -808,7 +803,7 @@ static bool p2m_split_superpage(struct p2m_domain *p2m, lpae_t *entry,
     /* Convenience aliases */
     mfn_t mfn = lpae_get_mfn(*entry);
     unsigned int next_level = level + 1;
-    unsigned int level_order = level_orders[next_level];
+    unsigned int level_order = XEN_PT_LEVEL_ORDER(next_level);
 
     /*
      * This should only be called with target != level and the entry is
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 04/19] xen/arm: mm: Allow other mapping size in xen_pt_update_entry()
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (2 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 03/19] xen/arm: p2m: Replace level_{orders, masks} arrays with XEN_PT_LEVEL_{ORDER, MASK} Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-04-01 23:35   ` Stefano Stabellini
  2022-02-21 10:22 ` [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit Julien Grall
                   ` (15 subsequent siblings)
  19 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

From: Julien Grall <julien.grall@arm.com>

At the moment, xen_pt_update_entry() only supports mapping at level 3
(i.e 4KB mapping). While this is fine for most of the runtime helper,
the boot code will require to use superpage mapping.

We don't want to allow superpage mapping by default as some of the
callers may expect small mappings (i.e populate_pt_range()) or even
expect to unmap only a part of a superpage.

To keep the code simple, a new flag _PAGE_BLOCK is introduced to
allow the caller to enable superpage mapping.

As the code doesn't support all the combinations, xen_pt_check_entry()
is extended to take into account the cases we don't support when
using block mapping:
    - Replacing a table with a mapping. This may happen if region was
    first mapped with 4KB mapping and then later on replaced with a 2MB
    (or 1GB mapping).
    - Removing/modifying a table. This may happen if a caller try to
    remove a region with _PAGE_BLOCK set when it was created without it.

Note that the current restriction means that the caller must ensure that
_PAGE_BLOCK is consistently set/cleared across all the updates on a
given virtual region. This ought to be fine with the expected use-cases.

More rework will be necessary if we wanted to remove the restrictions.

Note that nr_mfns is now marked const as it is used for flushing the
TLBs and we don't want it to be modified.

Signed-off-by: Julien Grall <julien.grall@arm.com>
Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v3:
        - Fix clash after prefixing the PT macros with XEN_PT_
        - Fix typoes in the commit message
        - Support superpage mappings even if nr is not suitably aligned
        - Move the logic to find the level in a separate function

    Changes in v2:
        - Pass the target level rather than the order to
        xen_pt_update_entry()
        - Update some comments
        - Open-code paddr_to_pfn()
        - Add my AWS signed-off-by
---
 xen/arch/arm/include/asm/page.h |   4 ++
 xen/arch/arm/mm.c               | 108 ++++++++++++++++++++++++++------
 2 files changed, 94 insertions(+), 18 deletions(-)

diff --git a/xen/arch/arm/include/asm/page.h b/xen/arch/arm/include/asm/page.h
index c6f9fb0d4e0c..07998df47bac 100644
--- a/xen/arch/arm/include/asm/page.h
+++ b/xen/arch/arm/include/asm/page.h
@@ -69,6 +69,7 @@
  * [3:4] Permission flags
  * [5]   Page present
  * [6]   Only populate page tables
+ * [7]   Superpage mappings is allowed
  */
 #define PAGE_AI_MASK(x) ((x) & 0x7U)
 
@@ -82,6 +83,9 @@
 #define _PAGE_PRESENT    (1U << 5)
 #define _PAGE_POPULATE   (1U << 6)
 
+#define _PAGE_BLOCK_BIT     7
+#define _PAGE_BLOCK         (1U << _PAGE_BLOCK_BIT)
+
 /*
  * _PAGE_DEVICE and _PAGE_NORMAL are convenience defines. They are not
  * meant to be used outside of this header.
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 515d0906f85b..3af69b396bd1 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1063,9 +1063,10 @@ static int xen_pt_next_level(bool read_only, unsigned int level,
 }
 
 /* Sanity check of the entry */
-static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int flags)
+static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int level,
+                               unsigned int flags)
 {
-    /* Sanity check when modifying a page. */
+    /* Sanity check when modifying an entry. */
     if ( (flags & _PAGE_PRESENT) && mfn_eq(mfn, INVALID_MFN) )
     {
         /* We don't allow modifying an invalid entry. */
@@ -1075,6 +1076,13 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int flags)
             return false;
         }
 
+        /* We don't allow modifying a table entry */
+        if ( !lpae_is_mapping(entry, level) )
+        {
+            mm_printk("Modifying a table entry is not allowed.\n");
+            return false;
+        }
+
         /* We don't allow changing memory attributes. */
         if ( entry.pt.ai != PAGE_AI_MASK(flags) )
         {
@@ -1090,7 +1098,7 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int flags)
             return false;
         }
     }
-    /* Sanity check when inserting a page */
+    /* Sanity check when inserting a mapping */
     else if ( flags & _PAGE_PRESENT )
     {
         /* We should be here with a valid MFN. */
@@ -1099,18 +1107,28 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int flags)
         /* We don't allow replacing any valid entry. */
         if ( lpae_is_valid(entry) )
         {
-            mm_printk("Changing MFN for a valid entry is not allowed (%#"PRI_mfn" -> %#"PRI_mfn").\n",
-                      mfn_x(lpae_get_mfn(entry)), mfn_x(mfn));
+            if ( lpae_is_mapping(entry, level) )
+                mm_printk("Changing MFN for a valid entry is not allowed (%#"PRI_mfn" -> %#"PRI_mfn").\n",
+                          mfn_x(lpae_get_mfn(entry)), mfn_x(mfn));
+            else
+                mm_printk("Trying to replace a table with a mapping.\n");
             return false;
         }
     }
-    /* Sanity check when removing a page. */
+    /* Sanity check when removing a mapping. */
     else if ( (flags & (_PAGE_PRESENT|_PAGE_POPULATE)) == 0 )
     {
         /* We should be here with an invalid MFN. */
         ASSERT(mfn_eq(mfn, INVALID_MFN));
 
-        /* We don't allow removing page with contiguous bit set. */
+        /* We don't allow removing a table */
+        if ( lpae_is_table(entry, level) )
+        {
+            mm_printk("Removing a table is not allowed.\n");
+            return false;
+        }
+
+        /* We don't allow removing a mapping with contiguous bit set. */
         if ( entry.pt.contig )
         {
             mm_printk("Removing entry with contiguous bit set is not allowed.\n");
@@ -1128,13 +1146,13 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int flags)
     return true;
 }
 
+/* Update an entry at the level @target. */
 static int xen_pt_update_entry(mfn_t root, unsigned long virt,
-                               mfn_t mfn, unsigned int flags)
+                               mfn_t mfn, unsigned int target,
+                               unsigned int flags)
 {
     int rc;
     unsigned int level;
-    /* We only support 4KB mapping (i.e level 3) for now */
-    unsigned int target = 3;
     lpae_t *table;
     /*
      * The intermediate page tables are read-only when the MFN is not valid
@@ -1189,7 +1207,7 @@ static int xen_pt_update_entry(mfn_t root, unsigned long virt,
     entry = table + offsets[level];
 
     rc = -EINVAL;
-    if ( !xen_pt_check_entry(*entry, mfn, flags) )
+    if ( !xen_pt_check_entry(*entry, mfn, level, flags) )
         goto out;
 
     /* If we are only populating page-table, then we are done. */
@@ -1207,8 +1225,11 @@ static int xen_pt_update_entry(mfn_t root, unsigned long virt,
         {
             pte = mfn_to_xen_entry(mfn, PAGE_AI_MASK(flags));
 
-            /* Third level entries set pte.pt.table = 1 */
-            pte.pt.table = 1;
+            /*
+             * First and second level pages set pte.pt.table = 0, but
+             * third level entries set pte.pt.table = 1.
+             */
+            pte.pt.table = (level == 3);
         }
         else /* We are updating the permission => Copy the current pte. */
             pte = *entry;
@@ -1228,15 +1249,56 @@ out:
     return rc;
 }
 
+/* Return the level where mapping should be done */
+static int xen_pt_mapping_level(unsigned long vfn, mfn_t mfn, unsigned long nr,
+                                unsigned int flags)
+{
+    unsigned int level;
+    unsigned long mask;
+
+    /*
+      * Don't take into account the MFN when removing mapping (i.e
+      * MFN_INVALID) to calculate the correct target order.
+      *
+      * Per the Arm Arm, `vfn` and `mfn` must be both superpage aligned.
+      * They are or-ed together and then checked against the size of
+      * each level.
+      *
+      * `left` is not included and checked separately to allow
+      * superpage mapping even if it is not properly aligned (the
+      * user may have asked to map 2MB + 4k).
+      */
+     mask = !mfn_eq(mfn, INVALID_MFN) ? mfn_x(mfn) : 0;
+     mask |= vfn;
+
+     /*
+      * Always use level 3 mapping unless the caller request block
+      * mapping.
+      */
+     if ( likely(!(flags & _PAGE_BLOCK)) )
+         level = 3;
+     else if ( !(mask & (BIT(FIRST_ORDER, UL) - 1)) &&
+               (nr >= BIT(FIRST_ORDER, UL)) )
+         level = 1;
+     else if ( !(mask & (BIT(SECOND_ORDER, UL) - 1)) &&
+               (nr >= BIT(SECOND_ORDER, UL)) )
+         level = 2;
+     else
+         level = 3;
+
+     return level;
+}
+
 static DEFINE_SPINLOCK(xen_pt_lock);
 
 static int xen_pt_update(unsigned long virt,
                          mfn_t mfn,
-                         unsigned long nr_mfns,
+                         const unsigned long nr_mfns,
                          unsigned int flags)
 {
     int rc = 0;
-    unsigned long addr = virt, addr_end = addr + nr_mfns * PAGE_SIZE;
+    unsigned long vfn = virt >> PAGE_SHIFT;
+    unsigned long left = nr_mfns;
 
     /*
      * For arm32, page-tables are different on each CPUs. Yet, they share
@@ -1268,14 +1330,24 @@ static int xen_pt_update(unsigned long virt,
 
     spin_lock(&xen_pt_lock);
 
-    for ( ; addr < addr_end; addr += PAGE_SIZE )
+    while ( left )
     {
-        rc = xen_pt_update_entry(root, addr, mfn, flags);
+        unsigned int order, level;
+
+        level = xen_pt_mapping_level(vfn, mfn, left, flags);
+        order = XEN_PT_LEVEL_ORDER(level);
+
+        ASSERT(left >= BIT(order, UL));
+
+        rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level, flags);
         if ( rc )
             break;
 
+        vfn += 1U << order;
         if ( !mfn_eq(mfn, INVALID_MFN) )
-            mfn = mfn_add(mfn, 1);
+            mfn = mfn_add(mfn, 1U << order);
+
+        left -= (1U << order);
     }
 
     /*
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (3 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 04/19] xen/arm: mm: Allow other mapping size in xen_pt_update_entry() Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-02-26 19:30   ` Julien Grall
  2022-04-01 23:53   ` Stefano Stabellini
  2022-02-21 10:22 ` [PATCH v3 06/19] xen/arm: mm: Avoid flushing the TLBs when mapping are inserted Julien Grall
                   ` (14 subsequent siblings)
  19 siblings, 2 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

From: Julien Grall <jgrall@amazon.com>

In follow-up patches, we will use xen_pt_update() (or its callers)
to handle large mappings (e.g. frametable, xenheap). They are also
not going to be modified once created.

The page-table entries have an hint to indicate that whether an
entry is contiguous to another 16 entries (assuming 4KB). When the
processor support the hint, one TLB entry will be created per
contiguous region.

For now this is tied to _PAGE_BLOCK. We can untie it in the future
if there are use-cases where we may want to use _PAGE_BLOCK without
setting the contiguous (couldn't think of any yet).

Note that to avoid extra complexity, mappings with the contiguous
bit set cannot be removed. Given the expected use, this restriction
ought to be fine.

Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v3:
        - New patch
---
 xen/arch/arm/include/asm/page.h |  4 ++
 xen/arch/arm/mm.c               | 80 ++++++++++++++++++++++++++++++---
 2 files changed, 77 insertions(+), 7 deletions(-)

diff --git a/xen/arch/arm/include/asm/page.h b/xen/arch/arm/include/asm/page.h
index 07998df47bac..e7cd62190c7f 100644
--- a/xen/arch/arm/include/asm/page.h
+++ b/xen/arch/arm/include/asm/page.h
@@ -70,6 +70,7 @@
  * [5]   Page present
  * [6]   Only populate page tables
  * [7]   Superpage mappings is allowed
+ * [8]   Set contiguous bit (internal flag)
  */
 #define PAGE_AI_MASK(x) ((x) & 0x7U)
 
@@ -86,6 +87,9 @@
 #define _PAGE_BLOCK_BIT     7
 #define _PAGE_BLOCK         (1U << _PAGE_BLOCK_BIT)
 
+#define _PAGE_CONTIG_BIT    8
+#define _PAGE_CONTIG        (1U << _PAGE_CONTIG_BIT)
+
 /*
  * _PAGE_DEVICE and _PAGE_NORMAL are convenience defines. They are not
  * meant to be used outside of this header.
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 3af69b396bd1..fd16c1541ce2 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1237,6 +1237,8 @@ static int xen_pt_update_entry(mfn_t root, unsigned long virt,
         /* Set permission */
         pte.pt.ro = PAGE_RO_MASK(flags);
         pte.pt.xn = PAGE_XN_MASK(flags);
+        /* Set contiguous bit */
+        pte.pt.contig = !!(flags & _PAGE_CONTIG);
     }
 
     write_pte(entry, pte);
@@ -1289,6 +1291,51 @@ static int xen_pt_mapping_level(unsigned long vfn, mfn_t mfn, unsigned long nr,
      return level;
 }
 
+#define XEN_PT_4K_NR_CONTIG 16
+
+/*
+ * Check whether the contiguous bit can be set. Return the number of
+ * contiguous entry allowed. If not allowed, return 1.
+ */
+static unsigned int xen_pt_check_contig(unsigned long vfn, mfn_t mfn,
+                                        unsigned int level, unsigned long left,
+                                        unsigned int flags)
+{
+    unsigned long nr_contig;
+
+    /*
+     * Allow the contiguous bit to set when the caller requests block
+     * mapping.
+     */
+    if ( !(flags & _PAGE_BLOCK) )
+        return 1;
+
+    /*
+     * We don't allow to remove mapping with the contiguous bit set.
+     * So shortcut the logic and directly return 1.
+     */
+    if ( mfn_eq(mfn, INVALID_MFN) )
+        return 1;
+
+    /*
+     * The number of contiguous entries varies depending on the page
+     * granularity used. The logic below assumes 4KB.
+     */
+    BUILD_BUG_ON(PAGE_SIZE != SZ_4K);
+
+    /*
+     * In order to enable the contiguous bit, we should have enough entries
+     * to map left and both the virtual and physical address should be
+     * aligned to the size of 16 translation tables entries.
+     */
+    nr_contig = BIT(XEN_PT_LEVEL_ORDER(level), UL) * XEN_PT_4K_NR_CONTIG;
+
+    if ( (left < nr_contig) || ((mfn_x(mfn) | vfn) & (nr_contig - 1)) )
+        return 1;
+
+    return XEN_PT_4K_NR_CONTIG;
+}
+
 static DEFINE_SPINLOCK(xen_pt_lock);
 
 static int xen_pt_update(unsigned long virt,
@@ -1322,6 +1369,12 @@ static int xen_pt_update(unsigned long virt,
         return -EINVAL;
     }
 
+    if ( flags & _PAGE_CONTIG )
+    {
+        mm_printk("_PAGE_CONTIG is an internal only flag.\n");
+        return -EINVAL;
+    }
+
     if ( !IS_ALIGNED(virt, PAGE_SIZE) )
     {
         mm_printk("The virtual address is not aligned to the page-size.\n");
@@ -1333,21 +1386,34 @@ static int xen_pt_update(unsigned long virt,
     while ( left )
     {
         unsigned int order, level;
+        unsigned int nr_contig;
+        unsigned int new_flags;
 
         level = xen_pt_mapping_level(vfn, mfn, left, flags);
         order = XEN_PT_LEVEL_ORDER(level);
 
         ASSERT(left >= BIT(order, UL));
 
-        rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level, flags);
-        if ( rc )
-            break;
+        /*
+         * Check if we can set the contiguous mapping and update the
+         * flags accordingly.
+         */
+        nr_contig = xen_pt_check_contig(vfn, mfn, level, left, flags);
+        new_flags = flags | ((nr_contig > 1) ? _PAGE_CONTIG : 0);
 
-        vfn += 1U << order;
-        if ( !mfn_eq(mfn, INVALID_MFN) )
-            mfn = mfn_add(mfn, 1U << order);
+        for ( ; nr_contig > 0; nr_contig-- )
+        {
+            rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level,
+                                     new_flags);
+            if ( rc )
+                break;
 
-        left -= (1U << order);
+            vfn += 1U << order;
+            if ( !mfn_eq(mfn, INVALID_MFN) )
+                mfn = mfn_add(mfn, 1U << order);
+
+            left -= (1U << order);
+        }
     }
 
     /*
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 06/19] xen/arm: mm: Avoid flushing the TLBs when mapping are inserted
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (4 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-04-02  0:00   ` Stefano Stabellini
  2022-02-21 10:22 ` [PATCH v3 07/19] xen/arm: mm: Don't open-code Xen PT update in remove_early_mappings() Julien Grall
                   ` (13 subsequent siblings)
  19 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

From: Julien Grall <jgrall@amazon.com>

Currently, the function xen_pt_update() will flush the TLBs even when
the mappings are inserted. This is a bit wasteful because we don't
allow mapping replacement. Even if we were, the flush would need to
happen earlier because mapping replacement should use Break-Before-Make
when updating the entry.

A single call to xen_pt_update() can perform a single action. IOW, it
is not possible to, for instance, mix inserting and removing mappings.
Therefore, we can use `flags` to determine what action is performed.

This change will be particularly help to limit the impact of switching
boot time mapping to use xen_pt_update().

Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v2:
        - New patch
---
 xen/arch/arm/mm.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index fd16c1541ce2..7b4b9de8693e 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1104,7 +1104,13 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int level,
         /* We should be here with a valid MFN. */
         ASSERT(!mfn_eq(mfn, INVALID_MFN));
 
-        /* We don't allow replacing any valid entry. */
+        /*
+         * We don't allow replacing any valid entry.
+         *
+         * Note that the function xen_pt_update() relies on this
+         * assumption and will skip the TLB flush. The function will need
+         * to be updated if the check is relaxed.
+         */
         if ( lpae_is_valid(entry) )
         {
             if ( lpae_is_mapping(entry, level) )
@@ -1417,11 +1423,16 @@ static int xen_pt_update(unsigned long virt,
     }
 
     /*
-     * Flush the TLBs even in case of failure because we may have
+     * The TLBs flush can be safely skipped when a mapping is inserted
+     * as we don't allow mapping replacement (see xen_pt_check_entry()).
+     *
+     * For all the other cases, the TLBs will be flushed unconditionally
+     * even if the mapping has failed. This is because we may have
      * partially modified the PT. This will prevent any unexpected
      * behavior afterwards.
      */
-    flush_xen_tlb_range_va(virt, PAGE_SIZE * nr_mfns);
+    if ( !(flags & _PAGE_PRESENT) || mfn_eq(mfn, INVALID_MFN) )
+        flush_xen_tlb_range_va(virt, PAGE_SIZE * nr_mfns);
 
     spin_unlock(&xen_pt_lock);
 
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 07/19] xen/arm: mm: Don't open-code Xen PT update in remove_early_mappings()
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (5 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 06/19] xen/arm: mm: Avoid flushing the TLBs when mapping are inserted Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-04-02  0:04   ` Stefano Stabellini
  2022-02-21 10:22 ` [PATCH v3 08/19] xen/arm: mm: Re-implement early_fdt_map() using map_pages_to_xen() Julien Grall
                   ` (12 subsequent siblings)
  19 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

From: Julien Grall <julien.grall@arm.com>

Now that xen_pt_update_entry() is able to deal with different mapping
size, we can replace the open-coding of the page-tables update by a call
to modify_xen_mappings().

As the function is not meant to fail, a BUG_ON() is added to check the
return.

Signed-off-by: Julien Grall <julien.grall@arm.com>
Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v2:
        - Stay consistent with how function name are used in the commit
        message
        - Add my AWS signed-off-by
---
 xen/arch/arm/mm.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 7b4b9de8693e..f088a4b2de96 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -599,11 +599,11 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
 
 void __init remove_early_mappings(void)
 {
-    lpae_t pte = {0};
-    write_pte(xen_second + second_table_offset(BOOT_FDT_VIRT_START), pte);
-    write_pte(xen_second + second_table_offset(BOOT_FDT_VIRT_START + SZ_2M),
-              pte);
-    flush_xen_tlb_range_va(BOOT_FDT_VIRT_START, BOOT_FDT_SLOT_SIZE);
+    int rc;
+
+    rc = modify_xen_mappings(BOOT_FDT_VIRT_START, BOOT_FDT_VIRT_END,
+                             _PAGE_BLOCK);
+    BUG_ON(rc);
 }
 
 /*
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 08/19] xen/arm: mm: Re-implement early_fdt_map() using map_pages_to_xen()
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (6 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 07/19] xen/arm: mm: Don't open-code Xen PT update in remove_early_mappings() Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-03-18  7:36   ` Hongda Deng
  2022-04-02  0:10   ` Stefano Stabellini
  2022-02-21 10:22 ` [PATCH v3 09/19] xen/arm32: mm: Check if the virtual address is shared before updating it Julien Grall
                   ` (11 subsequent siblings)
  19 siblings, 2 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

From: Julien Grall <julien.grall@arm.com>

Now that map_pages_to_xen() has been extended to support 2MB mappings,
we can replace the create_mappings() calls by map_pages_to_xen() calls.

The mapping can also be marked read-only has Xen as no business to
modify the host Device Tree.

Signed-off-by: Julien Grall <julien.grall@arm.com>
Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v2:
        - Add my AWS signed-off-by
        - Fix typo in the commit message
---
 xen/arch/arm/mm.c | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index f088a4b2de96..24de8dcb9042 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -559,6 +559,7 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
     paddr_t offset;
     void *fdt_virt;
     uint32_t size;
+    int rc;
 
     /*
      * Check whether the physical FDT address is set and meets the minimum
@@ -574,8 +575,12 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
     /* The FDT is mapped using 2MB superpage */
     BUILD_BUG_ON(BOOT_FDT_VIRT_START % SZ_2M);
 
-    create_mappings(xen_second, BOOT_FDT_VIRT_START, paddr_to_pfn(base_paddr),
-                    SZ_2M >> PAGE_SHIFT, SZ_2M);
+    rc = map_pages_to_xen(BOOT_FDT_VIRT_START, maddr_to_mfn(base_paddr),
+                          SZ_2M >> PAGE_SHIFT,
+                          PAGE_HYPERVISOR_RO | _PAGE_BLOCK);
+    if ( rc )
+        panic("Unable to map the device-tree.\n");
+
 
     offset = fdt_paddr % SECOND_SIZE;
     fdt_virt = (void *)BOOT_FDT_VIRT_START + offset;
@@ -589,9 +594,12 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
 
     if ( (offset + size) > SZ_2M )
     {
-        create_mappings(xen_second, BOOT_FDT_VIRT_START + SZ_2M,
-                        paddr_to_pfn(base_paddr + SZ_2M),
-                        SZ_2M >> PAGE_SHIFT, SZ_2M);
+        rc = map_pages_to_xen(BOOT_FDT_VIRT_START + SZ_2M,
+                              maddr_to_mfn(base_paddr + SZ_2M),
+                              SZ_2M >> PAGE_SHIFT,
+                              PAGE_HYPERVISOR_RO | _PAGE_BLOCK);
+        if ( rc )
+            panic("Unable to map the device-tree\n");
     }
 
     return fdt_virt;
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 09/19] xen/arm32: mm: Check if the virtual address is shared before updating it
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (7 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 08/19] xen/arm: mm: Re-implement early_fdt_map() using map_pages_to_xen() Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-03-18 10:44   ` Hongda Deng
  2022-03-19 15:59   ` Julien Grall
  2022-02-21 10:22 ` [PATCH v3 10/19] xen/arm32: mm: Re-implement setup_xenheap_mappings() using map_pages_to_xen() Julien Grall
                   ` (10 subsequent siblings)
  19 siblings, 2 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

From: Julien Grall <jgrall@amazon.com>

Only the first 2GB of the virtual address space is shared between all
the page-tables on Arm32.

There is a long outstanding TODO in xen_pt_update() stating that the
function can only work with shared mapping. Nobody has ever called
the function with private mapping, however as we add more callers
there is a risk to mess things up.

Introduce a new define to mark the end of the shared mappings and use
it in xen_pt_update() to verify if the address is correct.

Note that on Arm64, all the mappings are shared. Some compiler may
complain about an always true check, so the new define is not introduced
for arm64 and the code is protected with an #ifdef.

Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v2:
        - New patch
---
 xen/arch/arm/include/asm/config.h |  4 ++++
 xen/arch/arm/mm.c                 | 11 +++++++++--
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/include/asm/config.h b/xen/arch/arm/include/asm/config.h
index c7b77912013e..85d4a510ce8a 100644
--- a/xen/arch/arm/include/asm/config.h
+++ b/xen/arch/arm/include/asm/config.h
@@ -137,6 +137,10 @@
 
 #define XENHEAP_VIRT_START     _AT(vaddr_t,0x40000000)
 #define XENHEAP_VIRT_END       _AT(vaddr_t,0x7fffffff)
+
+/* The first 2GB is always shared between all the page-tables. */
+#define SHARED_VIRT_END        _AT(vaddr_t, 0x7fffffff)
+
 #define DOMHEAP_VIRT_START     _AT(vaddr_t,0x80000000)
 #define DOMHEAP_VIRT_END       _AT(vaddr_t,0xffffffff)
 
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 24de8dcb9042..f18f65745595 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1365,11 +1365,18 @@ static int xen_pt_update(unsigned long virt,
      * For arm32, page-tables are different on each CPUs. Yet, they share
      * some common mappings. It is assumed that only common mappings
      * will be modified with this function.
-     *
-     * XXX: Add a check.
      */
     const mfn_t root = virt_to_mfn(THIS_CPU_PGTABLE);
 
+#ifdef SHARED_VIRT_END
+    if ( virt > SHARED_VIRT_END ||
+         (SHARED_VIRT_END - virt) < nr_mfns )
+    {
+        mm_printk("Trying to map outside of the shared area.\n");
+        return -EINVAL;
+    }
+#endif
+
     /*
      * The hardware was configured to forbid mapping both writeable and
      * executable.
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 10/19] xen/arm32: mm: Re-implement setup_xenheap_mappings() using map_pages_to_xen()
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (8 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 09/19] xen/arm32: mm: Check if the virtual address is shared before updating it Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-04-02  0:11   ` Stefano Stabellini
  2022-05-14  9:42   ` Julien Grall
  2022-02-21 10:22 ` [PATCH v3 11/19] xen/arm: mm: Allocate xen page tables in domheap rather than xenheap Julien Grall
                   ` (9 subsequent siblings)
  19 siblings, 2 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

From: Julien Grall <jgrall@amazon.com>

Now that map_pages_to_xen() has been extended to support 2MB mappings,
we can replace the create_mappings() call by map_pages_to_xen() call.

Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v3:
        - Fix build when CONFIG_DEBUG=y

    Changes in v2:
        - New patch

    TODOs:
        - add support for contiguous mapping
---
 xen/arch/arm/mm.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index f18f65745595..1e5c2c45dcf9 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -809,7 +809,12 @@ void mmu_init_secondary_cpu(void)
 void __init setup_xenheap_mappings(unsigned long base_mfn,
                                    unsigned long nr_mfns)
 {
-    create_mappings(xen_second, XENHEAP_VIRT_START, base_mfn, nr_mfns, MB(32));
+    int rc;
+
+    rc = map_pages_to_xen(XENHEAP_VIRT_START, _mfn(base_mfn), nr_mfns,
+                          PAGE_HYPERVISOR_RW | _PAGE_BLOCK);
+    if ( rc )
+        panic("Unable to setup the xenheap mappings.\n");
 
     /* Record where the xenheap is, for translation routines. */
     xenheap_virt_end = XENHEAP_VIRT_START + nr_mfns * PAGE_SIZE;
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 11/19] xen/arm: mm: Allocate xen page tables in domheap rather than xenheap
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (9 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 10/19] xen/arm32: mm: Re-implement setup_xenheap_mappings() using map_pages_to_xen() Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-02-21 10:22 ` [PATCH v3 12/19] xen/arm: mm: Allow page-table allocation from the boot allocator Julien Grall
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

From: Julien Grall <jgrall@amazon.com>

xen_{un,}map_table() already uses the helper to map/unmap pages
on-demand (note this is currently a NOP on arm64). So switching to
domheap don't have any disavantage.

But this as the benefit:
    - to keep the page tables unmapped if an arch decided to do so
    - reduce xenheap use on arm32 which can be pretty small

Signed-off-by: Julien Grall <jgrall@amazon.com>
Acked-by: Stefano Stabellini <sstabellini@kernel.org>

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

    Changes in v2:
        - New patch
---
 xen/arch/arm/mm.c | 36 +++++++++++++++++++++---------------
 1 file changed, 21 insertions(+), 15 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 1e5c2c45dcf9..58364bb6c820 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -972,21 +972,6 @@ void *ioremap(paddr_t pa, size_t len)
     return ioremap_attr(pa, len, PAGE_HYPERVISOR_NOCACHE);
 }
 
-static int create_xen_table(lpae_t *entry)
-{
-    void *p;
-    lpae_t pte;
-
-    p = alloc_xenheap_page();
-    if ( p == NULL )
-        return -ENOMEM;
-    clear_page(p);
-    pte = mfn_to_xen_entry(virt_to_mfn(p), MT_NORMAL);
-    pte.pt.table = 1;
-    write_pte(entry, pte);
-    return 0;
-}
-
 static lpae_t *xen_map_table(mfn_t mfn)
 {
     /*
@@ -1027,6 +1012,27 @@ static void xen_unmap_table(const lpae_t *table)
     unmap_domain_page(table);
 }
 
+static int create_xen_table(lpae_t *entry)
+{
+    struct page_info *pg;
+    void *p;
+    lpae_t pte;
+
+    pg = alloc_domheap_page(NULL, 0);
+    if ( pg == NULL )
+        return -ENOMEM;
+
+    p = xen_map_table(page_to_mfn(pg));
+    clear_page(p);
+    xen_unmap_table(p);
+
+    pte = mfn_to_xen_entry(page_to_mfn(pg), MT_NORMAL);
+    pte.pt.table = 1;
+    write_pte(entry, pte);
+
+    return 0;
+}
+
 #define XEN_TABLE_MAP_FAILED 0
 #define XEN_TABLE_SUPER_PAGE 1
 #define XEN_TABLE_NORMAL_PAGE 2
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 12/19] xen/arm: mm: Allow page-table allocation from the boot allocator
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (10 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 11/19] xen/arm: mm: Allocate xen page tables in domheap rather than xenheap Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-04-05 20:58   ` Stefano Stabellini
  2022-02-21 10:22 ` [PATCH v3 13/19] xen/arm: Move fixmap definitions in a separate header Julien Grall
                   ` (7 subsequent siblings)
  19 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

From: Julien Grall <julien.grall@arm.com>

At the moment, page-table can only be allocated from domheap. This means
it is not possible to create mapping in the page-tables via
map_pages_to_xen() if page-table needs to be allocated.

In order to avoid open-coding page-tables update in early boot, we need
to be able to allocate page-tables much earlier. Thankfully, we have the
boot allocator for those cases.

create_xen_table() is updated to cater early boot allocation by using
alloc_boot_pages().

Note, this is not sufficient to bootstrap the page-tables (i.e mapping
before any memory is actually mapped). This will be addressed
separately.

Signed-off-by: Julien Grall <julien.grall@arm.com>
Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v2:
        - New patch
---
 xen/arch/arm/mm.c | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 58364bb6c820..f70b8cc7ce87 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -1014,19 +1014,27 @@ static void xen_unmap_table(const lpae_t *table)
 
 static int create_xen_table(lpae_t *entry)
 {
-    struct page_info *pg;
+    mfn_t mfn;
     void *p;
     lpae_t pte;
 
-    pg = alloc_domheap_page(NULL, 0);
-    if ( pg == NULL )
-        return -ENOMEM;
+    if ( system_state != SYS_STATE_early_boot )
+    {
+        struct page_info *pg = alloc_domheap_page(NULL, 0);
+
+        if ( pg == NULL )
+            return -ENOMEM;
+
+        mfn = page_to_mfn(pg);
+    }
+    else
+        mfn = alloc_boot_pages(1, 1);
 
-    p = xen_map_table(page_to_mfn(pg));
+    p = xen_map_table(mfn);
     clear_page(p);
     xen_unmap_table(p);
 
-    pte = mfn_to_xen_entry(page_to_mfn(pg), MT_NORMAL);
+    pte = mfn_to_xen_entry(mfn, MT_NORMAL);
     pte.pt.table = 1;
     write_pte(entry, pte);
 
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 13/19] xen/arm: Move fixmap definitions in a separate header
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (11 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 12/19] xen/arm: mm: Allow page-table allocation from the boot allocator Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-02-22 15:10   ` Jan Beulich
  2022-04-05 21:12   ` Stefano Stabellini
  2022-02-21 10:22 ` [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure Julien Grall
                   ` (6 subsequent siblings)
  19 siblings, 2 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Jan Beulich,
	Wei Liu

From: Julien Grall <jgrall@amazon.com>

To use properly the fixmap definitions, their user would need
also new to include <xen/acpi.h>. This is not very great when
the user itself is not meant to directly use ACPI definitions.

Including <xen/acpi.h> in <asm/config.h> is not option because
the latter header is included by everyone. So move out the fixmap
entries definition in a new header.

Take the opportunity to also move {set, clear}_fixmap() prototypes
in the new header.

Note that most of the definitions in <xen/acpi.h> now need to be
surrounded with #ifndef __ASSEMBLY__ because <asm/fixmap.h> will
be used in assembly (see EARLY_UART_VIRTUAL_ADDRESS).

The split will become more helpful in a follow-up patch where new
fixmap entries will be defined.

Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v3:
        - Patch added
---
 xen/arch/arm/acpi/lib.c                 |  2 ++
 xen/arch/arm/include/asm/config.h       |  6 ------
 xen/arch/arm/include/asm/early_printk.h |  1 +
 xen/arch/arm/include/asm/fixmap.h       | 24 ++++++++++++++++++++++++
 xen/arch/arm/include/asm/mm.h           |  4 ----
 xen/arch/arm/kernel.c                   |  1 +
 xen/arch/arm/mm.c                       |  1 +
 xen/include/xen/acpi.h                  | 18 +++++++++++-------
 8 files changed, 40 insertions(+), 17 deletions(-)
 create mode 100644 xen/arch/arm/include/asm/fixmap.h

diff --git a/xen/arch/arm/acpi/lib.c b/xen/arch/arm/acpi/lib.c
index a59cc4074cfb..41d521f720ac 100644
--- a/xen/arch/arm/acpi/lib.c
+++ b/xen/arch/arm/acpi/lib.c
@@ -25,6 +25,8 @@
 #include <xen/init.h>
 #include <xen/mm.h>
 
+#include <asm/fixmap.h>
+
 static bool fixmap_inuse;
 
 char *__acpi_map_table(paddr_t phys, unsigned long size)
diff --git a/xen/arch/arm/include/asm/config.h b/xen/arch/arm/include/asm/config.h
index 85d4a510ce8a..51908bf9422c 100644
--- a/xen/arch/arm/include/asm/config.h
+++ b/xen/arch/arm/include/asm/config.h
@@ -175,12 +175,6 @@
 
 #endif
 
-/* Fixmap slots */
-#define FIXMAP_CONSOLE  0  /* The primary UART */
-#define FIXMAP_MISC     1  /* Ephemeral mappings of hardware */
-#define FIXMAP_ACPI_BEGIN  2  /* Start mappings of ACPI tables */
-#define FIXMAP_ACPI_END    (FIXMAP_ACPI_BEGIN + NUM_FIXMAP_ACPI_PAGES - 1)  /* End mappings of ACPI tables */
-
 #define NR_hypercalls 64
 
 #define STACK_ORDER 3
diff --git a/xen/arch/arm/include/asm/early_printk.h b/xen/arch/arm/include/asm/early_printk.h
index 8dc911cf48a3..c5149b2976da 100644
--- a/xen/arch/arm/include/asm/early_printk.h
+++ b/xen/arch/arm/include/asm/early_printk.h
@@ -11,6 +11,7 @@
 #define __ARM_EARLY_PRINTK_H__
 
 #include <xen/page-size.h>
+#include <asm/fixmap.h>
 
 #ifdef CONFIG_EARLY_PRINTK
 
diff --git a/xen/arch/arm/include/asm/fixmap.h b/xen/arch/arm/include/asm/fixmap.h
new file mode 100644
index 000000000000..1cee51e52ab9
--- /dev/null
+++ b/xen/arch/arm/include/asm/fixmap.h
@@ -0,0 +1,24 @@
+/*
+ * fixmap.h: compile-time virtual memory allocation
+ */
+#ifndef __ASM_FIXMAP_H
+#define __ASM_FIXMAP_H
+
+#include <xen/acpi.h>
+
+/* Fixmap slots */
+#define FIXMAP_CONSOLE  0  /* The primary UART */
+#define FIXMAP_MISC     1  /* Ephemeral mappings of hardware */
+#define FIXMAP_ACPI_BEGIN  2  /* Start mappings of ACPI tables */
+#define FIXMAP_ACPI_END    (FIXMAP_ACPI_BEGIN + NUM_FIXMAP_ACPI_PAGES - 1)  /* End mappings of ACPI tables */
+
+#ifndef __ASSEMBLY__
+
+/* Map a page in a fixmap entry */
+extern void set_fixmap(unsigned map, mfn_t mfn, unsigned attributes);
+/* Remove a mapping from a fixmap entry */
+extern void clear_fixmap(unsigned map);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_FIXMAP_H */
diff --git a/xen/arch/arm/include/asm/mm.h b/xen/arch/arm/include/asm/mm.h
index 424aaf28230b..045a8ba4bb63 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -191,10 +191,6 @@ extern void mmu_init_secondary_cpu(void);
 extern void setup_xenheap_mappings(unsigned long base_mfn, unsigned long nr_mfns);
 /* Map a frame table to cover physical addresses ps through pe */
 extern void setup_frametable_mappings(paddr_t ps, paddr_t pe);
-/* Map a 4k page in a fixmap entry */
-extern void set_fixmap(unsigned map, mfn_t mfn, unsigned attributes);
-/* Remove a mapping from a fixmap entry */
-extern void clear_fixmap(unsigned map);
 /* map a physical range in virtual memory */
 void __iomem *ioremap_attr(paddr_t start, size_t len, unsigned attributes);
 
diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
index 8f43caa1866d..25ded1c056d9 100644
--- a/xen/arch/arm/kernel.c
+++ b/xen/arch/arm/kernel.c
@@ -15,6 +15,7 @@
 #include <xen/vmap.h>
 
 #include <asm/byteorder.h>
+#include <asm/fixmap.h>
 #include <asm/kernel.h>
 #include <asm/setup.h>
 
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index f70b8cc7ce87..d6a4b9407c43 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -41,6 +41,7 @@
 #include <xen/sizes.h>
 #include <xen/libfdt/libfdt.h>
 
+#include <asm/fixmap.h>
 #include <asm/setup.h>
 
 /* Override macros from asm/page.h to make them work with mfn_t */
diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
index 08834f140266..500aaa538551 100644
--- a/xen/include/xen/acpi.h
+++ b/xen/include/xen/acpi.h
@@ -28,6 +28,15 @@
 #define _LINUX
 #endif
 
+/*
+ * Fixmap pages to reserve for ACPI boot-time tables (see
+ * arch/x86/include/asm/fixmap.h or arch/arm/include/asm/fixmap.h),
+ * 64 pages(256KB) is large enough for most cases.)
+ */
+#define NUM_FIXMAP_ACPI_PAGES  64
+
+#ifndef __ASSEMBLY__
+
 #include <xen/list.h>
 
 #include <acpi/acpi.h>
@@ -39,13 +48,6 @@
 #define ACPI_MADT_GET_POLARITY(inti)	ACPI_MADT_GET_(POLARITY, inti)
 #define ACPI_MADT_GET_TRIGGER(inti)	ACPI_MADT_GET_(TRIGGER, inti)
 
-/*
- * Fixmap pages to reserve for ACPI boot-time tables (see
- * arch/x86/include/asm/fixmap.h or arch/arm/include/asm/config.h,
- * 64 pages(256KB) is large enough for most cases.)
- */
-#define NUM_FIXMAP_ACPI_PAGES  64
-
 #define BAD_MADT_ENTRY(entry, end) (                                        \
                 (!(entry)) || (unsigned long)(entry) + sizeof(*(entry)) > (end) ||  \
                 (entry)->header.length < sizeof(*(entry)))
@@ -207,4 +209,6 @@ void acpi_reboot(void);
 void acpi_dmar_zap(void);
 void acpi_dmar_reinstate(void);
 
+#endif /* __ASSEMBLY__ */
+
 #endif /*_LINUX_ACPI_H*/
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (12 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 13/19] xen/arm: Move fixmap definitions in a separate header Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-02-22 15:22   ` Jan Beulich
  2022-04-05 21:27   ` Stefano Stabellini
  2022-02-21 10:22 ` [PATCH v3 15/19] xen/arm: mm: Clean-up the includes and order them Julien Grall
                   ` (5 subsequent siblings)
  19 siblings, 2 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Wei Liu, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, George Dunlap, Hongyan Xia, Julien Grall,
	Jan Beulich, Wei Liu, Andrew Cooper, Roger Pau Monné

From: Wei Liu <wei.liu2@citrix.com>

The basic idea is like Persistent Kernel Map (PKMAP) in Linux. We
pre-populate all the relevant page tables before the system is fully
set up.

We will need it on Arm in order to rework the arm64 version of
xenheap_setup_mappings() as we may need to use pages allocated from
the boot allocator before they are effectively mapped.

This infrastructure is not lock-protected therefore can only be used
before smpboot. After smpboot, map_domain_page() has to be used.

This is based on the x86 version [1] that was originally implemented
by Wei Liu.

The PMAP infrastructure is implemented in common code with some
arch helpers to set/clear the page-table entries and convertion
between a fixmap slot to a virtual address...

As mfn_to_xen_entry() now needs to be exported, take the opportunity
to swich the parameter attr from unsigned to unsigned int.

[1] <e92da4ad6015b6089737fcccba3ec1d6424649a5.1588278317.git.hongyxia@amazon.com>

Signed-off-by: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Hongyan Xia <hongyxia@amazon.com>
[julien: Adapted for Arm]
Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v3:
        - s/BITS_PER_LONG/BITS_PER_BYTE/
        - Move pmap to common code

    Changes in v2:
        - New patch

Cc: Jan Beulich <jbeulich@suse.com>
Cc: Wei Liu <wl@xen.org>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: Roger Pau Monné <roger.pau@citrix.com>
---
 xen/arch/arm/Kconfig              |  1 +
 xen/arch/arm/include/asm/fixmap.h | 17 +++++++
 xen/arch/arm/include/asm/lpae.h   |  8 ++++
 xen/arch/arm/include/asm/pmap.h   | 33 +++++++++++++
 xen/arch/arm/mm.c                 |  7 +--
 xen/common/Kconfig                |  3 ++
 xen/common/Makefile               |  1 +
 xen/common/pmap.c                 | 79 +++++++++++++++++++++++++++++++
 xen/include/xen/pmap.h            | 16 +++++++
 9 files changed, 159 insertions(+), 6 deletions(-)
 create mode 100644 xen/arch/arm/include/asm/pmap.h
 create mode 100644 xen/common/pmap.c
 create mode 100644 xen/include/xen/pmap.h

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index ecfa6822e4d3..a89a67802aa9 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -14,6 +14,7 @@ config ARM
 	select HAS_DEVICE_TREE
 	select HAS_PASSTHROUGH
 	select HAS_PDX
+	select HAS_PMAP
 	select IOMMU_FORCE_PT_SHARE
 
 config ARCH_DEFCONFIG
diff --git a/xen/arch/arm/include/asm/fixmap.h b/xen/arch/arm/include/asm/fixmap.h
index 1cee51e52ab9..c46a15e59de4 100644
--- a/xen/arch/arm/include/asm/fixmap.h
+++ b/xen/arch/arm/include/asm/fixmap.h
@@ -5,12 +5,20 @@
 #define __ASM_FIXMAP_H
 
 #include <xen/acpi.h>
+#include <xen/pmap.h>
 
 /* Fixmap slots */
 #define FIXMAP_CONSOLE  0  /* The primary UART */
 #define FIXMAP_MISC     1  /* Ephemeral mappings of hardware */
 #define FIXMAP_ACPI_BEGIN  2  /* Start mappings of ACPI tables */
 #define FIXMAP_ACPI_END    (FIXMAP_ACPI_BEGIN + NUM_FIXMAP_ACPI_PAGES - 1)  /* End mappings of ACPI tables */
+#define FIXMAP_PMAP_BEGIN (FIXMAP_ACPI_END + 1) /* Start of PMAP */
+#define FIXMAP_PMAP_END (FIXMAP_PMAP_BEGIN + NUM_FIX_PMAP - 1) /* End of PMAP */
+
+#define FIXMAP_LAST FIXMAP_PMAP_END
+
+#define FIXADDR_START FIXMAP_ADDR(0)
+#define FIXADDR_TOP FIXMAP_ADDR(FIXMAP_LAST)
 
 #ifndef __ASSEMBLY__
 
@@ -19,6 +27,15 @@ extern void set_fixmap(unsigned map, mfn_t mfn, unsigned attributes);
 /* Remove a mapping from a fixmap entry */
 extern void clear_fixmap(unsigned map);
 
+#define fix_to_virt(slot) ((void *)FIXMAP_ADDR(slot))
+
+static inline unsigned int virt_to_fix(vaddr_t vaddr)
+{
+    BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
+
+    return ((vaddr - FIXADDR_START) >> PAGE_SHIFT);
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_FIXMAP_H */
diff --git a/xen/arch/arm/include/asm/lpae.h b/xen/arch/arm/include/asm/lpae.h
index 8cf932b5c947..6099037da1c0 100644
--- a/xen/arch/arm/include/asm/lpae.h
+++ b/xen/arch/arm/include/asm/lpae.h
@@ -4,6 +4,7 @@
 #ifndef __ASSEMBLY__
 
 #include <xen/page-defs.h>
+#include <xen/mm-frame.h>
 
 /*
  * WARNING!  Unlike the x86 pagetable code, where l1 is the lowest level and
@@ -168,6 +169,13 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
         third_table_offset(addr)            \
     }
 
+/*
+ * Standard entry type that we'll use to build Xen's own pagetables.
+ * We put the same permissions at every level, because they're ignored
+ * by the walker in non-leaf entries.
+ */
+lpae_t mfn_to_xen_entry(mfn_t mfn, unsigned int attr);
+
 #endif /* __ASSEMBLY__ */
 
 /*
diff --git a/xen/arch/arm/include/asm/pmap.h b/xen/arch/arm/include/asm/pmap.h
new file mode 100644
index 000000000000..70eafe2891d7
--- /dev/null
+++ b/xen/arch/arm/include/asm/pmap.h
@@ -0,0 +1,33 @@
+#ifndef __ASM_PMAP_H__
+#define __ASM_PMAP_H__
+
+#include <xen/mm.h>
+
+/* XXX: Find an header to declare it */
+extern lpae_t xen_fixmap[XEN_PT_LPAE_ENTRIES];
+
+static inline void arch_pmap_map(unsigned int slot, mfn_t mfn)
+{
+    lpae_t *entry = &xen_fixmap[slot];
+    lpae_t pte;
+
+    ASSERT(!lpae_is_valid(*entry));
+
+    pte = mfn_to_xen_entry(mfn, PAGE_HYPERVISOR_RW);
+    pte.pt.table = 1;
+    write_pte(entry, pte);
+}
+
+static inline void arch_pmap_unmap(unsigned int slot)
+{
+    lpae_t pte = {};
+
+    write_pte(&xen_fixmap[slot], pte);
+
+    flush_xen_tlb_range_va_local(FIXMAP_ADDR(slot), PAGE_SIZE);
+}
+
+void arch_pmap_map_slot(unsigned int slot, mfn_t mfn);
+void arch_pmap_clear_slot(void *ptr);
+
+#endif /* __ASM_PMAP_H__ */
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index d6a4b9407c43..b7942464d4de 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -290,12 +290,7 @@ void dump_hyp_walk(vaddr_t addr)
     dump_pt_walk(ttbr, addr, HYP_PT_ROOT_LEVEL, 1);
 }
 
-/*
- * Standard entry type that we'll use to build Xen's own pagetables.
- * We put the same permissions at every level, because they're ignored
- * by the walker in non-leaf entries.
- */
-static inline lpae_t mfn_to_xen_entry(mfn_t mfn, unsigned attr)
+lpae_t mfn_to_xen_entry(mfn_t mfn, unsigned int attr)
 {
     lpae_t e = (lpae_t) {
         .pt = {
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index db687b1785e7..b6c55af2eb03 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -49,6 +49,9 @@ config HAS_KEXEC
 config HAS_PDX
 	bool
 
+config HAS_PMAP
+	bool
+
 config HAS_SCHED_GRANULARITY
 	bool
 
diff --git a/xen/common/Makefile b/xen/common/Makefile
index ca839118e4d1..8b42b0828134 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -28,6 +28,7 @@ obj-y += multicall.o
 obj-y += notifier.o
 obj-y += page_alloc.o
 obj-$(CONFIG_HAS_PDX) += pdx.o
+obj-bin-$(CONFIG_HAS_PMAP) += pmap.init.o
 obj-$(CONFIG_PERF_COUNTERS) += perfc.o
 obj-y += preempt.o
 obj-y += random.o
diff --git a/xen/common/pmap.c b/xen/common/pmap.c
new file mode 100644
index 000000000000..cea730ead545
--- /dev/null
+++ b/xen/common/pmap.c
@@ -0,0 +1,79 @@
+#include <xen/bitops.h>
+#include <xen/init.h>
+#include <xen/pmap.h>
+
+#include <asm/pmap.h>
+#include <asm/fixmap.h>
+
+/*
+ * Simple mapping infrastructure to map / unmap pages in fixed map.
+ * This is used to set up the page table for mapcache, which is used
+ * by map domain page infrastructure.
+ *
+ * This structure is not protected by any locks, so it must not be used after
+ * smp bring-up.
+ */
+
+/* Bitmap to track which slot is used */
+static unsigned long __initdata inuse;
+
+void *__init pmap_map(mfn_t mfn)
+{
+    unsigned long flags;
+    unsigned int idx;
+    unsigned int slot;
+
+    BUILD_BUG_ON(sizeof(inuse) * BITS_PER_BYTE < NUM_FIX_PMAP);
+
+    ASSERT(system_state < SYS_STATE_smp_boot);
+
+    local_irq_save(flags);
+
+    idx = find_first_zero_bit(&inuse, NUM_FIX_PMAP);
+    if ( idx == NUM_FIX_PMAP )
+        panic("Out of PMAP slots\n");
+
+    __set_bit(idx, &inuse);
+
+    slot = idx + FIXMAP_PMAP_BEGIN;
+    ASSERT(slot >= FIXMAP_PMAP_BEGIN && slot <= FIXMAP_PMAP_END);
+
+    /*
+     * We cannot use set_fixmap() here. We use PMAP when there is no direct map,
+     * so map_pages_to_xen() called by set_fixmap() needs to map pages on
+     * demand, which then calls pmap() again, resulting in a loop. Modify the
+     * PTEs directly instead. The same is true for pmap_unmap().
+     */
+    arch_pmap_map(slot, mfn);
+
+    local_irq_restore(flags);
+
+    return fix_to_virt(slot);
+}
+
+void __init pmap_unmap(const void *p)
+{
+    unsigned long flags;
+    unsigned int idx;
+    unsigned int slot = virt_to_fix((unsigned long)p);
+
+    ASSERT(system_state < SYS_STATE_smp_boot);
+    ASSERT(slot >= FIXMAP_PMAP_BEGIN && slot <= FIXMAP_PMAP_END);
+
+    idx = slot - FIXMAP_PMAP_BEGIN;
+    local_irq_save(flags);
+
+    __clear_bit(idx, &inuse);
+    arch_pmap_unmap(slot);
+
+    local_irq_restore(flags);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/xen/pmap.h b/xen/include/xen/pmap.h
new file mode 100644
index 000000000000..93e61b10870e
--- /dev/null
+++ b/xen/include/xen/pmap.h
@@ -0,0 +1,16 @@
+#ifndef __XEN_PMAP_H__
+#define __XEN_PMAP_H__
+
+/* Large enough for mapping 5 levels of page tables with some headroom */
+#define NUM_FIX_PMAP 8
+
+#ifndef __ASSEMBLY__
+
+#include <xen/mm-frame.h>
+
+void *pmap_map(mfn_t mfn);
+void pmap_unmap(const void *p);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __XEN_PMAP_H__ */
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 15/19] xen/arm: mm: Clean-up the includes and order them
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (13 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-04-05 21:29   ` Stefano Stabellini
  2022-02-21 10:22 ` [PATCH v3 16/19] xen/arm: mm: Use the PMAP helpers in xen_{,un}map_table() Julien Grall
                   ` (4 subsequent siblings)
  19 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

From: Julien Grall <jgrall@amazon.com>

The numbers of includes in mm.c has been growing quite a lot. However
some of them (e.g. xen/device_tree.h, xen/softirq.h) doesn't look
to be directly used by the file or other will be included by
larger headers (e.g asm/flushtlb.h will be included by xen/mm.h).

So trim down the number of includes. Take the opportunity to order
them with the xen headers first, then asm headers and last public
headers.

Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v3:
        - Patch added
---
 xen/arch/arm/mm.c | 27 ++++++++++-----------------
 1 file changed, 10 insertions(+), 17 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index b7942464d4de..659bdf25e0ff 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -17,33 +17,26 @@
  * GNU General Public License for more details.
  */
 
-#include <xen/compile.h>
-#include <xen/types.h>
-#include <xen/device_tree.h>
-#include <xen/init.h>
-#include <xen/mm.h>
-#include <xen/preempt.h>
+#include <xen/domain_page.h>
 #include <xen/errno.h>
 #include <xen/grant_table.h>
-#include <xen/softirq.h>
-#include <xen/event.h>
 #include <xen/guest_access.h>
-#include <xen/domain_page.h>
-#include <xen/err.h>
-#include <asm/page.h>
-#include <asm/current.h>
-#include <asm/flushtlb.h>
-#include <public/memory.h>
+#include <xen/init.h>
+#include <xen/libfdt/libfdt.h>
+#include <xen/mm.h>
+#include <xen/pfn.h>
 #include <xen/sched.h>
+#include <xen/sizes.h>
+#include <xen/types.h>
 #include <xen/vmap.h>
+
 #include <xsm/xsm.h>
-#include <xen/pfn.h>
-#include <xen/sizes.h>
-#include <xen/libfdt/libfdt.h>
 
 #include <asm/fixmap.h>
 #include <asm/setup.h>
 
+#include <public/memory.h>
+
 /* Override macros from asm/page.h to make them work with mfn_t */
 #undef virt_to_mfn
 #define virt_to_mfn(va) _mfn(__virt_to_mfn(va))
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 16/19] xen/arm: mm: Use the PMAP helpers in xen_{,un}map_table()
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (14 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 15/19] xen/arm: mm: Clean-up the includes and order them Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-04-05 21:36   ` Stefano Stabellini
  2022-02-21 10:22 ` [PATCH v3 17/19] xen/arm64: mm: Add memory to the boot allocator first Julien Grall
                   ` (3 subsequent siblings)
  19 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

From: Julien Grall <jgrall@amazon.com>

During early boot, it is not possible to use xen_{,un}map_table()
if the page tables are not residing the Xen binary.

This is a blocker to switch some of the helpers to use xen_pt_update()
as we may need to allocate extra page tables and access them before
the domheap has been initialized (see setup_xenheap_mappings()).

xen_{,un}map_table() are now updated to use the PMAP helpers for early
boot map/unmap. Note that the special case for page-tables residing
in Xen binary has been dropped because it is "complex" and was
only added as a workaround in 8d4f1b8878e0 ("xen/arm: mm: Allow
generic xen page-tables helpers to be called early").

Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v2:
        - New patch
---
 xen/arch/arm/mm.c | 33 +++++++++------------------------
 1 file changed, 9 insertions(+), 24 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 659bdf25e0ff..11b6b60a2bc1 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -25,6 +25,7 @@
 #include <xen/libfdt/libfdt.h>
 #include <xen/mm.h>
 #include <xen/pfn.h>
+#include <xen/pmap.h>
 #include <xen/sched.h>
 #include <xen/sizes.h>
 #include <xen/types.h>
@@ -964,27 +965,11 @@ void *ioremap(paddr_t pa, size_t len)
 static lpae_t *xen_map_table(mfn_t mfn)
 {
     /*
-     * We may require to map the page table before map_domain_page() is
-     * useable. The requirements here is it must be useable as soon as
-     * page-tables are allocated dynamically via alloc_boot_pages().
-     *
-     * We need to do the check on physical address rather than virtual
-     * address to avoid truncation on Arm32. Therefore is_kernel() cannot
-     * be used.
+     * During early boot, map_domain_page() may be unusable. Use the
+     * PMAP to map temporarily a page-table.
      */
     if ( system_state == SYS_STATE_early_boot )
-    {
-        if ( is_xen_fixed_mfn(mfn) )
-        {
-            /*
-             * It is fine to demote the type because the size of Xen
-             * will always fit in vaddr_t.
-             */
-            vaddr_t offset = mfn_to_maddr(mfn) - virt_to_maddr(&_start);
-
-            return (lpae_t *)(XEN_VIRT_START + offset);
-        }
-    }
+        return pmap_map(mfn);
 
     return map_domain_page(mfn);
 }
@@ -993,12 +978,12 @@ static void xen_unmap_table(const lpae_t *table)
 {
     /*
      * During early boot, xen_map_table() will not use map_domain_page()
-     * for page-tables residing in Xen binary. So skip the unmap part.
+     * but the PMAP.
      */
-    if ( system_state == SYS_STATE_early_boot && is_kernel(table) )
-        return;
-
-    unmap_domain_page(table);
+    if ( system_state == SYS_STATE_early_boot )
+        pmap_unmap(table);
+    else
+        unmap_domain_page(table);
 }
 
 static int create_xen_table(lpae_t *entry)
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 17/19] xen/arm64: mm: Add memory to the boot allocator first
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (15 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 16/19] xen/arm: mm: Use the PMAP helpers in xen_{,un}map_table() Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-04-05 21:50   ` Stefano Stabellini
  2022-02-21 10:22 ` [PATCH v3 18/19] xen/arm: mm: Rework setup_xenheap_mappings() Julien Grall
                   ` (2 subsequent siblings)
  19 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

From: Julien Grall <jgrall@amazon.com>

Currently, memory is added to the boot allocator after the xenheap
mappings are done. This will break if the first mapping is more than
512GB of RAM.

In addition to that, a follow-up patch will rework setup_xenheap_mappings()
to use smaller mappings (e.g. 2MB, 4KB). So it will be necessary to have
memory in the boot allocator earlier.

Only free memory (e.g. not reserved or modules) can be added to the boot
allocator. It might be possible that some regions (including the first
one) will have no free memory.

So we need to add all the free memory to the boot allocator first
and then add do the mappings.

Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v3:
        - Patch added
---
 xen/arch/arm/setup.c | 63 +++++++++++++++++++++++++++++---------------
 1 file changed, 42 insertions(+), 21 deletions(-)

diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index d5d0792ed48a..777cf96639f5 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -767,30 +767,18 @@ static void __init setup_mm(void)
     init_staticmem_pages();
 }
 #else /* CONFIG_ARM_64 */
-static void __init setup_mm(void)
+static void __init populate_boot_allocator(void)
 {
-    paddr_t ram_start = ~0;
-    paddr_t ram_end = 0;
-    paddr_t ram_size = 0;
-    int bank;
-
-    init_pdx();
+    unsigned int i;
+    const struct meminfo *banks = &bootinfo.mem;
 
-    total_pages = 0;
-    for ( bank = 0 ; bank < bootinfo.mem.nr_banks; bank++ )
+    for ( i = 0; i < banks->nr_banks; i++ )
     {
-        paddr_t bank_start = bootinfo.mem.bank[bank].start;
-        paddr_t bank_size = bootinfo.mem.bank[bank].size;
-        paddr_t bank_end = bank_start + bank_size;
+        const struct membank *bank = &banks->bank[i];
+        paddr_t bank_end = bank->start + bank->size;
         paddr_t s, e;
 
-        ram_size = ram_size + bank_size;
-        ram_start = min(ram_start,bank_start);
-        ram_end = max(ram_end,bank_end);
-
-        setup_xenheap_mappings(bank_start>>PAGE_SHIFT, bank_size>>PAGE_SHIFT);
-
-        s = bank_start;
+        s = bank->start;
         while ( s < bank_end )
         {
             paddr_t n = bank_end;
@@ -798,9 +786,7 @@ static void __init setup_mm(void)
             e = next_module(s, &n);
 
             if ( e == ~(paddr_t)0 )
-            {
                 e = n = bank_end;
-            }
 
             if ( e > bank_end )
                 e = bank_end;
@@ -809,6 +795,41 @@ static void __init setup_mm(void)
             s = n;
         }
     }
+}
+
+static void __init setup_mm(void)
+{
+    const struct meminfo *banks = &bootinfo.mem;
+    paddr_t ram_start = ~0;
+    paddr_t ram_end = 0;
+    paddr_t ram_size = 0;
+    unsigned int i;
+
+    init_pdx();
+
+    /*
+     * We need some memory to allocate the page-tables used for the xenheap
+     * mappings. But some regions may contain memory already allocated
+     * for other uses (e.g. modules, reserved-memory...).
+     *
+     * For simplify add all the free regions in the boot allocator.
+     */
+    populate_boot_allocator();
+
+    total_pages = 0;
+
+    for ( i = 0; i < banks->nr_banks; i++ )
+    {
+        const struct membank *bank = &banks->bank[i];
+        paddr_t bank_end = bank->start + bank->size;
+
+        ram_size = ram_size + bank->size;
+        ram_start = min(ram_start, bank->start);
+        ram_end = max(ram_end, bank_end);
+
+        setup_xenheap_mappings(PFN_DOWN(bank->start),
+                               PFN_DOWN(bank->size));
+    }
 
     total_pages += ram_size >> PAGE_SHIFT;
 
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 18/19] xen/arm: mm: Rework setup_xenheap_mappings()
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (16 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 17/19] xen/arm64: mm: Add memory to the boot allocator first Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-04-05 23:57   ` Stefano Stabellini
  2022-02-21 10:22 ` [PATCH v3 19/19] xen/arm: mm: Re-implement setup_frame_table_mappings() with map_pages_to_xen() Julien Grall
  2022-02-27 19:25 ` [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
  19 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

From: Julien Grall <julien.grall@arm.com>

The current implementation of setup_xenheap_mappings() is using 1GB
mappings. This can lead to unexpected result because the mapping
may alias a non-cachable region (such as device or reserved regions).
For more details see B2.8 in ARM DDI 0487H.a.

map_pages_to_xen() was recently reworked to allow superpage mappings,
support contiguous mapping and deal with the use of pagge-tables before
they are mapped.

Most of the code in setup_xenheap_mappings() is now replaced with a
single call to map_pages_to_xen().

Signed-off-by: Julien Grall <julien.grall@arm.com>
Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v3:
        - Don't use 1GB mapping
        - Re-order code in setup_mm() in a separate patch

    Changes in v2:
        - New patch
---
 xen/arch/arm/mm.c | 87 ++++++++++-------------------------------------
 1 file changed, 18 insertions(+), 69 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 11b6b60a2bc1..4af59375d998 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -138,17 +138,6 @@ static DEFINE_PAGE_TABLE(cpu0_pgtable);
 static DEFINE_PAGE_TABLES(cpu0_dommap, DOMHEAP_SECOND_PAGES);
 #endif
 
-#ifdef CONFIG_ARM_64
-/* The first page of the first level mapping of the xenheap. The
- * subsequent xenheap first level pages are dynamically allocated, but
- * we need this one to bootstrap ourselves. */
-static DEFINE_PAGE_TABLE(xenheap_first_first);
-/* The zeroeth level slot which uses xenheap_first_first. Used because
- * setup_xenheap_mappings otherwise relies on mfn_to_virt which isn't
- * valid for a non-xenheap mapping. */
-static __initdata int xenheap_first_first_slot = -1;
-#endif
-
 /* Common pagetable leaves */
 /* Second level page tables.
  *
@@ -815,77 +804,37 @@ void __init setup_xenheap_mappings(unsigned long base_mfn,
 void __init setup_xenheap_mappings(unsigned long base_mfn,
                                    unsigned long nr_mfns)
 {
-    lpae_t *first, pte;
-    unsigned long mfn, end_mfn;
-    vaddr_t vaddr;
-
-    /* Align to previous 1GB boundary */
-    mfn = base_mfn & ~((FIRST_SIZE>>PAGE_SHIFT)-1);
+    int rc;
 
     /* First call sets the xenheap physical and virtual offset. */
     if ( mfn_eq(xenheap_mfn_start, INVALID_MFN) )
     {
+        unsigned long mfn_gb = base_mfn & ~((FIRST_SIZE >> PAGE_SHIFT) - 1);
+
         xenheap_mfn_start = _mfn(base_mfn);
         xenheap_base_pdx = mfn_to_pdx(_mfn(base_mfn));
+        /*
+         * The base address may not be aligned to the first level
+         * size (e.g. 1GB when using 4KB pages). This would prevent
+         * superpage mappings for all the regions because the virtual
+         * address and machine address should both be suitably aligned.
+         *
+         * Prevent that by offsetting the start of the xenheap virtual
+         * address.
+         */
         xenheap_virt_start = DIRECTMAP_VIRT_START +
-            (base_mfn - mfn) * PAGE_SIZE;
+            (base_mfn - mfn_gb) * PAGE_SIZE;
     }
 
     if ( base_mfn < mfn_x(xenheap_mfn_start) )
         panic("cannot add xenheap mapping at %lx below heap start %lx\n",
               base_mfn, mfn_x(xenheap_mfn_start));
 
-    end_mfn = base_mfn + nr_mfns;
-
-    /*
-     * Virtual address aligned to previous 1GB to match physical
-     * address alignment done above.
-     */
-    vaddr = (vaddr_t)__mfn_to_virt(base_mfn) & FIRST_MASK;
-
-    while ( mfn < end_mfn )
-    {
-        int slot = zeroeth_table_offset(vaddr);
-        lpae_t *p = &xen_pgtable[slot];
-
-        if ( p->pt.valid )
-        {
-            /* mfn_to_virt is not valid on the 1st 1st mfn, since it
-             * is not within the xenheap. */
-            first = slot == xenheap_first_first_slot ?
-                xenheap_first_first : mfn_to_virt(lpae_get_mfn(*p));
-        }
-        else if ( xenheap_first_first_slot == -1)
-        {
-            /* Use xenheap_first_first to bootstrap the mappings */
-            first = xenheap_first_first;
-
-            pte = pte_of_xenaddr((vaddr_t)xenheap_first_first);
-            pte.pt.table = 1;
-            write_pte(p, pte);
-
-            xenheap_first_first_slot = slot;
-        }
-        else
-        {
-            mfn_t first_mfn = alloc_boot_pages(1, 1);
-
-            clear_page(mfn_to_virt(first_mfn));
-            pte = mfn_to_xen_entry(first_mfn, MT_NORMAL);
-            pte.pt.table = 1;
-            write_pte(p, pte);
-            first = mfn_to_virt(first_mfn);
-        }
-
-        pte = mfn_to_xen_entry(_mfn(mfn), MT_NORMAL);
-        /* TODO: Set pte.pt.contig when appropriate. */
-        write_pte(&first[first_table_offset(vaddr)], pte);
-
-        mfn += FIRST_SIZE>>PAGE_SHIFT;
-        vaddr += FIRST_SIZE;
-    }
-
-    flush_xen_tlb_local();
+    rc = map_pages_to_xen((vaddr_t)__mfn_to_virt(base_mfn),
+                          _mfn(base_mfn), nr_mfns,
+                          PAGE_HYPERVISOR_RW | _PAGE_BLOCK);
+    if ( rc )
+        panic("Unable to setup the xenheap mappings.\n");
 }
 #endif
 
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* [PATCH v3 19/19] xen/arm: mm: Re-implement setup_frame_table_mappings() with map_pages_to_xen()
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (17 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 18/19] xen/arm: mm: Rework setup_xenheap_mappings() Julien Grall
@ 2022-02-21 10:22 ` Julien Grall
  2022-03-16  6:10   ` Hongda Deng
  2022-04-06  0:01   ` Stefano Stabellini
  2022-02-27 19:25 ` [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
  19 siblings, 2 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-21 10:22 UTC (permalink / raw)
  To: xen-devel
  Cc: julien, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

From: Julien Grall <julien.grall@arm.com>

Now that map_pages_to_xen() has been extended to support 2MB mappings,
we can replace the create_mappings() call by map_pages_to_xen() call.

This has the advantage to remove the differences between 32-bit and
64-bit code.

Lastly remove create_mappings() as there is no more callers.

Signed-off-by: Julien Grall <julien.grall@arm.com>
Signed-off-by: Julien Grall <jgrall@amazon.com>

---
    Changes in v3:
        - Fix typo in the commit message
        - Remove the TODO regarding contiguous bit

    Changes in v2:
        - New patch
---
 xen/arch/arm/mm.c | 63 ++++-------------------------------------------
 1 file changed, 5 insertions(+), 58 deletions(-)

diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 4af59375d998..d73f49d5b6fc 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -354,40 +354,6 @@ void clear_fixmap(unsigned map)
     BUG_ON(res != 0);
 }
 
-/* Create Xen's mappings of memory.
- * Mapping_size must be either 2MB or 32MB.
- * Base and virt must be mapping_size aligned.
- * Size must be a multiple of mapping_size.
- * second must be a contiguous set of second level page tables
- * covering the region starting at virt_offset. */
-static void __init create_mappings(lpae_t *second,
-                                   unsigned long virt_offset,
-                                   unsigned long base_mfn,
-                                   unsigned long nr_mfns,
-                                   unsigned int mapping_size)
-{
-    unsigned long i, count;
-    const unsigned long granularity = mapping_size >> PAGE_SHIFT;
-    lpae_t pte, *p;
-
-    ASSERT((mapping_size == MB(2)) || (mapping_size == MB(32)));
-    ASSERT(!((virt_offset >> PAGE_SHIFT) % granularity));
-    ASSERT(!(base_mfn % granularity));
-    ASSERT(!(nr_mfns % granularity));
-
-    count = nr_mfns / XEN_PT_LPAE_ENTRIES;
-    p = second + second_linear_offset(virt_offset);
-    pte = mfn_to_xen_entry(_mfn(base_mfn), MT_NORMAL);
-    if ( granularity == 16 * XEN_PT_LPAE_ENTRIES )
-        pte.pt.contig = 1;  /* These maps are in 16-entry contiguous chunks. */
-    for ( i = 0; i < count; i++ )
-    {
-        write_pte(p + i, pte);
-        pte.pt.base += 1 << XEN_PT_LPAE_SHIFT;
-    }
-    flush_xen_tlb_local();
-}
-
 #ifdef CONFIG_DOMAIN_PAGE
 void *map_domain_page_global(mfn_t mfn)
 {
@@ -846,36 +812,17 @@ void __init setup_frametable_mappings(paddr_t ps, paddr_t pe)
     unsigned long frametable_size = nr_pdxs * sizeof(struct page_info);
     mfn_t base_mfn;
     const unsigned long mapping_size = frametable_size < MB(32) ? MB(2) : MB(32);
-#ifdef CONFIG_ARM_64
-    lpae_t *second, pte;
-    unsigned long nr_second;
-    mfn_t second_base;
-    int i;
-#endif
+    int rc;
 
     frametable_base_pdx = mfn_to_pdx(maddr_to_mfn(ps));
     /* Round up to 2M or 32M boundary, as appropriate. */
     frametable_size = ROUNDUP(frametable_size, mapping_size);
     base_mfn = alloc_boot_pages(frametable_size >> PAGE_SHIFT, 32<<(20-12));
 
-#ifdef CONFIG_ARM_64
-    /* Compute the number of second level pages. */
-    nr_second = ROUNDUP(frametable_size, FIRST_SIZE) >> FIRST_SHIFT;
-    second_base = alloc_boot_pages(nr_second, 1);
-    second = mfn_to_virt(second_base);
-    for ( i = 0; i < nr_second; i++ )
-    {
-        clear_page(mfn_to_virt(mfn_add(second_base, i)));
-        pte = mfn_to_xen_entry(mfn_add(second_base, i), MT_NORMAL);
-        pte.pt.table = 1;
-        write_pte(&xen_first[first_table_offset(FRAMETABLE_VIRT_START)+i], pte);
-    }
-    create_mappings(second, 0, mfn_x(base_mfn), frametable_size >> PAGE_SHIFT,
-                    mapping_size);
-#else
-    create_mappings(xen_second, FRAMETABLE_VIRT_START, mfn_x(base_mfn),
-                    frametable_size >> PAGE_SHIFT, mapping_size);
-#endif
+    rc = map_pages_to_xen(FRAMETABLE_VIRT_START, base_mfn,
+                          frametable_size >> PAGE_SHIFT, PAGE_HYPERVISOR_RW);
+    if ( rc )
+        panic("Unable to setup the frametable mappings.\n");
 
     memset(&frame_table[0], 0, nr_pdxs * sizeof(struct page_info));
     memset(&frame_table[nr_pdxs], -1,
-- 
2.32.0



^ permalink raw reply related	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 01/19] xen/arm: lpae: Rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS
  2022-02-21 10:22 ` [PATCH v3 01/19] xen/arm: lpae: Rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS Julien Grall
@ 2022-02-22 13:30   ` Michal Orzel
  2022-02-24 22:19     ` Julien Grall
  2022-02-22 15:21   ` Bertrand Marquis
  1 sibling, 1 reply; 79+ messages in thread
From: Michal Orzel @ 2022-02-22 13:30 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk

Hi Julien,

On 21.02.2022 11:22, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> Commit 05031fa87357 "xen/arm: guest_walk: Only generate necessary
> offsets/masks" introduced LPAE_ENTRIES_MASK_GS. In a follow-up patch,
> we will use it for to define LPAE_ENTRY_MASK.
> 
for is unneddded. Should be "we will use it to define..."

> This will lead to inconsistent naming. As LPAE_ENTRY_MASK is used in
> many places, it is better to rename LPAE_ENTRIES_MASK_GS and avoid
> some churn.
> 
> So rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v2:
>         - New patch
> ---
>  xen/arch/arm/include/asm/lpae.h | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/arm/include/asm/lpae.h b/xen/arch/arm/include/asm/lpae.h
> index e94de2e7d8e8..4fb9a40a4ca9 100644
> --- a/xen/arch/arm/include/asm/lpae.h
> +++ b/xen/arch/arm/include/asm/lpae.h
> @@ -180,7 +180,7 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
>   */
>  #define LPAE_SHIFT_GS(gs)         ((gs) - 3)
>  #define LPAE_ENTRIES_GS(gs)       (_AC(1, U) << LPAE_SHIFT_GS(gs))
> -#define LPAE_ENTRIES_MASK_GS(gs)  (LPAE_ENTRIES_GS(gs) - 1)
> +#define LPAE_ENTRY_MASK_GS(gs)  (LPAE_ENTRIES_GS(gs) - 1)

Incorrect indentation of (LPAE_ENTRIES_GS(gs) - 1)
> 
>  #define LEVEL_ORDER_GS(gs, lvl)   ((3 - (lvl)) * LPAE_SHIFT_GS(gs))
>  #define LEVEL_SHIFT_GS(gs, lvl)   (LEVEL_ORDER_GS(gs, lvl) + (gs))
> @@ -188,7 +188,7 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
>  
>  /* Offset in the table at level 'lvl' */
>  #define LPAE_TABLE_INDEX_GS(gs, lvl, addr)   \
> -    (((addr) >> LEVEL_SHIFT_GS(gs, lvl)) & LPAE_ENTRIES_MASK_GS(gs))
> +    (((addr) >> LEVEL_SHIFT_GS(gs, lvl)) & LPAE_ENTRY_MASK_GS(gs))
>  
>  /* Generate an array @var containing the offset for each level from @addr */
>  #define DECLARE_OFFSETS(var, addr)          \
> 

Cheers,
Michal


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 02/19] xen/arm: lpae: Use the generic helpers to defined the Xen PT helpers
  2022-02-21 10:22 ` [PATCH v3 02/19] xen/arm: lpae: Use the generic helpers to defined the Xen PT helpers Julien Grall
@ 2022-02-22 14:26   ` Michal Orzel
  2022-02-22 15:38   ` Bertrand Marquis
  1 sibling, 0 replies; 79+ messages in thread
From: Michal Orzel @ 2022-02-22 14:26 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk

Hi Julien,

On 21.02.2022 11:22, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> Currently, Xen PT helpers are only working with 4KB page granularity
> and open-code the generic helpers. To allow more flexibility, we can
> re-use the generic helpers and pass Xen's page granularity
> (PAGE_SHIFT).
> 
> As Xen PT helpers are used in both C and assembly, we need to move
> the generic helpers definition outside of the !__ASSEMBLY__ section.
> 
> Take the opportunity to prefix LPAE_ENTRIES, LPAE_ENTRIES and
> LPAE_ENTRIES_MASK with XEN_PT_.
> 
> Note the aliases for each level are still kept for the time being so we
> can avoid a massive patch to change all the callers.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v3:
>       - Prefix the new define with XEN_PT_
> 
>     Changes in v2:
>         - New patch
> ---
>  xen/arch/arm/arm32/head.S       | 14 +++----
>  xen/arch/arm/arm64/head.S       | 14 +++----
>  xen/arch/arm/include/asm/lpae.h | 73 ++++++++++++++++++---------------
>  xen/arch/arm/mm.c               | 33 ++++++++-------
>  xen/arch/arm/p2m.c              | 13 +++---
>  5 files changed, 80 insertions(+), 67 deletions(-)
> 

Reviewed-by: Michal Orzel <michal.orzel@arm.com>

Cheers,
Michal


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 13/19] xen/arm: Move fixmap definitions in a separate header
  2022-02-21 10:22 ` [PATCH v3 13/19] xen/arm: Move fixmap definitions in a separate header Julien Grall
@ 2022-02-22 15:10   ` Jan Beulich
  2022-04-05 21:12   ` Stefano Stabellini
  1 sibling, 0 replies; 79+ messages in thread
From: Jan Beulich @ 2022-02-22 15:10 UTC (permalink / raw)
  To: Julien Grall
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Wei Liu,
	xen-devel

On 21.02.2022 11:22, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> To use properly the fixmap definitions, their user would need
> also new to include <xen/acpi.h>. This is not very great when
> the user itself is not meant to directly use ACPI definitions.
> 
> Including <xen/acpi.h> in <asm/config.h> is not option because
> the latter header is included by everyone. So move out the fixmap
> entries definition in a new header.
> 
> Take the opportunity to also move {set, clear}_fixmap() prototypes
> in the new header.
> 
> Note that most of the definitions in <xen/acpi.h> now need to be
> surrounded with #ifndef __ASSEMBLY__ because <asm/fixmap.h> will
> be used in assembly (see EARLY_UART_VIRTUAL_ADDRESS).
> 
> The split will become more helpful in a follow-up patch where new
> fixmap entries will be defined.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>

Acked-by: Jan Beulich <jbeulich@suse.com>



^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 01/19] xen/arm: lpae: Rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS
  2022-02-21 10:22 ` [PATCH v3 01/19] xen/arm: lpae: Rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS Julien Grall
  2022-02-22 13:30   ` Michal Orzel
@ 2022-02-22 15:21   ` Bertrand Marquis
  1 sibling, 0 replies; 79+ messages in thread
From: Bertrand Marquis @ 2022-02-22 15:21 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Volodymyr Babchuk

Hi Julien,

> On 21 Feb 2022, at 10:22, Julien Grall <julien@xen.org> wrote:
> 
> From: Julien Grall <jgrall@amazon.com>
> 
> Commit 05031fa87357 "xen/arm: guest_walk: Only generate necessary
> offsets/masks" introduced LPAE_ENTRIES_MASK_GS. In a follow-up patch,
> we will use it for to define LPAE_ENTRY_MASK.
> 
> This will lead to inconsistent naming. As LPAE_ENTRY_MASK is used in
> many places, it is better to rename LPAE_ENTRIES_MASK_GS and avoid
> some churn.
> 
> So rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>

With the 2 small fixes suggested by Michal, you can add my
Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>

Cheers
Bertrand

> 
> ---
>    Changes in v2:
>        - New patch
> ---
> xen/arch/arm/include/asm/lpae.h | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/arm/include/asm/lpae.h b/xen/arch/arm/include/asm/lpae.h
> index e94de2e7d8e8..4fb9a40a4ca9 100644
> --- a/xen/arch/arm/include/asm/lpae.h
> +++ b/xen/arch/arm/include/asm/lpae.h
> @@ -180,7 +180,7 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
>  */
> #define LPAE_SHIFT_GS(gs)         ((gs) - 3)
> #define LPAE_ENTRIES_GS(gs)       (_AC(1, U) << LPAE_SHIFT_GS(gs))
> -#define LPAE_ENTRIES_MASK_GS(gs)  (LPAE_ENTRIES_GS(gs) - 1)
> +#define LPAE_ENTRY_MASK_GS(gs)  (LPAE_ENTRIES_GS(gs) - 1)
> 
> #define LEVEL_ORDER_GS(gs, lvl)   ((3 - (lvl)) * LPAE_SHIFT_GS(gs))
> #define LEVEL_SHIFT_GS(gs, lvl)   (LEVEL_ORDER_GS(gs, lvl) + (gs))
> @@ -188,7 +188,7 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
> 
> /* Offset in the table at level 'lvl' */
> #define LPAE_TABLE_INDEX_GS(gs, lvl, addr)   \
> -    (((addr) >> LEVEL_SHIFT_GS(gs, lvl)) & LPAE_ENTRIES_MASK_GS(gs))
> +    (((addr) >> LEVEL_SHIFT_GS(gs, lvl)) & LPAE_ENTRY_MASK_GS(gs))
> 
> /* Generate an array @var containing the offset for each level from @addr */
> #define DECLARE_OFFSETS(var, addr)          \
> -- 
> 2.32.0
> 



^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure
  2022-02-21 10:22 ` [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure Julien Grall
@ 2022-02-22 15:22   ` Jan Beulich
  2022-02-28  9:55     ` Julien Grall
  2022-04-05 21:27   ` Stefano Stabellini
  1 sibling, 1 reply; 79+ messages in thread
From: Jan Beulich @ 2022-02-22 15:22 UTC (permalink / raw)
  To: Julien Grall
  Cc: Wei Liu, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk,
	George Dunlap, Hongyan Xia, Julien Grall, Wei Liu, Andrew Cooper,
	Roger Pau Monné,
	xen-devel

On 21.02.2022 11:22, Julien Grall wrote:
> --- a/xen/common/Makefile
> +++ b/xen/common/Makefile
> @@ -28,6 +28,7 @@ obj-y += multicall.o
>  obj-y += notifier.o
>  obj-y += page_alloc.o
>  obj-$(CONFIG_HAS_PDX) += pdx.o
> +obj-bin-$(CONFIG_HAS_PMAP) += pmap.init.o
>  obj-$(CONFIG_PERF_COUNTERS) += perfc.o
>  obj-y += preempt.o
>  obj-y += random.o

Nit: Please move the insertion one line further down.

> --- /dev/null
> +++ b/xen/common/pmap.c
> @@ -0,0 +1,79 @@
> +#include <xen/bitops.h>
> +#include <xen/init.h>
> +#include <xen/pmap.h>
> +
> +#include <asm/pmap.h>
> +#include <asm/fixmap.h>
> +
> +/*
> + * Simple mapping infrastructure to map / unmap pages in fixed map.
> + * This is used to set up the page table for mapcache, which is used
> + * by map domain page infrastructure.

Is this comment stale from its original x86 purpose?

> + * This structure is not protected by any locks, so it must not be used after
> + * smp bring-up.
> + */
> +
> +/* Bitmap to track which slot is used */
> +static unsigned long __initdata inuse;

I guess this wants to use DECLARE_BITMAP(), for ...

> +void *__init pmap_map(mfn_t mfn)
> +{
> +    unsigned long flags;
> +    unsigned int idx;
> +    unsigned int slot;
> +
> +    BUILD_BUG_ON(sizeof(inuse) * BITS_PER_BYTE < NUM_FIX_PMAP);
> +
> +    ASSERT(system_state < SYS_STATE_smp_boot);
> +
> +    local_irq_save(flags);
> +
> +    idx = find_first_zero_bit(&inuse, NUM_FIX_PMAP);

... this to be correct irrespective of how large NUM_FIX_PMAP is?
I think that's preferable over the BUILD_BUG_ON().

> +    if ( idx == NUM_FIX_PMAP )
> +        panic("Out of PMAP slots\n");
> +
> +    __set_bit(idx, &inuse);
> +
> +    slot = idx + FIXMAP_PMAP_BEGIN;
> +    ASSERT(slot >= FIXMAP_PMAP_BEGIN && slot <= FIXMAP_PMAP_END);
> +
> +    /*
> +     * We cannot use set_fixmap() here. We use PMAP when there is no direct map,
> +     * so map_pages_to_xen() called by set_fixmap() needs to map pages on
> +     * demand, which then calls pmap() again, resulting in a loop. Modify the
> +     * PTEs directly instead. The same is true for pmap_unmap().
> +     */
> +    arch_pmap_map(slot, mfn);

I'm less certain here, but like above I'm under the impression
that this comment may no longer be accurate.

> +    local_irq_restore(flags);

What is this IRQ save/restore intended to protect against, when
use of this function is limited to pre-SMP boot anyway?

Jan



^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 02/19] xen/arm: lpae: Use the generic helpers to defined the Xen PT helpers
  2022-02-21 10:22 ` [PATCH v3 02/19] xen/arm: lpae: Use the generic helpers to defined the Xen PT helpers Julien Grall
  2022-02-22 14:26   ` Michal Orzel
@ 2022-02-22 15:38   ` Bertrand Marquis
  2022-02-24 22:24     ` Julien Grall
  1 sibling, 1 reply; 79+ messages in thread
From: Bertrand Marquis @ 2022-02-22 15:38 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Volodymyr Babchuk

Hi Julien,

> On 21 Feb 2022, at 10:22, Julien Grall <julien@xen.org> wrote:
> 
> From: Julien Grall <jgrall@amazon.com>
> 
> Currently, Xen PT helpers are only working with 4KB page granularity
> and open-code the generic helpers. To allow more flexibility, we can
> re-use the generic helpers and pass Xen's page granularity
> (PAGE_SHIFT).
> 
> As Xen PT helpers are used in both C and assembly, we need to move
> the generic helpers definition outside of the !__ASSEMBLY__ section.
> 
> Take the opportunity to prefix LPAE_ENTRIES, LPAE_ENTRIES and
> LPAE_ENTRIES_MASK with XEN_PT_.

The list needs to be fixed to be SHIFT, ENTRIES and ENTRY_MASK.

> 
> Note the aliases for each level are still kept for the time being so we
> can avoid a massive patch to change all the callers.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>

With this fixed:
Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>

Cheers
Bertrand

> 
> ---
>    Changes in v3:
>      - Prefix the new define with XEN_PT_
> 
>    Changes in v2:
>        - New patch
> ---
> xen/arch/arm/arm32/head.S       | 14 +++----
> xen/arch/arm/arm64/head.S       | 14 +++----
> xen/arch/arm/include/asm/lpae.h | 73 ++++++++++++++++++---------------
> xen/arch/arm/mm.c               | 33 ++++++++-------
> xen/arch/arm/p2m.c              | 13 +++---
> 5 files changed, 80 insertions(+), 67 deletions(-)
> 
> diff --git a/xen/arch/arm/arm32/head.S b/xen/arch/arm/arm32/head.S
> index b5912d381b98..b1d209ea2842 100644
> --- a/xen/arch/arm/arm32/head.S
> +++ b/xen/arch/arm/arm32/head.S
> @@ -375,7 +375,7 @@ ENDPROC(cpu_init)
>  */
> .macro create_table_entry, ptbl, tbl, virt, shift, mmu=0
>         lsr   r1, \virt, #\shift
> -        mov_w r2, LPAE_ENTRY_MASK
> +        mov_w r2, XEN_PT_LPAE_ENTRY_MASK
>         and   r1, r1, r2             /* r1 := slot in \tlb */
>         lsl   r1, r1, #3             /* r1 := slot offset in \tlb */
> 
> @@ -410,7 +410,7 @@ ENDPROC(cpu_init)
>  * and be distinct.
>  */
> .macro create_mapping_entry, ptbl, virt, phys, type=PT_MEM_L3, mmu=0
> -        mov_w r2, LPAE_ENTRY_MASK
> +        mov_w r2, XEN_PT_LPAE_ENTRY_MASK
>         lsr   r1, \virt, #THIRD_SHIFT
>         and   r1, r1, r2             /* r1 := slot in \tlb */
>         lsl   r1, r1, #3             /* r1 := slot offset in \tlb */
> @@ -465,7 +465,7 @@ create_page_tables:
> 1:      strd  r2, r3, [r4, r1]       /* Map vaddr(start) */
>         add   r2, r2, #PAGE_SIZE     /* Next page */
>         add   r1, r1, #8             /* Next slot */
> -        cmp   r1, #(LPAE_ENTRIES<<3) /* 512*8-byte entries per page */
> +        cmp   r1, #(XEN_PT_LPAE_ENTRIES<<3) /* 512*8-byte entries per page */
>         blo   1b
> 
>         /*
> @@ -487,7 +487,7 @@ create_page_tables:
>          * the second level.
>          */
>         lsr   r1, r9, #FIRST_SHIFT
> -        mov_w r0, LPAE_ENTRY_MASK
> +        mov_w r0, XEN_PT_LPAE_ENTRY_MASK
>         and   r1, r1, r0              /* r1 := first slot */
>         cmp   r1, #XEN_FIRST_SLOT
>         beq   1f
> @@ -502,7 +502,7 @@ create_page_tables:
>          * it.
>          */
>         lsr   r1, r9, #SECOND_SHIFT
> -        mov_w r0, LPAE_ENTRY_MASK
> +        mov_w r0, XEN_PT_LPAE_ENTRY_MASK
>         and   r1, r1, r0             /* r1 := second slot */
>         cmp   r1, #XEN_SECOND_SLOT
>         beq   virtphys_clash
> @@ -573,7 +573,7 @@ remove_identity_mapping:
>          * table if the slot is not XEN_FIRST_SLOT.
>          */
>         lsr   r1, r9, #FIRST_SHIFT
> -        mov_w r0, LPAE_ENTRY_MASK
> +        mov_w r0, XEN_PT_LPAE_ENTRY_MASK
>         and   r1, r1, r0              /* r1 := first slot */
>         cmp   r1, #XEN_FIRST_SLOT
>         beq   1f
> @@ -589,7 +589,7 @@ remove_identity_mapping:
>          * table if the slot is not XEN_SECOND_SLOT.
>          */
>         lsr   r1, r9, #SECOND_SHIFT
> -        mov_w r0, LPAE_ENTRY_MASK
> +        mov_w r0, XEN_PT_LPAE_ENTRY_MASK
>         and   r1, r1, r0             /* r1 := second slot */
>         cmp   r1, #XEN_SECOND_SLOT
>         beq   identity_mapping_removed
> diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
> index 51b00ab0bea6..314b800b3f8e 100644
> --- a/xen/arch/arm/arm64/head.S
> +++ b/xen/arch/arm/arm64/head.S
> @@ -509,7 +509,7 @@ ENDPROC(cpu_init)
>  */
> .macro create_table_entry, ptbl, tbl, virt, shift, tmp1, tmp2, tmp3
>         lsr   \tmp1, \virt, #\shift
> -        and   \tmp1, \tmp1, #LPAE_ENTRY_MASK/* \tmp1 := slot in \tlb */
> +        and   \tmp1, \tmp1, #XEN_PT_LPAE_ENTRY_MASK/* \tmp1 := slot in \tlb */
> 
>         load_paddr \tmp2, \tbl
>         mov   \tmp3, #PT_PT                 /* \tmp3 := right for linear PT */
> @@ -541,7 +541,7 @@ ENDPROC(cpu_init)
>         and   \tmp3, \phys, #THIRD_MASK     /* \tmp3 := PAGE_ALIGNED(phys) */
> 
>         lsr   \tmp1, \virt, #THIRD_SHIFT
> -        and   \tmp1, \tmp1, #LPAE_ENTRY_MASK/* \tmp1 := slot in \tlb */
> +        and   \tmp1, \tmp1, #XEN_PT_LPAE_ENTRY_MASK/* \tmp1 := slot in \tlb */
> 
>         mov   \tmp2, #\type                 /* \tmp2 := right for section PT */
>         orr   \tmp2, \tmp2, \tmp3           /*          + PAGE_ALIGNED(phys) */
> @@ -586,7 +586,7 @@ create_page_tables:
> 1:      str   x2, [x4, x1]           /* Map vaddr(start) */
>         add   x2, x2, #PAGE_SIZE     /* Next page */
>         add   x1, x1, #8             /* Next slot */
> -        cmp   x1, #(LPAE_ENTRIES<<3) /* 512 entries per page */
> +        cmp   x1, #(XEN_PT_LPAE_ENTRIES<<3) /* 512 entries per page */
>         b.lt  1b
> 
>         /*
> @@ -621,7 +621,7 @@ create_page_tables:
>          * the second level.
>          */
>         lsr   x0, x19, #FIRST_SHIFT
> -        and   x0, x0, #LPAE_ENTRY_MASK  /* x0 := first slot */
> +        and   x0, x0, #XEN_PT_LPAE_ENTRY_MASK  /* x0 := first slot */
>         cmp   x0, #XEN_FIRST_SLOT
>         beq   1f
>         create_table_entry boot_first, boot_second_id, x19, FIRST_SHIFT, x0, x1, x2
> @@ -635,7 +635,7 @@ create_page_tables:
>          * it.
>          */
>         lsr   x0, x19, #SECOND_SHIFT
> -        and   x0, x0, #LPAE_ENTRY_MASK  /* x0 := first slot */
> +        and   x0, x0, #XEN_PT_LPAE_ENTRY_MASK  /* x0 := first slot */
>         cmp   x0, #XEN_SECOND_SLOT
>         beq   virtphys_clash
>         create_table_entry boot_second, boot_third_id, x19, SECOND_SHIFT, x0, x1, x2
> @@ -715,7 +715,7 @@ remove_identity_mapping:
>          * table if the slot is not XEN_FIRST_SLOT.
>          */
>         lsr   x1, x19, #FIRST_SHIFT
> -        and   x1, x1, #LPAE_ENTRY_MASK  /* x1 := first slot */
> +        and   x1, x1, #XEN_PT_LPAE_ENTRY_MASK  /* x1 := first slot */
>         cmp   x1, #XEN_FIRST_SLOT
>         beq   1f
>         /* It is not in slot XEN_FIRST_SLOT, remove the entry. */
> @@ -729,7 +729,7 @@ remove_identity_mapping:
>          * table if the slot is not XEN_SECOND_SLOT.
>          */
>         lsr   x1, x19, #SECOND_SHIFT
> -        and   x1, x1, #LPAE_ENTRY_MASK  /* x1 := first slot */
> +        and   x1, x1, #XEN_PT_LPAE_ENTRY_MASK  /* x1 := first slot */
>         cmp   x1, #XEN_SECOND_SLOT
>         beq   identity_mapping_removed
>         /* It is not in slot 1, remove the entry */
> diff --git a/xen/arch/arm/include/asm/lpae.h b/xen/arch/arm/include/asm/lpae.h
> index 4fb9a40a4ca9..8cf932b5c947 100644
> --- a/xen/arch/arm/include/asm/lpae.h
> +++ b/xen/arch/arm/include/asm/lpae.h
> @@ -159,6 +159,17 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
> #define lpae_get_mfn(pte)    (_mfn((pte).walk.base))
> #define lpae_set_mfn(pte, mfn)  ((pte).walk.base = mfn_x(mfn))
> 
> +/* Generate an array @var containing the offset for each level from @addr */
> +#define DECLARE_OFFSETS(var, addr)          \
> +    const unsigned int var[4] = {           \
> +        zeroeth_table_offset(addr),         \
> +        first_table_offset(addr),           \
> +        second_table_offset(addr),          \
> +        third_table_offset(addr)            \
> +    }
> +
> +#endif /* __ASSEMBLY__ */
> +
> /*
>  * AArch64 supports pages with different sizes (4K, 16K, and 64K).
>  * Provide a set of generic helpers that will compute various
> @@ -190,17 +201,6 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
> #define LPAE_TABLE_INDEX_GS(gs, lvl, addr)   \
>     (((addr) >> LEVEL_SHIFT_GS(gs, lvl)) & LPAE_ENTRY_MASK_GS(gs))
> 
> -/* Generate an array @var containing the offset for each level from @addr */
> -#define DECLARE_OFFSETS(var, addr)          \
> -    const unsigned int var[4] = {           \
> -        zeroeth_table_offset(addr),         \
> -        first_table_offset(addr),           \
> -        second_table_offset(addr),          \
> -        third_table_offset(addr)            \
> -    }
> -
> -#endif /* __ASSEMBLY__ */
> -
> /*
>  * These numbers add up to a 48-bit input address space.
>  *
> @@ -211,26 +211,35 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
>  * therefore 39-bits are sufficient.
>  */
> 
> -#define LPAE_SHIFT      9
> -#define LPAE_ENTRIES    (_AC(1,U) << LPAE_SHIFT)
> -#define LPAE_ENTRY_MASK (LPAE_ENTRIES - 1)
> -
> -#define THIRD_SHIFT    (PAGE_SHIFT)
> -#define THIRD_ORDER    (THIRD_SHIFT - PAGE_SHIFT)
> -#define THIRD_SIZE     (_AT(paddr_t, 1) << THIRD_SHIFT)
> -#define THIRD_MASK     (~(THIRD_SIZE - 1))
> -#define SECOND_SHIFT   (THIRD_SHIFT + LPAE_SHIFT)
> -#define SECOND_ORDER   (SECOND_SHIFT - PAGE_SHIFT)
> -#define SECOND_SIZE    (_AT(paddr_t, 1) << SECOND_SHIFT)
> -#define SECOND_MASK    (~(SECOND_SIZE - 1))
> -#define FIRST_SHIFT    (SECOND_SHIFT + LPAE_SHIFT)
> -#define FIRST_ORDER    (FIRST_SHIFT - PAGE_SHIFT)
> -#define FIRST_SIZE     (_AT(paddr_t, 1) << FIRST_SHIFT)
> -#define FIRST_MASK     (~(FIRST_SIZE - 1))
> -#define ZEROETH_SHIFT  (FIRST_SHIFT + LPAE_SHIFT)
> -#define ZEROETH_ORDER  (ZEROETH_SHIFT - PAGE_SHIFT)
> -#define ZEROETH_SIZE   (_AT(paddr_t, 1) << ZEROETH_SHIFT)
> -#define ZEROETH_MASK   (~(ZEROETH_SIZE - 1))
> +#define XEN_PT_LPAE_SHIFT         LPAE_SHIFT_GS(PAGE_SHIFT)
> +#define XEN_PT_LPAE_ENTRIES       LPAE_ENTRIES_GS(PAGE_SHIFT)
> +#define XEN_PT_LPAE_ENTRY_MASK    LPAE_ENTRY_MASK_GS(PAGE_SHIFT)
> +
> +#define XEN_PT_LEVEL_SHIFT(lvl)   LEVEL_SHIFT_GS(PAGE_SHIFT, lvl)
> +#define XEN_PT_LEVEL_ORDER(lvl)   LEVEL_ORDER_GS(PAGE_SHIFT, lvl)
> +#define XEN_PT_LEVEL_SIZE(lvl)    LEVEL_SIZE_GS(PAGE_SHIFT, lvl)
> +#define XEN_PT_LEVEL_MASK(lvl)    (~(XEN_PT_LEVEL_SIZE(lvl) - 1))
> +
> +/* Convenience aliases */
> +#define THIRD_SHIFT         XEN_PT_LEVEL_SHIFT(3)
> +#define THIRD_ORDER         XEN_PT_LEVEL_ORDER(3)
> +#define THIRD_SIZE          XEN_PT_LEVEL_SIZE(3)
> +#define THIRD_MASK          XEN_PT_LEVEL_MASK(3)
> +
> +#define SECOND_SHIFT        XEN_PT_LEVEL_SHIFT(2)
> +#define SECOND_ORDER        XEN_PT_LEVEL_ORDER(2)
> +#define SECOND_SIZE         XEN_PT_LEVEL_SIZE(2)
> +#define SECOND_MASK         XEN_PT_LEVEL_MASK(2)
> +
> +#define FIRST_SHIFT         XEN_PT_LEVEL_SHIFT(1)
> +#define FIRST_ORDER         XEN_PT_LEVEL_ORDER(1)
> +#define FIRST_SIZE          XEN_PT_LEVEL_SIZE(1)
> +#define FIRST_MASK          XEN_PT_LEVEL_MASK(1)
> +
> +#define ZEROETH_SHIFT       XEN_PT_LEVEL_SHIFT(0)
> +#define ZEROETH_ORDER       XEN_PT_LEVEL_ORDER(0)
> +#define ZEROETH_SIZE        XEN_PT_LEVEL_SIZE(0)
> +#define ZEROETH_MASK        XEN_PT_LEVEL_MASK(0)
> 
> /* Calculate the offsets into the pagetables for a given VA */
> #define zeroeth_linear_offset(va) ((va) >> ZEROETH_SHIFT)
> @@ -238,7 +247,7 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
> #define second_linear_offset(va) ((va) >> SECOND_SHIFT)
> #define third_linear_offset(va) ((va) >> THIRD_SHIFT)
> 
> -#define TABLE_OFFSET(offs) (_AT(unsigned int, offs) & LPAE_ENTRY_MASK)
> +#define TABLE_OFFSET(offs) (_AT(unsigned int, offs) & XEN_PT_LPAE_ENTRY_MASK)
> #define first_table_offset(va)  TABLE_OFFSET(first_linear_offset(va))
> #define second_table_offset(va) TABLE_OFFSET(second_linear_offset(va))
> #define third_table_offset(va)  TABLE_OFFSET(third_linear_offset(va))
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index b1eae767c27c..515d0906f85b 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -71,10 +71,11 @@ mm_printk(const char *fmt, ...) {}
>  *  in C).
>  */
> #define DEFINE_BOOT_PAGE_TABLE(name)                                          \
> -lpae_t __aligned(PAGE_SIZE) __section(".data.page_aligned") name[LPAE_ENTRIES]
> +lpae_t __aligned(PAGE_SIZE) __section(".data.page_aligned")                   \
> +    name[XEN_PT_LPAE_ENTRIES]
> 
> #define DEFINE_PAGE_TABLES(name, nr)                    \
> -lpae_t __aligned(PAGE_SIZE) name[LPAE_ENTRIES * (nr)]
> +lpae_t __aligned(PAGE_SIZE) name[XEN_PT_LPAE_ENTRIES * (nr)]
> 
> #define DEFINE_PAGE_TABLE(name) DEFINE_PAGE_TABLES(name, 1)
> 
> @@ -207,7 +208,7 @@ static void __init __maybe_unused build_assertions(void)
>     BUILD_BUG_ON(zeroeth_table_offset(XEN_VIRT_START));
> #endif
>     BUILD_BUG_ON(first_table_offset(XEN_VIRT_START));
> -    BUILD_BUG_ON(second_linear_offset(XEN_VIRT_START) >= LPAE_ENTRIES);
> +    BUILD_BUG_ON(second_linear_offset(XEN_VIRT_START) >= XEN_PT_LPAE_ENTRIES);
> #ifdef CONFIG_DOMAIN_PAGE
>     BUILD_BUG_ON(DOMHEAP_VIRT_START & ~FIRST_MASK);
> #endif
> @@ -256,7 +257,7 @@ void dump_pt_walk(paddr_t ttbr, paddr_t addr,
> 
>     for ( level = root_level; ; level++ )
>     {
> -        if ( offsets[level] > LPAE_ENTRIES )
> +        if ( offsets[level] > XEN_PT_LPAE_ENTRIES )
>             break;
> 
>         pte = mapping[offsets[level]];
> @@ -395,15 +396,15 @@ static void __init create_mappings(lpae_t *second,
>     ASSERT(!(base_mfn % granularity));
>     ASSERT(!(nr_mfns % granularity));
> 
> -    count = nr_mfns / LPAE_ENTRIES;
> +    count = nr_mfns / XEN_PT_LPAE_ENTRIES;
>     p = second + second_linear_offset(virt_offset);
>     pte = mfn_to_xen_entry(_mfn(base_mfn), MT_NORMAL);
> -    if ( granularity == 16 * LPAE_ENTRIES )
> +    if ( granularity == 16 * XEN_PT_LPAE_ENTRIES )
>         pte.pt.contig = 1;  /* These maps are in 16-entry contiguous chunks. */
>     for ( i = 0; i < count; i++ )
>     {
>         write_pte(p + i, pte);
> -        pte.pt.base += 1 << LPAE_SHIFT;
> +        pte.pt.base += 1 << XEN_PT_LPAE_SHIFT;
>     }
>     flush_xen_tlb_local();
> }
> @@ -424,7 +425,7 @@ void *map_domain_page(mfn_t mfn)
> {
>     unsigned long flags;
>     lpae_t *map = this_cpu(xen_dommap);
> -    unsigned long slot_mfn = mfn_x(mfn) & ~LPAE_ENTRY_MASK;
> +    unsigned long slot_mfn = mfn_x(mfn) & ~XEN_PT_LPAE_ENTRY_MASK;
>     vaddr_t va;
>     lpae_t pte;
>     int i, slot;
> @@ -435,7 +436,7 @@ void *map_domain_page(mfn_t mfn)
>      * entry is a 2MB superpage pte.  We use the available bits of each
>      * PTE as a reference count; when the refcount is zero the slot can
>      * be reused. */
> -    for ( slot = (slot_mfn >> LPAE_SHIFT) % DOMHEAP_ENTRIES, i = 0;
> +    for ( slot = (slot_mfn >> XEN_PT_LPAE_SHIFT) % DOMHEAP_ENTRIES, i = 0;
>           i < DOMHEAP_ENTRIES;
>           slot = (slot + 1) % DOMHEAP_ENTRIES, i++ )
>     {
> @@ -477,7 +478,7 @@ void *map_domain_page(mfn_t mfn)
> 
>     va = (DOMHEAP_VIRT_START
>           + (slot << SECOND_SHIFT)
> -          + ((mfn_x(mfn) & LPAE_ENTRY_MASK) << THIRD_SHIFT));
> +          + ((mfn_x(mfn) & XEN_PT_LPAE_ENTRY_MASK) << THIRD_SHIFT));
> 
>     /*
>      * We may not have flushed this specific subpage at map time,
> @@ -513,7 +514,7 @@ mfn_t domain_page_map_to_mfn(const void *ptr)
>     unsigned long va = (unsigned long)ptr;
>     lpae_t *map = this_cpu(xen_dommap);
>     int slot = (va - DOMHEAP_VIRT_START) >> SECOND_SHIFT;
> -    unsigned long offset = (va>>THIRD_SHIFT) & LPAE_ENTRY_MASK;
> +    unsigned long offset = (va>>THIRD_SHIFT) & XEN_PT_LPAE_ENTRY_MASK;
> 
>     if ( va >= VMAP_VIRT_START && va < VMAP_VIRT_END )
>         return virt_to_mfn(va);
> @@ -654,7 +655,8 @@ void __init setup_pagetables(unsigned long boot_phys_offset)
>     /* Initialise first level entries, to point to second level entries */
>     for ( i = 0; i < 2; i++)
>     {
> -        p[i] = pte_of_xenaddr((uintptr_t)(xen_second+i*LPAE_ENTRIES));
> +        p[i] = pte_of_xenaddr((uintptr_t)(xen_second +
> +                                          i * XEN_PT_LPAE_ENTRIES));
>         p[i].pt.table = 1;
>         p[i].pt.xn = 0;
>     }
> @@ -663,13 +665,14 @@ void __init setup_pagetables(unsigned long boot_phys_offset)
>     for ( i = 0; i < DOMHEAP_SECOND_PAGES; i++ )
>     {
>         p[first_table_offset(DOMHEAP_VIRT_START+i*FIRST_SIZE)]
> -            = pte_of_xenaddr((uintptr_t)(cpu0_dommap+i*LPAE_ENTRIES));
> +            = pte_of_xenaddr((uintptr_t)(cpu0_dommap +
> +                                         i * XEN_PT_LPAE_ENTRIES));
>         p[first_table_offset(DOMHEAP_VIRT_START+i*FIRST_SIZE)].pt.table = 1;
>     }
> #endif
> 
>     /* Break up the Xen mapping into 4k pages and protect them separately. */
> -    for ( i = 0; i < LPAE_ENTRIES; i++ )
> +    for ( i = 0; i < XEN_PT_LPAE_ENTRIES; i++ )
>     {
>         vaddr_t va = XEN_VIRT_START + (i << PAGE_SHIFT);
> 
> @@ -768,7 +771,7 @@ int init_secondary_pagetables(int cpu)
>      * domheap mapping pages. */
>     for ( i = 0; i < DOMHEAP_SECOND_PAGES; i++ )
>     {
> -        pte = mfn_to_xen_entry(virt_to_mfn(domheap+i*LPAE_ENTRIES),
> +        pte = mfn_to_xen_entry(virt_to_mfn(domheap + i * XEN_PT_LPAE_ENTRIES),
>                                MT_NORMAL);
>         pte.pt.table = 1;
>         write_pte(&first[first_table_offset(DOMHEAP_VIRT_START+i*FIRST_SIZE)], pte);
> diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
> index 02cf852d4cf1..493a1e25879a 100644
> --- a/xen/arch/arm/p2m.c
> +++ b/xen/arch/arm/p2m.c
> @@ -233,7 +233,8 @@ static lpae_t *p2m_get_root_pointer(struct p2m_domain *p2m,
>      * we can't use (P2M_ROOT_LEVEL - 1) because the root level might be
>      * 0. Yet we still want to check if all the unused bits are zeroed.
>      */
> -    root_table = gfn_x(gfn) >> (level_orders[P2M_ROOT_LEVEL] + LPAE_SHIFT);
> +    root_table = gfn_x(gfn) >> (level_orders[P2M_ROOT_LEVEL] +
> +                                XEN_PT_LPAE_SHIFT);
>     if ( root_table >= P2M_ROOT_PAGES )
>         return NULL;
> 
> @@ -773,7 +774,7 @@ static void p2m_free_entry(struct p2m_domain *p2m,
>     }
> 
>     table = map_domain_page(lpae_get_mfn(entry));
> -    for ( i = 0; i < LPAE_ENTRIES; i++ )
> +    for ( i = 0; i < XEN_PT_LPAE_ENTRIES; i++ )
>         p2m_free_entry(p2m, *(table + i), level + 1);
> 
>     unmap_domain_page(table);
> @@ -827,7 +828,7 @@ static bool p2m_split_superpage(struct p2m_domain *p2m, lpae_t *entry,
>      * We are either splitting a first level 1G page into 512 second level
>      * 2M pages, or a second level 2M page into 512 third level 4K pages.
>      */
> -    for ( i = 0; i < LPAE_ENTRIES; i++ )
> +    for ( i = 0; i < XEN_PT_LPAE_ENTRIES; i++ )
>     {
>         lpae_t *new_entry = table + i;
> 
> @@ -850,7 +851,7 @@ static bool p2m_split_superpage(struct p2m_domain *p2m, lpae_t *entry,
>     /* Update stats */
>     p2m->stats.shattered[level]++;
>     p2m->stats.mappings[level]--;
> -    p2m->stats.mappings[next_level] += LPAE_ENTRIES;
> +    p2m->stats.mappings[next_level] += XEN_PT_LPAE_ENTRIES;
> 
>     /*
>      * Shatter superpage in the page to the level we want to make the
> @@ -888,7 +889,7 @@ static int __p2m_set_entry(struct p2m_domain *p2m,
>                            p2m_access_t a)
> {
>     unsigned int level = 0;
> -    unsigned int target = 3 - (page_order / LPAE_SHIFT);
> +    unsigned int target = 3 - (page_order / XEN_PT_LPAE_SHIFT);
>     lpae_t *entry, *table, orig_pte;
>     int rc;
>     /* A mapping is removed if the MFN is invalid. */
> @@ -1142,7 +1143,7 @@ static void p2m_invalidate_table(struct p2m_domain *p2m, mfn_t mfn)
> 
>     table = map_domain_page(mfn);
> 
> -    for ( i = 0; i < LPAE_ENTRIES; i++ )
> +    for ( i = 0; i < XEN_PT_LPAE_ENTRIES; i++ )
>     {
>         lpae_t pte = table[i];
> 
> -- 
> 2.32.0
> 



^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 03/19] xen/arm: p2m: Replace level_{orders, masks} arrays with XEN_PT_LEVEL_{ORDER, MASK}
  2022-02-21 10:22 ` [PATCH v3 03/19] xen/arm: p2m: Replace level_{orders, masks} arrays with XEN_PT_LEVEL_{ORDER, MASK} Julien Grall
@ 2022-02-22 15:55   ` Bertrand Marquis
  2022-02-24 22:41     ` Julien Grall
  0 siblings, 1 reply; 79+ messages in thread
From: Bertrand Marquis @ 2022-02-22 15:55 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Volodymyr Babchuk

Hi Julien,

> On 21 Feb 2022, at 10:22, Julien Grall <julien@xen.org> wrote:
> 
> From: Julien Grall <jgrall@amazon.com>
> 
> The array level_orders and level_masks can be replaced with the
> recently introduced macros LEVEL_ORDER and LEVEL_MASK.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>

Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>

One open question: At this stage the convenience aliases that you
kept in include/asm/lpae.h are used in a very limited number of places.
Could we remove those and use only XEN_PT_LEVEL_* to make the
code a bit more coherent.

Not something to do here but could be done in a following patch after
this serie

Cheers
Bertrand

> 
> ---
>    Changes in v3:
>        - Fix clashes after prefixing the PT macros with XEN_PT_
> 
>    Changes in v2:
>        - New patch
> 
>    The goal is to remove completely the static arrays so they
>    don't need to be global (or duplicated) when adding superpage
>    support for Xen PT.
> 
>    This also has the added benefits to replace a couple of loads
>    with only a few instructions working on immediate.
> ---
> xen/arch/arm/p2m.c | 17 ++++++-----------
> 1 file changed, 6 insertions(+), 11 deletions(-)
> 
> diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
> index 493a1e25879a..1d1059f7d2bd 100644
> --- a/xen/arch/arm/p2m.c
> +++ b/xen/arch/arm/p2m.c
> @@ -37,12 +37,6 @@ static unsigned int __read_mostly max_vmid = MAX_VMID_8_BIT;
>  */
> unsigned int __read_mostly p2m_ipa_bits = 64;
> 
> -/* Helpers to lookup the properties of each level */
> -static const paddr_t level_masks[] =
> -    { ZEROETH_MASK, FIRST_MASK, SECOND_MASK, THIRD_MASK };
> -static const uint8_t level_orders[] =
> -    { ZEROETH_ORDER, FIRST_ORDER, SECOND_ORDER, THIRD_ORDER };
> -
> static mfn_t __read_mostly empty_root_mfn;
> 
> static uint64_t generate_vttbr(uint16_t vmid, mfn_t root_mfn)
> @@ -233,7 +227,7 @@ static lpae_t *p2m_get_root_pointer(struct p2m_domain *p2m,
>      * we can't use (P2M_ROOT_LEVEL - 1) because the root level might be
>      * 0. Yet we still want to check if all the unused bits are zeroed.
>      */
> -    root_table = gfn_x(gfn) >> (level_orders[P2M_ROOT_LEVEL] +
> +    root_table = gfn_x(gfn) >> (XEN_PT_LEVEL_ORDER(P2M_ROOT_LEVEL) +
>                                 XEN_PT_LPAE_SHIFT);
>     if ( root_table >= P2M_ROOT_PAGES )
>         return NULL;
> @@ -380,7 +374,7 @@ mfn_t p2m_get_entry(struct p2m_domain *p2m, gfn_t gfn,
>     if ( gfn_x(gfn) > gfn_x(p2m->max_mapped_gfn) )
>     {
>         for ( level = P2M_ROOT_LEVEL; level < 3; level++ )
> -            if ( (gfn_x(gfn) & (level_masks[level] >> PAGE_SHIFT)) >
> +            if ( (gfn_x(gfn) & (XEN_PT_LEVEL_MASK(level) >> PAGE_SHIFT)) >
>                  gfn_x(p2m->max_mapped_gfn) )
>                 break;
> 
> @@ -423,7 +417,8 @@ mfn_t p2m_get_entry(struct p2m_domain *p2m, gfn_t gfn,
>          * The entry may point to a superpage. Find the MFN associated
>          * to the GFN.
>          */
> -        mfn = mfn_add(mfn, gfn_x(gfn) & ((1UL << level_orders[level]) - 1));
> +        mfn = mfn_add(mfn,
> +                      gfn_x(gfn) & ((1UL << XEN_PT_LEVEL_ORDER(level)) - 1));
> 
>         if ( valid )
>             *valid = lpae_is_valid(entry);
> @@ -434,7 +429,7 @@ out_unmap:
> 
> out:
>     if ( page_order )
> -        *page_order = level_orders[level];
> +        *page_order = XEN_PT_LEVEL_ORDER(level);
> 
>     return mfn;
> }
> @@ -808,7 +803,7 @@ static bool p2m_split_superpage(struct p2m_domain *p2m, lpae_t *entry,
>     /* Convenience aliases */
>     mfn_t mfn = lpae_get_mfn(*entry);
>     unsigned int next_level = level + 1;
> -    unsigned int level_order = level_orders[next_level];
> +    unsigned int level_order = XEN_PT_LEVEL_ORDER(next_level);
> 
>     /*
>      * This should only be called with target != level and the entry is
> -- 
> 2.32.0
> 



^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 01/19] xen/arm: lpae: Rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS
  2022-02-22 13:30   ` Michal Orzel
@ 2022-02-24 22:19     ` Julien Grall
  0 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-24 22:19 UTC (permalink / raw)
  To: Michal Orzel, xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk



On 22/02/2022 13:30, Michal Orzel wrote:
> Hi Julien,

Hi Michal,

> On 21.02.2022 11:22, Julien Grall wrote:
>> From: Julien Grall <jgrall@amazon.com>
>>
>> Commit 05031fa87357 "xen/arm: guest_walk: Only generate necessary
>> offsets/masks" introduced LPAE_ENTRIES_MASK_GS. In a follow-up patch,
>> we will use it for to define LPAE_ENTRY_MASK.
>>
> for is unneddded. Should be "we will use it to define..."

I fixed this one and ...

> 
>> This will lead to inconsistent naming. As LPAE_ENTRY_MASK is used in
>> many places, it is better to rename LPAE_ENTRIES_MASK_GS and avoid
>> some churn.
>>
>> So rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS.
>>
>> Signed-off-by: Julien Grall <jgrall@amazon.com>
>>
>> ---
>>      Changes in v2:
>>          - New patch
>> ---
>>   xen/arch/arm/include/asm/lpae.h | 4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/xen/arch/arm/include/asm/lpae.h b/xen/arch/arm/include/asm/lpae.h
>> index e94de2e7d8e8..4fb9a40a4ca9 100644
>> --- a/xen/arch/arm/include/asm/lpae.h
>> +++ b/xen/arch/arm/include/asm/lpae.h
>> @@ -180,7 +180,7 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
>>    */
>>   #define LPAE_SHIFT_GS(gs)         ((gs) - 3)
>>   #define LPAE_ENTRIES_GS(gs)       (_AC(1, U) << LPAE_SHIFT_GS(gs))
>> -#define LPAE_ENTRIES_MASK_GS(gs)  (LPAE_ENTRIES_GS(gs) - 1)
>> +#define LPAE_ENTRY_MASK_GS(gs)  (LPAE_ENTRIES_GS(gs) - 1)
> 
> Incorrect indentation of (LPAE_ENTRIES_GS(gs) - 1)

... this one in my tree. I will commit it with Bertrand's reviewed-by.

Thank you for the review!

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 02/19] xen/arm: lpae: Use the generic helpers to defined the Xen PT helpers
  2022-02-22 15:38   ` Bertrand Marquis
@ 2022-02-24 22:24     ` Julien Grall
  0 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-24 22:24 UTC (permalink / raw)
  To: Bertrand Marquis
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Volodymyr Babchuk



On 22/02/2022 15:38, Bertrand Marquis wrote:
> Hi Julien,

Hi Bertrand,

>> On 21 Feb 2022, at 10:22, Julien Grall <julien@xen.org> wrote:
>>
>> From: Julien Grall <jgrall@amazon.com>
>>
>> Currently, Xen PT helpers are only working with 4KB page granularity
>> and open-code the generic helpers. To allow more flexibility, we can
>> re-use the generic helpers and pass Xen's page granularity
>> (PAGE_SHIFT).
>>
>> As Xen PT helpers are used in both C and assembly, we need to move
>> the generic helpers definition outside of the !__ASSEMBLY__ section.
>>
>> Take the opportunity to prefix LPAE_ENTRIES, LPAE_ENTRIES and
>> LPAE_ENTRIES_MASK with XEN_PT_.
> 
> The list needs to be fixed to be SHIFT, ENTRIES and ENTRY_MASK.

I have fixed it in my tree and will commit it with...

>>
>> Note the aliases for each level are still kept for the time being so we
>> can avoid a massive patch to change all the callers.
>>
>> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> With this fixed:
> Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>

Michal's and your's reviewed-by.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 03/19] xen/arm: p2m: Replace level_{orders, masks} arrays with XEN_PT_LEVEL_{ORDER, MASK}
  2022-02-22 15:55   ` Bertrand Marquis
@ 2022-02-24 22:41     ` Julien Grall
  2022-02-25  8:27       ` Bertrand Marquis
  0 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-24 22:41 UTC (permalink / raw)
  To: Bertrand Marquis
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Volodymyr Babchuk



On 22/02/2022 15:55, Bertrand Marquis wrote:
> Hi Julien,

Hi Bertrand,

>> On 21 Feb 2022, at 10:22, Julien Grall <julien@xen.org> wrote:
>>
>> From: Julien Grall <jgrall@amazon.com>
>>
>> The array level_orders and level_masks can be replaced with the
>> recently introduced macros LEVEL_ORDER and LEVEL_MASK.
>>
>> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>
> 
> One open question: At this stage the convenience aliases that you
> kept in include/asm/lpae.h are used in a very limited number of places.

I am not sure I would call it very limited:

42sh> ack "(FIRST|SECOND|THIRD)_(ORDER|SHIFT|MASK)" | wc -l
65

That's including the 9 definitions.

> Could we remove those and use only XEN_PT_LEVEL_* to make the
> code a bit more coherent.

I made an attempt in the past and it resulted to longer line in 
assembly. So I am on the fence to whether the aliases should be 
completely removed.

At the same time, XEN_PT_LEVEL(...) is handy for places where we don't 
know at compile time the level.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 03/19] xen/arm: p2m: Replace level_{orders, masks} arrays with XEN_PT_LEVEL_{ORDER, MASK}
  2022-02-24 22:41     ` Julien Grall
@ 2022-02-25  8:27       ` Bertrand Marquis
  2022-02-25 16:41         ` Julien Grall
  0 siblings, 1 reply; 79+ messages in thread
From: Bertrand Marquis @ 2022-02-25  8:27 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Volodymyr Babchuk

Hi Julien,

> On 24 Feb 2022, at 22:41, Julien Grall <julien@xen.org> wrote:
> 
> 
> 
> On 22/02/2022 15:55, Bertrand Marquis wrote:
>> Hi Julien,
> 
> Hi Bertrand,
> 
>>> On 21 Feb 2022, at 10:22, Julien Grall <julien@xen.org> wrote:
>>> 
>>> From: Julien Grall <jgrall@amazon.com>
>>> 
>>> The array level_orders and level_masks can be replaced with the
>>> recently introduced macros LEVEL_ORDER and LEVEL_MASK.
>>> 
>>> Signed-off-by: Julien Grall <jgrall@amazon.com>
>> Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>
>> One open question: At this stage the convenience aliases that you
>> kept in include/asm/lpae.h are used in a very limited number of places.
> 
> I am not sure I would call it very limited:
> 
> 42sh> ack "(FIRST|SECOND|THIRD)_(ORDER|SHIFT|MASK)" | wc -l
> 65
> 
> That's including the 9 definitions.

My bad I looked with your full serie in my tree.

> 
>> Could we remove those and use only XEN_PT_LEVEL_* to make the
>> code a bit more coherent.
> 
> I made an attempt in the past and it resulted to longer line in assembly. So I am on the fence to whether the aliases should be completely removed.
> 
> At the same time, XEN_PT_LEVEL(...) is handy for places where we don't know at compile time the level.

One other big argument for making the switch is that XEN_PT_LEVEL is far more specific then FIRST_ORDER and others which are very unspecific names.

Anyway definitely something that we could do after your serie.

Cheers
Bertrand

> 
> Cheers,
> 
> -- 
> Julien Grall



^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 03/19] xen/arm: p2m: Replace level_{orders, masks} arrays with XEN_PT_LEVEL_{ORDER, MASK}
  2022-02-25  8:27       ` Bertrand Marquis
@ 2022-02-25 16:41         ` Julien Grall
  0 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-25 16:41 UTC (permalink / raw)
  To: Bertrand Marquis
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Volodymyr Babchuk



On 25/02/2022 08:27, Bertrand Marquis wrote:
> Hi Julien,

Hi Bertrand,

> 
>> On 24 Feb 2022, at 22:41, Julien Grall <julien@xen.org> wrote:
>>
>>
>>
>> On 22/02/2022 15:55, Bertrand Marquis wrote:
>>> Hi Julien,
>>
>> Hi Bertrand,
>>
>>>> On 21 Feb 2022, at 10:22, Julien Grall <julien@xen.org> wrote:
>>>>
>>>> From: Julien Grall <jgrall@amazon.com>
>>>>
>>>> The array level_orders and level_masks can be replaced with the
>>>> recently introduced macros LEVEL_ORDER and LEVEL_MASK.
>>>>
>>>> Signed-off-by: Julien Grall <jgrall@amazon.com>
>>> Reviewed-by: Bertrand Marquis <bertrand.marquis@arm.com>
>>> One open question: At this stage the convenience aliases that you
>>> kept in include/asm/lpae.h are used in a very limited number of places.
>>
>> I am not sure I would call it very limited:
>>
>> 42sh> ack "(FIRST|SECOND|THIRD)_(ORDER|SHIFT|MASK)" | wc -l
>> 65
>>
>> That's including the 9 definitions.
> 
> My bad I looked with your full serie in my tree.
> 
>>
>>> Could we remove those and use only XEN_PT_LEVEL_* to make the
>>> code a bit more coherent.
>>
>> I made an attempt in the past and it resulted to longer line in assembly. So I am on the fence to whether the aliases should be completely removed.
>>
>> At the same time, XEN_PT_LEVEL(...) is handy for places where we don't know at compile time the level.
> 
> One other big argument for making the switch is that XEN_PT_LEVEL is far more specific then FIRST_ORDER and others which are very unspecific names.

How about renaming them to XEN_PT_L0_ORDER? Or maybe XPT_L0_ORDER?

This would allows us to keep the assembly line relatively short.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit
  2022-02-21 10:22 ` [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit Julien Grall
@ 2022-02-26 19:30   ` Julien Grall
  2022-03-21  5:46     ` Hongda Deng
  2022-04-01 23:53   ` Stefano Stabellini
  1 sibling, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-26 19:30 UTC (permalink / raw)
  To: xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk

Hi,

On 21/02/2022 10:22, Julien Grall wrote:
> @@ -1333,21 +1386,34 @@ static int xen_pt_update(unsigned long virt,
>       while ( left )
>       {
>           unsigned int order, level;
> +        unsigned int nr_contig;
> +        unsigned int new_flags;
>   
>           level = xen_pt_mapping_level(vfn, mfn, left, flags);
>           order = XEN_PT_LEVEL_ORDER(level);
>   
>           ASSERT(left >= BIT(order, UL));
>   
> -        rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level, flags);
> -        if ( rc )
> -            break;
> +        /*
> +         * Check if we can set the contiguous mapping and update the
> +         * flags accordingly.
> +         */
> +        nr_contig = xen_pt_check_contig(vfn, mfn, level, left, flags);
> +        new_flags = flags | ((nr_contig > 1) ? _PAGE_CONTIG : 0);
>   
> -        vfn += 1U << order;
> -        if ( !mfn_eq(mfn, INVALID_MFN) )
> -            mfn = mfn_add(mfn, 1U << order);
> +        for ( ; nr_contig > 0; nr_contig-- )
> +        {
> +            rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level,
> +                                     new_flags);
> +            if ( rc )
> +                break;
>   
> -        left -= (1U << order);
> +            vfn += 1U << order;
> +            if ( !mfn_eq(mfn, INVALID_MFN) )
> +                mfn = mfn_add(mfn, 1U << order);
> +
> +            left -= (1U << order);
> +        }

I forgot to add:

if ( rc )
   break;

Without it, the outer loop will never exit in case of an error.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings
  2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
                   ` (18 preceding siblings ...)
  2022-02-21 10:22 ` [PATCH v3 19/19] xen/arm: mm: Re-implement setup_frame_table_mappings() with map_pages_to_xen() Julien Grall
@ 2022-02-27 19:25 ` Julien Grall
  19 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-27 19:25 UTC (permalink / raw)
  To: xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Jan Beulich,
	Wei Liu, Roger Pau Monné

On 21/02/2022 10:21, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> Hi all,
> 
> This series was originally sent as "xen/arm: mm: Add limited support
> for superpages" [1] and finally has grown enough to remove most of
> the open-coding mappings in the boot code.
> 
> This will help to:
>      1) Get better compliance with the Arm memory model
>      2) Pave the way to support other page size (64KB, 16KB)
> 
> The previous version was spent a few months ago. So I have decided
> to remove all the acked-by/reviewed-by tags.
> 
> Cheers,
> 
> [1] <20201119190751.22345-1-julien@xen.org>
> [2] <PA4PR08MB6253F49C13ED56811BA5B64E92479@PA4PR08MB6253.eurprd08.prod.outlook.com>
> 
> Julien Grall (18):
>    xen/arm: lpae: Rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS
>    xen/arm: lpae: Use the generic helpers to defined the Xen PT helpers
>    xen/arm: p2m: Replace level_{orders, masks} arrays with
>      XEN_PT_LEVEL_{ORDER, MASK}

The first 3 patches are fully reviewed. So I have committed them. The 
rest of the patches need review.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure
  2022-02-22 15:22   ` Jan Beulich
@ 2022-02-28  9:55     ` Julien Grall
  2022-02-28 10:10       ` Jan Beulich
  0 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-28  9:55 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Wei Liu, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk,
	George Dunlap, Hongyan Xia, Julien Grall, Wei Liu, Andrew Cooper,
	Roger Pau Monné,
	xen-devel

Hi Jan,

On 22/02/2022 15:22, Jan Beulich wrote:
> On 21.02.2022 11:22, Julien Grall wrote:
>> --- a/xen/common/Makefile
>> +++ b/xen/common/Makefile
>> @@ -28,6 +28,7 @@ obj-y += multicall.o
>>   obj-y += notifier.o
>>   obj-y += page_alloc.o
>>   obj-$(CONFIG_HAS_PDX) += pdx.o
>> +obj-bin-$(CONFIG_HAS_PMAP) += pmap.init.o
>>   obj-$(CONFIG_PERF_COUNTERS) += perfc.o
>>   obj-y += preempt.o
>>   obj-y += random.o
> 
> Nit: Please move the insertion one line further down.

Doh. I have moved the insertion.

> 
>> --- /dev/null
>> +++ b/xen/common/pmap.c
>> @@ -0,0 +1,79 @@
>> +#include <xen/bitops.h>
>> +#include <xen/init.h>
>> +#include <xen/pmap.h>
>> +
>> +#include <asm/pmap.h>
>> +#include <asm/fixmap.h>
>> +
>> +/*
>> + * Simple mapping infrastructure to map / unmap pages in fixed map.
>> + * This is used to set up the page table for mapcache, which is used
>> + * by map domain page infrastructure.
> 
> Is this comment stale from its original x86 purpose?
Yes. I should reword to:

"This is used to set the page table before the map domain page 
infrastructure is initialized".

> 
>> + * This structure is not protected by any locks, so it must not be used after
>> + * smp bring-up.
>> + */
>> +
>> +/* Bitmap to track which slot is used */
>> +static unsigned long __initdata inuse;
> 
> I guess this wants to use DECLARE_BITMAP(), for ...
> 
>> +void *__init pmap_map(mfn_t mfn)
>> +{
>> +    unsigned long flags;
>> +    unsigned int idx;
>> +    unsigned int slot;
>> +
>> +    BUILD_BUG_ON(sizeof(inuse) * BITS_PER_BYTE < NUM_FIX_PMAP);
>> +
>> +    ASSERT(system_state < SYS_STATE_smp_boot);
>> +
>> +    local_irq_save(flags);
>> +
>> +    idx = find_first_zero_bit(&inuse, NUM_FIX_PMAP);
> 
> ... this to be correct irrespective of how large NUM_FIX_PMAP is?
> I think that's preferable over the BUILD_BUG_ON().

I agree. I will have a look to use DECLARE_BITMAP().

> 
>> +    if ( idx == NUM_FIX_PMAP )
>> +        panic("Out of PMAP slots\n");
>> +
>> +    __set_bit(idx, &inuse);
>> +
>> +    slot = idx + FIXMAP_PMAP_BEGIN;
>> +    ASSERT(slot >= FIXMAP_PMAP_BEGIN && slot <= FIXMAP_PMAP_END);
>> +
>> +    /*
>> +     * We cannot use set_fixmap() here. We use PMAP when there is no direct map,
>> +     * so map_pages_to_xen() called by set_fixmap() needs to map pages on
>> +     * demand, which then calls pmap() again, resulting in a loop. Modify the
>> +     * PTEs directly instead. The same is true for pmap_unmap().
>> +     */
>> +    arch_pmap_map(slot, mfn);
> 
> I'm less certain here, but like above I'm under the impression
> that this comment may no longer be accurate.

This comment is still accurate for Arm. I also expect it to be accurate 
for all architectures because set_fixmap() is likely going to be 
implemented with generic PT helpers.

So I think it makes sense to keep it in common code. This explains why 
we are calling arch_pmap_map() rather than set_fixmap() directly.

> 
>> +    local_irq_restore(flags);
> 
> What is this IRQ save/restore intended to protect against, when
> use of this function is limited to pre-SMP boot anyway?

Hmmm... This patch has been through various revision before me. I went 
through the archives and couldn't tell why local_irq_restore() was added.

Looking at the code, none of the Xen page-table helpers expect to be 
called from interrupt context. So I am thinking to replace with an 
ASSERT/BUG_ON !in_irq().

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure
  2022-02-28  9:55     ` Julien Grall
@ 2022-02-28 10:10       ` Jan Beulich
  2022-02-28 10:20         ` Julien Grall
  0 siblings, 1 reply; 79+ messages in thread
From: Jan Beulich @ 2022-02-28 10:10 UTC (permalink / raw)
  To: Julien Grall
  Cc: Wei Liu, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk,
	George Dunlap, Hongyan Xia, Julien Grall, Wei Liu, Andrew Cooper,
	Roger Pau Monné,
	xen-devel

On 28.02.2022 10:55, Julien Grall wrote:
> On 22/02/2022 15:22, Jan Beulich wrote:
>> On 21.02.2022 11:22, Julien Grall wrote:
>>> +    /*
>>> +     * We cannot use set_fixmap() here. We use PMAP when there is no direct map,
>>> +     * so map_pages_to_xen() called by set_fixmap() needs to map pages on
>>> +     * demand, which then calls pmap() again, resulting in a loop. Modify the
>>> +     * PTEs directly instead. The same is true for pmap_unmap().
>>> +     */
>>> +    arch_pmap_map(slot, mfn);
>>
>> I'm less certain here, but like above I'm under the impression
>> that this comment may no longer be accurate.
> 
> This comment is still accurate for Arm. I also expect it to be accurate 
> for all architectures because set_fixmap() is likely going to be 
> implemented with generic PT helpers.
> 
> So I think it makes sense to keep it in common code. This explains why 
> we are calling arch_pmap_map() rather than set_fixmap() directly.

I guess I was rather after "when there is no direct map" alluding to the
planned removal of it on x86.

Jan



^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure
  2022-02-28 10:10       ` Jan Beulich
@ 2022-02-28 10:20         ` Julien Grall
  2022-02-28 10:30           ` Jan Beulich
  0 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-02-28 10:20 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Wei Liu, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk,
	George Dunlap, Hongyan Xia, Julien Grall, Wei Liu, Andrew Cooper,
	Roger Pau Monné,
	xen-devel

Hi Jan,

On 28/02/2022 10:10, Jan Beulich wrote:
> On 28.02.2022 10:55, Julien Grall wrote:
>> On 22/02/2022 15:22, Jan Beulich wrote:
>>> On 21.02.2022 11:22, Julien Grall wrote:
>>>> +    /*
>>>> +     * We cannot use set_fixmap() here. We use PMAP when there is no direct map,
>>>> +     * so map_pages_to_xen() called by set_fixmap() needs to map pages on
>>>> +     * demand, which then calls pmap() again, resulting in a loop. Modify the
>>>> +     * PTEs directly instead. The same is true for pmap_unmap().
>>>> +     */
>>>> +    arch_pmap_map(slot, mfn);
>>>
>>> I'm less certain here, but like above I'm under the impression
>>> that this comment may no longer be accurate.
>>
>> This comment is still accurate for Arm. I also expect it to be accurate
>> for all architectures because set_fixmap() is likely going to be
>> implemented with generic PT helpers.
>>
>> So I think it makes sense to keep it in common code. This explains why
>> we are calling arch_pmap_map() rather than set_fixmap() directly.
> 
> I guess I was rather after "when there is no direct map" alluding to the
> planned removal of it on x86.
It is one way to interpret it. The other way is that pmap will be used 
when the directmap is not yet in place.

But I guess I could be less specific and refers to the fact the domain 
page infrastructure is not yet setup. Would that be better for you?

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure
  2022-02-28 10:20         ` Julien Grall
@ 2022-02-28 10:30           ` Jan Beulich
  2022-02-28 10:52             ` Julien Grall
  0 siblings, 1 reply; 79+ messages in thread
From: Jan Beulich @ 2022-02-28 10:30 UTC (permalink / raw)
  To: Julien Grall
  Cc: Wei Liu, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk,
	George Dunlap, Hongyan Xia, Julien Grall, Wei Liu, Andrew Cooper,
	Roger Pau Monné,
	xen-devel

On 28.02.2022 11:20, Julien Grall wrote:
> On 28/02/2022 10:10, Jan Beulich wrote:
>> On 28.02.2022 10:55, Julien Grall wrote:
>>> On 22/02/2022 15:22, Jan Beulich wrote:
>>>> On 21.02.2022 11:22, Julien Grall wrote:
>>>>> +    /*
>>>>> +     * We cannot use set_fixmap() here. We use PMAP when there is no direct map,
>>>>> +     * so map_pages_to_xen() called by set_fixmap() needs to map pages on
>>>>> +     * demand, which then calls pmap() again, resulting in a loop. Modify the
>>>>> +     * PTEs directly instead. The same is true for pmap_unmap().
>>>>> +     */
>>>>> +    arch_pmap_map(slot, mfn);
>>>>
>>>> I'm less certain here, but like above I'm under the impression
>>>> that this comment may no longer be accurate.
>>>
>>> This comment is still accurate for Arm. I also expect it to be accurate
>>> for all architectures because set_fixmap() is likely going to be
>>> implemented with generic PT helpers.
>>>
>>> So I think it makes sense to keep it in common code. This explains why
>>> we are calling arch_pmap_map() rather than set_fixmap() directly.
>>
>> I guess I was rather after "when there is no direct map" alluding to the
>> planned removal of it on x86.
> It is one way to interpret it. The other way is that pmap will be used 
> when the directmap is not yet in place.
> 
> But I guess I could be less specific and refers to the fact the domain 
> page infrastructure is not yet setup. Would that be better for you?

That or simply add "(yet)" to what is there.

Jan



^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure
  2022-02-28 10:30           ` Jan Beulich
@ 2022-02-28 10:52             ` Julien Grall
  0 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-02-28 10:52 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Wei Liu, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk,
	George Dunlap, Hongyan Xia, Julien Grall, Wei Liu, Andrew Cooper,
	Roger Pau Monné,
	xen-devel

Hi Jan,

On 28/02/2022 10:30, Jan Beulich wrote:
> On 28.02.2022 11:20, Julien Grall wrote:
>> On 28/02/2022 10:10, Jan Beulich wrote:
>>> On 28.02.2022 10:55, Julien Grall wrote:
>>>> On 22/02/2022 15:22, Jan Beulich wrote:
>>>>> On 21.02.2022 11:22, Julien Grall wrote:
>>>>>> +    /*
>>>>>> +     * We cannot use set_fixmap() here. We use PMAP when there is no direct map,
>>>>>> +     * so map_pages_to_xen() called by set_fixmap() needs to map pages on
>>>>>> +     * demand, which then calls pmap() again, resulting in a loop. Modify the
>>>>>> +     * PTEs directly instead. The same is true for pmap_unmap().
>>>>>> +     */
>>>>>> +    arch_pmap_map(slot, mfn);
>>>>>
>>>>> I'm less certain here, but like above I'm under the impression
>>>>> that this comment may no longer be accurate.
>>>>
>>>> This comment is still accurate for Arm. I also expect it to be accurate
>>>> for all architectures because set_fixmap() is likely going to be
>>>> implemented with generic PT helpers.
>>>>
>>>> So I think it makes sense to keep it in common code. This explains why
>>>> we are calling arch_pmap_map() rather than set_fixmap() directly.
>>>
>>> I guess I was rather after "when there is no direct map" alluding to the
>>> planned removal of it on x86.
>> It is one way to interpret it. The other way is that pmap will be used
>> when the directmap is not yet in place.
>>
>> But I guess I could be less specific and refers to the fact the domain
>> page infrastructure is not yet setup. Would that be better for you?
> 
> That or simply add "(yet)" to what is there.

I will do that in the next version.

Thanks!

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* RE: [PATCH v3 19/19] xen/arm: mm: Re-implement setup_frame_table_mappings() with map_pages_to_xen()
  2022-02-21 10:22 ` [PATCH v3 19/19] xen/arm: mm: Re-implement setup_frame_table_mappings() with map_pages_to_xen() Julien Grall
@ 2022-03-16  6:10   ` Hongda Deng
  2022-04-06  0:01   ` Stefano Stabellini
  1 sibling, 0 replies; 79+ messages in thread
From: Hongda Deng @ 2022-03-16  6:10 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

Hi Julien,

> -----Original Message-----
> From: Xen-devel <xen-devel-bounces@lists.xenproject.org> On Behalf Of Julien
> Grall
> Sent: 2022年2月21日 18:22
> To: xen-devel@lists.xenproject.org
> Cc: julien@xen.org; Julien Grall <Julien.Grall@arm.com>; Stefano Stabellini
> <sstabellini@kernel.org>; Bertrand Marquis <Bertrand.Marquis@arm.com>;
> Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>; Julien Grall
> <jgrall@amazon.com>
> Subject: [PATCH v3 19/19] xen/arm: mm: Re-implement
> setup_frame_table_mappings() with map_pages_to_xen()
> 
> From: Julien Grall <julien.grall@arm.com>
> 
> Now that map_pages_to_xen() has been extended to support 2MB mappings,
> we can replace the create_mappings() call by map_pages_to_xen() call.
> 
> This has the advantage to remove the differences between 32-bit and
> 64-bit code.
> 
> Lastly remove create_mappings() as there is no more callers.
> 
> Signed-off-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v3:
>         - Fix typo in the commit message
>         - Remove the TODO regarding contiguous bit
> 
>     Changes in v2:
>         - New patch

For the all 19 patches:

Tested-by: Hongda Deng <Hongda.Deng@arm.com>

> ---
>  xen/arch/arm/mm.c | 63 ++++-------------------------------------------
>  1 file changed, 5 insertions(+), 58 deletions(-)
> 
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index 4af59375d998..d73f49d5b6fc 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -354,40 +354,6 @@ void clear_fixmap(unsigned map)
>      BUG_ON(res != 0);
>  }
> 
> -/* Create Xen's mappings of memory.
> - * Mapping_size must be either 2MB or 32MB.
> - * Base and virt must be mapping_size aligned.
> - * Size must be a multiple of mapping_size.
> - * second must be a contiguous set of second level page tables
> - * covering the region starting at virt_offset. */
> -static void __init create_mappings(lpae_t *second,
> -                                   unsigned long virt_offset,
> -                                   unsigned long base_mfn,
> -                                   unsigned long nr_mfns,
> -                                   unsigned int mapping_size)
> -{
> -    unsigned long i, count;
> -    const unsigned long granularity = mapping_size >> PAGE_SHIFT;
> -    lpae_t pte, *p;
> -
> -    ASSERT((mapping_size == MB(2)) || (mapping_size == MB(32)));
> -    ASSERT(!((virt_offset >> PAGE_SHIFT) % granularity));
> -    ASSERT(!(base_mfn % granularity));
> -    ASSERT(!(nr_mfns % granularity));
> -
> -    count = nr_mfns / XEN_PT_LPAE_ENTRIES;
> -    p = second + second_linear_offset(virt_offset);
> -    pte = mfn_to_xen_entry(_mfn(base_mfn), MT_NORMAL);
> -    if ( granularity == 16 * XEN_PT_LPAE_ENTRIES )
> -        pte.pt.contig = 1;  /* These maps are in 16-entry contiguous chunks. */
> -    for ( i = 0; i < count; i++ )
> -    {
> -        write_pte(p + i, pte);
> -        pte.pt.base += 1 << XEN_PT_LPAE_SHIFT;
> -    }
> -    flush_xen_tlb_local();
> -}
> -
>  #ifdef CONFIG_DOMAIN_PAGE
>  void *map_domain_page_global(mfn_t mfn)
>  {
> @@ -846,36 +812,17 @@ void __init setup_frametable_mappings(paddr_t ps,
> paddr_t pe)
>      unsigned long frametable_size = nr_pdxs * sizeof(struct page_info);
>      mfn_t base_mfn;
>      const unsigned long mapping_size = frametable_size < MB(32) ? MB(2) :
> MB(32);
> -#ifdef CONFIG_ARM_64
> -    lpae_t *second, pte;
> -    unsigned long nr_second;
> -    mfn_t second_base;
> -    int i;
> -#endif
> +    int rc;
> 
>      frametable_base_pdx = mfn_to_pdx(maddr_to_mfn(ps));
>      /* Round up to 2M or 32M boundary, as appropriate. */
>      frametable_size = ROUNDUP(frametable_size, mapping_size);
>      base_mfn = alloc_boot_pages(frametable_size >> PAGE_SHIFT, 32<<(20-12));
> 
> -#ifdef CONFIG_ARM_64
> -    /* Compute the number of second level pages. */
> -    nr_second = ROUNDUP(frametable_size, FIRST_SIZE) >> FIRST_SHIFT;
> -    second_base = alloc_boot_pages(nr_second, 1);
> -    second = mfn_to_virt(second_base);
> -    for ( i = 0; i < nr_second; i++ )
> -    {
> -        clear_page(mfn_to_virt(mfn_add(second_base, i)));
> -        pte = mfn_to_xen_entry(mfn_add(second_base, i), MT_NORMAL);
> -        pte.pt.table = 1;
> -        write_pte(&xen_first[first_table_offset(FRAMETABLE_VIRT_START)+i], pte);
> -    }
> -    create_mappings(second, 0, mfn_x(base_mfn), frametable_size >>
> PAGE_SHIFT,
> -                    mapping_size);
> -#else
> -    create_mappings(xen_second, FRAMETABLE_VIRT_START, mfn_x(base_mfn),
> -                    frametable_size >> PAGE_SHIFT, mapping_size);
> -#endif
> +    rc = map_pages_to_xen(FRAMETABLE_VIRT_START, base_mfn,
> +                          frametable_size >> PAGE_SHIFT, PAGE_HYPERVISOR_RW);
> +    if ( rc )
> +        panic("Unable to setup the frametable mappings.\n");
> 
>      memset(&frame_table[0], 0, nr_pdxs * sizeof(struct page_info));
>      memset(&frame_table[nr_pdxs], -1,
> --
> 2.32.0
> 



^ permalink raw reply	[flat|nested] 79+ messages in thread

* RE: [PATCH v3 08/19] xen/arm: mm: Re-implement early_fdt_map() using map_pages_to_xen()
  2022-02-21 10:22 ` [PATCH v3 08/19] xen/arm: mm: Re-implement early_fdt_map() using map_pages_to_xen() Julien Grall
@ 2022-03-18  7:36   ` Hongda Deng
  2022-03-18 19:44     ` Julien Grall
  2022-04-02  0:10   ` Stefano Stabellini
  1 sibling, 1 reply; 79+ messages in thread
From: Hongda Deng @ 2022-03-18  7:36 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

Hi Julien,

> -----Original Message-----
> From: Xen-devel <xen-devel-bounces@lists.xenproject.org> On Behalf Of Julien
> Grall
> Sent: 2022年2月21日 18:22
> To: xen-devel@lists.xenproject.org
> Cc: julien@xen.org; Julien Grall <Julien.Grall@arm.com>; Stefano Stabellini
> <sstabellini@kernel.org>; Bertrand Marquis <Bertrand.Marquis@arm.com>;
> Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>; Julien Grall
> <jgrall@amazon.com>
> Subject: [PATCH v3 08/19] xen/arm: mm: Re-implement early_fdt_map() using
> map_pages_to_xen()
> 
> From: Julien Grall <julien.grall@arm.com>
> 
> Now that map_pages_to_xen() has been extended to support 2MB mappings,
> we can replace the create_mappings() calls by map_pages_to_xen() calls.
> 
> The mapping can also be marked read-only has Xen as no business to

In my opinion I think it may should be:
	... read-only as Xen has no business ...
instead of:
	... read-only has Xen as no business ...

For this and other patches before this:
Reviewed-by: Hongda Deng <Hongda.Heng@arm.com>

> modify the host Device Tree.
> 
> Signed-off-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v2:
>         - Add my AWS signed-off-by
>         - Fix typo in the commit message
> ---
>  xen/arch/arm/mm.c | 18 +++++++++++++-----
>  1 file changed, 13 insertions(+), 5 deletions(-)
> 
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index f088a4b2de96..24de8dcb9042 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -559,6 +559,7 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
>      paddr_t offset;
>      void *fdt_virt;
>      uint32_t size;
> +    int rc;
> 
>      /*
>       * Check whether the physical FDT address is set and meets the minimum
> @@ -574,8 +575,12 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
>      /* The FDT is mapped using 2MB superpage */
>      BUILD_BUG_ON(BOOT_FDT_VIRT_START % SZ_2M);
> 
> -    create_mappings(xen_second, BOOT_FDT_VIRT_START,
> paddr_to_pfn(base_paddr),
> -                    SZ_2M >> PAGE_SHIFT, SZ_2M);
> +    rc = map_pages_to_xen(BOOT_FDT_VIRT_START,
> maddr_to_mfn(base_paddr),
> +                          SZ_2M >> PAGE_SHIFT,
> +                          PAGE_HYPERVISOR_RO | _PAGE_BLOCK);
> +    if ( rc )
> +        panic("Unable to map the device-tree.\n");
> +
> 
>      offset = fdt_paddr % SECOND_SIZE;
>      fdt_virt = (void *)BOOT_FDT_VIRT_START + offset;
> @@ -589,9 +594,12 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
> 
>      if ( (offset + size) > SZ_2M )
>      {
> -        create_mappings(xen_second, BOOT_FDT_VIRT_START + SZ_2M,
> -                        paddr_to_pfn(base_paddr + SZ_2M),
> -                        SZ_2M >> PAGE_SHIFT, SZ_2M);
> +        rc = map_pages_to_xen(BOOT_FDT_VIRT_START + SZ_2M,
> +                              maddr_to_mfn(base_paddr + SZ_2M),
> +                              SZ_2M >> PAGE_SHIFT,
> +                              PAGE_HYPERVISOR_RO | _PAGE_BLOCK);
> +        if ( rc )
> +            panic("Unable to map the device-tree\n");
>      }
> 
>      return fdt_virt;
> --
> 2.32.0
> 

Cheers,
---
Hongda


^ permalink raw reply	[flat|nested] 79+ messages in thread

* RE: [PATCH v3 09/19] xen/arm32: mm: Check if the virtual address is shared before updating it
  2022-02-21 10:22 ` [PATCH v3 09/19] xen/arm32: mm: Check if the virtual address is shared before updating it Julien Grall
@ 2022-03-18 10:44   ` Hongda Deng
  2022-03-18 22:15     ` Julien Grall
  2022-03-19 15:59   ` Julien Grall
  1 sibling, 1 reply; 79+ messages in thread
From: Hongda Deng @ 2022-03-18 10:44 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk

Hi Julien,

> -----Original Message-----
> From: Xen-devel <xen-devel-bounces@lists.xenproject.org> On Behalf Of Julien
> Grall
> Sent: 2022年2月21日 18:22
> To: xen-devel@lists.xenproject.org
> Cc: julien@xen.org; Julien Grall <jgrall@amazon.com>; Stefano Stabellini
> <sstabellini@kernel.org>; Bertrand Marquis <Bertrand.Marquis@arm.com>;
> Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>
> Subject: [PATCH v3 09/19] xen/arm32: mm: Check if the virtual address is shared
> before updating it
> 
> From: Julien Grall <jgrall@amazon.com>
> 
> Only the first 2GB of the virtual address space is shared between all
> the page-tables on Arm32.
> 
> There is a long outstanding TODO in xen_pt_update() stating that the
> function can only work with shared mapping. Nobody has ever called
> the function with private mapping, however as we add more callers
> there is a risk to mess things up.
> 
> Introduce a new define to mark the end of the shared mappings and use
> it in xen_pt_update() to verify if the address is correct.
> 
> Note that on Arm64, all the mappings are shared. Some compiler may
> complain about an always true check, so the new define is not introduced
> for arm64 and the code is protected with an #ifdef.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v2:
>         - New patch
> ---
>  xen/arch/arm/include/asm/config.h |  4 ++++
>  xen/arch/arm/mm.c                 | 11 +++++++++--
>  2 files changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/xen/arch/arm/include/asm/config.h
> b/xen/arch/arm/include/asm/config.h
> index c7b77912013e..85d4a510ce8a 100644
> --- a/xen/arch/arm/include/asm/config.h
> +++ b/xen/arch/arm/include/asm/config.h
> @@ -137,6 +137,10 @@
> 
>  #define XENHEAP_VIRT_START     _AT(vaddr_t,0x40000000)
>  #define XENHEAP_VIRT_END       _AT(vaddr_t,0x7fffffff)
> +
> +/* The first 2GB is always shared between all the page-tables. */
> +#define SHARED_VIRT_END        _AT(vaddr_t, 0x7fffffff)
> +
>  #define DOMHEAP_VIRT_START     _AT(vaddr_t,0x80000000)
>  #define DOMHEAP_VIRT_END       _AT(vaddr_t,0xffffffff)
> 
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index 24de8dcb9042..f18f65745595 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -1365,11 +1365,18 @@ static int xen_pt_update(unsigned long virt,
>       * For arm32, page-tables are different on each CPUs. Yet, they share
>       * some common mappings. It is assumed that only common mappings
>       * will be modified with this function.
> -     *
> -     * XXX: Add a check.
>       */
>      const mfn_t root = virt_to_mfn(THIS_CPU_PGTABLE);
> 
> +#ifdef SHARED_VIRT_END
> +    if ( virt > SHARED_VIRT_END ||
> +         (SHARED_VIRT_END - virt) < nr_mfns )

Why not convert (SHARED_VIRT_END - virt) to page number before comparation? 
I think nr_mfns is something related to page numbers, so maybe something like PAGE_SHIFT or round_pgdown is needed.

I am just wondering, and forgive me if I am wrong. 

> +    {
> +        mm_printk("Trying to map outside of the shared area.\n");
> +        return -EINVAL;
> +    }
> +#endif
> +
>      /*
>       * The hardware was configured to forbid mapping both writeable and
>       * executable.
> --
> 2.32.0
> 

Cheers,
---
Hongda


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 08/19] xen/arm: mm: Re-implement early_fdt_map() using map_pages_to_xen()
  2022-03-18  7:36   ` Hongda Deng
@ 2022-03-18 19:44     ` Julien Grall
  0 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-03-18 19:44 UTC (permalink / raw)
  To: Hongda Deng, xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

On 18/03/2022 07:36, Hongda Deng wrote:
> Hi Julien,

Hi Hongda,

>> -----Original Message-----
>> From: Xen-devel <xen-devel-bounces@lists.xenproject.org> On Behalf Of Julien
>> Grall
>> Sent: 2022年2月21日 18:22
>> To: xen-devel@lists.xenproject.org
>> Cc: julien@xen.org; Julien Grall <Julien.Grall@arm.com>; Stefano Stabellini
>> <sstabellini@kernel.org>; Bertrand Marquis <Bertrand.Marquis@arm.com>;
>> Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>; Julien Grall
>> <jgrall@amazon.com>
>> Subject: [PATCH v3 08/19] xen/arm: mm: Re-implement early_fdt_map() using
>> map_pages_to_xen()
>>
>> From: Julien Grall <julien.grall@arm.com>
>>
>> Now that map_pages_to_xen() has been extended to support 2MB mappings,
>> we can replace the create_mappings() calls by map_pages_to_xen() calls.
>>
>> The mapping can also be marked read-only has Xen as no business to
> 
> In my opinion I think it may should be:
> 	... read-only as Xen has no business ...
> instead of:
> 	... read-only has Xen as no business ...

You are right, I have updated the commit message.

> 
> For this and other patches before this:
> Reviewed-by: Hongda Deng <Hongda.Heng@arm.com>

There is one bug in patch #5 (I sent an e-mail with the possible fix). 
Can you confirm you are still happy with me to keep your reviewed-by for 
that patch?

For the other patches, I have already committed patch #1-#3. So I will 
add your tag on patches #4, #6, #7, #8.

Thank you for the review!

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 09/19] xen/arm32: mm: Check if the virtual address is shared before updating it
  2022-03-18 10:44   ` Hongda Deng
@ 2022-03-18 22:15     ` Julien Grall
  0 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-03-18 22:15 UTC (permalink / raw)
  To: Hongda Deng, xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk

On 18/03/2022 10:44, Hongda Deng wrote:
> Hi Julien,

Hi Hongda,

>> -----Original Message-----
>> From: Xen-devel <xen-devel-bounces@lists.xenproject.org> On Behalf Of Julien
>> Grall
>> Sent: 2022年2月21日 18:22
>> To: xen-devel@lists.xenproject.org
>> Cc: julien@xen.org; Julien Grall <jgrall@amazon.com>; Stefano Stabellini
>> <sstabellini@kernel.org>; Bertrand Marquis <Bertrand.Marquis@arm.com>;
>> Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>
>> Subject: [PATCH v3 09/19] xen/arm32: mm: Check if the virtual address is shared
>> before updating it
>>
>> From: Julien Grall <jgrall@amazon.com>
>>
>> Only the first 2GB of the virtual address space is shared between all
>> the page-tables on Arm32.
>>
>> There is a long outstanding TODO in xen_pt_update() stating that the
>> function can only work with shared mapping. Nobody has ever called
>> the function with private mapping, however as we add more callers
>> there is a risk to mess things up.
>>
>> Introduce a new define to mark the end of the shared mappings and use
>> it in xen_pt_update() to verify if the address is correct.
>>
>> Note that on Arm64, all the mappings are shared. Some compiler may
>> complain about an always true check, so the new define is not introduced
>> for arm64 and the code is protected with an #ifdef.
>>
>> Signed-off-by: Julien Grall <jgrall@amazon.com>
>>
>> ---
>>      Changes in v2:
>>          - New patch
>> ---
>>   xen/arch/arm/include/asm/config.h |  4 ++++
>>   xen/arch/arm/mm.c                 | 11 +++++++++--
>>   2 files changed, 13 insertions(+), 2 deletions(-)
>>
>> diff --git a/xen/arch/arm/include/asm/config.h
>> b/xen/arch/arm/include/asm/config.h
>> index c7b77912013e..85d4a510ce8a 100644
>> --- a/xen/arch/arm/include/asm/config.h
>> +++ b/xen/arch/arm/include/asm/config.h
>> @@ -137,6 +137,10 @@
>>
>>   #define XENHEAP_VIRT_START     _AT(vaddr_t,0x40000000)
>>   #define XENHEAP_VIRT_END       _AT(vaddr_t,0x7fffffff)
>> +
>> +/* The first 2GB is always shared between all the page-tables. */
>> +#define SHARED_VIRT_END        _AT(vaddr_t, 0x7fffffff)
>> +
>>   #define DOMHEAP_VIRT_START     _AT(vaddr_t,0x80000000)
>>   #define DOMHEAP_VIRT_END       _AT(vaddr_t,0xffffffff)
>>
>> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
>> index 24de8dcb9042..f18f65745595 100644
>> --- a/xen/arch/arm/mm.c
>> +++ b/xen/arch/arm/mm.c
>> @@ -1365,11 +1365,18 @@ static int xen_pt_update(unsigned long virt,
>>        * For arm32, page-tables are different on each CPUs. Yet, they share
>>        * some common mappings. It is assumed that only common mappings
>>        * will be modified with this function.
>> -     *
>> -     * XXX: Add a check.
>>        */
>>       const mfn_t root = virt_to_mfn(THIS_CPU_PGTABLE);
>>
>> +#ifdef SHARED_VIRT_END
>> +    if ( virt > SHARED_VIRT_END ||
>> +         (SHARED_VIRT_END - virt) < nr_mfns )
> 
> Why not convert (SHARED_VIRT_END - virt) to page number before comparation?
> I think nr_mfns is something related to page numbers, so maybe something like PAGE_SHIFT or round_pgdown is needed.

You are correct. nr_mfns should be shifted by PAGE_SHIFT. I have updated 
check to:

(SHARED_VIRT_END - virt) < pfn_to_paddr(nr_mfns)

Thanks for spotting it!

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 09/19] xen/arm32: mm: Check if the virtual address is shared before updating it
  2022-02-21 10:22 ` [PATCH v3 09/19] xen/arm32: mm: Check if the virtual address is shared before updating it Julien Grall
  2022-03-18 10:44   ` Hongda Deng
@ 2022-03-19 15:59   ` Julien Grall
  1 sibling, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-03-19 15:59 UTC (permalink / raw)
  To: xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk

Hi,

On 21/02/2022 10:22, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> Only the first 2GB of the virtual address space is shared between all
> the page-tables on Arm32.
> 
> There is a long outstanding TODO in xen_pt_update() stating that the
> function can only work with shared mapping. Nobody has ever called
> the function with private mapping, however as we add more callers
> there is a risk to mess things up.
> 
> Introduce a new define to mark the end of the shared mappings and use
> it in xen_pt_update() to verify if the address is correct.
> 
> Note that on Arm64, all the mappings are shared. Some compiler may
> complain about an always true check, so the new define is not introduced
> for arm64 and the code is protected with an #ifdef.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>      Changes in v2:
>          - New patch
> ---
>   xen/arch/arm/include/asm/config.h |  4 ++++
>   xen/arch/arm/mm.c                 | 11 +++++++++--

While I working on removing the identity mapping, I realized this patch 
is actually getting in my way for arm32. I am planning to have multiple 
region that are shared, but still a single unshared region (the domheap 
mapping area).

So I will rework the patch to check is the address is part of the 
unshared region.

I will drop the patch from the series and move it to the next one.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* RE: [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit
  2022-02-26 19:30   ` Julien Grall
@ 2022-03-21  5:46     ` Hongda Deng
  0 siblings, 0 replies; 79+ messages in thread
From: Hongda Deng @ 2022-03-21  5:46 UTC (permalink / raw)
  To: Julien Grall, xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk

Hi Julien,

> -----Original Message-----
> From: Xen-devel <xen-devel-bounces@lists.xenproject.org> On Behalf Of Julien
> Grall
> Sent: 2022年2月27日 3:30
> To: xen-devel@lists.xenproject.org
> Cc: Julien Grall <jgrall@amazon.com>; Stefano Stabellini
> <sstabellini@kernel.org>; Bertrand Marquis <Bertrand.Marquis@arm.com>;
> Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>
> Subject: Re: [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit
> 
> Hi,
> 
> On 21/02/2022 10:22, Julien Grall wrote:
> > @@ -1333,21 +1386,34 @@ static int xen_pt_update(unsigned long virt,
> >       while ( left )
> >       {
> >           unsigned int order, level;
> > +        unsigned int nr_contig;
> > +        unsigned int new_flags;
> >
> >           level = xen_pt_mapping_level(vfn, mfn, left, flags);
> >           order = XEN_PT_LEVEL_ORDER(level);
> >
> >           ASSERT(left >= BIT(order, UL));
> >
> > -        rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level, flags);
> > -        if ( rc )
> > -            break;
> > +        /*
> > +         * Check if we can set the contiguous mapping and update the
> > +         * flags accordingly.
> > +         */
> > +        nr_contig = xen_pt_check_contig(vfn, mfn, level, left, flags);
> > +        new_flags = flags | ((nr_contig > 1) ? _PAGE_CONTIG : 0);
> >
> > -        vfn += 1U << order;
> > -        if ( !mfn_eq(mfn, INVALID_MFN) )
> > -            mfn = mfn_add(mfn, 1U << order);
> > +        for ( ; nr_contig > 0; nr_contig-- )
> > +        {
> > +            rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level,
> > +                                     new_flags);
> > +            if ( rc )
> > +                break;
> >
> > -        left -= (1U << order);
> > +            vfn += 1U << order;
> > +            if ( !mfn_eq(mfn, INVALID_MFN) )
> > +                mfn = mfn_add(mfn, 1U << order);
> > +
> > +            left -= (1U << order);
> > +        }
> 
> I forgot to add:
> 
> if ( rc )
>    break;
> 
> Without it, the outer loop will never exit in case of an error.
> 
> Cheers,
> 
> --
> Julien Grall

Yep, I am happy with that.

Reviewed-by: Hongda Deng <Hongda.Deng@arm.com>

Cheers,
---
Hongda


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 04/19] xen/arm: mm: Allow other mapping size in xen_pt_update_entry()
  2022-02-21 10:22 ` [PATCH v3 04/19] xen/arm: mm: Allow other mapping size in xen_pt_update_entry() Julien Grall
@ 2022-04-01 23:35   ` Stefano Stabellini
  2022-04-02 15:59     ` Julien Grall
  0 siblings, 1 reply; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-01 23:35 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <julien.grall@arm.com>
> 
> At the moment, xen_pt_update_entry() only supports mapping at level 3
> (i.e 4KB mapping). While this is fine for most of the runtime helper,
> the boot code will require to use superpage mapping.
> 
> We don't want to allow superpage mapping by default as some of the
> callers may expect small mappings (i.e populate_pt_range()) or even
> expect to unmap only a part of a superpage.
> 
> To keep the code simple, a new flag _PAGE_BLOCK is introduced to
> allow the caller to enable superpage mapping.
> 
> As the code doesn't support all the combinations, xen_pt_check_entry()
> is extended to take into account the cases we don't support when
> using block mapping:
>     - Replacing a table with a mapping. This may happen if region was
>     first mapped with 4KB mapping and then later on replaced with a 2MB
>     (or 1GB mapping).
>     - Removing/modifying a table. This may happen if a caller try to
>     remove a region with _PAGE_BLOCK set when it was created without it.
> 
> Note that the current restriction means that the caller must ensure that
> _PAGE_BLOCK is consistently set/cleared across all the updates on a
> given virtual region. This ought to be fine with the expected use-cases.
> 
> More rework will be necessary if we wanted to remove the restrictions.
> 
> Note that nr_mfns is now marked const as it is used for flushing the
> TLBs and we don't want it to be modified.
> 
> Signed-off-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v3:
>         - Fix clash after prefixing the PT macros with XEN_PT_
>         - Fix typoes in the commit message
>         - Support superpage mappings even if nr is not suitably aligned
>         - Move the logic to find the level in a separate function
> 
>     Changes in v2:
>         - Pass the target level rather than the order to
>         xen_pt_update_entry()
>         - Update some comments
>         - Open-code paddr_to_pfn()
>         - Add my AWS signed-off-by
> ---
>  xen/arch/arm/include/asm/page.h |   4 ++
>  xen/arch/arm/mm.c               | 108 ++++++++++++++++++++++++++------
>  2 files changed, 94 insertions(+), 18 deletions(-)
> 
> diff --git a/xen/arch/arm/include/asm/page.h b/xen/arch/arm/include/asm/page.h
> index c6f9fb0d4e0c..07998df47bac 100644
> --- a/xen/arch/arm/include/asm/page.h
> +++ b/xen/arch/arm/include/asm/page.h
> @@ -69,6 +69,7 @@
>   * [3:4] Permission flags
>   * [5]   Page present
>   * [6]   Only populate page tables
> + * [7]   Superpage mappings is allowed
>   */
>  #define PAGE_AI_MASK(x) ((x) & 0x7U)
>  
> @@ -82,6 +83,9 @@
>  #define _PAGE_PRESENT    (1U << 5)
>  #define _PAGE_POPULATE   (1U << 6)
>  
> +#define _PAGE_BLOCK_BIT     7
> +#define _PAGE_BLOCK         (1U << _PAGE_BLOCK_BIT)
> +
>  /*
>   * _PAGE_DEVICE and _PAGE_NORMAL are convenience defines. They are not
>   * meant to be used outside of this header.
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index 515d0906f85b..3af69b396bd1 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -1063,9 +1063,10 @@ static int xen_pt_next_level(bool read_only, unsigned int level,
>  }
>  
>  /* Sanity check of the entry */
> -static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int flags)
> +static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int level,
> +                               unsigned int flags)
>  {
> -    /* Sanity check when modifying a page. */
> +    /* Sanity check when modifying an entry. */
>      if ( (flags & _PAGE_PRESENT) && mfn_eq(mfn, INVALID_MFN) )
>      {
>          /* We don't allow modifying an invalid entry. */
> @@ -1075,6 +1076,13 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int flags)
>              return false;
>          }
>  
> +        /* We don't allow modifying a table entry */
> +        if ( !lpae_is_mapping(entry, level) )
> +        {
> +            mm_printk("Modifying a table entry is not allowed.\n");
> +            return false;
> +        }
> +
>          /* We don't allow changing memory attributes. */
>          if ( entry.pt.ai != PAGE_AI_MASK(flags) )
>          {
> @@ -1090,7 +1098,7 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int flags)
>              return false;
>          }
>      }
> -    /* Sanity check when inserting a page */
> +    /* Sanity check when inserting a mapping */
>      else if ( flags & _PAGE_PRESENT )
>      {
>          /* We should be here with a valid MFN. */
> @@ -1099,18 +1107,28 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int flags)
>          /* We don't allow replacing any valid entry. */
>          if ( lpae_is_valid(entry) )
>          {
> -            mm_printk("Changing MFN for a valid entry is not allowed (%#"PRI_mfn" -> %#"PRI_mfn").\n",
> -                      mfn_x(lpae_get_mfn(entry)), mfn_x(mfn));
> +            if ( lpae_is_mapping(entry, level) )
> +                mm_printk("Changing MFN for a valid entry is not allowed (%#"PRI_mfn" -> %#"PRI_mfn").\n",
> +                          mfn_x(lpae_get_mfn(entry)), mfn_x(mfn));
> +            else
> +                mm_printk("Trying to replace a table with a mapping.\n");
>              return false;
>          }
>      }
> -    /* Sanity check when removing a page. */
> +    /* Sanity check when removing a mapping. */
>      else if ( (flags & (_PAGE_PRESENT|_PAGE_POPULATE)) == 0 )
>      {
>          /* We should be here with an invalid MFN. */
>          ASSERT(mfn_eq(mfn, INVALID_MFN));
>  
> -        /* We don't allow removing page with contiguous bit set. */
> +        /* We don't allow removing a table */
> +        if ( lpae_is_table(entry, level) )
> +        {
> +            mm_printk("Removing a table is not allowed.\n");
> +            return false;
> +        }
> +
> +        /* We don't allow removing a mapping with contiguous bit set. */
>          if ( entry.pt.contig )
>          {
>              mm_printk("Removing entry with contiguous bit set is not allowed.\n");
> @@ -1128,13 +1146,13 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int flags)
>      return true;
>  }
>  
> +/* Update an entry at the level @target. */
>  static int xen_pt_update_entry(mfn_t root, unsigned long virt,
> -                               mfn_t mfn, unsigned int flags)
> +                               mfn_t mfn, unsigned int target,
> +                               unsigned int flags)
>  {
>      int rc;
>      unsigned int level;
> -    /* We only support 4KB mapping (i.e level 3) for now */
> -    unsigned int target = 3;
>      lpae_t *table;
>      /*
>       * The intermediate page tables are read-only when the MFN is not valid
> @@ -1189,7 +1207,7 @@ static int xen_pt_update_entry(mfn_t root, unsigned long virt,
>      entry = table + offsets[level];
>  
>      rc = -EINVAL;
> -    if ( !xen_pt_check_entry(*entry, mfn, flags) )
> +    if ( !xen_pt_check_entry(*entry, mfn, level, flags) )
>          goto out;
>  
>      /* If we are only populating page-table, then we are done. */
> @@ -1207,8 +1225,11 @@ static int xen_pt_update_entry(mfn_t root, unsigned long virt,
>          {
>              pte = mfn_to_xen_entry(mfn, PAGE_AI_MASK(flags));
>  
> -            /* Third level entries set pte.pt.table = 1 */
> -            pte.pt.table = 1;
> +            /*
> +             * First and second level pages set pte.pt.table = 0, but
> +             * third level entries set pte.pt.table = 1.
> +             */
> +            pte.pt.table = (level == 3);
>          }
>          else /* We are updating the permission => Copy the current pte. */
>              pte = *entry;
> @@ -1228,15 +1249,56 @@ out:
>      return rc;
>  }
>  
> +/* Return the level where mapping should be done */
> +static int xen_pt_mapping_level(unsigned long vfn, mfn_t mfn, unsigned long nr,
> +                                unsigned int flags)
> +{
> +    unsigned int level;
> +    unsigned long mask;

Shouldn't mask be 64-bit on aarch32?


> +    /*
> +      * Don't take into account the MFN when removing mapping (i.e
> +      * MFN_INVALID) to calculate the correct target order.
> +      *
> +      * Per the Arm Arm, `vfn` and `mfn` must be both superpage aligned.
> +      * They are or-ed together and then checked against the size of
> +      * each level.
> +      *
> +      * `left` is not included and checked separately to allow
> +      * superpage mapping even if it is not properly aligned (the
> +      * user may have asked to map 2MB + 4k).
> +      */
> +     mask = !mfn_eq(mfn, INVALID_MFN) ? mfn_x(mfn) : 0;
> +     mask |= vfn;
> +
> +     /*
> +      * Always use level 3 mapping unless the caller request block
> +      * mapping.
> +      */
> +     if ( likely(!(flags & _PAGE_BLOCK)) )
> +         level = 3;
> +     else if ( !(mask & (BIT(FIRST_ORDER, UL) - 1)) &&
> +               (nr >= BIT(FIRST_ORDER, UL)) )
> +         level = 1;
> +     else if ( !(mask & (BIT(SECOND_ORDER, UL) - 1)) &&
> +               (nr >= BIT(SECOND_ORDER, UL)) )
> +         level = 2;
> +     else
> +         level = 3;
> +
> +     return level;

As far as I can tell this function is correct

> +}
> +
>  static DEFINE_SPINLOCK(xen_pt_lock);
>  
>  static int xen_pt_update(unsigned long virt,
>                           mfn_t mfn,
> -                         unsigned long nr_mfns,
> +                         const unsigned long nr_mfns,

Why const? nr_mfns is an unsigned long so it is passed as value: it
couldn't change the caller's parameter anyway. Just curious.


>                           unsigned int flags)
>  {
>      int rc = 0;
> -    unsigned long addr = virt, addr_end = addr + nr_mfns * PAGE_SIZE;
> +    unsigned long vfn = virt >> PAGE_SHIFT;
> +    unsigned long left = nr_mfns;
>  
>      /*
>       * For arm32, page-tables are different on each CPUs. Yet, they share
> @@ -1268,14 +1330,24 @@ static int xen_pt_update(unsigned long virt,
>  
>      spin_lock(&xen_pt_lock);
>  
> -    for ( ; addr < addr_end; addr += PAGE_SIZE )
> +    while ( left )
>      {
> -        rc = xen_pt_update_entry(root, addr, mfn, flags);
> +        unsigned int order, level;
> +
> +        level = xen_pt_mapping_level(vfn, mfn, left, flags);
> +        order = XEN_PT_LEVEL_ORDER(level);
> +
> +        ASSERT(left >= BIT(order, UL));
> +
> +        rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level, flags);

NIT: I know we don't have vfn_to_vaddr at the moment and there is no
widespread usage of vfn in Xen anyway, but it looks off to use
pfn_to_paddr on a vfn parameter. Maybe open-code pfn_to_paddr instead?
Or introduce vfn_to_vaddr locally in this file?


>          if ( rc )
>              break;
>  
> +        vfn += 1U << order;
>          if ( !mfn_eq(mfn, INVALID_MFN) )
> -            mfn = mfn_add(mfn, 1);
> +            mfn = mfn_add(mfn, 1U << order);
> +
> +        left -= (1U << order);

This looks correct. I don't have any other feedback on this patch.


>      /*
> -- 
> 2.32.0
> 


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit
  2022-02-21 10:22 ` [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit Julien Grall
  2022-02-26 19:30   ` Julien Grall
@ 2022-04-01 23:53   ` Stefano Stabellini
  2022-04-02 16:18     ` Julien Grall
  1 sibling, 1 reply; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-01 23:53 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> In follow-up patches, we will use xen_pt_update() (or its callers)
> to handle large mappings (e.g. frametable, xenheap). They are also
> not going to be modified once created.
> 
> The page-table entries have an hint to indicate that whether an
> entry is contiguous to another 16 entries (assuming 4KB). When the
> processor support the hint, one TLB entry will be created per
> contiguous region.
> 
> For now this is tied to _PAGE_BLOCK. We can untie it in the future
> if there are use-cases where we may want to use _PAGE_BLOCK without
> setting the contiguous (couldn't think of any yet).
> 
> Note that to avoid extra complexity, mappings with the contiguous
> bit set cannot be removed. Given the expected use, this restriction
> ought to be fine.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v3:
>         - New patch
> ---
>  xen/arch/arm/include/asm/page.h |  4 ++
>  xen/arch/arm/mm.c               | 80 ++++++++++++++++++++++++++++++---
>  2 files changed, 77 insertions(+), 7 deletions(-)
> 
> diff --git a/xen/arch/arm/include/asm/page.h b/xen/arch/arm/include/asm/page.h
> index 07998df47bac..e7cd62190c7f 100644
> --- a/xen/arch/arm/include/asm/page.h
> +++ b/xen/arch/arm/include/asm/page.h
> @@ -70,6 +70,7 @@
>   * [5]   Page present
>   * [6]   Only populate page tables
>   * [7]   Superpage mappings is allowed
> + * [8]   Set contiguous bit (internal flag)
>   */
>  #define PAGE_AI_MASK(x) ((x) & 0x7U)
>  
> @@ -86,6 +87,9 @@
>  #define _PAGE_BLOCK_BIT     7
>  #define _PAGE_BLOCK         (1U << _PAGE_BLOCK_BIT)
>  
> +#define _PAGE_CONTIG_BIT    8
> +#define _PAGE_CONTIG        (1U << _PAGE_CONTIG_BIT)
> +
>  /*
>   * _PAGE_DEVICE and _PAGE_NORMAL are convenience defines. They are not
>   * meant to be used outside of this header.
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index 3af69b396bd1..fd16c1541ce2 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -1237,6 +1237,8 @@ static int xen_pt_update_entry(mfn_t root, unsigned long virt,
>          /* Set permission */
>          pte.pt.ro = PAGE_RO_MASK(flags);
>          pte.pt.xn = PAGE_XN_MASK(flags);
> +        /* Set contiguous bit */
> +        pte.pt.contig = !!(flags & _PAGE_CONTIG);
>      }
>  
>      write_pte(entry, pte);
> @@ -1289,6 +1291,51 @@ static int xen_pt_mapping_level(unsigned long vfn, mfn_t mfn, unsigned long nr,
>       return level;
>  }
>  
> +#define XEN_PT_4K_NR_CONTIG 16
> +
> +/*
> + * Check whether the contiguous bit can be set. Return the number of
> + * contiguous entry allowed. If not allowed, return 1.
> + */
> +static unsigned int xen_pt_check_contig(unsigned long vfn, mfn_t mfn,
> +                                        unsigned int level, unsigned long left,
> +                                        unsigned int flags)
> +{
> +    unsigned long nr_contig;
> +
> +    /*
> +     * Allow the contiguous bit to set when the caller requests block
> +     * mapping.
> +     */
> +    if ( !(flags & _PAGE_BLOCK) )
> +        return 1;
> +
> +    /*
> +     * We don't allow to remove mapping with the contiguous bit set.
> +     * So shortcut the logic and directly return 1.
> +     */
> +    if ( mfn_eq(mfn, INVALID_MFN) )
> +        return 1;
> +
> +    /*
> +     * The number of contiguous entries varies depending on the page
> +     * granularity used. The logic below assumes 4KB.
> +     */
> +    BUILD_BUG_ON(PAGE_SIZE != SZ_4K);
> +
> +    /*
> +     * In order to enable the contiguous bit, we should have enough entries
> +     * to map left and both the virtual and physical address should be
> +     * aligned to the size of 16 translation tables entries.
> +     */
> +    nr_contig = BIT(XEN_PT_LEVEL_ORDER(level), UL) * XEN_PT_4K_NR_CONTIG;
> +
> +    if ( (left < nr_contig) || ((mfn_x(mfn) | vfn) & (nr_contig - 1)) )
> +        return 1;
> +
> +    return XEN_PT_4K_NR_CONTIG;
> +}
> +
>  static DEFINE_SPINLOCK(xen_pt_lock);
>  
>  static int xen_pt_update(unsigned long virt,
> @@ -1322,6 +1369,12 @@ static int xen_pt_update(unsigned long virt,
>          return -EINVAL;
>      }
>  
> +    if ( flags & _PAGE_CONTIG )
> +    {
> +        mm_printk("_PAGE_CONTIG is an internal only flag.\n");
> +        return -EINVAL;
> +    }
> +
>      if ( !IS_ALIGNED(virt, PAGE_SIZE) )
>      {
>          mm_printk("The virtual address is not aligned to the page-size.\n");
> @@ -1333,21 +1386,34 @@ static int xen_pt_update(unsigned long virt,
>      while ( left )
>      {
>          unsigned int order, level;
> +        unsigned int nr_contig;
> +        unsigned int new_flags;
>  
>          level = xen_pt_mapping_level(vfn, mfn, left, flags);
>          order = XEN_PT_LEVEL_ORDER(level);
>  
>          ASSERT(left >= BIT(order, UL));
>  
> -        rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level, flags);
> -        if ( rc )
> -            break;
> +        /*
> +         * Check if we can set the contiguous mapping and update the
> +         * flags accordingly.
> +         */
> +        nr_contig = xen_pt_check_contig(vfn, mfn, level, left, flags);
> +        new_flags = flags | ((nr_contig > 1) ? _PAGE_CONTIG : 0);

Here is an optional idea to make the code simpler. We could move the
flags changes (adding/removing _PAGE_CONTIG) to xen_pt_check_contig.
That way, we could remove the inner loop.

xen_pt_check_contig could check if _PAGE_CONTIG is already set and based
on alignment, it should be able to figure out when it needs to be
disabled.

But also this code works as far as I can tell.


> -        vfn += 1U << order;
> -        if ( !mfn_eq(mfn, INVALID_MFN) )
> -            mfn = mfn_add(mfn, 1U << order);
> +        for ( ; nr_contig > 0; nr_contig-- )
> +        {
> +            rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level,
> +                                     new_flags);
> +            if ( rc )
> +                break;
>  
> -        left -= (1U << order);
> +            vfn += 1U << order;
> +            if ( !mfn_eq(mfn, INVALID_MFN) )
> +                mfn = mfn_add(mfn, 1U << order);
> +
> +            left -= (1U << order);
> +        }
>      }
>  
>      /*
> -- 
> 2.32.0
> 


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 06/19] xen/arm: mm: Avoid flushing the TLBs when mapping are inserted
  2022-02-21 10:22 ` [PATCH v3 06/19] xen/arm: mm: Avoid flushing the TLBs when mapping are inserted Julien Grall
@ 2022-04-02  0:00   ` Stefano Stabellini
  2022-04-02 16:38     ` Julien Grall
  0 siblings, 1 reply; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-02  0:00 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> Currently, the function xen_pt_update() will flush the TLBs even when
> the mappings are inserted. This is a bit wasteful because we don't
> allow mapping replacement. Even if we were, the flush would need to
> happen earlier because mapping replacement should use Break-Before-Make
> when updating the entry.
> 
> A single call to xen_pt_update() can perform a single action. IOW, it
> is not possible to, for instance, mix inserting and removing mappings.
> Therefore, we can use `flags` to determine what action is performed.
> 
> This change will be particularly help to limit the impact of switching
> boot time mapping to use xen_pt_update().
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v2:
>         - New patch
> ---
>  xen/arch/arm/mm.c | 17 ++++++++++++++---
>  1 file changed, 14 insertions(+), 3 deletions(-)
> 
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index fd16c1541ce2..7b4b9de8693e 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -1104,7 +1104,13 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int level,
>          /* We should be here with a valid MFN. */
>          ASSERT(!mfn_eq(mfn, INVALID_MFN));
>  
> -        /* We don't allow replacing any valid entry. */
> +        /*
> +         * We don't allow replacing any valid entry.
> +         *
> +         * Note that the function xen_pt_update() relies on this
> +         * assumption and will skip the TLB flush. The function will need
> +         * to be updated if the check is relaxed.
> +         */
>          if ( lpae_is_valid(entry) )
>          {
>              if ( lpae_is_mapping(entry, level) )
> @@ -1417,11 +1423,16 @@ static int xen_pt_update(unsigned long virt,
>      }
>  
>      /*
> -     * Flush the TLBs even in case of failure because we may have
> +     * The TLBs flush can be safely skipped when a mapping is inserted
> +     * as we don't allow mapping replacement (see xen_pt_check_entry()).
> +     *
> +     * For all the other cases, the TLBs will be flushed unconditionally
> +     * even if the mapping has failed. This is because we may have
>       * partially modified the PT. This will prevent any unexpected
>       * behavior afterwards.
>       */
> -    flush_xen_tlb_range_va(virt, PAGE_SIZE * nr_mfns);
> +    if ( !(flags & _PAGE_PRESENT) || mfn_eq(mfn, INVALID_MFN) )
> +        flush_xen_tlb_range_va(virt, PAGE_SIZE * nr_mfns);

I am trying to think of a care where the following wouldn't be enough
but I cannot come up with one:

   if ( mfn_eq(mfn, INVALID_MFN) )
       flush_xen_tlb_range_va(virt, PAGE_SIZE * nr_mfns);


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 07/19] xen/arm: mm: Don't open-code Xen PT update in remove_early_mappings()
  2022-02-21 10:22 ` [PATCH v3 07/19] xen/arm: mm: Don't open-code Xen PT update in remove_early_mappings() Julien Grall
@ 2022-04-02  0:04   ` Stefano Stabellini
  2022-04-02 16:47     ` Julien Grall
  0 siblings, 1 reply; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-02  0:04 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <julien.grall@arm.com>
> 
> Now that xen_pt_update_entry() is able to deal with different mapping
> size, we can replace the open-coding of the page-tables update by a call
> to modify_xen_mappings().
> 
> As the function is not meant to fail, a BUG_ON() is added to check the
> return.
> 
> Signed-off-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Julien Grall <jgrall@amazon.com>

Nice!


> ---
>     Changes in v2:
>         - Stay consistent with how function name are used in the commit
>         message
>         - Add my AWS signed-off-by
> ---
>  xen/arch/arm/mm.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index 7b4b9de8693e..f088a4b2de96 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -599,11 +599,11 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
>  
>  void __init remove_early_mappings(void)
>  {
> -    lpae_t pte = {0};
> -    write_pte(xen_second + second_table_offset(BOOT_FDT_VIRT_START), pte);
> -    write_pte(xen_second + second_table_offset(BOOT_FDT_VIRT_START + SZ_2M),
> -              pte);
> -    flush_xen_tlb_range_va(BOOT_FDT_VIRT_START, BOOT_FDT_SLOT_SIZE);
> +    int rc;
> +
> +    rc = modify_xen_mappings(BOOT_FDT_VIRT_START, BOOT_FDT_VIRT_END,
> +                             _PAGE_BLOCK);
> +    BUG_ON(rc);

Am I right that we are actually destroying the mapping, which usually is
done by calling destroy_xen_mappings, but we cannot call
destroy_xen_mappings in this case because it doesn't take a flags
parameter?

If so, then I would add a flags parameter to destroy_xen_mappings
instead of calling modify_xen_mappings just to pass _PAGE_BLOCK.
But I don't feel strongly about it so if you don't feel like making the
change to destroy_xen_mappings, you can add my acked-by here anyway.


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 08/19] xen/arm: mm: Re-implement early_fdt_map() using map_pages_to_xen()
  2022-02-21 10:22 ` [PATCH v3 08/19] xen/arm: mm: Re-implement early_fdt_map() using map_pages_to_xen() Julien Grall
  2022-03-18  7:36   ` Hongda Deng
@ 2022-04-02  0:10   ` Stefano Stabellini
  2022-04-02 17:02     ` Julien Grall
  1 sibling, 1 reply; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-02  0:10 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <julien.grall@arm.com>
> 
> Now that map_pages_to_xen() has been extended to support 2MB mappings,
> we can replace the create_mappings() calls by map_pages_to_xen() calls.
> 
> The mapping can also be marked read-only has Xen as no business to
> modify the host Device Tree.
> 
> Signed-off-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v2:
>         - Add my AWS signed-off-by
>         - Fix typo in the commit message
> ---
>  xen/arch/arm/mm.c | 18 +++++++++++++-----
>  1 file changed, 13 insertions(+), 5 deletions(-)
> 
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index f088a4b2de96..24de8dcb9042 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -559,6 +559,7 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
>      paddr_t offset;
>      void *fdt_virt;
>      uint32_t size;
> +    int rc;
>  
>      /*
>       * Check whether the physical FDT address is set and meets the minimum
> @@ -574,8 +575,12 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
>      /* The FDT is mapped using 2MB superpage */
>      BUILD_BUG_ON(BOOT_FDT_VIRT_START % SZ_2M);
>  
> -    create_mappings(xen_second, BOOT_FDT_VIRT_START, paddr_to_pfn(base_paddr),
> -                    SZ_2M >> PAGE_SHIFT, SZ_2M);
> +    rc = map_pages_to_xen(BOOT_FDT_VIRT_START, maddr_to_mfn(base_paddr),
> +                          SZ_2M >> PAGE_SHIFT,
> +                          PAGE_HYPERVISOR_RO | _PAGE_BLOCK);
> +    if ( rc )
> +        panic("Unable to map the device-tree.\n");
> +
>  
>      offset = fdt_paddr % SECOND_SIZE;
>      fdt_virt = (void *)BOOT_FDT_VIRT_START + offset;
> @@ -589,9 +594,12 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
>  
>      if ( (offset + size) > SZ_2M )
>      {
> -        create_mappings(xen_second, BOOT_FDT_VIRT_START + SZ_2M,
> -                        paddr_to_pfn(base_paddr + SZ_2M),
> -                        SZ_2M >> PAGE_SHIFT, SZ_2M);
> +        rc = map_pages_to_xen(BOOT_FDT_VIRT_START + SZ_2M,
> +                              maddr_to_mfn(base_paddr + SZ_2M),
> +                              SZ_2M >> PAGE_SHIFT,
> +                              PAGE_HYPERVISOR_RO | _PAGE_BLOCK);
> +        if ( rc )
> +            panic("Unable to map the device-tree\n");
>      }

Very good! :-)

I have a small preference for making the change to PAGE_HYPERVISOR_RO in
a separate patch because it would make it easier to revert in the
future if we need so (e.g. overlays...). But it is OK either way.


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 10/19] xen/arm32: mm: Re-implement setup_xenheap_mappings() using map_pages_to_xen()
  2022-02-21 10:22 ` [PATCH v3 10/19] xen/arm32: mm: Re-implement setup_xenheap_mappings() using map_pages_to_xen() Julien Grall
@ 2022-04-02  0:11   ` Stefano Stabellini
  2022-05-14  9:42   ` Julien Grall
  1 sibling, 0 replies; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-02  0:11 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> Now that map_pages_to_xen() has been extended to support 2MB mappings,
> we can replace the create_mappings() call by map_pages_to_xen() call.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>

Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>     Changes in v3:
>         - Fix build when CONFIG_DEBUG=y
> 
>     Changes in v2:
>         - New patch
> 
>     TODOs:
>         - add support for contiguous mapping
> ---
>  xen/arch/arm/mm.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index f18f65745595..1e5c2c45dcf9 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -809,7 +809,12 @@ void mmu_init_secondary_cpu(void)
>  void __init setup_xenheap_mappings(unsigned long base_mfn,
>                                     unsigned long nr_mfns)
>  {
> -    create_mappings(xen_second, XENHEAP_VIRT_START, base_mfn, nr_mfns, MB(32));
> +    int rc;
> +
> +    rc = map_pages_to_xen(XENHEAP_VIRT_START, _mfn(base_mfn), nr_mfns,
> +                          PAGE_HYPERVISOR_RW | _PAGE_BLOCK);
> +    if ( rc )
> +        panic("Unable to setup the xenheap mappings.\n");
>  
>      /* Record where the xenheap is, for translation routines. */
>      xenheap_virt_end = XENHEAP_VIRT_START + nr_mfns * PAGE_SIZE;
> -- 
> 2.32.0
> 


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 04/19] xen/arm: mm: Allow other mapping size in xen_pt_update_entry()
  2022-04-01 23:35   ` Stefano Stabellini
@ 2022-04-02 15:59     ` Julien Grall
  2022-04-05 20:46       ` Stefano Stabellini
  0 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-04-02 15:59 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, Julien Grall, Bertrand Marquis, Volodymyr Babchuk,
	Julien Grall

Hi,

On 02/04/2022 00:35, Stefano Stabellini wrote:
>> +/* Return the level where mapping should be done */
>> +static int xen_pt_mapping_level(unsigned long vfn, mfn_t mfn, unsigned long nr,
>> +                                unsigned int flags)
>> +{
>> +    unsigned int level;
>> +    unsigned long mask;
> 
> Shouldn't mask be 64-bit on aarch32?

The 3 variables we will use (mfn, vfn, nr) are unsigned long. So it is 
fine to define the mask as unsigned long.

>> +}
>> +
>>   static DEFINE_SPINLOCK(xen_pt_lock);
>>   
>>   static int xen_pt_update(unsigned long virt,
>>                            mfn_t mfn,
>> -                         unsigned long nr_mfns,
>> +                         const unsigned long nr_mfns,
> 
> Why const? nr_mfns is an unsigned long so it is passed as value: it
> couldn't change the caller's parameter anyway. Just curious.

Because nr_mfns is used to flush the TLBs. In the original I made the 
mistake to decrement the variable and only discovered later on when the 
TLB contained the wrong entry.

Such bug tends to be very subtle and it is hard to find the root cause. 
So better mark the variable const to avoid any surprise.

The short version of what I wrote is in the commit message. I can write 
a small comment in the code if you want.

>>                            unsigned int flags)
>>   {
>>       int rc = 0;
>> -    unsigned long addr = virt, addr_end = addr + nr_mfns * PAGE_SIZE;
>> +    unsigned long vfn = virt >> PAGE_SHIFT;
>> +    unsigned long left = nr_mfns;
>>   
>>       /*
>>        * For arm32, page-tables are different on each CPUs. Yet, they share
>> @@ -1268,14 +1330,24 @@ static int xen_pt_update(unsigned long virt,
>>   
>>       spin_lock(&xen_pt_lock);
>>   
>> -    for ( ; addr < addr_end; addr += PAGE_SIZE )
>> +    while ( left )
>>       {
>> -        rc = xen_pt_update_entry(root, addr, mfn, flags);
>> +        unsigned int order, level;
>> +
>> +        level = xen_pt_mapping_level(vfn, mfn, left, flags);
>> +        order = XEN_PT_LEVEL_ORDER(level);
>> +
>> +        ASSERT(left >= BIT(order, UL));
>> +
>> +        rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level, flags);
> 
> NIT: I know we don't have vfn_to_vaddr at the moment and there is no
> widespread usage of vfn in Xen anyway, but it looks off to use
> pfn_to_paddr on a vfn parameter. Maybe open-code pfn_to_paddr instead?
> Or introduce vfn_to_vaddr locally in this file?

To avoid inconsistency with mfn_to_maddr() and gfn_to_gaddr(), I don't 
want ot introduce vfn_to_vaddr() withtout the typesafe part. I think 
this is a bit over the top for now.

So I will open-code pfn_to_paddr().

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit
  2022-04-01 23:53   ` Stefano Stabellini
@ 2022-04-02 16:18     ` Julien Grall
  2022-04-05 20:47       ` Stefano Stabellini
  0 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-04-02 16:18 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, Julien Grall, Bertrand Marquis, Volodymyr Babchuk

Hi,

On 02/04/2022 00:53, Stefano Stabellini wrote:
> On Mon, 21 Feb 2022, Julien Grall wrote:
>> @@ -1333,21 +1386,34 @@ static int xen_pt_update(unsigned long virt,
>>       while ( left )
>>       {
>>           unsigned int order, level;
>> +        unsigned int nr_contig;
>> +        unsigned int new_flags;
>>   
>>           level = xen_pt_mapping_level(vfn, mfn, left, flags);
>>           order = XEN_PT_LEVEL_ORDER(level);
>>   
>>           ASSERT(left >= BIT(order, UL));
>>   
>> -        rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level, flags);
>> -        if ( rc )
>> -            break;
>> +        /*
>> +         * Check if we can set the contiguous mapping and update the
>> +         * flags accordingly.
>> +         */
>> +        nr_contig = xen_pt_check_contig(vfn, mfn, level, left, flags);
>> +        new_flags = flags | ((nr_contig > 1) ? _PAGE_CONTIG : 0);
> 
> Here is an optional idea to make the code simpler. We could move the
> flags changes (adding/removing _PAGE_CONTIG) to xen_pt_check_contig.
> That way, we could remove the inner loop.
> 
> xen_pt_check_contig could check if _PAGE_CONTIG is already set and based
> on alignment, it should be able to figure out when it needs to be
> disabled.

My initial attempt was to do everything in a loop. But this didn't pan 
out as I wanted (I felt the code was complex) and there are extra work 
to be done for the next 31 entries (assuming 4KB granularity).

Hence the two loops. Unfortunately, I didn't keep my first attempt. So I 
can't realy show what I wrote.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 06/19] xen/arm: mm: Avoid flushing the TLBs when mapping are inserted
  2022-04-02  0:00   ` Stefano Stabellini
@ 2022-04-02 16:38     ` Julien Grall
  2022-04-05 20:49       ` Stefano Stabellini
  0 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-04-02 16:38 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, Julien Grall, Bertrand Marquis, Volodymyr Babchuk

Hi Stefano,

On 02/04/2022 01:00, Stefano Stabellini wrote:
> On Mon, 21 Feb 2022, Julien Grall wrote:
>> From: Julien Grall <jgrall@amazon.com>
>>
>> Currently, the function xen_pt_update() will flush the TLBs even when
>> the mappings are inserted. This is a bit wasteful because we don't
>> allow mapping replacement. Even if we were, the flush would need to
>> happen earlier because mapping replacement should use Break-Before-Make
>> when updating the entry.
>>
>> A single call to xen_pt_update() can perform a single action. IOW, it
>> is not possible to, for instance, mix inserting and removing mappings.
>> Therefore, we can use `flags` to determine what action is performed.
>>
>> This change will be particularly help to limit the impact of switching
>> boot time mapping to use xen_pt_update().
>>
>> Signed-off-by: Julien Grall <jgrall@amazon.com>
>>
>> ---
>>      Changes in v2:
>>          - New patch
>> ---
>>   xen/arch/arm/mm.c | 17 ++++++++++++++---
>>   1 file changed, 14 insertions(+), 3 deletions(-)
>>
>> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
>> index fd16c1541ce2..7b4b9de8693e 100644
>> --- a/xen/arch/arm/mm.c
>> +++ b/xen/arch/arm/mm.c
>> @@ -1104,7 +1104,13 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t mfn, unsigned int level,
>>           /* We should be here with a valid MFN. */
>>           ASSERT(!mfn_eq(mfn, INVALID_MFN));
>>   
>> -        /* We don't allow replacing any valid entry. */
>> +        /*
>> +         * We don't allow replacing any valid entry.
>> +         *
>> +         * Note that the function xen_pt_update() relies on this
>> +         * assumption and will skip the TLB flush. The function will need
>> +         * to be updated if the check is relaxed.
>> +         */
>>           if ( lpae_is_valid(entry) )
>>           {
>>               if ( lpae_is_mapping(entry, level) )
>> @@ -1417,11 +1423,16 @@ static int xen_pt_update(unsigned long virt,
>>       }
>>   
>>       /*
>> -     * Flush the TLBs even in case of failure because we may have
>> +     * The TLBs flush can be safely skipped when a mapping is inserted
>> +     * as we don't allow mapping replacement (see xen_pt_check_entry()).
>> +     *
>> +     * For all the other cases, the TLBs will be flushed unconditionally
>> +     * even if the mapping has failed. This is because we may have
>>        * partially modified the PT. This will prevent any unexpected
>>        * behavior afterwards.
>>        */
>> -    flush_xen_tlb_range_va(virt, PAGE_SIZE * nr_mfns);
>> +    if ( !(flags & _PAGE_PRESENT) || mfn_eq(mfn, INVALID_MFN) )
>> +        flush_xen_tlb_range_va(virt, PAGE_SIZE * nr_mfns);
> 
> I am trying to think of a care where the following wouldn't be enough
> but I cannot come up with one:
> 
>     if ( mfn_eq(mfn, INVALID_MFN) )
>         flush_xen_tlb_range_va(virt, PAGE_SIZE * nr_mfns);

_PAGE_PRESENT is not set for two cases: when removing a page or 
populating page-tables for a region. Both of them will expect an 
INVALID_MFN (see the two asserts in xen_pt_check_entry()).

Therefore your solution should work. However, technically the 'mfn' is 
ignored in both situation (hence why this is an ASSERT() rather than a 
prod check).

Also, I feel it is better to flush more than less (missing a flush could 
have catastrophic result). So I chose to be explicit in which case the 
flush can be skipped.

Maybe it would be clearer if I write:

  !((flags & _PAGE_PRESENT) && !mfn_eq(mfn, INVALID_MFN))

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 07/19] xen/arm: mm: Don't open-code Xen PT update in remove_early_mappings()
  2022-04-02  0:04   ` Stefano Stabellini
@ 2022-04-02 16:47     ` Julien Grall
  2022-04-05 20:51       ` Stefano Stabellini
  0 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-04-02 16:47 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, Julien Grall, Bertrand Marquis, Volodymyr Babchuk,
	Julien Grall

Hi Stefano,

On 02/04/2022 01:04, Stefano Stabellini wrote:
> On Mon, 21 Feb 2022, Julien Grall wrote:
>> From: Julien Grall <julien.grall@arm.com>
>>
>> Now that xen_pt_update_entry() is able to deal with different mapping
>> size, we can replace the open-coding of the page-tables update by a call
>> to modify_xen_mappings().
>>
>> As the function is not meant to fail, a BUG_ON() is added to check the
>> return.
>>
>> Signed-off-by: Julien Grall <julien.grall@arm.com>
>> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> Nice!
> 
> 
>> ---
>>      Changes in v2:
>>          - Stay consistent with how function name are used in the commit
>>          message
>>          - Add my AWS signed-off-by
>> ---
>>   xen/arch/arm/mm.c | 10 +++++-----
>>   1 file changed, 5 insertions(+), 5 deletions(-)
>>
>> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
>> index 7b4b9de8693e..f088a4b2de96 100644
>> --- a/xen/arch/arm/mm.c
>> +++ b/xen/arch/arm/mm.c
>> @@ -599,11 +599,11 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
>>   
>>   void __init remove_early_mappings(void)
>>   {
>> -    lpae_t pte = {0};
>> -    write_pte(xen_second + second_table_offset(BOOT_FDT_VIRT_START), pte);
>> -    write_pte(xen_second + second_table_offset(BOOT_FDT_VIRT_START + SZ_2M),
>> -              pte);
>> -    flush_xen_tlb_range_va(BOOT_FDT_VIRT_START, BOOT_FDT_SLOT_SIZE);
>> +    int rc;
>> +
>> +    rc = modify_xen_mappings(BOOT_FDT_VIRT_START, BOOT_FDT_VIRT_END,
>> +                             _PAGE_BLOCK);
>> +    BUG_ON(rc);
> 
> Am I right that we are actually destroying the mapping, which usually is
> done by calling destroy_xen_mappings, but we cannot call
> destroy_xen_mappings in this case because it doesn't take a flags
> parameter?

You are right.

> 
> If so, then I would add a flags parameter to destroy_xen_mappings
> instead of calling modify_xen_mappings just to pass _PAGE_BLOCK.
> But I don't feel strongly about it so if you don't feel like making the
> change to destroy_xen_mappings, you can add my acked-by here anyway.

destroy_xen_mappings() is a function used by common code. This is the 
only place so far where I need to pass _PAGE_BLOCK and I don't expect it 
to be used by the common code any time soon.

So I am not in favor to add an extra parameter for destroy_xen_mappings().

Would you prefer if I open-code the call to xen_pt_update?

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 08/19] xen/arm: mm: Re-implement early_fdt_map() using map_pages_to_xen()
  2022-04-02  0:10   ` Stefano Stabellini
@ 2022-04-02 17:02     ` Julien Grall
  0 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-04-02 17:02 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, Julien Grall, Bertrand Marquis, Volodymyr Babchuk,
	Julien Grall

Hi Stefano,

On 02/04/2022 01:10, Stefano Stabellini wrote:
> On Mon, 21 Feb 2022, Julien Grall wrote:
>> From: Julien Grall <julien.grall@arm.com>
>>
>> Now that map_pages_to_xen() has been extended to support 2MB mappings,
>> we can replace the create_mappings() calls by map_pages_to_xen() calls.
>>
>> The mapping can also be marked read-only has Xen as no business to
>> modify the host Device Tree.
>>
>> Signed-off-by: Julien Grall <julien.grall@arm.com>
>> Signed-off-by: Julien Grall <jgrall@amazon.com>
>>
>> ---
>>      Changes in v2:
>>          - Add my AWS signed-off-by
>>          - Fix typo in the commit message
>> ---
>>   xen/arch/arm/mm.c | 18 +++++++++++++-----
>>   1 file changed, 13 insertions(+), 5 deletions(-)
>>
>> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
>> index f088a4b2de96..24de8dcb9042 100644
>> --- a/xen/arch/arm/mm.c
>> +++ b/xen/arch/arm/mm.c
>> @@ -559,6 +559,7 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
>>       paddr_t offset;
>>       void *fdt_virt;
>>       uint32_t size;
>> +    int rc;
>>   
>>       /*
>>        * Check whether the physical FDT address is set and meets the minimum
>> @@ -574,8 +575,12 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
>>       /* The FDT is mapped using 2MB superpage */
>>       BUILD_BUG_ON(BOOT_FDT_VIRT_START % SZ_2M);
>>   
>> -    create_mappings(xen_second, BOOT_FDT_VIRT_START, paddr_to_pfn(base_paddr),
>> -                    SZ_2M >> PAGE_SHIFT, SZ_2M);
>> +    rc = map_pages_to_xen(BOOT_FDT_VIRT_START, maddr_to_mfn(base_paddr),
>> +                          SZ_2M >> PAGE_SHIFT,
>> +                          PAGE_HYPERVISOR_RO | _PAGE_BLOCK);
>> +    if ( rc )
>> +        panic("Unable to map the device-tree.\n");
>> +
>>   
>>       offset = fdt_paddr % SECOND_SIZE;
>>       fdt_virt = (void *)BOOT_FDT_VIRT_START + offset;
>> @@ -589,9 +594,12 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
>>   
>>       if ( (offset + size) > SZ_2M )
>>       {
>> -        create_mappings(xen_second, BOOT_FDT_VIRT_START + SZ_2M,
>> -                        paddr_to_pfn(base_paddr + SZ_2M),
>> -                        SZ_2M >> PAGE_SHIFT, SZ_2M);
>> +        rc = map_pages_to_xen(BOOT_FDT_VIRT_START + SZ_2M,
>> +                              maddr_to_mfn(base_paddr + SZ_2M),
>> +                              SZ_2M >> PAGE_SHIFT,
>> +                              PAGE_HYPERVISOR_RO | _PAGE_BLOCK);
>> +        if ( rc )
>> +            panic("Unable to map the device-tree\n");
>>       }
> 
> Very good! :-)
> 
> I have a small preference for making the change to PAGE_HYPERVISOR_RO in
> a separate patch because it would make it easier to revert in the
> future if we need so (e.g. overlays...). But it is OK either way.

The mapping is only used for early boot. For runtime we are relocating 
the FDT and it is writable.

That said, I don't think the FDT should ever be writable. The size of 
the FDT is bounded and therefore you will likely not be able to add a 
new property/node without relocating it.

I haven't looked at latest DT overlay series. But in the previous 
version I was under the impression that only the unflatten version would 
be touched. IOW, the flatten version would be untouched. Can you confirm 
this is still the case?

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 04/19] xen/arm: mm: Allow other mapping size in xen_pt_update_entry()
  2022-04-02 15:59     ` Julien Grall
@ 2022-04-05 20:46       ` Stefano Stabellini
  2022-04-10 12:17         ` Julien Grall
  0 siblings, 1 reply; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-05 20:46 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, xen-devel, Julien Grall, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

On Sat, 2 Apr 2022, Julien Grall wrote:
> On 02/04/2022 00:35, Stefano Stabellini wrote:
> > > +/* Return the level where mapping should be done */
> > > +static int xen_pt_mapping_level(unsigned long vfn, mfn_t mfn, unsigned
> > > long nr,
> > > +                                unsigned int flags)
> > > +{
> > > +    unsigned int level;
> > > +    unsigned long mask;
> > 
> > Shouldn't mask be 64-bit on aarch32?
> 
> The 3 variables we will use (mfn, vfn, nr) are unsigned long. So it is fine to
> define the mask as unsigned long.

Good point


> > > +}
> > > +
> > >   static DEFINE_SPINLOCK(xen_pt_lock);
> > >     static int xen_pt_update(unsigned long virt,
> > >                            mfn_t mfn,
> > > -                         unsigned long nr_mfns,
> > > +                         const unsigned long nr_mfns,
> > 
> > Why const? nr_mfns is an unsigned long so it is passed as value: it
> > couldn't change the caller's parameter anyway. Just curious.
> 
> Because nr_mfns is used to flush the TLBs. In the original I made the mistake
> to decrement the variable and only discovered later on when the TLB contained
> the wrong entry.
> 
> Such bug tends to be very subtle and it is hard to find the root cause. So
> better mark the variable const to avoid any surprise.
> 
> The short version of what I wrote is in the commit message. I can write a
> small comment in the code if you want.

No, that's fine. Thanks for the explanation.


> > >                            unsigned int flags)
> > >   {
> > >       int rc = 0;
> > > -    unsigned long addr = virt, addr_end = addr + nr_mfns * PAGE_SIZE;
> > > +    unsigned long vfn = virt >> PAGE_SHIFT;
> > > +    unsigned long left = nr_mfns;
> > >         /*
> > >        * For arm32, page-tables are different on each CPUs. Yet, they
> > > share
> > > @@ -1268,14 +1330,24 @@ static int xen_pt_update(unsigned long virt,
> > >         spin_lock(&xen_pt_lock);
> > >   -    for ( ; addr < addr_end; addr += PAGE_SIZE )
> > > +    while ( left )
> > >       {
> > > -        rc = xen_pt_update_entry(root, addr, mfn, flags);
> > > +        unsigned int order, level;
> > > +
> > > +        level = xen_pt_mapping_level(vfn, mfn, left, flags);
> > > +        order = XEN_PT_LEVEL_ORDER(level);
> > > +
> > > +        ASSERT(left >= BIT(order, UL));
> > > +
> > > +        rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level,
> > > flags);
> > 
> > NIT: I know we don't have vfn_to_vaddr at the moment and there is no
> > widespread usage of vfn in Xen anyway, but it looks off to use
> > pfn_to_paddr on a vfn parameter. Maybe open-code pfn_to_paddr instead?
> > Or introduce vfn_to_vaddr locally in this file?
> 
> To avoid inconsistency with mfn_to_maddr() and gfn_to_gaddr(), I don't want ot
> introduce vfn_to_vaddr() withtout the typesafe part. I think this is a bit
> over the top for now.
> 
> So I will open-code pfn_to_paddr().

Sounds good


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit
  2022-04-02 16:18     ` Julien Grall
@ 2022-04-05 20:47       ` Stefano Stabellini
  0 siblings, 0 replies; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-05 20:47 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, xen-devel, Julien Grall, Bertrand Marquis,
	Volodymyr Babchuk

On Sat, 2 Apr 2022, Julien Grall wrote:
> On 02/04/2022 00:53, Stefano Stabellini wrote:
> > On Mon, 21 Feb 2022, Julien Grall wrote:
> > > @@ -1333,21 +1386,34 @@ static int xen_pt_update(unsigned long virt,
> > >       while ( left )
> > >       {
> > >           unsigned int order, level;
> > > +        unsigned int nr_contig;
> > > +        unsigned int new_flags;
> > >             level = xen_pt_mapping_level(vfn, mfn, left, flags);
> > >           order = XEN_PT_LEVEL_ORDER(level);
> > >             ASSERT(left >= BIT(order, UL));
> > >   -        rc = xen_pt_update_entry(root, pfn_to_paddr(vfn), mfn, level,
> > > flags);
> > > -        if ( rc )
> > > -            break;
> > > +        /*
> > > +         * Check if we can set the contiguous mapping and update the
> > > +         * flags accordingly.
> > > +         */
> > > +        nr_contig = xen_pt_check_contig(vfn, mfn, level, left, flags);
> > > +        new_flags = flags | ((nr_contig > 1) ? _PAGE_CONTIG : 0);
> > 
> > Here is an optional idea to make the code simpler. We could move the
> > flags changes (adding/removing _PAGE_CONTIG) to xen_pt_check_contig.
> > That way, we could remove the inner loop.
> > 
> > xen_pt_check_contig could check if _PAGE_CONTIG is already set and based
> > on alignment, it should be able to figure out when it needs to be
> > disabled.
> 
> My initial attempt was to do everything in a loop. But this didn't pan out as
> I wanted (I felt the code was complex) and there are extra work to be done for
> the next 31 entries (assuming 4KB granularity).
> 
> Hence the two loops. Unfortunately, I didn't keep my first attempt. So I can't
> realy show what I wrote.

I trusted you that the resulting code with a single loop was worse.

Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 06/19] xen/arm: mm: Avoid flushing the TLBs when mapping are inserted
  2022-04-02 16:38     ` Julien Grall
@ 2022-04-05 20:49       ` Stefano Stabellini
  2022-04-10 12:30         ` Julien Grall
  0 siblings, 1 reply; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-05 20:49 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, xen-devel, Julien Grall, Bertrand Marquis,
	Volodymyr Babchuk

On Sat, 2 Apr 2022, Julien Grall wrote:
> Hi Stefano,
> 
> On 02/04/2022 01:00, Stefano Stabellini wrote:
> > On Mon, 21 Feb 2022, Julien Grall wrote:
> > > From: Julien Grall <jgrall@amazon.com>
> > > 
> > > Currently, the function xen_pt_update() will flush the TLBs even when
> > > the mappings are inserted. This is a bit wasteful because we don't
> > > allow mapping replacement. Even if we were, the flush would need to
> > > happen earlier because mapping replacement should use Break-Before-Make
> > > when updating the entry.
> > > 
> > > A single call to xen_pt_update() can perform a single action. IOW, it
> > > is not possible to, for instance, mix inserting and removing mappings.
> > > Therefore, we can use `flags` to determine what action is performed.
> > > 
> > > This change will be particularly help to limit the impact of switching
> > > boot time mapping to use xen_pt_update().
> > > 
> > > Signed-off-by: Julien Grall <jgrall@amazon.com>
> > > 
> > > ---
> > >      Changes in v2:
> > >          - New patch
> > > ---
> > >   xen/arch/arm/mm.c | 17 ++++++++++++++---
> > >   1 file changed, 14 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> > > index fd16c1541ce2..7b4b9de8693e 100644
> > > --- a/xen/arch/arm/mm.c
> > > +++ b/xen/arch/arm/mm.c
> > > @@ -1104,7 +1104,13 @@ static bool xen_pt_check_entry(lpae_t entry, mfn_t
> > > mfn, unsigned int level,
> > >           /* We should be here with a valid MFN. */
> > >           ASSERT(!mfn_eq(mfn, INVALID_MFN));
> > >   -        /* We don't allow replacing any valid entry. */
> > > +        /*
> > > +         * We don't allow replacing any valid entry.
> > > +         *
> > > +         * Note that the function xen_pt_update() relies on this
> > > +         * assumption and will skip the TLB flush. The function will need
> > > +         * to be updated if the check is relaxed.
> > > +         */
> > >           if ( lpae_is_valid(entry) )
> > >           {
> > >               if ( lpae_is_mapping(entry, level) )
> > > @@ -1417,11 +1423,16 @@ static int xen_pt_update(unsigned long virt,
> > >       }
> > >         /*
> > > -     * Flush the TLBs even in case of failure because we may have
> > > +     * The TLBs flush can be safely skipped when a mapping is inserted
> > > +     * as we don't allow mapping replacement (see xen_pt_check_entry()).
> > > +     *
> > > +     * For all the other cases, the TLBs will be flushed unconditionally
> > > +     * even if the mapping has failed. This is because we may have
> > >        * partially modified the PT. This will prevent any unexpected
> > >        * behavior afterwards.
> > >        */
> > > -    flush_xen_tlb_range_va(virt, PAGE_SIZE * nr_mfns);
> > > +    if ( !(flags & _PAGE_PRESENT) || mfn_eq(mfn, INVALID_MFN) )
> > > +        flush_xen_tlb_range_va(virt, PAGE_SIZE * nr_mfns);
> > 
> > I am trying to think of a care where the following wouldn't be enough
> > but I cannot come up with one:
> > 
> >     if ( mfn_eq(mfn, INVALID_MFN) )
> >         flush_xen_tlb_range_va(virt, PAGE_SIZE * nr_mfns);
> 
> _PAGE_PRESENT is not set for two cases: when removing a page or populating
> page-tables for a region. Both of them will expect an INVALID_MFN (see the two
> asserts in xen_pt_check_entry()).
> 
> Therefore your solution should work. However, technically the 'mfn' is ignored
> in both situation (hence why this is an ASSERT() rather than a prod check).
> 
> Also, I feel it is better to flush more than less (missing a flush could have
> catastrophic result). So I chose to be explicit in which case the flush can be
> skipped.
> 
> Maybe it would be clearer if I write:
> 
>  !((flags & _PAGE_PRESENT) && !mfn_eq(mfn, INVALID_MFN))

It is not much a matter of clarity -- I just wanted to check with you
the reasons for the if condition because, as you wrote, wrong tlb
flushes can have catastrophic effects.

That said, actually I prefer your second version:

  !((flags & _PAGE_PRESENT) && !mfn_eq(mfn, INVALID_MFN))


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 07/19] xen/arm: mm: Don't open-code Xen PT update in remove_early_mappings()
  2022-04-02 16:47     ` Julien Grall
@ 2022-04-05 20:51       ` Stefano Stabellini
  0 siblings, 0 replies; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-05 20:51 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, xen-devel, Julien Grall, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

On Sat, 2 Apr 2022, Julien Grall wrote:
> On 02/04/2022 01:04, Stefano Stabellini wrote:
> > On Mon, 21 Feb 2022, Julien Grall wrote:
> > > From: Julien Grall <julien.grall@arm.com>
> > > 
> > > Now that xen_pt_update_entry() is able to deal with different mapping
> > > size, we can replace the open-coding of the page-tables update by a call
> > > to modify_xen_mappings().
> > > 
> > > As the function is not meant to fail, a BUG_ON() is added to check the
> > > return.
> > > 
> > > Signed-off-by: Julien Grall <julien.grall@arm.com>
> > > Signed-off-by: Julien Grall <jgrall@amazon.com>
> > 
> > Nice!
> > 
> > 
> > > ---
> > >      Changes in v2:
> > >          - Stay consistent with how function name are used in the commit
> > >          message
> > >          - Add my AWS signed-off-by
> > > ---
> > >   xen/arch/arm/mm.c | 10 +++++-----
> > >   1 file changed, 5 insertions(+), 5 deletions(-)
> > > 
> > > diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> > > index 7b4b9de8693e..f088a4b2de96 100644
> > > --- a/xen/arch/arm/mm.c
> > > +++ b/xen/arch/arm/mm.c
> > > @@ -599,11 +599,11 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
> > >     void __init remove_early_mappings(void)
> > >   {
> > > -    lpae_t pte = {0};
> > > -    write_pte(xen_second + second_table_offset(BOOT_FDT_VIRT_START),
> > > pte);
> > > -    write_pte(xen_second + second_table_offset(BOOT_FDT_VIRT_START +
> > > SZ_2M),
> > > -              pte);
> > > -    flush_xen_tlb_range_va(BOOT_FDT_VIRT_START, BOOT_FDT_SLOT_SIZE);
> > > +    int rc;
> > > +
> > > +    rc = modify_xen_mappings(BOOT_FDT_VIRT_START, BOOT_FDT_VIRT_END,
> > > +                             _PAGE_BLOCK);
> > > +    BUG_ON(rc);
> > 
> > Am I right that we are actually destroying the mapping, which usually is
> > done by calling destroy_xen_mappings, but we cannot call
> > destroy_xen_mappings in this case because it doesn't take a flags
> > parameter?
> 
> You are right.
> 
> > 
> > If so, then I would add a flags parameter to destroy_xen_mappings
> > instead of calling modify_xen_mappings just to pass _PAGE_BLOCK.
> > But I don't feel strongly about it so if you don't feel like making the
> > change to destroy_xen_mappings, you can add my acked-by here anyway.
> 
> destroy_xen_mappings() is a function used by common code. This is the only
> place so far where I need to pass _PAGE_BLOCK and I don't expect it to be used
> by the common code any time soon.
> 
> So I am not in favor to add an extra parameter for destroy_xen_mappings().
> 
> Would you prefer if I open-code the call to xen_pt_update?

No need, just add a one-line in-code comment like:

    /* destroy the _PAGE_BLOCK mapping */


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 12/19] xen/arm: mm: Allow page-table allocation from the boot allocator
  2022-02-21 10:22 ` [PATCH v3 12/19] xen/arm: mm: Allow page-table allocation from the boot allocator Julien Grall
@ 2022-04-05 20:58   ` Stefano Stabellini
  0 siblings, 0 replies; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-05 20:58 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <julien.grall@arm.com>
> 
> At the moment, page-table can only be allocated from domheap. This means
> it is not possible to create mapping in the page-tables via
> map_pages_to_xen() if page-table needs to be allocated.
> 
> In order to avoid open-coding page-tables update in early boot, we need
> to be able to allocate page-tables much earlier. Thankfully, we have the
> boot allocator for those cases.
> 
> create_xen_table() is updated to cater early boot allocation by using
> alloc_boot_pages().
> 
> Note, this is not sufficient to bootstrap the page-tables (i.e mapping
> before any memory is actually mapped). This will be addressed
> separately.
> 
> Signed-off-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Julien Grall <jgrall@amazon.com>

Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>     Changes in v2:
>         - New patch
> ---
>  xen/arch/arm/mm.c | 20 ++++++++++++++------
>  1 file changed, 14 insertions(+), 6 deletions(-)
> 
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index 58364bb6c820..f70b8cc7ce87 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -1014,19 +1014,27 @@ static void xen_unmap_table(const lpae_t *table)
>  
>  static int create_xen_table(lpae_t *entry)
>  {
> -    struct page_info *pg;
> +    mfn_t mfn;
>      void *p;
>      lpae_t pte;
>  
> -    pg = alloc_domheap_page(NULL, 0);
> -    if ( pg == NULL )
> -        return -ENOMEM;
> +    if ( system_state != SYS_STATE_early_boot )
> +    {
> +        struct page_info *pg = alloc_domheap_page(NULL, 0);
> +
> +        if ( pg == NULL )
> +            return -ENOMEM;
> +
> +        mfn = page_to_mfn(pg);
> +    }
> +    else
> +        mfn = alloc_boot_pages(1, 1);
>  
> -    p = xen_map_table(page_to_mfn(pg));
> +    p = xen_map_table(mfn);
>      clear_page(p);
>      xen_unmap_table(p);
>  
> -    pte = mfn_to_xen_entry(page_to_mfn(pg), MT_NORMAL);
> +    pte = mfn_to_xen_entry(mfn, MT_NORMAL);
>      pte.pt.table = 1;
>      write_pte(entry, pte);


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 13/19] xen/arm: Move fixmap definitions in a separate header
  2022-02-21 10:22 ` [PATCH v3 13/19] xen/arm: Move fixmap definitions in a separate header Julien Grall
  2022-02-22 15:10   ` Jan Beulich
@ 2022-04-05 21:12   ` Stefano Stabellini
  2022-04-05 21:47     ` Julien Grall
  1 sibling, 1 reply; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-05 21:12 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Jan Beulich,
	Wei Liu

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> To use properly the fixmap definitions, their user would need
> also new to include <xen/acpi.h>. This is not very great when
> the user itself is not meant to directly use ACPI definitions.
> 
> Including <xen/acpi.h> in <asm/config.h> is not option because
> the latter header is included by everyone. So move out the fixmap
> entries definition in a new header.
> 
> Take the opportunity to also move {set, clear}_fixmap() prototypes
> in the new header.
> 
> Note that most of the definitions in <xen/acpi.h> now need to be
> surrounded with #ifndef __ASSEMBLY__ because <asm/fixmap.h> will
> be used in assembly (see EARLY_UART_VIRTUAL_ADDRESS).
> 
> The split will become more helpful in a follow-up patch where new
> fixmap entries will be defined.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v3:
>         - Patch added
> ---
>  xen/arch/arm/acpi/lib.c                 |  2 ++
>  xen/arch/arm/include/asm/config.h       |  6 ------
>  xen/arch/arm/include/asm/early_printk.h |  1 +
>  xen/arch/arm/include/asm/fixmap.h       | 24 ++++++++++++++++++++++++
>  xen/arch/arm/include/asm/mm.h           |  4 ----
>  xen/arch/arm/kernel.c                   |  1 +
>  xen/arch/arm/mm.c                       |  1 +
>  xen/include/xen/acpi.h                  | 18 +++++++++++-------
>  8 files changed, 40 insertions(+), 17 deletions(-)
>  create mode 100644 xen/arch/arm/include/asm/fixmap.h
> 
> diff --git a/xen/arch/arm/acpi/lib.c b/xen/arch/arm/acpi/lib.c
> index a59cc4074cfb..41d521f720ac 100644
> --- a/xen/arch/arm/acpi/lib.c
> +++ b/xen/arch/arm/acpi/lib.c
> @@ -25,6 +25,8 @@
>  #include <xen/init.h>
>  #include <xen/mm.h>
>  
> +#include <asm/fixmap.h>
> +
>  static bool fixmap_inuse;
>  
>  char *__acpi_map_table(paddr_t phys, unsigned long size)
> diff --git a/xen/arch/arm/include/asm/config.h b/xen/arch/arm/include/asm/config.h
> index 85d4a510ce8a..51908bf9422c 100644
> --- a/xen/arch/arm/include/asm/config.h
> +++ b/xen/arch/arm/include/asm/config.h
> @@ -175,12 +175,6 @@
>  
>  #endif
>  
> -/* Fixmap slots */
> -#define FIXMAP_CONSOLE  0  /* The primary UART */
> -#define FIXMAP_MISC     1  /* Ephemeral mappings of hardware */
> -#define FIXMAP_ACPI_BEGIN  2  /* Start mappings of ACPI tables */
> -#define FIXMAP_ACPI_END    (FIXMAP_ACPI_BEGIN + NUM_FIXMAP_ACPI_PAGES - 1)  /* End mappings of ACPI tables */
> -
>  #define NR_hypercalls 64
>  
>  #define STACK_ORDER 3
> diff --git a/xen/arch/arm/include/asm/early_printk.h b/xen/arch/arm/include/asm/early_printk.h
> index 8dc911cf48a3..c5149b2976da 100644
> --- a/xen/arch/arm/include/asm/early_printk.h
> +++ b/xen/arch/arm/include/asm/early_printk.h
> @@ -11,6 +11,7 @@
>  #define __ARM_EARLY_PRINTK_H__
>  
>  #include <xen/page-size.h>
> +#include <asm/fixmap.h>
>  
>  #ifdef CONFIG_EARLY_PRINTK
>  
> diff --git a/xen/arch/arm/include/asm/fixmap.h b/xen/arch/arm/include/asm/fixmap.h
> new file mode 100644
> index 000000000000..1cee51e52ab9
> --- /dev/null
> +++ b/xen/arch/arm/include/asm/fixmap.h
> @@ -0,0 +1,24 @@
> +/*
> + * fixmap.h: compile-time virtual memory allocation
> + */
> +#ifndef __ASM_FIXMAP_H
> +#define __ASM_FIXMAP_H
> +
> +#include <xen/acpi.h>
> +
> +/* Fixmap slots */
> +#define FIXMAP_CONSOLE  0  /* The primary UART */
> +#define FIXMAP_MISC     1  /* Ephemeral mappings of hardware */
> +#define FIXMAP_ACPI_BEGIN  2  /* Start mappings of ACPI tables */
> +#define FIXMAP_ACPI_END    (FIXMAP_ACPI_BEGIN + NUM_FIXMAP_ACPI_PAGES - 1)  /* End mappings of ACPI tables */
> +
> +#ifndef __ASSEMBLY__
> +
> +/* Map a page in a fixmap entry */
> +extern void set_fixmap(unsigned map, mfn_t mfn, unsigned attributes);
> +/* Remove a mapping from a fixmap entry */
> +extern void clear_fixmap(unsigned map);
> +
> +#endif /* __ASSEMBLY__ */
> +
> +#endif /* __ASM_FIXMAP_H */


It is a good idea to create fixmap.h, but I think it should be acpi.h to
include fixmap.h, not the other way around.

The appended changes build correctly on top of this patch.


diff --git a/xen/arch/arm/include/asm/fixmap.h b/xen/arch/arm/include/asm/fixmap.h
index 1cee51e52a..8cf9dbb618 100644
--- a/xen/arch/arm/include/asm/fixmap.h
+++ b/xen/arch/arm/include/asm/fixmap.h
@@ -4,8 +4,6 @@
 #ifndef __ASM_FIXMAP_H
 #define __ASM_FIXMAP_H
 
-#include <xen/acpi.h>
-
 /* Fixmap slots */
 #define FIXMAP_CONSOLE  0  /* The primary UART */
 #define FIXMAP_MISC     1  /* Ephemeral mappings of hardware */
@@ -14,6 +12,8 @@
 
 #ifndef __ASSEMBLY__
 
+#include <xen/mm-frame.h>
+
 /* Map a page in a fixmap entry */
 extern void set_fixmap(unsigned map, mfn_t mfn, unsigned attributes);
 /* Remove a mapping from a fixmap entry */
diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
index 1b9c75e68f..148673e77c 100644
--- a/xen/include/xen/acpi.h
+++ b/xen/include/xen/acpi.h
@@ -28,6 +28,8 @@
 #define _LINUX
 #endif
 
+#include <asm/fixmap.h>
+
 /*
  * Fixmap pages to reserve for ACPI boot-time tables (see
  * arch/x86/include/asm/fixmap.h or arch/arm/include/asm/fixmap.h),


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure
  2022-02-21 10:22 ` [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure Julien Grall
  2022-02-22 15:22   ` Jan Beulich
@ 2022-04-05 21:27   ` Stefano Stabellini
  2022-05-14 10:17     ` Julien Grall
  1 sibling, 1 reply; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-05 21:27 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Wei Liu, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, George Dunlap, Hongyan Xia, Julien Grall,
	Jan Beulich, Wei Liu, Andrew Cooper, Roger Pau Monné

[-- Attachment #1: Type: text/plain, Size: 10202 bytes --]

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Wei Liu <wei.liu2@citrix.com>
> 
> The basic idea is like Persistent Kernel Map (PKMAP) in Linux. We
> pre-populate all the relevant page tables before the system is fully
> set up.
> 
> We will need it on Arm in order to rework the arm64 version of
> xenheap_setup_mappings() as we may need to use pages allocated from
> the boot allocator before they are effectively mapped.
> 
> This infrastructure is not lock-protected therefore can only be used
> before smpboot. After smpboot, map_domain_page() has to be used.
> 
> This is based on the x86 version [1] that was originally implemented
> by Wei Liu.
> 
> The PMAP infrastructure is implemented in common code with some
> arch helpers to set/clear the page-table entries and convertion
> between a fixmap slot to a virtual address...
> 
> As mfn_to_xen_entry() now needs to be exported, take the opportunity
> to swich the parameter attr from unsigned to unsigned int.
> 
> [1] <e92da4ad6015b6089737fcccba3ec1d6424649a5.1588278317.git.hongyxia@amazon.com>
> 
> Signed-off-by: Wei Liu <wei.liu2@citrix.com>
> Signed-off-by: Hongyan Xia <hongyxia@amazon.com>
> [julien: Adapted for Arm]
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v3:
>         - s/BITS_PER_LONG/BITS_PER_BYTE/
>         - Move pmap to common code
> 
>     Changes in v2:
>         - New patch
> 
> Cc: Jan Beulich <jbeulich@suse.com>
> Cc: Wei Liu <wl@xen.org>
> Cc: Andrew Cooper <andrew.cooper3@citrix.com>
> Cc: Roger Pau Monné <roger.pau@citrix.com>
> ---
>  xen/arch/arm/Kconfig              |  1 +
>  xen/arch/arm/include/asm/fixmap.h | 17 +++++++
>  xen/arch/arm/include/asm/lpae.h   |  8 ++++
>  xen/arch/arm/include/asm/pmap.h   | 33 +++++++++++++
>  xen/arch/arm/mm.c                 |  7 +--
>  xen/common/Kconfig                |  3 ++
>  xen/common/Makefile               |  1 +
>  xen/common/pmap.c                 | 79 +++++++++++++++++++++++++++++++
>  xen/include/xen/pmap.h            | 16 +++++++
>  9 files changed, 159 insertions(+), 6 deletions(-)
>  create mode 100644 xen/arch/arm/include/asm/pmap.h
>  create mode 100644 xen/common/pmap.c
>  create mode 100644 xen/include/xen/pmap.h
> 
> diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
> index ecfa6822e4d3..a89a67802aa9 100644
> --- a/xen/arch/arm/Kconfig
> +++ b/xen/arch/arm/Kconfig
> @@ -14,6 +14,7 @@ config ARM
>  	select HAS_DEVICE_TREE
>  	select HAS_PASSTHROUGH
>  	select HAS_PDX
> +	select HAS_PMAP
>  	select IOMMU_FORCE_PT_SHARE
>  
>  config ARCH_DEFCONFIG
> diff --git a/xen/arch/arm/include/asm/fixmap.h b/xen/arch/arm/include/asm/fixmap.h
> index 1cee51e52ab9..c46a15e59de4 100644
> --- a/xen/arch/arm/include/asm/fixmap.h
> +++ b/xen/arch/arm/include/asm/fixmap.h
> @@ -5,12 +5,20 @@
>  #define __ASM_FIXMAP_H
>  
>  #include <xen/acpi.h>
> +#include <xen/pmap.h>
>  
>  /* Fixmap slots */
>  #define FIXMAP_CONSOLE  0  /* The primary UART */
>  #define FIXMAP_MISC     1  /* Ephemeral mappings of hardware */
>  #define FIXMAP_ACPI_BEGIN  2  /* Start mappings of ACPI tables */
>  #define FIXMAP_ACPI_END    (FIXMAP_ACPI_BEGIN + NUM_FIXMAP_ACPI_PAGES - 1)  /* End mappings of ACPI tables */
> +#define FIXMAP_PMAP_BEGIN (FIXMAP_ACPI_END + 1) /* Start of PMAP */
> +#define FIXMAP_PMAP_END (FIXMAP_PMAP_BEGIN + NUM_FIX_PMAP - 1) /* End of PMAP */
> +
> +#define FIXMAP_LAST FIXMAP_PMAP_END
> +
> +#define FIXADDR_START FIXMAP_ADDR(0)
> +#define FIXADDR_TOP FIXMAP_ADDR(FIXMAP_LAST)
>  
>  #ifndef __ASSEMBLY__
>  
> @@ -19,6 +27,15 @@ extern void set_fixmap(unsigned map, mfn_t mfn, unsigned attributes);
>  /* Remove a mapping from a fixmap entry */
>  extern void clear_fixmap(unsigned map);
>  
> +#define fix_to_virt(slot) ((void *)FIXMAP_ADDR(slot))
> +
> +static inline unsigned int virt_to_fix(vaddr_t vaddr)
> +{
> +    BUG_ON(vaddr >= FIXADDR_TOP || vaddr < FIXADDR_START);
> +
> +    return ((vaddr - FIXADDR_START) >> PAGE_SHIFT);
> +}
> +
>  #endif /* __ASSEMBLY__ */
>  
>  #endif /* __ASM_FIXMAP_H */
> diff --git a/xen/arch/arm/include/asm/lpae.h b/xen/arch/arm/include/asm/lpae.h
> index 8cf932b5c947..6099037da1c0 100644
> --- a/xen/arch/arm/include/asm/lpae.h
> +++ b/xen/arch/arm/include/asm/lpae.h
> @@ -4,6 +4,7 @@
>  #ifndef __ASSEMBLY__
>  
>  #include <xen/page-defs.h>
> +#include <xen/mm-frame.h>
>  
>  /*
>   * WARNING!  Unlike the x86 pagetable code, where l1 is the lowest level and
> @@ -168,6 +169,13 @@ static inline bool lpae_is_superpage(lpae_t pte, unsigned int level)
>          third_table_offset(addr)            \
>      }
>  
> +/*
> + * Standard entry type that we'll use to build Xen's own pagetables.
> + * We put the same permissions at every level, because they're ignored
> + * by the walker in non-leaf entries.
> + */
> +lpae_t mfn_to_xen_entry(mfn_t mfn, unsigned int attr);
> +
>  #endif /* __ASSEMBLY__ */
>  
>  /*
> diff --git a/xen/arch/arm/include/asm/pmap.h b/xen/arch/arm/include/asm/pmap.h
> new file mode 100644
> index 000000000000..70eafe2891d7
> --- /dev/null
> +++ b/xen/arch/arm/include/asm/pmap.h
> @@ -0,0 +1,33 @@
> +#ifndef __ASM_PMAP_H__
> +#define __ASM_PMAP_H__
> +
> +#include <xen/mm.h>
> +
> +/* XXX: Find an header to declare it */
> +extern lpae_t xen_fixmap[XEN_PT_LPAE_ENTRIES];

Why not fixmap.h?

The rest of the ARM stuff looks fine.


> +static inline void arch_pmap_map(unsigned int slot, mfn_t mfn)
> +{
> +    lpae_t *entry = &xen_fixmap[slot];
> +    lpae_t pte;
> +
> +    ASSERT(!lpae_is_valid(*entry));
> +
> +    pte = mfn_to_xen_entry(mfn, PAGE_HYPERVISOR_RW);
> +    pte.pt.table = 1;
> +    write_pte(entry, pte);
> +}
> +
> +static inline void arch_pmap_unmap(unsigned int slot)
> +{
> +    lpae_t pte = {};
> +
> +    write_pte(&xen_fixmap[slot], pte);
> +
> +    flush_xen_tlb_range_va_local(FIXMAP_ADDR(slot), PAGE_SIZE);
> +}
> +
> +void arch_pmap_map_slot(unsigned int slot, mfn_t mfn);
> +void arch_pmap_clear_slot(void *ptr);
> +
> +#endif /* __ASM_PMAP_H__ */
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index d6a4b9407c43..b7942464d4de 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -290,12 +290,7 @@ void dump_hyp_walk(vaddr_t addr)
>      dump_pt_walk(ttbr, addr, HYP_PT_ROOT_LEVEL, 1);
>  }
>  
> -/*
> - * Standard entry type that we'll use to build Xen's own pagetables.
> - * We put the same permissions at every level, because they're ignored
> - * by the walker in non-leaf entries.
> - */
> -static inline lpae_t mfn_to_xen_entry(mfn_t mfn, unsigned attr)
> +lpae_t mfn_to_xen_entry(mfn_t mfn, unsigned int attr)
>  {
>      lpae_t e = (lpae_t) {
>          .pt = {
> diff --git a/xen/common/Kconfig b/xen/common/Kconfig
> index db687b1785e7..b6c55af2eb03 100644
> --- a/xen/common/Kconfig
> +++ b/xen/common/Kconfig
> @@ -49,6 +49,9 @@ config HAS_KEXEC
>  config HAS_PDX
>  	bool
>  
> +config HAS_PMAP
> +	bool
> +
>  config HAS_SCHED_GRANULARITY
>  	bool
>  
> diff --git a/xen/common/Makefile b/xen/common/Makefile
> index ca839118e4d1..8b42b0828134 100644
> --- a/xen/common/Makefile
> +++ b/xen/common/Makefile
> @@ -28,6 +28,7 @@ obj-y += multicall.o
>  obj-y += notifier.o
>  obj-y += page_alloc.o
>  obj-$(CONFIG_HAS_PDX) += pdx.o
> +obj-bin-$(CONFIG_HAS_PMAP) += pmap.init.o
>  obj-$(CONFIG_PERF_COUNTERS) += perfc.o
>  obj-y += preempt.o
>  obj-y += random.o
> diff --git a/xen/common/pmap.c b/xen/common/pmap.c
> new file mode 100644
> index 000000000000..cea730ead545
> --- /dev/null
> +++ b/xen/common/pmap.c
> @@ -0,0 +1,79 @@
> +#include <xen/bitops.h>
> +#include <xen/init.h>
> +#include <xen/pmap.h>
> +
> +#include <asm/pmap.h>
> +#include <asm/fixmap.h>
> +
> +/*
> + * Simple mapping infrastructure to map / unmap pages in fixed map.
> + * This is used to set up the page table for mapcache, which is used
> + * by map domain page infrastructure.
> + *
> + * This structure is not protected by any locks, so it must not be used after
> + * smp bring-up.
> + */
> +
> +/* Bitmap to track which slot is used */
> +static unsigned long __initdata inuse;
> +
> +void *__init pmap_map(mfn_t mfn)
> +{
> +    unsigned long flags;
> +    unsigned int idx;
> +    unsigned int slot;
> +
> +    BUILD_BUG_ON(sizeof(inuse) * BITS_PER_BYTE < NUM_FIX_PMAP);
> +
> +    ASSERT(system_state < SYS_STATE_smp_boot);
> +
> +    local_irq_save(flags);
> +
> +    idx = find_first_zero_bit(&inuse, NUM_FIX_PMAP);
> +    if ( idx == NUM_FIX_PMAP )
> +        panic("Out of PMAP slots\n");
> +
> +    __set_bit(idx, &inuse);
> +
> +    slot = idx + FIXMAP_PMAP_BEGIN;
> +    ASSERT(slot >= FIXMAP_PMAP_BEGIN && slot <= FIXMAP_PMAP_END);
> +
> +    /*
> +     * We cannot use set_fixmap() here. We use PMAP when there is no direct map,
> +     * so map_pages_to_xen() called by set_fixmap() needs to map pages on
> +     * demand, which then calls pmap() again, resulting in a loop. Modify the
> +     * PTEs directly instead. The same is true for pmap_unmap().
> +     */
> +    arch_pmap_map(slot, mfn);
> +
> +    local_irq_restore(flags);
> +
> +    return fix_to_virt(slot);
> +}
> +
> +void __init pmap_unmap(const void *p)
> +{
> +    unsigned long flags;
> +    unsigned int idx;
> +    unsigned int slot = virt_to_fix((unsigned long)p);
> +
> +    ASSERT(system_state < SYS_STATE_smp_boot);
> +    ASSERT(slot >= FIXMAP_PMAP_BEGIN && slot <= FIXMAP_PMAP_END);
> +
> +    idx = slot - FIXMAP_PMAP_BEGIN;
> +    local_irq_save(flags);
> +
> +    __clear_bit(idx, &inuse);
> +    arch_pmap_unmap(slot);
> +
> +    local_irq_restore(flags);
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/include/xen/pmap.h b/xen/include/xen/pmap.h
> new file mode 100644
> index 000000000000..93e61b10870e
> --- /dev/null
> +++ b/xen/include/xen/pmap.h
> @@ -0,0 +1,16 @@
> +#ifndef __XEN_PMAP_H__
> +#define __XEN_PMAP_H__
> +
> +/* Large enough for mapping 5 levels of page tables with some headroom */
> +#define NUM_FIX_PMAP 8
> +
> +#ifndef __ASSEMBLY__
> +
> +#include <xen/mm-frame.h>
> +
> +void *pmap_map(mfn_t mfn);
> +void pmap_unmap(const void *p);
> +
> +#endif /* __ASSEMBLY__ */
> +
> +#endif /* __XEN_PMAP_H__ */
> -- 
> 2.32.0
> 

^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 15/19] xen/arm: mm: Clean-up the includes and order them
  2022-02-21 10:22 ` [PATCH v3 15/19] xen/arm: mm: Clean-up the includes and order them Julien Grall
@ 2022-04-05 21:29   ` Stefano Stabellini
  0 siblings, 0 replies; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-05 21:29 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> The numbers of includes in mm.c has been growing quite a lot. However
> some of them (e.g. xen/device_tree.h, xen/softirq.h) doesn't look
> to be directly used by the file or other will be included by
> larger headers (e.g asm/flushtlb.h will be included by xen/mm.h).
> 
> So trim down the number of includes. Take the opportunity to order
> them with the xen headers first, then asm headers and last public
> headers.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>

I'll trust you on this one :-)

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>     Changes in v3:
>         - Patch added
> ---
>  xen/arch/arm/mm.c | 27 ++++++++++-----------------
>  1 file changed, 10 insertions(+), 17 deletions(-)
> 
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index b7942464d4de..659bdf25e0ff 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -17,33 +17,26 @@
>   * GNU General Public License for more details.
>   */
>  
> -#include <xen/compile.h>
> -#include <xen/types.h>
> -#include <xen/device_tree.h>
> -#include <xen/init.h>
> -#include <xen/mm.h>
> -#include <xen/preempt.h>
> +#include <xen/domain_page.h>
>  #include <xen/errno.h>
>  #include <xen/grant_table.h>
> -#include <xen/softirq.h>
> -#include <xen/event.h>
>  #include <xen/guest_access.h>
> -#include <xen/domain_page.h>
> -#include <xen/err.h>
> -#include <asm/page.h>
> -#include <asm/current.h>
> -#include <asm/flushtlb.h>
> -#include <public/memory.h>
> +#include <xen/init.h>
> +#include <xen/libfdt/libfdt.h>
> +#include <xen/mm.h>
> +#include <xen/pfn.h>
>  #include <xen/sched.h>
> +#include <xen/sizes.h>
> +#include <xen/types.h>
>  #include <xen/vmap.h>
> +
>  #include <xsm/xsm.h>
> -#include <xen/pfn.h>
> -#include <xen/sizes.h>
> -#include <xen/libfdt/libfdt.h>
>  
>  #include <asm/fixmap.h>
>  #include <asm/setup.h>
>  
> +#include <public/memory.h>
> +
>  /* Override macros from asm/page.h to make them work with mfn_t */
>  #undef virt_to_mfn
>  #define virt_to_mfn(va) _mfn(__virt_to_mfn(va))
> -- 
> 2.32.0
> 


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 16/19] xen/arm: mm: Use the PMAP helpers in xen_{,un}map_table()
  2022-02-21 10:22 ` [PATCH v3 16/19] xen/arm: mm: Use the PMAP helpers in xen_{,un}map_table() Julien Grall
@ 2022-04-05 21:36   ` Stefano Stabellini
  0 siblings, 0 replies; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-05 21:36 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> During early boot, it is not possible to use xen_{,un}map_table()
> if the page tables are not residing the Xen binary.
> 
> This is a blocker to switch some of the helpers to use xen_pt_update()
> as we may need to allocate extra page tables and access them before
> the domheap has been initialized (see setup_xenheap_mappings()).
> 
> xen_{,un}map_table() are now updated to use the PMAP helpers for early
> boot map/unmap. Note that the special case for page-tables residing
> in Xen binary has been dropped because it is "complex" and was
> only added as a workaround in 8d4f1b8878e0 ("xen/arm: mm: Allow
> generic xen page-tables helpers to be called early").
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>


Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
>     Changes in v2:
>         - New patch
> ---
>  xen/arch/arm/mm.c | 33 +++++++++------------------------
>  1 file changed, 9 insertions(+), 24 deletions(-)
> 
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index 659bdf25e0ff..11b6b60a2bc1 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -25,6 +25,7 @@
>  #include <xen/libfdt/libfdt.h>
>  #include <xen/mm.h>
>  #include <xen/pfn.h>
> +#include <xen/pmap.h>
>  #include <xen/sched.h>
>  #include <xen/sizes.h>
>  #include <xen/types.h>
> @@ -964,27 +965,11 @@ void *ioremap(paddr_t pa, size_t len)
>  static lpae_t *xen_map_table(mfn_t mfn)
>  {
>      /*
> -     * We may require to map the page table before map_domain_page() is
> -     * useable. The requirements here is it must be useable as soon as
> -     * page-tables are allocated dynamically via alloc_boot_pages().
> -     *
> -     * We need to do the check on physical address rather than virtual
> -     * address to avoid truncation on Arm32. Therefore is_kernel() cannot
> -     * be used.
> +     * During early boot, map_domain_page() may be unusable. Use the
> +     * PMAP to map temporarily a page-table.
>       */
>      if ( system_state == SYS_STATE_early_boot )
> -    {
> -        if ( is_xen_fixed_mfn(mfn) )
> -        {
> -            /*
> -             * It is fine to demote the type because the size of Xen
> -             * will always fit in vaddr_t.
> -             */
> -            vaddr_t offset = mfn_to_maddr(mfn) - virt_to_maddr(&_start);
> -
> -            return (lpae_t *)(XEN_VIRT_START + offset);
> -        }
> -    }
> +        return pmap_map(mfn);
>  
>      return map_domain_page(mfn);
>  }
> @@ -993,12 +978,12 @@ static void xen_unmap_table(const lpae_t *table)
>  {
>      /*
>       * During early boot, xen_map_table() will not use map_domain_page()
> -     * for page-tables residing in Xen binary. So skip the unmap part.
> +     * but the PMAP.
>       */
> -    if ( system_state == SYS_STATE_early_boot && is_kernel(table) )
> -        return;
> -
> -    unmap_domain_page(table);
> +    if ( system_state == SYS_STATE_early_boot )
> +        pmap_unmap(table);
> +    else
> +        unmap_domain_page(table);
>  }
>  
>  static int create_xen_table(lpae_t *entry)
> -- 
> 2.32.0
> 


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 13/19] xen/arm: Move fixmap definitions in a separate header
  2022-04-05 21:12   ` Stefano Stabellini
@ 2022-04-05 21:47     ` Julien Grall
  2022-04-06  0:10       ` Stefano Stabellini
  0 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-04-05 21:47 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, Julien Grall, Bertrand Marquis, Volodymyr Babchuk,
	Andrew Cooper, George Dunlap, Jan Beulich, Wei Liu

Hi Stefano,

On 05/04/2022 22:12, Stefano Stabellini wrote:
>> +/* Map a page in a fixmap entry */
>> +extern void set_fixmap(unsigned map, mfn_t mfn, unsigned attributes);
>> +/* Remove a mapping from a fixmap entry */
>> +extern void clear_fixmap(unsigned map);
>> +
>> +#endif /* __ASSEMBLY__ */
>> +
>> +#endif /* __ASM_FIXMAP_H */
> 
> 
> It is a good idea to create fixmap.h, but I think it should be acpi.h to
> include fixmap.h, not the other way around.

As I wrote in the commit message, one definition in fixmap.h rely on 
define from acpi.h (i.e NUM_FIXMAP_ACPI_PAGES). So if we don't include 
it, then user of FIXMAP_PMAP_BEGIN (see next patch) will requires to 
include acpi.h in order to build.

Re-ordering the values would not help because the problem would exactly 
be the same but this time the acpi users would have to include pmap.h to 
define NUM_FIX_PMAP.

> 
> The appended changes build correctly on top of this patch.

That's expected because all the users of FIXMAP_ACPI_END will be 
including acpi.h. But after the next patch, we would need pmap.c to 
include acpi.h.

I don't think this would be right (and quite likely you would ask why
this is done). Hence this approach.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 17/19] xen/arm64: mm: Add memory to the boot allocator first
  2022-02-21 10:22 ` [PATCH v3 17/19] xen/arm64: mm: Add memory to the boot allocator first Julien Grall
@ 2022-04-05 21:50   ` Stefano Stabellini
  2022-04-05 22:12     ` Julien Grall
  0 siblings, 1 reply; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-05 21:50 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> Currently, memory is added to the boot allocator after the xenheap
> mappings are done. This will break if the first mapping is more than
> 512GB of RAM.
> 
> In addition to that, a follow-up patch will rework setup_xenheap_mappings()
> to use smaller mappings (e.g. 2MB, 4KB). So it will be necessary to have
> memory in the boot allocator earlier.
> 
> Only free memory (e.g. not reserved or modules) can be added to the boot
> allocator. It might be possible that some regions (including the first
> one) will have no free memory.
> 
> So we need to add all the free memory to the boot allocator first
> and then add do the mappings.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v3:
>         - Patch added
> ---
>  xen/arch/arm/setup.c | 63 +++++++++++++++++++++++++++++---------------
>  1 file changed, 42 insertions(+), 21 deletions(-)
> 
> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
> index d5d0792ed48a..777cf96639f5 100644
> --- a/xen/arch/arm/setup.c
> +++ b/xen/arch/arm/setup.c
> @@ -767,30 +767,18 @@ static void __init setup_mm(void)
>      init_staticmem_pages();
>  }
>  #else /* CONFIG_ARM_64 */
> -static void __init setup_mm(void)
> +static void __init populate_boot_allocator(void)
>  {
> -    paddr_t ram_start = ~0;
> -    paddr_t ram_end = 0;
> -    paddr_t ram_size = 0;
> -    int bank;
> -
> -    init_pdx();
> +    unsigned int i;
> +    const struct meminfo *banks = &bootinfo.mem;
>  
> -    total_pages = 0;
> -    for ( bank = 0 ; bank < bootinfo.mem.nr_banks; bank++ )
> +    for ( i = 0; i < banks->nr_banks; i++ )
>      {
> -        paddr_t bank_start = bootinfo.mem.bank[bank].start;
> -        paddr_t bank_size = bootinfo.mem.bank[bank].size;
> -        paddr_t bank_end = bank_start + bank_size;
> +        const struct membank *bank = &banks->bank[i];
> +        paddr_t bank_end = bank->start + bank->size;
>          paddr_t s, e;
>  
> -        ram_size = ram_size + bank_size;
> -        ram_start = min(ram_start,bank_start);
> -        ram_end = max(ram_end,bank_end);
> -
> -        setup_xenheap_mappings(bank_start>>PAGE_SHIFT, bank_size>>PAGE_SHIFT);
> -
> -        s = bank_start;
> +        s = bank->start;
>          while ( s < bank_end )
>          {
>              paddr_t n = bank_end;
> @@ -798,9 +786,7 @@ static void __init setup_mm(void)
>              e = next_module(s, &n);
>  
>              if ( e == ~(paddr_t)0 )
> -            {
>                  e = n = bank_end;
> -            }
>  
>              if ( e > bank_end )
>                  e = bank_end;
> @@ -809,6 +795,41 @@ static void __init setup_mm(void)
>              s = n;
>          }
>      }
> +}
> +
> +static void __init setup_mm(void)
> +{
> +    const struct meminfo *banks = &bootinfo.mem;
> +    paddr_t ram_start = ~0;
> +    paddr_t ram_end = 0;
> +    paddr_t ram_size = 0;
> +    unsigned int i;
> +
> +    init_pdx();
> +
> +    /*
> +     * We need some memory to allocate the page-tables used for the xenheap
> +     * mappings. But some regions may contain memory already allocated
> +     * for other uses (e.g. modules, reserved-memory...).
> +     *
> +     * For simplify add all the free regions in the boot allocator.
> +     */

We currently have:

BUG_ON(nr_bootmem_regions == (PAGE_SIZE / sizeof(struct bootmem_region)));

Do you think we should check for the limit in populate_boot_allocator?
Or there is no need because it is unrealistic to reach it?


> +    populate_boot_allocator();
> +
> +    total_pages = 0;
> +
> +    for ( i = 0; i < banks->nr_banks; i++ )
> +    {
> +        const struct membank *bank = &banks->bank[i];
> +        paddr_t bank_end = bank->start + bank->size;
> +
> +        ram_size = ram_size + bank->size;
> +        ram_start = min(ram_start, bank->start);
> +        ram_end = max(ram_end, bank_end);
> +
> +        setup_xenheap_mappings(PFN_DOWN(bank->start),
> +                               PFN_DOWN(bank->size));
> +    }
>  
>      total_pages += ram_size >> PAGE_SHIFT;
>  
> -- 
> 2.32.0
> 


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 17/19] xen/arm64: mm: Add memory to the boot allocator first
  2022-04-05 21:50   ` Stefano Stabellini
@ 2022-04-05 22:12     ` Julien Grall
  2022-04-06  0:02       ` Stefano Stabellini
  0 siblings, 1 reply; 79+ messages in thread
From: Julien Grall @ 2022-04-05 22:12 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, Julien Grall, Bertrand Marquis, Volodymyr Babchuk

Hi Stefano,

On 05/04/2022 22:50, Stefano Stabellini wrote:
>> +static void __init setup_mm(void)
>> +{
>> +    const struct meminfo *banks = &bootinfo.mem;
>> +    paddr_t ram_start = ~0;
>> +    paddr_t ram_end = 0;
>> +    paddr_t ram_size = 0;
>> +    unsigned int i;
>> +
>> +    init_pdx();
>> +
>> +    /*
>> +     * We need some memory to allocate the page-tables used for the xenheap
>> +     * mappings. But some regions may contain memory already allocated
>> +     * for other uses (e.g. modules, reserved-memory...).
>> +     *
>> +     * For simplify add all the free regions in the boot allocator.
>> +     */
> 
> We currently have:
> 
> BUG_ON(nr_bootmem_regions == (PAGE_SIZE / sizeof(struct bootmem_region)));

This has enough space for 256 distinct regions on arm64 (512 regions on 
arm32).

> 
> Do you think we should check for the limit in populate_boot_allocator?

This patch doesn't change the number of regions added to the boot 
allocator. So if we need to check the limit then I would rather deal 
separately (see more below).

> Or there is no need because it is unrealistic to reach it?
I can't say never because history told us on some UEFI systems, there 
will be a large number of regions exposed. I haven't heard anyone that 
would hit the BUG_ON().

The problem is what do we do if we hit the limit? We could ignore all 
the regions after. However, there are potentially a risk there would not 
be enough memory to cover the boot memory allocation (regions may be 
really small).

So if we ever hit the limit, then I think we should update the boot 
allocator.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 18/19] xen/arm: mm: Rework setup_xenheap_mappings()
  2022-02-21 10:22 ` [PATCH v3 18/19] xen/arm: mm: Rework setup_xenheap_mappings() Julien Grall
@ 2022-04-05 23:57   ` Stefano Stabellini
  0 siblings, 0 replies; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-05 23:57 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <julien.grall@arm.com>
> 
> The current implementation of setup_xenheap_mappings() is using 1GB
> mappings. This can lead to unexpected result because the mapping
> may alias a non-cachable region (such as device or reserved regions).
> For more details see B2.8 in ARM DDI 0487H.a.
> 
> map_pages_to_xen() was recently reworked to allow superpage mappings,
> support contiguous mapping and deal with the use of pagge-tables before

pagetables


> they are mapped.
> 
> Most of the code in setup_xenheap_mappings() is now replaced with a
> single call to map_pages_to_xen().
> 
> Signed-off-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v3:
>         - Don't use 1GB mapping
>         - Re-order code in setup_mm() in a separate patch
> 
>     Changes in v2:
>         - New patch
> ---
>  xen/arch/arm/mm.c | 87 ++++++++++-------------------------------------
>  1 file changed, 18 insertions(+), 69 deletions(-)

Very good!



> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index 11b6b60a2bc1..4af59375d998 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -138,17 +138,6 @@ static DEFINE_PAGE_TABLE(cpu0_pgtable);
>  static DEFINE_PAGE_TABLES(cpu0_dommap, DOMHEAP_SECOND_PAGES);
>  #endif
>  
> -#ifdef CONFIG_ARM_64
> -/* The first page of the first level mapping of the xenheap. The
> - * subsequent xenheap first level pages are dynamically allocated, but
> - * we need this one to bootstrap ourselves. */
> -static DEFINE_PAGE_TABLE(xenheap_first_first);
> -/* The zeroeth level slot which uses xenheap_first_first. Used because
> - * setup_xenheap_mappings otherwise relies on mfn_to_virt which isn't
> - * valid for a non-xenheap mapping. */
> -static __initdata int xenheap_first_first_slot = -1;
> -#endif
> -
>  /* Common pagetable leaves */
>  /* Second level page tables.
>   *
> @@ -815,77 +804,37 @@ void __init setup_xenheap_mappings(unsigned long base_mfn,
>  void __init setup_xenheap_mappings(unsigned long base_mfn,
>                                     unsigned long nr_mfns)
>  {
> -    lpae_t *first, pte;
> -    unsigned long mfn, end_mfn;
> -    vaddr_t vaddr;
> -
> -    /* Align to previous 1GB boundary */
> -    mfn = base_mfn & ~((FIRST_SIZE>>PAGE_SHIFT)-1);
> +    int rc;
>  
>      /* First call sets the xenheap physical and virtual offset. */
>      if ( mfn_eq(xenheap_mfn_start, INVALID_MFN) )
>      {
> +        unsigned long mfn_gb = base_mfn & ~((FIRST_SIZE >> PAGE_SHIFT) - 1);
> +
>          xenheap_mfn_start = _mfn(base_mfn);
>          xenheap_base_pdx = mfn_to_pdx(_mfn(base_mfn));
> +        /*
> +         * The base address may not be aligned to the first level
> +         * size (e.g. 1GB when using 4KB pages). This would prevent
> +         * superpage mappings for all the regions because the virtual
> +         * address and machine address should both be suitably aligned.
> +         *
> +         * Prevent that by offsetting the start of the xenheap virtual
> +         * address.
> +         */
>          xenheap_virt_start = DIRECTMAP_VIRT_START +
> -            (base_mfn - mfn) * PAGE_SIZE;
> +            (base_mfn - mfn_gb) * PAGE_SIZE;
>      }

[...]

> +    rc = map_pages_to_xen((vaddr_t)__mfn_to_virt(base_mfn),
> +                          _mfn(base_mfn), nr_mfns,
> +                          PAGE_HYPERVISOR_RW | _PAGE_BLOCK);
> +    if ( rc )
> +        panic("Unable to setup the xenheap mappings.\n");


I understand the intent of the code and I like it. maddr_to_virt is
implemented as:

    return (void *)(XENHEAP_VIRT_START -
                    (xenheap_base_pdx << PAGE_SHIFT) +
                    ((ma & ma_va_bottom_mask) |
                     ((ma & ma_top_mask) >> pfn_pdx_hole_shift)));

The PDX stuff is always difficult to follow and I cannot claim that I
traced through exactly what the resulting virtual address in the mapping
would be for a given base_mfn, but the patch looks correct compared to
the previous code.


Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 19/19] xen/arm: mm: Re-implement setup_frame_table_mappings() with map_pages_to_xen()
  2022-02-21 10:22 ` [PATCH v3 19/19] xen/arm: mm: Re-implement setup_frame_table_mappings() with map_pages_to_xen() Julien Grall
  2022-03-16  6:10   ` Hongda Deng
@ 2022-04-06  0:01   ` Stefano Stabellini
  2022-05-14 10:02     ` Julien Grall
  1 sibling, 1 reply; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-06  0:01 UTC (permalink / raw)
  To: Julien Grall
  Cc: xen-devel, Julien Grall, Stefano Stabellini, Bertrand Marquis,
	Volodymyr Babchuk, Julien Grall

On Mon, 21 Feb 2022, Julien Grall wrote:
> From: Julien Grall <julien.grall@arm.com>
> 
> Now that map_pages_to_xen() has been extended to support 2MB mappings,
> we can replace the create_mappings() call by map_pages_to_xen() call.
> 
> This has the advantage to remove the differences between 32-bit and
> 64-bit code.
> 
> Lastly remove create_mappings() as there is no more callers.
> 
> Signed-off-by: Julien Grall <julien.grall@arm.com>
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>     Changes in v3:
>         - Fix typo in the commit message
>         - Remove the TODO regarding contiguous bit
> 
>     Changes in v2:
>         - New patch
> ---
>  xen/arch/arm/mm.c | 63 ++++-------------------------------------------
>  1 file changed, 5 insertions(+), 58 deletions(-)
> 
> diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
> index 4af59375d998..d73f49d5b6fc 100644
> --- a/xen/arch/arm/mm.c
> +++ b/xen/arch/arm/mm.c
> @@ -354,40 +354,6 @@ void clear_fixmap(unsigned map)
>      BUG_ON(res != 0);
>  }
>  
> -/* Create Xen's mappings of memory.
> - * Mapping_size must be either 2MB or 32MB.
> - * Base and virt must be mapping_size aligned.
> - * Size must be a multiple of mapping_size.
> - * second must be a contiguous set of second level page tables
> - * covering the region starting at virt_offset. */
> -static void __init create_mappings(lpae_t *second,
> -                                   unsigned long virt_offset,
> -                                   unsigned long base_mfn,
> -                                   unsigned long nr_mfns,
> -                                   unsigned int mapping_size)
> -{
> -    unsigned long i, count;
> -    const unsigned long granularity = mapping_size >> PAGE_SHIFT;
> -    lpae_t pte, *p;
> -
> -    ASSERT((mapping_size == MB(2)) || (mapping_size == MB(32)));
> -    ASSERT(!((virt_offset >> PAGE_SHIFT) % granularity));
> -    ASSERT(!(base_mfn % granularity));
> -    ASSERT(!(nr_mfns % granularity));
> -
> -    count = nr_mfns / XEN_PT_LPAE_ENTRIES;
> -    p = second + second_linear_offset(virt_offset);
> -    pte = mfn_to_xen_entry(_mfn(base_mfn), MT_NORMAL);
> -    if ( granularity == 16 * XEN_PT_LPAE_ENTRIES )
> -        pte.pt.contig = 1;  /* These maps are in 16-entry contiguous chunks. */
> -    for ( i = 0; i < count; i++ )
> -    {
> -        write_pte(p + i, pte);
> -        pte.pt.base += 1 << XEN_PT_LPAE_SHIFT;
> -    }
> -    flush_xen_tlb_local();
> -}
> -
>  #ifdef CONFIG_DOMAIN_PAGE
>  void *map_domain_page_global(mfn_t mfn)
>  {
> @@ -846,36 +812,17 @@ void __init setup_frametable_mappings(paddr_t ps, paddr_t pe)
>      unsigned long frametable_size = nr_pdxs * sizeof(struct page_info);
>      mfn_t base_mfn;
>      const unsigned long mapping_size = frametable_size < MB(32) ? MB(2) : MB(32);
> -#ifdef CONFIG_ARM_64
> -    lpae_t *second, pte;
> -    unsigned long nr_second;
> -    mfn_t second_base;
> -    int i;
> -#endif
> +    int rc;
>  
>      frametable_base_pdx = mfn_to_pdx(maddr_to_mfn(ps));
>      /* Round up to 2M or 32M boundary, as appropriate. */
>      frametable_size = ROUNDUP(frametable_size, mapping_size);
>      base_mfn = alloc_boot_pages(frametable_size >> PAGE_SHIFT, 32<<(20-12));
>  
> -#ifdef CONFIG_ARM_64
> -    /* Compute the number of second level pages. */
> -    nr_second = ROUNDUP(frametable_size, FIRST_SIZE) >> FIRST_SHIFT;
> -    second_base = alloc_boot_pages(nr_second, 1);
> -    second = mfn_to_virt(second_base);
> -    for ( i = 0; i < nr_second; i++ )
> -    {
> -        clear_page(mfn_to_virt(mfn_add(second_base, i)));
> -        pte = mfn_to_xen_entry(mfn_add(second_base, i), MT_NORMAL);
> -        pte.pt.table = 1;
> -        write_pte(&xen_first[first_table_offset(FRAMETABLE_VIRT_START)+i], pte);
> -    }
> -    create_mappings(second, 0, mfn_x(base_mfn), frametable_size >> PAGE_SHIFT,
> -                    mapping_size);
> -#else
> -    create_mappings(xen_second, FRAMETABLE_VIRT_START, mfn_x(base_mfn),
> -                    frametable_size >> PAGE_SHIFT, mapping_size);
> -#endif
> +    rc = map_pages_to_xen(FRAMETABLE_VIRT_START, base_mfn,
> +                          frametable_size >> PAGE_SHIFT, PAGE_HYPERVISOR_RW);

Doesn't it need to be PAGE_HYPERVISOR_RW | _PAGE_BLOCK ?


> +    if ( rc )
> +        panic("Unable to setup the frametable mappings.\n");
>  
>      memset(&frame_table[0], 0, nr_pdxs * sizeof(struct page_info));
>      memset(&frame_table[nr_pdxs], -1,
> -- 
> 2.32.0
> 


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 17/19] xen/arm64: mm: Add memory to the boot allocator first
  2022-04-05 22:12     ` Julien Grall
@ 2022-04-06  0:02       ` Stefano Stabellini
  0 siblings, 0 replies; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-06  0:02 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, xen-devel, Julien Grall, Bertrand Marquis,
	Volodymyr Babchuk

On Tue, 5 Apr 2022, Julien Grall wrote:
> On 05/04/2022 22:50, Stefano Stabellini wrote:
> > > +static void __init setup_mm(void)
> > > +{
> > > +    const struct meminfo *banks = &bootinfo.mem;
> > > +    paddr_t ram_start = ~0;
> > > +    paddr_t ram_end = 0;
> > > +    paddr_t ram_size = 0;
> > > +    unsigned int i;
> > > +
> > > +    init_pdx();
> > > +
> > > +    /*
> > > +     * We need some memory to allocate the page-tables used for the
> > > xenheap
> > > +     * mappings. But some regions may contain memory already allocated
> > > +     * for other uses (e.g. modules, reserved-memory...).
> > > +     *
> > > +     * For simplify add all the free regions in the boot allocator.
> > > +     */
> > 
> > We currently have:
> > 
> > BUG_ON(nr_bootmem_regions == (PAGE_SIZE / sizeof(struct bootmem_region)));
> 
> This has enough space for 256 distinct regions on arm64 (512 regions on
> arm32).
> 
> > 
> > Do you think we should check for the limit in populate_boot_allocator?
> 
> This patch doesn't change the number of regions added to the boot allocator.
> So if we need to check the limit then I would rather deal separately (see more
> below).
> 
> > Or there is no need because it is unrealistic to reach it?
> I can't say never because history told us on some UEFI systems, there will be
> a large number of regions exposed. I haven't heard anyone that would hit the
> BUG_ON().
> 
> The problem is what do we do if we hit the limit? We could ignore all the
> regions after. However, there are potentially a risk there would not be enough
> memory to cover the boot memory allocation (regions may be really small).
> 
> So if we ever hit the limit, then I think we should update the boot allocator.

OK, thanks for the explanation.

Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 13/19] xen/arm: Move fixmap definitions in a separate header
  2022-04-05 21:47     ` Julien Grall
@ 2022-04-06  0:10       ` Stefano Stabellini
  2022-04-06  8:24         ` Julien Grall
  0 siblings, 1 reply; 79+ messages in thread
From: Stefano Stabellini @ 2022-04-06  0:10 UTC (permalink / raw)
  To: Julien Grall
  Cc: Stefano Stabellini, xen-devel, Julien Grall, Bertrand Marquis,
	Volodymyr Babchuk, Andrew Cooper, George Dunlap, Jan Beulich,
	Wei Liu

On Tue, 5 Apr 2022, Julien Grall wrote:
> On 05/04/2022 22:12, Stefano Stabellini wrote:
> > > +/* Map a page in a fixmap entry */
> > > +extern void set_fixmap(unsigned map, mfn_t mfn, unsigned attributes);
> > > +/* Remove a mapping from a fixmap entry */
> > > +extern void clear_fixmap(unsigned map);
> > > +
> > > +#endif /* __ASSEMBLY__ */
> > > +
> > > +#endif /* __ASM_FIXMAP_H */
> > 
> > 
> > It is a good idea to create fixmap.h, but I think it should be acpi.h to
> > include fixmap.h, not the other way around.
> 
> As I wrote in the commit message, one definition in fixmap.h rely on define
> from acpi.h (i.e NUM_FIXMAP_ACPI_PAGES). So if we don't include it, then user
> of FIXMAP_PMAP_BEGIN (see next patch) will requires to include acpi.h in order
> to build.
> 
> Re-ordering the values would not help because the problem would exactly be the
> same but this time the acpi users would have to include pmap.h to define
> NUM_FIX_PMAP.
> 
> > 
> > The appended changes build correctly on top of this patch.
> 
> That's expected because all the users of FIXMAP_ACPI_END will be including
> acpi.h. But after the next patch, we would need pmap.c to include acpi.h.
> 
> I don't think this would be right (and quite likely you would ask why
> this is done). Hence this approach.


I premise that I see your point and I don't feel very strongly either
way. In my opinion the fixmap is the low level "library" that others
make use of, so it should be acpi.h and pmap.h (the clients of the
library) that include fixmap.h and not the other way around.

So I would rather define NUM_FIXMAP_ACPI_PAGES and NUM_FIX_PMAP in
fixmap.h, then have both pmap.h and acpi.h include fixmap.h. It makes
more sense to me. However, I won't insist if you don't like it. Rough
patch below for reference.



diff --git a/xen/arch/arm/include/asm/fixmap.h b/xen/arch/arm/include/asm/fixmap.h
index c46a15e59d..a231ebfe25 100644
--- a/xen/arch/arm/include/asm/fixmap.h
+++ b/xen/arch/arm/include/asm/fixmap.h
@@ -4,8 +4,13 @@
 #ifndef __ASM_FIXMAP_H
 #define __ASM_FIXMAP_H
 
-#include <xen/acpi.h>
-#include <xen/pmap.h>
+#include <xen/lib.h>
+#include <asm/lpae.h>
+
+#define NUM_FIXMAP_ACPI_PAGES  64
+
+/* Large enough for mapping 5 levels of page tables with some headroom */
+#define NUM_FIX_PMAP 8
 
 /* Fixmap slots */
 #define FIXMAP_CONSOLE  0  /* The primary UART */
@@ -22,6 +27,10 @@
 
 #ifndef __ASSEMBLY__
 
+#include <xen/mm-frame.h>
+
+extern lpae_t xen_fixmap[XEN_PT_LPAE_ENTRIES];
+
 /* Map a page in a fixmap entry */
 extern void set_fixmap(unsigned map, mfn_t mfn, unsigned attributes);
 /* Remove a mapping from a fixmap entry */
diff --git a/xen/arch/arm/include/asm/pmap.h b/xen/arch/arm/include/asm/pmap.h
index 70eafe2891..31d29e021d 100644
--- a/xen/arch/arm/include/asm/pmap.h
+++ b/xen/arch/arm/include/asm/pmap.h
@@ -2,9 +2,8 @@
 #define __ASM_PMAP_H__
 
 #include <xen/mm.h>
+#include <asm/fixmap.h>
 
-/* XXX: Find an header to declare it */
-extern lpae_t xen_fixmap[XEN_PT_LPAE_ENTRIES];
 
 static inline void arch_pmap_map(unsigned int slot, mfn_t mfn)
 {
diff --git a/xen/include/xen/acpi.h b/xen/include/xen/acpi.h
index 1b9c75e68f..afcc9d5b4f 100644
--- a/xen/include/xen/acpi.h
+++ b/xen/include/xen/acpi.h
@@ -28,12 +28,7 @@
 #define _LINUX
 #endif
 
-/*
- * Fixmap pages to reserve for ACPI boot-time tables (see
- * arch/x86/include/asm/fixmap.h or arch/arm/include/asm/fixmap.h),
- * 64 pages(256KB) is large enough for most cases.)
- */
-#define NUM_FIXMAP_ACPI_PAGES  64
+#include <asm/fixmap.h>
 
 #ifndef __ASSEMBLY__
 
diff --git a/xen/include/xen/pmap.h b/xen/include/xen/pmap.h
index 93e61b1087..aa892154c0 100644
--- a/xen/include/xen/pmap.h
+++ b/xen/include/xen/pmap.h
@@ -1,9 +1,6 @@
 #ifndef __XEN_PMAP_H__
 #define __XEN_PMAP_H__
 
-/* Large enough for mapping 5 levels of page tables with some headroom */
-#define NUM_FIX_PMAP 8
-
 #ifndef __ASSEMBLY__
 
 #include <xen/mm-frame.h>


^ permalink raw reply related	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 13/19] xen/arm: Move fixmap definitions in a separate header
  2022-04-06  0:10       ` Stefano Stabellini
@ 2022-04-06  8:24         ` Julien Grall
  0 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-04-06  8:24 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, Julien Grall, Bertrand Marquis, Volodymyr Babchuk,
	Andrew Cooper, George Dunlap, Jan Beulich, Wei Liu,
	Roger Pau Monné

Hi,

On 06/04/2022 01:10, Stefano Stabellini wrote:
> On Tue, 5 Apr 2022, Julien Grall wrote:
>> On 05/04/2022 22:12, Stefano Stabellini wrote:
>>>> +/* Map a page in a fixmap entry */
>>>> +extern void set_fixmap(unsigned map, mfn_t mfn, unsigned attributes);
>>>> +/* Remove a mapping from a fixmap entry */
>>>> +extern void clear_fixmap(unsigned map);
>>>> +
>>>> +#endif /* __ASSEMBLY__ */
>>>> +
>>>> +#endif /* __ASM_FIXMAP_H */
>>>
>>>
>>> It is a good idea to create fixmap.h, but I think it should be acpi.h to
>>> include fixmap.h, not the other way around.
>>
>> As I wrote in the commit message, one definition in fixmap.h rely on define
>> from acpi.h (i.e NUM_FIXMAP_ACPI_PAGES). So if we don't include it, then user
>> of FIXMAP_PMAP_BEGIN (see next patch) will requires to include acpi.h in order
>> to build.
>>
>> Re-ordering the values would not help because the problem would exactly be the
>> same but this time the acpi users would have to include pmap.h to define
>> NUM_FIX_PMAP.
>>
>>>
>>> The appended changes build correctly on top of this patch.
>>
>> That's expected because all the users of FIXMAP_ACPI_END will be including
>> acpi.h. But after the next patch, we would need pmap.c to include acpi.h.
>>
>> I don't think this would be right (and quite likely you would ask why
>> this is done). Hence this approach.
> 
> 
> I premise that I see your point and I don't feel very strongly either
> way. In my opinion the fixmap is the low level "library" that others
> make use of, so it should be acpi.h and pmap.h (the clients of the
> library) that include fixmap.h and not the other way around.

That's one way to see it. The way I see it is each component decide how 
much entries they need. So I think it is better to move the definition 
to each components as they are best suited to decide the value.

> However, I won't insist if you don't like it. Rough
> patch below for reference.

I want to stay close to what x86 is doing to avoid any headers mess. 
This is what my patch is doing. Now, if x86 folks are happy to move the 
definition per-arch or in a xen/fixmap.h. Then I can look at it.

Andrew, Jan, Roger, Wei, what do you think?

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 04/19] xen/arm: mm: Allow other mapping size in xen_pt_update_entry()
  2022-04-05 20:46       ` Stefano Stabellini
@ 2022-04-10 12:17         ` Julien Grall
  0 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-04-10 12:17 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, Julien Grall, Bertrand Marquis, Volodymyr Babchuk,
	Julien Grall

Hi Stefano,

On 05/04/2022 21:46, Stefano Stabellini wrote:
> On Sat, 2 Apr 2022, Julien Grall wrote:
>> On 02/04/2022 00:35, Stefano Stabellini wrote:
>>>> +/* Return the level where mapping should be done */
>>>> +static int xen_pt_mapping_level(unsigned long vfn, mfn_t mfn, unsigned
>>>> long nr,
>>>> +                                unsigned int flags)
>>>> +{
>>>> +    unsigned int level;
>>>> +    unsigned long mask;
>>>
>>> Shouldn't mask be 64-bit on aarch32?
>>
>> The 3 variables we will use (mfn, vfn, nr) are unsigned long. So it is fine to
>> define the mask as unsigned long.
> 
> Good point
> 
> 
>>>> +}
>>>> +
>>>>    static DEFINE_SPINLOCK(xen_pt_lock);
>>>>      static int xen_pt_update(unsigned long virt,
>>>>                             mfn_t mfn,
>>>> -                         unsigned long nr_mfns,
>>>> +                         const unsigned long nr_mfns,
>>>
>>> Why const? nr_mfns is an unsigned long so it is passed as value: it
>>> couldn't change the caller's parameter anyway. Just curious.
>>
>> Because nr_mfns is used to flush the TLBs. In the original I made the mistake
>> to decrement the variable and only discovered later on when the TLB contained
>> the wrong entry.
>>
>> Such bug tends to be very subtle and it is hard to find the root cause. So
>> better mark the variable const to avoid any surprise.
>>
>> The short version of what I wrote is in the commit message. I can write a
>> small comment in the code if you want.
> 
> No, that's fine. Thanks for the explanation.

I thought about it and decided to add a comment. This will avoid someone 
to remove the 'const'.

Cheers,
-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 06/19] xen/arm: mm: Avoid flushing the TLBs when mapping are inserted
  2022-04-05 20:49       ` Stefano Stabellini
@ 2022-04-10 12:30         ` Julien Grall
  0 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-04-10 12:30 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, Julien Grall, Bertrand Marquis, Volodymyr Babchuk

Hi Stefano,

On 05/04/2022 21:49, Stefano Stabellini wrote:
> On Sat, 2 Apr 2022, Julien Grall wrote:
>> Maybe it would be clearer if I write:
>>
>>   !((flags & _PAGE_PRESENT) && !mfn_eq(mfn, INVALID_MFN))
> 
> It is not much a matter of clarity -- I just wanted to check with you
> the reasons for the if condition because, as you wrote, wrong tlb
> flushes can have catastrophic effects.
> 
> That said, actually I prefer your second version:
> 
>    !((flags & _PAGE_PRESENT) && !mfn_eq(mfn, INVALID_MFN))

I have updated the patch to use this switch.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 10/19] xen/arm32: mm: Re-implement setup_xenheap_mappings() using map_pages_to_xen()
  2022-02-21 10:22 ` [PATCH v3 10/19] xen/arm32: mm: Re-implement setup_xenheap_mappings() using map_pages_to_xen() Julien Grall
  2022-04-02  0:11   ` Stefano Stabellini
@ 2022-05-14  9:42   ` Julien Grall
  1 sibling, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-05-14  9:42 UTC (permalink / raw)
  To: xen-devel
  Cc: Julien Grall, Stefano Stabellini, Bertrand Marquis, Volodymyr Babchuk



On 21/02/2022 10:22, Julien Grall wrote:
> From: Julien Grall <jgrall@amazon.com>
> 
> Now that map_pages_to_xen() has been extended to support 2MB mappings,
> we can replace the create_mappings() call by map_pages_to_xen() call.
> 
> Signed-off-by: Julien Grall <jgrall@amazon.com>
> 
> ---
>      Changes in v3:
>          - Fix build when CONFIG_DEBUG=y
> 
>      Changes in v2:
>          - New patch
> 
>      TODOs:
>          - add support for contiguous mapping

This todo was a left-over because _PAGE_BLOCK will try to use the 
contiguous bit (see patch #5).

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 19/19] xen/arm: mm: Re-implement setup_frame_table_mappings() with map_pages_to_xen()
  2022-04-06  0:01   ` Stefano Stabellini
@ 2022-05-14 10:02     ` Julien Grall
  0 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-05-14 10:02 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, Julien Grall, Bertrand Marquis, Volodymyr Babchuk,
	Julien Grall

Hi Stefano,

On 06/04/2022 01:01, Stefano Stabellini wrote:
> On Mon, 21 Feb 2022, Julien Grall wrote:
>>       frametable_base_pdx = mfn_to_pdx(maddr_to_mfn(ps));
>>       /* Round up to 2M or 32M boundary, as appropriate. */
>>       frametable_size = ROUNDUP(frametable_size, mapping_size);
>>       base_mfn = alloc_boot_pages(frametable_size >> PAGE_SHIFT, 32<<(20-12));
>>   
>> -#ifdef CONFIG_ARM_64
>> -    /* Compute the number of second level pages. */
>> -    nr_second = ROUNDUP(frametable_size, FIRST_SIZE) >> FIRST_SHIFT;
>> -    second_base = alloc_boot_pages(nr_second, 1);
>> -    second = mfn_to_virt(second_base);
>> -    for ( i = 0; i < nr_second; i++ )
>> -    {
>> -        clear_page(mfn_to_virt(mfn_add(second_base, i)));
>> -        pte = mfn_to_xen_entry(mfn_add(second_base, i), MT_NORMAL);
>> -        pte.pt.table = 1;
>> -        write_pte(&xen_first[first_table_offset(FRAMETABLE_VIRT_START)+i], pte);
>> -    }
>> -    create_mappings(second, 0, mfn_x(base_mfn), frametable_size >> PAGE_SHIFT,
>> -                    mapping_size);
>> -#else
>> -    create_mappings(xen_second, FRAMETABLE_VIRT_START, mfn_x(base_mfn),
>> -                    frametable_size >> PAGE_SHIFT, mapping_size);
>> -#endif
>> +    rc = map_pages_to_xen(FRAMETABLE_VIRT_START, base_mfn,
>> +                          frametable_size >> PAGE_SHIFT, PAGE_HYPERVISOR_RW);
> 
> Doesn't it need to be PAGE_HYPERVISOR_RW | _PAGE_BLOCK ?

You are right. Otherwise, it would only use small pages. I will fix it 
in the next version.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

* Re: [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure
  2022-04-05 21:27   ` Stefano Stabellini
@ 2022-05-14 10:17     ` Julien Grall
  0 siblings, 0 replies; 79+ messages in thread
From: Julien Grall @ 2022-05-14 10:17 UTC (permalink / raw)
  To: Stefano Stabellini
  Cc: xen-devel, Wei Liu, Bertrand Marquis, Volodymyr Babchuk,
	George Dunlap, Hongyan Xia, Julien Grall, Jan Beulich, Wei Liu,
	Andrew Cooper, Roger Pau Monné



On 05/04/2022 22:27, Stefano Stabellini wrote:
> On Mon, 21 Feb 2022, Julien Grall wrote:
>> diff --git a/xen/arch/arm/include/asm/pmap.h b/xen/arch/arm/include/asm/pmap.h
>> new file mode 100644
>> index 000000000000..70eafe2891d7
>> --- /dev/null
>> +++ b/xen/arch/arm/include/asm/pmap.h
>> @@ -0,0 +1,33 @@
>> +#ifndef __ASM_PMAP_H__
>> +#define __ASM_PMAP_H__
>> +
>> +#include <xen/mm.h>
>> +
>> +/* XXX: Find an header to declare it */
>> +extern lpae_t xen_fixmap[XEN_PT_LPAE_ENTRIES];
> 
> Why not fixmap.h?

I wanted to find a helper that would only get included by pmap.c and 
mm.c, this would help to prevent someone to use xen_fixmap[] directly.

Anyway, I am OK with fixmap.h and we will rely on review to catch any 
new user of xen_fixmap.

Cheers,

-- 
Julien Grall


^ permalink raw reply	[flat|nested] 79+ messages in thread

end of thread, other threads:[~2022-05-14 10:17 UTC | newest]

Thread overview: 79+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-21 10:21 [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall
2022-02-21 10:22 ` [PATCH v3 01/19] xen/arm: lpae: Rename LPAE_ENTRIES_MASK_GS to LPAE_ENTRY_MASK_GS Julien Grall
2022-02-22 13:30   ` Michal Orzel
2022-02-24 22:19     ` Julien Grall
2022-02-22 15:21   ` Bertrand Marquis
2022-02-21 10:22 ` [PATCH v3 02/19] xen/arm: lpae: Use the generic helpers to defined the Xen PT helpers Julien Grall
2022-02-22 14:26   ` Michal Orzel
2022-02-22 15:38   ` Bertrand Marquis
2022-02-24 22:24     ` Julien Grall
2022-02-21 10:22 ` [PATCH v3 03/19] xen/arm: p2m: Replace level_{orders, masks} arrays with XEN_PT_LEVEL_{ORDER, MASK} Julien Grall
2022-02-22 15:55   ` Bertrand Marquis
2022-02-24 22:41     ` Julien Grall
2022-02-25  8:27       ` Bertrand Marquis
2022-02-25 16:41         ` Julien Grall
2022-02-21 10:22 ` [PATCH v3 04/19] xen/arm: mm: Allow other mapping size in xen_pt_update_entry() Julien Grall
2022-04-01 23:35   ` Stefano Stabellini
2022-04-02 15:59     ` Julien Grall
2022-04-05 20:46       ` Stefano Stabellini
2022-04-10 12:17         ` Julien Grall
2022-02-21 10:22 ` [PATCH v3 05/19] xen/arm: mm: Add support for the contiguous bit Julien Grall
2022-02-26 19:30   ` Julien Grall
2022-03-21  5:46     ` Hongda Deng
2022-04-01 23:53   ` Stefano Stabellini
2022-04-02 16:18     ` Julien Grall
2022-04-05 20:47       ` Stefano Stabellini
2022-02-21 10:22 ` [PATCH v3 06/19] xen/arm: mm: Avoid flushing the TLBs when mapping are inserted Julien Grall
2022-04-02  0:00   ` Stefano Stabellini
2022-04-02 16:38     ` Julien Grall
2022-04-05 20:49       ` Stefano Stabellini
2022-04-10 12:30         ` Julien Grall
2022-02-21 10:22 ` [PATCH v3 07/19] xen/arm: mm: Don't open-code Xen PT update in remove_early_mappings() Julien Grall
2022-04-02  0:04   ` Stefano Stabellini
2022-04-02 16:47     ` Julien Grall
2022-04-05 20:51       ` Stefano Stabellini
2022-02-21 10:22 ` [PATCH v3 08/19] xen/arm: mm: Re-implement early_fdt_map() using map_pages_to_xen() Julien Grall
2022-03-18  7:36   ` Hongda Deng
2022-03-18 19:44     ` Julien Grall
2022-04-02  0:10   ` Stefano Stabellini
2022-04-02 17:02     ` Julien Grall
2022-02-21 10:22 ` [PATCH v3 09/19] xen/arm32: mm: Check if the virtual address is shared before updating it Julien Grall
2022-03-18 10:44   ` Hongda Deng
2022-03-18 22:15     ` Julien Grall
2022-03-19 15:59   ` Julien Grall
2022-02-21 10:22 ` [PATCH v3 10/19] xen/arm32: mm: Re-implement setup_xenheap_mappings() using map_pages_to_xen() Julien Grall
2022-04-02  0:11   ` Stefano Stabellini
2022-05-14  9:42   ` Julien Grall
2022-02-21 10:22 ` [PATCH v3 11/19] xen/arm: mm: Allocate xen page tables in domheap rather than xenheap Julien Grall
2022-02-21 10:22 ` [PATCH v3 12/19] xen/arm: mm: Allow page-table allocation from the boot allocator Julien Grall
2022-04-05 20:58   ` Stefano Stabellini
2022-02-21 10:22 ` [PATCH v3 13/19] xen/arm: Move fixmap definitions in a separate header Julien Grall
2022-02-22 15:10   ` Jan Beulich
2022-04-05 21:12   ` Stefano Stabellini
2022-04-05 21:47     ` Julien Grall
2022-04-06  0:10       ` Stefano Stabellini
2022-04-06  8:24         ` Julien Grall
2022-02-21 10:22 ` [PATCH v3 14/19] xen/arm: add Persistent Map (PMAP) infrastructure Julien Grall
2022-02-22 15:22   ` Jan Beulich
2022-02-28  9:55     ` Julien Grall
2022-02-28 10:10       ` Jan Beulich
2022-02-28 10:20         ` Julien Grall
2022-02-28 10:30           ` Jan Beulich
2022-02-28 10:52             ` Julien Grall
2022-04-05 21:27   ` Stefano Stabellini
2022-05-14 10:17     ` Julien Grall
2022-02-21 10:22 ` [PATCH v3 15/19] xen/arm: mm: Clean-up the includes and order them Julien Grall
2022-04-05 21:29   ` Stefano Stabellini
2022-02-21 10:22 ` [PATCH v3 16/19] xen/arm: mm: Use the PMAP helpers in xen_{,un}map_table() Julien Grall
2022-04-05 21:36   ` Stefano Stabellini
2022-02-21 10:22 ` [PATCH v3 17/19] xen/arm64: mm: Add memory to the boot allocator first Julien Grall
2022-04-05 21:50   ` Stefano Stabellini
2022-04-05 22:12     ` Julien Grall
2022-04-06  0:02       ` Stefano Stabellini
2022-02-21 10:22 ` [PATCH v3 18/19] xen/arm: mm: Rework setup_xenheap_mappings() Julien Grall
2022-04-05 23:57   ` Stefano Stabellini
2022-02-21 10:22 ` [PATCH v3 19/19] xen/arm: mm: Re-implement setup_frame_table_mappings() with map_pages_to_xen() Julien Grall
2022-03-16  6:10   ` Hongda Deng
2022-04-06  0:01   ` Stefano Stabellini
2022-05-14 10:02     ` Julien Grall
2022-02-27 19:25 ` [PATCH v3 00/19] xen/arm: mm: Remove open-coding mappings Julien Grall

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.