Re: [PATCH v5 02/11] xen/arm: avoid repetitive checking in process_shm_node

2023-12-07 Thread Penny Zheng

Hi Michal

On 2023/12/6 19:35, Michal Orzel wrote:

Hi Penny,

On 06/12/2023 10:06, Penny Zheng wrote:



Putting overlap and overflow checking in the loop is causing repetitive
operation, so this commit extracts both checking outside the loop.

Signed-off-by: Penny Zheng 

In general the patch looks good to me:
Reviewed-by: Michal Orzel 



Thx~


That said, there are 2 things I realized during review.


---
v6:
new commit
---
  xen/arch/arm/static-shmem.c | 39 +++--
  1 file changed, 16 insertions(+), 23 deletions(-)

diff --git a/xen/arch/arm/static-shmem.c b/xen/arch/arm/static-shmem.c
index cb268cd2ed..1a1a9386e4 100644
--- a/xen/arch/arm/static-shmem.c
+++ b/xen/arch/arm/static-shmem.c
@@ -349,7 +349,7 @@ int __init process_shm_node(const void *fdt, int node, 
uint32_t address_cells,
  {
  const struct fdt_property *prop, *prop_id, *prop_role;
  const __be32 *cell;
-paddr_t paddr, gaddr, size;
+paddr_t paddr, gaddr, size, end;
  struct meminfo *mem = &bootinfo.reserved_mem;
  unsigned int i;
  int len;
@@ -422,6 +422,13 @@ int __init process_shm_node(const void *fdt, int node, 
uint32_t address_cells,
  return -EINVAL;
  }

+end = paddr + size;
+if ( end <= paddr )
+{
+printk("fdt: static shared memory region %s overflow\n", shm_id);
+return -EINVAL;
+}
+
  for ( i = 0; i < mem->nr_banks; i++ )
  {
  /*
@@ -441,30 +448,13 @@ int __init process_shm_node(const void *fdt, int node, 
uint32_t address_cells,
  return -EINVAL;
  }
  }
+else if ( strcmp(shm_id, mem->bank[i].shm_id) != 0 )
+continue;
  else
  {
-paddr_t end = paddr + size;
-paddr_t bank_end = mem->bank[i].start + mem->bank[i].size;
-
-if ( (end <= paddr) || (bank_end <= mem->bank[i].start) )

You are iterating over reserved memory regions in general, so apart from shmem 
regions there might be truly /reserved ones.
It appears that we don't have overflow check in device_tree_get_meminfo, so 
this second check was the only place to detect that
(protected by a feature, so not very useful) :) This is just an observation and 
I agree to drop it. We should be checking for an
overflow in device_tree_get_meminfo.



True~


The second observation I made is that we don't seem to assign and check the 
return code from device_tree_for_each_node.
This means, that any error while parsing the early fdt (e.g. static shm issues) 
does not stop Xen from booting, which might result in strange behavior later on.
If others agree, I'm ok to send a fix for that.

~Michal


Penny Zheng
Many thanks



[PATCH v5 10/11] xen/arm: fix duplicate /reserved-memory node in Dom0

2023-12-06 Thread Penny Zheng
In case there is a /reserved-memory node already present in the host dtb,
current Xen codes would create yet another /reserved-memory node specially
for the static shm in Dom0 Device Tree.

Xen will use write_properties() to copy the reserved memory nodes from host dtb
to Dom0 FDT, so we want to insert the shm node along with the copying.
And avoiding duplication, we add a checking before make_resv_memory_node().

Signed-off-by: Penny Zheng 

---
v3 -> v4:
new commit
---
v4 -> v5:
rebase and no change
---
 xen/arch/arm/domain_build.c | 27 ++---
 xen/arch/arm/include/asm/kernel.h   |  2 ++
 xen/arch/arm/include/asm/static-shmem.h | 14 +
 xen/arch/arm/static-shmem.c |  6 +++---
 4 files changed, 43 insertions(+), 6 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index e040f8a6d9..f098678ea3 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -752,6 +752,23 @@ static int __init write_properties(struct domain *d, 
struct kernel_info *kinfo,
 }
 }
 
+if ( dt_node_path_is_equal(node, "/reserved-memory") )
+{
+kinfo->resv_mem = true;
+
+/* shared memory provided. */
+if ( kinfo->shminfo.nr_banks != 0 )
+{
+uint32_t addrcells = dt_n_addr_cells(node),
+ sizecells = dt_n_size_cells(node);
+
+res = make_shm_memory_node(d, kinfo->fdt,
+   addrcells, sizecells, kinfo);
+if ( res )
+return res;
+}
+}
+
 return 0;
 }
 
@@ -1856,9 +1873,13 @@ static int __init handle_node(struct domain *d, struct 
kernel_info *kinfo,
 return res;
 }
 
-res = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells, 
kinfo);
-if ( res )
-return res;
+/* Avoid duplicate /reserved-memory nodes in Device Tree */
+if ( !kinfo->resv_mem )
+{
+res = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells, 
kinfo);
+if ( res )
+return res;
+}
 }
 
 res = fdt_end_node(kinfo->fdt);
diff --git a/xen/arch/arm/include/asm/kernel.h 
b/xen/arch/arm/include/asm/kernel.h
index db3d8232fa..8fe2105a91 100644
--- a/xen/arch/arm/include/asm/kernel.h
+++ b/xen/arch/arm/include/asm/kernel.h
@@ -39,6 +39,8 @@ struct kernel_info {
 void *fdt; /* flat device tree */
 paddr_t unassigned_mem; /* RAM not (yet) assigned to a bank */
 struct meminfo mem;
+/* Whether we have /reserved-memory node in host Device Tree */
+bool resv_mem;
 /* Static shared memory banks */
 struct {
 unsigned int nr_banks;
diff --git a/xen/arch/arm/include/asm/static-shmem.h 
b/xen/arch/arm/include/asm/static-shmem.h
index d149985291..6cb4ef9646 100644
--- a/xen/arch/arm/include/asm/static-shmem.h
+++ b/xen/arch/arm/include/asm/static-shmem.h
@@ -33,6 +33,11 @@ int remove_shm_from_rangeset(const struct kernel_info *kinfo,
 
 int remove_shm_holes_for_domU(const struct kernel_info *kinfo,
   struct meminfo *orig_ext);
+
+int make_shm_memory_node(const struct domain *d,
+ void *fdt,
+ int addrcells, int sizecells,
+ const struct kernel_info *kinfo);
 #else /* !CONFIG_STATIC_SHM */
 
 static inline int make_resv_memory_node(const struct domain *d, void *fdt,
@@ -72,6 +77,15 @@ static inline int remove_shm_holes_for_domU(const struct 
kernel_info *kinfo,
 {
 return 0;
 }
+
+static inline int make_shm_memory_node(const struct domain *d,
+   void *fdt,
+   int addrcells, int sizecells,
+   const struct kernel_info *kinfo)
+{
+return 0;
+}
+
 #endif /* CONFIG_STATIC_SHM */
 
 #endif /* __ASM_STATIC_SHMEM_H_ */
diff --git a/xen/arch/arm/static-shmem.c b/xen/arch/arm/static-shmem.c
index a06949abaf..bfce5bbad0 100644
--- a/xen/arch/arm/static-shmem.c
+++ b/xen/arch/arm/static-shmem.c
@@ -505,9 +505,9 @@ int __init process_shm(struct domain *d, struct kernel_info 
*kinfo,
 return 0;
 }
 
-static int __init make_shm_memory_node(const struct domain *d, void *fdt,
-   int addrcells, int sizecells,
-   const struct kernel_info *kinfo)
+int __init make_shm_memory_node(const struct domain *d, void *fdt,
+int addrcells, int sizecells,
+const struct kernel_info *kinfo)
 {
 unsigned int i = 0;
 int res = 0;
-- 
2.25.1




[PATCH v5 11/11] xen/arm: create another /memory node for static shm

2023-12-06 Thread Penny Zheng
Static shared memory region shall be described both under /memory and
/reserved-memory.

We introduce export_shm_memory_node() to create another /memory node to
contain the static shared memory ranges.

Signed-off-by: Penny Zheng 

---
v3 -> v4:
new commit
---
v4 -> v5:
rebase and no changes
---
 xen/arch/arm/dom0less-build.c   |  8 
 xen/arch/arm/domain_build.c |  8 
 xen/arch/arm/include/asm/static-shmem.h | 10 ++
 xen/arch/arm/static-shmem.c | 19 +++
 4 files changed, 45 insertions(+)

diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c
index ac096fa3fa..870b8a553f 100644
--- a/xen/arch/arm/dom0less-build.c
+++ b/xen/arch/arm/dom0less-build.c
@@ -645,6 +645,14 @@ static int __init prepare_dtb_domU(struct domain *d, 
struct kernel_info *kinfo)
 if ( ret )
 goto err;
 
+/* Create a memory node to store the static shared memory regions */
+if ( kinfo->shminfo.nr_banks != 0 )
+{
+ret = export_shm_memory_node(d, kinfo, addrcells, sizecells);
+if ( ret )
+goto err;
+}
+
 ret = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells, kinfo);
 if ( ret )
 goto err;
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index f098678ea3..4e450cb4c7 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1873,6 +1873,14 @@ static int __init handle_node(struct domain *d, struct 
kernel_info *kinfo,
 return res;
 }
 
+/* Create a memory node to store the static shared memory regions */
+if ( kinfo->shminfo.nr_banks != 0 )
+{
+res = export_shm_memory_node(d, kinfo, addrcells, sizecells);
+if ( res )
+return res;
+}
+
 /* Avoid duplicate /reserved-memory nodes in Device Tree */
 if ( !kinfo->resv_mem )
 {
diff --git a/xen/arch/arm/include/asm/static-shmem.h 
b/xen/arch/arm/include/asm/static-shmem.h
index 6cb4ef9646..385fd24c17 100644
--- a/xen/arch/arm/include/asm/static-shmem.h
+++ b/xen/arch/arm/include/asm/static-shmem.h
@@ -38,6 +38,10 @@ int make_shm_memory_node(const struct domain *d,
  void *fdt,
  int addrcells, int sizecells,
  const struct kernel_info *kinfo);
+
+int export_shm_memory_node(const struct domain *d,
+   const struct kernel_info *kinfo,
+   int addrcells, int sizecells);
 #else /* !CONFIG_STATIC_SHM */
 
 static inline int make_resv_memory_node(const struct domain *d, void *fdt,
@@ -86,6 +90,12 @@ static inline int make_shm_memory_node(const struct domain 
*d,
 return 0;
 }
 
+static inline int export_shm_memory_node(const struct domain *d,
+ const struct kernel_info *kinfo,
+ int addrcells, int sizecells)
+{
+return 0;
+}
 #endif /* CONFIG_STATIC_SHM */
 
 #endif /* __ASM_STATIC_SHMEM_H_ */
diff --git a/xen/arch/arm/static-shmem.c b/xen/arch/arm/static-shmem.c
index bfce5bbad0..e583aae685 100644
--- a/xen/arch/arm/static-shmem.c
+++ b/xen/arch/arm/static-shmem.c
@@ -505,6 +505,25 @@ int __init process_shm(struct domain *d, struct 
kernel_info *kinfo,
 return 0;
 }
 
+int __init export_shm_memory_node(const struct domain *d,
+  const struct kernel_info *kinfo,
+  int addrcells, int sizecells)
+{
+unsigned int i = 0;
+struct meminfo shm_meminfo;
+
+/* Extract meminfo from kinfo.shminfo */
+for ( ; i < kinfo->shminfo.nr_banks; i++ )
+{
+shm_meminfo.bank[i].start = kinfo->shminfo.bank[i].membank.start;
+shm_meminfo.bank[i].size = kinfo->shminfo.bank[i].membank.size;
+shm_meminfo.bank[i].type = MEMBANK_DEFAULT;
+}
+shm_meminfo.nr_banks = kinfo->shminfo.nr_banks;
+
+return make_memory_node(d, kinfo->fdt, addrcells, sizecells, &shm_meminfo);
+}
+
 int __init make_shm_memory_node(const struct domain *d, void *fdt,
 int addrcells, int sizecells,
 const struct kernel_info *kinfo)
-- 
2.25.1




[PATCH v5 09/11] xen/docs: refine docs about static shared memory

2023-12-06 Thread Penny Zheng
This commit amends docs(docs/misc/arm/device-tree/booting.txt) to include the
new scenario where host address is not provided in "xen,shared-mem" property,
and we also add a new example to explain in detail.

We also fix some buggy info in the docs, like SHMID is "my-shared-mem-1",
not "0x1".

Signed-off-by: Penny Zheng 
---
 docs/misc/arm/device-tree/booting.txt | 52 ---
 1 file changed, 39 insertions(+), 13 deletions(-)

diff --git a/docs/misc/arm/device-tree/booting.txt 
b/docs/misc/arm/device-tree/booting.txt
index bbd955e9c2..ac4bad6fe5 100644
--- a/docs/misc/arm/device-tree/booting.txt
+++ b/docs/misc/arm/device-tree/booting.txt
@@ -590,7 +590,7 @@ communication.
 An array takes a physical address, which is the base address of the
 shared memory region in host physical address space, a size, and a guest
 physical address, as the target address of the mapping.
-e.g. xen,shared-mem = < [host physical address] [guest address] [size] >
+e.g. xen,shared-mem = < [host physical address] [guest address] [size] >;
 
 It shall also meet the following criteria:
 1) If the SHM ID matches with an existing region, the address range of the
@@ -601,8 +601,8 @@ communication.
 The number of cells for the host address (and size) is the same as the
 guest pseudo-physical address and they are inherited from the parent node.
 
-Host physical address is optional, when missing Xen decides the location
-(currently unimplemented).
+Host physical address is optional, when missing Xen decides the location.
+e.g. xen,shared-mem = < [guest address] [size] >;
 
 - role (Optional)
 
@@ -629,7 +629,7 @@ chosen {
 role = "owner";
 xen,shm-id = "my-shared-mem-0";
 xen,shared-mem = <0x1000 0x1000 0x1000>;
-}
+};
 
 domU1 {
 compatible = "xen,domain";
@@ -640,25 +640,36 @@ chosen {
 vpl011;
 
 /*
- * shared memory region identified as 0x0(xen,shm-id = <0x0>)
- * is shared between Dom0 and DomU1.
+ * shared memory region "my-shared-mem-0" is shared
+ * between Dom0 and DomU1.
  */
 domU1-shared-mem@1000 {
 compatible = "xen,domain-shared-memory-v1";
 role = "borrower";
 xen,shm-id = "my-shared-mem-0";
 xen,shared-mem = <0x1000 0x5000 0x1000>;
-}
+};
 
 /*
- * shared memory region identified as 0x1(xen,shm-id = <0x1>)
- * is shared between DomU1 and DomU2.
+ * shared memory region "my-shared-mem-1" is shared between
+ * DomU1 and DomU2.
  */
 domU1-shared-mem@5000 {
 compatible = "xen,domain-shared-memory-v1";
 xen,shm-id = "my-shared-mem-1";
 xen,shared-mem = <0x5000 0x6000 0x2000>;
-}
+};
+
+/*
+ * shared memory region "my-shared-mem-2" is shared between
+ * DomU1 and DomU2.
+ */
+domU1-shared-mem-2 {
+compatible = "xen,domain-shared-memory-v1";
+xen,shm-id = "my-shared-mem-2";
+role = "owner";
+xen,shared-mem = <0x8000 0x2000>;
+};
 
 ..
 
@@ -672,14 +683,21 @@ chosen {
 cpus = <1>;
 
 /*
- * shared memory region identified as 0x1(xen,shm-id = <0x1>)
- * is shared between domU1 and domU2.
+ * shared memory region "my-shared-mem-1" is shared between
+ * domU1 and domU2.
  */
 domU2-shared-mem@5000 {
 compatible = "xen,domain-shared-memory-v1";
 xen,shm-id = "my-shared-mem-1";
 xen,shared-mem = <0x5000 0x7000 0x2000>;
-}
+};
+
+domU2-shared-mem-2 {
+compatible = "xen,domain-shared-memory-v1";
+xen,shm-id = "my-shared-mem-2";
+role = "borrower";
+xen,shared-mem = <0x9000 0x2000>;
+};
 
 ..
 };
@@ -699,3 +717,11 @@ shared between DomU1 and DomU2. It will get mapped at 
0x6000 in DomU1 guest
 physical address space, and at 0x7000 in DomU2 guest physical address 
space.
 DomU1 and DomU2 are both the borrower domain, the owner domain is the default
 owner domain DOMID_IO.
+
+For the static shared memory region "my-shared-mem-2", since host physical
+address is not provided by user, Xen will automatically allocate 512MB
+from heap as static shared memory to be shared between DomU1 and DomU2.
+The automatically allocated static shared memory will get mapped at
+0x8000 in DomU1 guest physical address space, and at 0x9000 in DomU2
+guest physical address space. DomU1 is explicitly defined as the owner domain,
+and DomU2 is the borrower domain.
-- 
2.25.1




[PATCH v5 08/11] xen/p2m: put reference for superpage

2023-12-06 Thread Penny Zheng
We are doing foreign memory mapping for static shared memory, and
there is a great possibility that it could be super mapped.
But today, p2m_put_l3_page could not handle superpages.

This commits implements a new function p2m_put_superpage to handle superpages,
specifically for helping put extra references for foreign superpages.

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- new commit
---
v2 -> v3:
- rebase and no change
---
v3 -> v4:
rebase and no change
---
v4 -> v5:
rebase and no change
---
 xen/arch/arm/mmu/p2m.c | 58 +++---
 1 file changed, 43 insertions(+), 15 deletions(-)

diff --git a/xen/arch/arm/mmu/p2m.c b/xen/arch/arm/mmu/p2m.c
index 6a5a080307..810c89397c 100644
--- a/xen/arch/arm/mmu/p2m.c
+++ b/xen/arch/arm/mmu/p2m.c
@@ -752,17 +752,9 @@ static int p2m_mem_access_radix_set(struct p2m_domain 
*p2m, gfn_t gfn,
 return rc;
 }
 
-/*
- * Put any references on the single 4K page referenced by pte.
- * TODO: Handle superpages, for now we only take special references for leaf
- * pages (specifically foreign ones, which can't be super mapped today).
- */
-static void p2m_put_l3_page(const lpae_t pte)
+/* Put any references on the single 4K page referenced by mfn. */
+static void p2m_put_l3_page(mfn_t mfn, unsigned type)
 {
-mfn_t mfn = lpae_get_mfn(pte);
-
-ASSERT(p2m_is_valid(pte));
-
 /*
  * TODO: Handle other p2m types
  *
@@ -770,16 +762,53 @@ static void p2m_put_l3_page(const lpae_t pte)
  * flush the TLBs if the page is reallocated before the end of
  * this loop.
  */
-if ( p2m_is_foreign(pte.p2m.type) )
+if ( p2m_is_foreign(type) )
 {
 ASSERT(mfn_valid(mfn));
 put_page(mfn_to_page(mfn));
 }
 /* Detect the xenheap page and mark the stored GFN as invalid. */
-else if ( p2m_is_ram(pte.p2m.type) && is_xen_heap_mfn(mfn) )
+else if ( p2m_is_ram(type) && is_xen_heap_mfn(mfn) )
 page_set_xenheap_gfn(mfn_to_page(mfn), INVALID_GFN);
 }
 
+/* Put any references on the superpage referenced by mfn. */
+static void p2m_put_superpage(mfn_t mfn, unsigned int next_level, unsigned 
type)
+{
+unsigned int i;
+unsigned int level_order = XEN_PT_LEVEL_ORDER(next_level);
+
+for ( i = 0; i < XEN_PT_LPAE_ENTRIES; i++ )
+{
+if ( next_level == 3 )
+p2m_put_l3_page(mfn, type);
+else
+p2m_put_superpage(mfn, next_level + 1, type);
+
+mfn = mfn_add(mfn, 1 << level_order);
+}
+}
+
+/* Put any references on the page referenced by pte. */
+static void p2m_put_page(const lpae_t pte, unsigned int level)
+{
+mfn_t mfn = lpae_get_mfn(pte);
+
+ASSERT(p2m_is_valid(pte));
+
+/*
+ * We are either having a first level 1G superpage or a
+ * second level 2M superpage.
+ */
+if ( p2m_is_superpage(pte, level) )
+return p2m_put_superpage(mfn, level + 1, pte.p2m.type);
+else
+{
+ASSERT(level == 3);
+return p2m_put_l3_page(mfn, pte.p2m.type);
+}
+}
+
 /* Free lpae sub-tree behind an entry */
 static void p2m_free_entry(struct p2m_domain *p2m,
lpae_t entry, unsigned int level)
@@ -808,9 +837,8 @@ static void p2m_free_entry(struct p2m_domain *p2m,
 #endif
 
 p2m->stats.mappings[level]--;
-/* Nothing to do if the entry is a super-page. */
-if ( level == 3 )
-p2m_put_l3_page(entry);
+p2m_put_page(entry, level);
+
 return;
 }
 
-- 
2.25.1




[PATCH v5 06/11] xen/arm: support static shared memory when host address not provided

2023-12-06 Thread Penny Zheng
In order to support static shared memory when host address not provided,
we shall do the following modification:
- we shall let Xen allocate memory from heap for static shared memory
at first domain, no matter it is owner or borrower.
- In acquire_shared_memory_bank, as static shared memory has already
been allocated from heap, we shall assign them to the owner domain
using function "assign_pages".
- Function get_shm_pages_reference is created to add as many
additional reference as the number of borrowers.
- We implement a new helper "add_foreign_mapping_for_borrower" to set
up foreign memory mapping for borrower.

Instead of using multiple function parameters to deliver various shm-related
info, like host physical address, SHMID, etc, and with the introduction
of new struct "shm_memnode" to include banked host memory info, we switch to
use "shm_memnode" as function parameter to replace them all, to make codes more
clear and tidy.

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- combine commits 4 - 6 in Serie 1
- Adapt to changes of introducing "struct shm_memnode"
---
v2 -> v3
- fix infinite loop bug and bad indentation
- rebase
---
v3 -> v4:
rebase and no change
---
v4 -> v5:
rebase and no change
---
 xen/arch/arm/domain_build.c |   6 +-
 xen/arch/arm/include/asm/domain_build.h |   5 +
 xen/arch/arm/static-shmem.c | 223 
 3 files changed, 163 insertions(+), 71 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index c69d481d34..c58996e3e9 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -440,9 +440,9 @@ static void __init allocate_memory_11(struct domain *d,
 }
 
 #ifdef CONFIG_DOM0LESS_BOOT
-static bool __init allocate_domheap_memory(struct domain *d,
-   paddr_t tot_size,
-   void *mem, enum meminfo_type type)
+bool __init allocate_domheap_memory(struct domain *d,
+paddr_t tot_size,
+void *mem, enum meminfo_type type)
 {
 struct page_info *pg;
 unsigned int max_order = ~0;
diff --git a/xen/arch/arm/include/asm/domain_build.h 
b/xen/arch/arm/include/asm/domain_build.h
index da9e6025f3..1b75a4c6a8 100644
--- a/xen/arch/arm/include/asm/domain_build.h
+++ b/xen/arch/arm/include/asm/domain_build.h
@@ -51,6 +51,11 @@ static inline int prepare_acpi(struct domain *d, struct 
kernel_info *kinfo)
 int prepare_acpi(struct domain *d, struct kernel_info *kinfo);
 #endif
 
+#ifdef CONFIG_DOM0LESS_BOOT
+bool allocate_domheap_memory(struct domain *d, paddr_t tot_size,
+ void *mem, enum meminfo_type type);
+#endif
+
 #endif
 
 /*
diff --git a/xen/arch/arm/static-shmem.c b/xen/arch/arm/static-shmem.c
index a9eb26d543..b04e58172b 100644
--- a/xen/arch/arm/static-shmem.c
+++ b/xen/arch/arm/static-shmem.c
@@ -50,6 +50,11 @@ void __init retrieve_shm_meminfo(void *mem, unsigned int 
*max_mem_banks,
 *bank = meminfo->bank;
 }
 
+static bool __init is_shm_allocated_from_heap(struct shm_memnode *node)
+{
+return (node->meminfo.nr_banks != 0);
+}
+
 static int __init acquire_nr_borrower_domain(const char *shm_id,
  unsigned long *nr_borrowers)
 {
@@ -75,12 +80,12 @@ static int __init acquire_nr_borrower_domain(const char 
*shm_id,
  * This function checks whether the static shared memory region is
  * already allocated to dom_io.
  */
-static bool __init is_shm_allocated_to_domio(paddr_t pbase)
+static bool __init is_shm_allocated_to_domio(struct shm_memnode *node)
 {
 struct page_info *page;
 struct domain *d;
 
-page = maddr_to_page(pbase);
+page = maddr_to_page(node->meminfo.bank[0].start);
 d = page_get_owner_and_reference(page);
 if ( d == NULL )
 return false;
@@ -98,67 +103,128 @@ static bool __init is_shm_allocated_to_domio(paddr_t 
pbase)
 }
 
 static mfn_t __init acquire_shared_memory_bank(struct domain *d,
-   paddr_t pbase, paddr_t psize)
+   struct shm_meminfo *meminfo,
+   bool paddr_assigned)
 {
-mfn_t smfn;
-unsigned long nr_pfns;
-int res;
+int res, i = 0;
 
-/*
- * Pages of statically shared memory shall be included
- * into domain_tot_pages().
- */
-nr_pfns = PFN_DOWN(psize);
-if ( (UINT_MAX - d->max_pages) < nr_pfns )
+for ( ; i < meminfo->nr_banks; i++ )
 {
-printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages: %lu.\n",
-   d, nr_pfns);
-return INVALID_MFN;
+paddr_t pbase = meminfo->bank[i].start, psize = meminfo->bank[i].size;
+unsigned long nr_pfns;
+
+/*
+ * Pages of statically shared 

[PATCH v5 04/11] xen/arm: introduce allocate_domheap_memory and guest_physmap_memory

2023-12-06 Thread Penny Zheng
We split the code of allocate_bank_memory into two parts,
allocate_domheap_memory and guest_physmap_memory.

One is about allocating guest RAM from heap, which could be re-used later for
allocating static shared memory from heap when host address is not provided.
The other is building up guest P2M mapping.

We also define a set of MACRO helpers to access common fields in data
structure of "meminfo" type, e.g. "struct meminfo" is one of them, and
later new "struct shm_meminfo" is also one of them.
This kind of structures must have the following characteristics:
- an array of "struct membank"
- a member called "nr_banks" indicating current array size
- a field indicating the maximum array size
When introducing a new data structure, according callbacks with function type
"retrieve_fn" shall be defined for using MACRO helpers.
This commit defines callback "retrieve_meminfo" for data structure
"struct meminfo".

Signed-off-by: Penny Zheng 
---
v1 -> v2:
-  define a set of MACRO helpers to access common fields in data structure of
"meminfo" type. "struct meminfo" is one of them, and according callback
"retrieve_meminfo" is also introduced here.
- typo of changing 1ULL to 1UL
---
v2 -> v3
- rebase and no changes
---
v3 -> v4:
rebase and no change
---
v4 -> v5:
rebase and no change
---
 xen/arch/arm/domain_build.c  | 119 +--
 xen/arch/arm/include/asm/setup.h |  33 +
 2 files changed, 129 insertions(+), 23 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 64ae944431..a8bc78baa5 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -51,6 +51,28 @@ boolean_param("ext_regions", opt_ext_regions);
 static u64 __initdata dom0_mem;
 static bool __initdata dom0_mem_set;
 
+#ifdef CONFIG_DOM0LESS_BOOT
+static void __init retrieve_meminfo(void *mem, unsigned int *max_mem_banks,
+struct membank **bank,
+unsigned int **nr_banks)
+{
+struct meminfo *meminfo = (struct meminfo *)mem;
+
+if ( max_mem_banks )
+*max_mem_banks = NR_MEM_BANKS;
+
+if ( nr_banks )
+*nr_banks = &(meminfo->nr_banks);
+
+if ( bank )
+*bank = meminfo->bank;
+}
+
+retrieve_fn __initdata retrievers[MAX_MEMINFO_TYPE] = {
+[NORMAL_MEMINFO] = retrieve_meminfo,
+};
+#endif
+
 static int __init parse_dom0_mem(const char *s)
 {
 dom0_mem_set = true;
@@ -415,32 +437,20 @@ static void __init allocate_memory_11(struct domain *d,
 }
 
 #ifdef CONFIG_DOM0LESS_BOOT
-bool __init allocate_bank_memory(struct domain *d, struct kernel_info *kinfo,
- gfn_t sgfn, paddr_t tot_size)
+static bool __init allocate_domheap_memory(struct domain *d,
+   paddr_t tot_size,
+   void *mem, enum meminfo_type type)
 {
-int res;
 struct page_info *pg;
-struct membank *bank;
 unsigned int max_order = ~0;
-
-/*
- * allocate_bank_memory can be called with a tot_size of zero for
- * the second memory bank. It is not an error and we can safely
- * avoid creating a zero-size memory bank.
- */
-if ( tot_size == 0 )
-return true;
-
-bank = &kinfo->mem.bank[kinfo->mem.nr_banks];
-bank->start = gfn_to_gaddr(sgfn);
-bank->size = tot_size;
+unsigned int *nr_banks = GET_NR_BANKS(mem, type);
 
 while ( tot_size > 0 )
 {
 unsigned int order = get_allocation_size(tot_size);
+struct membank *membank;
 
 order = min(max_order, order);
-
 pg = alloc_domheap_pages(d, order, 0);
 if ( !pg )
 {
@@ -460,15 +470,78 @@ bool __init allocate_bank_memory(struct domain *d, struct 
kernel_info *kinfo,
 continue;
 }
 
-res = guest_physmap_add_page(d, sgfn, page_to_mfn(pg), order);
-if ( res )
-{
-dprintk(XENLOG_ERR, "Failed map pages to DOMU: %d", res);
+if ( *nr_banks == MAX_MEM_BANKS(type) )
 return false;
-}
+
+membank = GET_MEMBANK(mem, type, *nr_banks);
+membank->start = mfn_to_maddr(page_to_mfn(pg));
+membank->size = 1ULL << (PAGE_SHIFT + order);
+(*nr_banks)++;
+tot_size -= membank->size;
+}
+
+return true;
+}
+
+static int __init guest_physmap_memory(struct domain *d,
+   void *mem, enum meminfo_type type,
+   gfn_t sgfn)
+{
+unsigned int i;
+int res;
+unsigned int *nr_banks = GET_NR_BANKS(mem, type);
+
+for ( i = 0; i < *nr_banks; i++ )
+{
+struct membank *membank = GET_MEMBANK(mem, type, i);
+paddr_t start = membank->start;
+  

[PATCH v5 07/11] xen/arm: remove shm holes for extended regions

2023-12-06 Thread Penny Zheng
Static shared memory acts as reserved memory in guest, so it shall be
excluded from extended regions.

Extended regions are taken care of under three different scenarios:
normal DomU, direct-map domain with iommu on, and direct-map domain
with iommu off.

For normal DomU, we create a new function "remove_shm_holes_for_domU", to
firstly transfer original outputs into the format of "struct rangeset",
then use "remove_shm_from_rangeset" to remove static shm from them.

For direct-map domain with iommu on, after we get guest shm info from "kinfo",
we use "remove_shm_from_rangeset" to remove static shm.

For direct-map domain with iommu off, as static shm has already been taken
care of through reserved memory banks, we do nothing.

Signed-off-by: Penny Zheng 

---
v1 -> v2:
- new commit
---
v2 -> v3:
- error out non-zero res before remove_shm_holes_for_domU
- rebase
---
v3 -> v4:
rebase and no change
---
v4 -> v5:
rebase and no change
---
 xen/arch/arm/domain_build.c | 19 +-
 xen/arch/arm/include/asm/domain_build.h |  2 +
 xen/arch/arm/include/asm/static-shmem.h | 17 +
 xen/arch/arm/static-shmem.c | 83 +
 4 files changed, 118 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index c58996e3e9..e040f8a6d9 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -887,8 +887,8 @@ int __init make_memory_node(const struct domain *d,
 return res;
 }
 
-static int __init add_ext_regions(unsigned long s_gfn, unsigned long e_gfn,
-  void *data)
+int __init add_ext_regions(unsigned long s_gfn, unsigned long e_gfn,
+   void *data)
 {
 struct meminfo *ext_regions = data;
 paddr_t start, size;
@@ -1062,6 +1062,8 @@ static int __init handle_pci_range(const struct 
dt_device_node *dev,
  * - MMIO
  * - Host RAM
  * - PCI aperture
+ * - Static shared memory regions, which are described by special property
+ *   "xen,static-shm"
  */
 static int __init find_memory_holes(const struct kernel_info *kinfo,
 struct meminfo *ext_regions)
@@ -1078,6 +1080,14 @@ static int __init find_memory_holes(const struct 
kernel_info *kinfo,
 if ( !mem_holes )
 return -ENOMEM;
 
+/* Remove static shared memory regions */
+if ( kinfo->shminfo.nr_banks != 0 )
+{
+res = remove_shm_from_rangeset(kinfo, mem_holes);
+if ( res )
+goto out;
+}
+
 /* Start with maximum possible addressable physical memory range */
 start = 0;
 end = (1ULL << p2m_ipa_bits) - 1;
@@ -1180,7 +1190,10 @@ static int __init find_domU_holes(const struct 
kernel_info *kinfo,
 res = 0;
 }
 
-return res;
+if ( res )
+return res;
+
+return remove_shm_holes_for_domU(kinfo, ext_regions);
 }
 
 int __init make_hypervisor_node(struct domain *d,
diff --git a/xen/arch/arm/include/asm/domain_build.h 
b/xen/arch/arm/include/asm/domain_build.h
index 1b75a4c6a8..0433e76e68 100644
--- a/xen/arch/arm/include/asm/domain_build.h
+++ b/xen/arch/arm/include/asm/domain_build.h
@@ -56,6 +56,8 @@ bool allocate_domheap_memory(struct domain *d, paddr_t 
tot_size,
  void *mem, enum meminfo_type type);
 #endif
 
+int add_ext_regions(unsigned long s_gfn, unsigned long e_gfn, void *data);
+
 #endif
 
 /*
diff --git a/xen/arch/arm/include/asm/static-shmem.h 
b/xen/arch/arm/include/asm/static-shmem.h
index a67445cec8..d149985291 100644
--- a/xen/arch/arm/include/asm/static-shmem.h
+++ b/xen/arch/arm/include/asm/static-shmem.h
@@ -27,6 +27,12 @@ int process_shm_node(const void *fdt, int node, uint32_t 
address_cells,
 void retrieve_shm_meminfo(void *mem, unsigned int *max_mem_banks,
   struct membank **bank,
   unsigned int **nr_banks);
+
+int remove_shm_from_rangeset(const struct kernel_info *kinfo,
+ struct rangeset *rangeset);
+
+int remove_shm_holes_for_domU(const struct kernel_info *kinfo,
+  struct meminfo *orig_ext);
 #else /* !CONFIG_STATIC_SHM */
 
 static inline int make_resv_memory_node(const struct domain *d, void *fdt,
@@ -55,6 +61,17 @@ static inline int process_shm_node(const void *fdt, int node,
 return -EINVAL;
 }
 
+static inline int remove_shm_from_rangeset(const struct kernel_info *kinfo,
+   struct rangeset *rangeset)
+{
+return 0;
+}
+
+static inline int remove_shm_holes_for_domU(const struct kernel_info *kinfo,
+struct meminfo *orig_ext)
+{
+return 0;
+}
 #endif /* CONFIG_STATIC_SHM */
 
 #endif /* __ASM_STATIC_SHMEM_H_ */
diff --git a/xen/arch/arm/static-shmem.c b/xen/arch/arm/static-shmem.c
index b04e58172b..a06949abaf 100644
--- a/xen/arch/arm/static-shme

[PATCH v5 02/11] xen/arm: avoid repetitive checking in process_shm_node

2023-12-06 Thread Penny Zheng
Putting overlap and overflow checking in the loop is causing repetitive
operation, so this commit extracts both checking outside the loop.

Signed-off-by: Penny Zheng 
---
v6:
new commit
---
 xen/arch/arm/static-shmem.c | 39 +++--
 1 file changed, 16 insertions(+), 23 deletions(-)

diff --git a/xen/arch/arm/static-shmem.c b/xen/arch/arm/static-shmem.c
index cb268cd2ed..1a1a9386e4 100644
--- a/xen/arch/arm/static-shmem.c
+++ b/xen/arch/arm/static-shmem.c
@@ -349,7 +349,7 @@ int __init process_shm_node(const void *fdt, int node, 
uint32_t address_cells,
 {
 const struct fdt_property *prop, *prop_id, *prop_role;
 const __be32 *cell;
-paddr_t paddr, gaddr, size;
+paddr_t paddr, gaddr, size, end;
 struct meminfo *mem = &bootinfo.reserved_mem;
 unsigned int i;
 int len;
@@ -422,6 +422,13 @@ int __init process_shm_node(const void *fdt, int node, 
uint32_t address_cells,
 return -EINVAL;
 }
 
+end = paddr + size;
+if ( end <= paddr )
+{
+printk("fdt: static shared memory region %s overflow\n", shm_id);
+return -EINVAL;
+}
+
 for ( i = 0; i < mem->nr_banks; i++ )
 {
 /*
@@ -441,30 +448,13 @@ int __init process_shm_node(const void *fdt, int node, 
uint32_t address_cells,
 return -EINVAL;
 }
 }
+else if ( strcmp(shm_id, mem->bank[i].shm_id) != 0 )
+continue;
 else
 {
-paddr_t end = paddr + size;
-paddr_t bank_end = mem->bank[i].start + mem->bank[i].size;
-
-if ( (end <= paddr) || (bank_end <= mem->bank[i].start) )
-{
-printk("fdt: static shared memory region %s overflow\n", 
shm_id);
-return -EINVAL;
-}
-
-if ( check_reserved_regions_overlap(paddr, size) )
-return -EINVAL;
-else
-{
-if ( strcmp(shm_id, mem->bank[i].shm_id) != 0 )
-continue;
-else
-{
-printk("fdt: different shared memory region could not 
share the same shm ID %s\n",
-   shm_id);
-return -EINVAL;
-}
-}
+printk("fdt: different shared memory region could not share the 
same shm ID %s\n",
+   shm_id);
+return -EINVAL;
 }
 }
 
@@ -472,6 +462,9 @@ int __init process_shm_node(const void *fdt, int node, 
uint32_t address_cells,
 {
 if ( i < NR_MEM_BANKS )
 {
+if ( check_reserved_regions_overlap(paddr, size) )
+return -EINVAL;
+
 /* Static shared memory shall be reserved from any other use. */
 safe_strcpy(mem->bank[mem->nr_banks].shm_id, shm_id);
 mem->bank[mem->nr_banks].start = paddr;
-- 
2.25.1




[PATCH v5 05/11] xen/arm: use paddr_assigned to indicate whether host address is provided

2023-12-06 Thread Penny Zheng
We use paddr_assigned to indicate whether host address is provided, by
checking the length of "xen,shared-mem" property.

The shm matching criteria shall also be adapt to cover the new scenario, by
adding when host address is not provided, if SHMID matches, the region size
must exactly match too.

During domain creation, right now, a static shared memory node could be
banked with a statically configured host memory bank, or arbitrary
host memory of dedicated size, which will later be allocated from heap by Xen.
To cover both scenarios, we create a new structure shm_meminfo. It is very
alike meminfo, but with the maximum array size being a smaller number
NR_SHM_BANKS(16).
As "shm_meminfo" is also a new member of "enum meminfo_type", we shall implement
its own callback "retrieve_shm_meminfo" to have access to all MACRO
helpers, e.g. GET_MEMBANK(...).

Also, to make codes tidy and clear, we extract codes about parsing
"xen,shared-mem" property from function "process_shm" and move them into
a new helper "parse_shm_property".

Signed-off-by: Penny Zheng 
---
v1 -> v2
- In order to get allocated banked host memory info during domain creation,
we create a new structure shm_meminfo. It is very alike meminfo, with
the maximum array size being NR_SHM_BANKS. As shm_meminfo is a new
member of type meminfo_type, we shall implement its own callback
retrieve_shm_meminfo to have access to all MACRO helpers, e.g.
GET_MEMBANK(...)
- rename "acquire_shm_memnode" to "find_shm_memnode"
---
v2 -> v3
- rebase and no changes
---
v3 -> v4:
- rebase and no change
---
v4 -> v5:
- fix bugs of that tot_size and membank shall not be member of union,
but struct, to differentiate two types of static shared memory node.
---
 xen/arch/arm/domain_build.c |   3 +
 xen/arch/arm/include/asm/setup.h|  14 +-
 xen/arch/arm/include/asm/static-shmem.h |   3 +
 xen/arch/arm/static-shmem.c | 360 ++--
 4 files changed, 293 insertions(+), 87 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index a8bc78baa5..c69d481d34 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -70,6 +70,9 @@ static void __init retrieve_meminfo(void *mem, unsigned int 
*max_mem_banks,
 
 retrieve_fn __initdata retrievers[MAX_MEMINFO_TYPE] = {
 [NORMAL_MEMINFO] = retrieve_meminfo,
+#ifdef CONFIG_STATIC_SHM
+[SHM_MEMINFO] = retrieve_shm_meminfo,
+#endif
 };
 #endif
 
diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/setup.h
index bc5f08be97..043588cd2d 100644
--- a/xen/arch/arm/include/asm/setup.h
+++ b/xen/arch/arm/include/asm/setup.h
@@ -59,6 +59,9 @@ struct meminfo {
 
 enum meminfo_type {
 NORMAL_MEMINFO,
+#ifdef CONFIG_STATIC_SHM
+SHM_MEMINFO,
+#endif
 MAX_MEMINFO_TYPE,
 };
 
@@ -150,7 +153,16 @@ struct bootinfo {
 unsigned int nr_nodes;
 struct {
 struct shm_node node;
-const struct membank *membank;
+/*
+ * For a static shared memory node, it is either banked with
+ * a statically configured host memory bank, or arbitrary host
+ * memory which will be allocated by Xen with a specified total
+ * size(tot_size).
+ */
+struct {
+const struct membank *membank;
+paddr_t tot_size;
+};
 } shm_nodes[NR_MEM_BANKS];
 } shminfo;
 #endif
diff --git a/xen/arch/arm/include/asm/static-shmem.h 
b/xen/arch/arm/include/asm/static-shmem.h
index 66a3f4c146..a67445cec8 100644
--- a/xen/arch/arm/include/asm/static-shmem.h
+++ b/xen/arch/arm/include/asm/static-shmem.h
@@ -24,6 +24,9 @@ static inline int process_shm_chosen(struct domain *d,
 int process_shm_node(const void *fdt, int node, uint32_t address_cells,
  uint32_t size_cells);
 
+void retrieve_shm_meminfo(void *mem, unsigned int *max_mem_banks,
+  struct membank **bank,
+  unsigned int **nr_banks);
 #else /* !CONFIG_STATIC_SHM */
 
 static inline int make_resv_memory_node(const struct domain *d, void *fdt,
diff --git a/xen/arch/arm/static-shmem.c b/xen/arch/arm/static-shmem.c
index 6a3d8a54bd..a9eb26d543 100644
--- a/xen/arch/arm/static-shmem.c
+++ b/xen/arch/arm/static-shmem.c
@@ -6,6 +6,50 @@
 #include 
 #include 
 
+#define NR_SHM_BANKS 16
+
+/*
+ * There are two types of static shared memory node:
+ * A static shared memory node could be banked with a statically
+ * configured host memory bank, or a set of arbitrary host memory
+ * banks allocated from heap by Xen on runtime.
+ */
+struct shm_meminfo {
+unsigned int nr_banks;
+struct membank bank[NR_SHM_BANKS];
+paddr_t tot_size;
+};
+
+/*
+ * struct shm_memnode holds banked host memory info for a static
+ * shared memory node
+ */
+struct shm_memnode {
+char shm_i

[PATCH v5 00/11] Follow-up static shared memory PART I

2023-12-06 Thread Penny Zheng
There are some unsolving issues on current 4.18 static shared memory
feature[1], including:
- In order to avoid keeping growing 'membank', having the shared memory
info in separate structures is preferred.
- Missing implementation on having the host address optional in
"xen,shared-mem" property
- Removing static shared memory from extended regions
- Missing reference release on foreign superpage
- Fix duplicated /reserved-memory node on Dom0
- Missing static shm node declaration on guest /memory node
- Missing "xen,offset" feature, which is introduced in Linux DOC[2]

All above objects have been divided into two parts to complete. And this
patch serie is PART I.

[1] https://lore.kernel.org/all/20220908135513.1800511-1-penny.zh...@arm.com/
[2] 
https://www.kernel.org/doc/Documentation/devicetree/bindings/reserved-memory/xen%2Cshared-memory.txt

Penny Zheng (11):
  xen/arm: remove stale addr_cells/size_cells in assign_shared_memory
  xen/arm: avoid repetitive checking in process_shm_node
  xen/arm: re-define a set of data structures for static shared memory
region
  xen/arm: introduce allocate_domheap_memory and guest_physmap_memory
  xen/arm: use paddr_assigned to indicate whether host address is
provided
  xen/arm: support static shared memory when host address not provided
  xen/arm: remove shm holes for extended regions
  xen/p2m: put reference for superpage
  xen/docs: refine docs about static shared memory
  xen/arm: fix duplicate /reserved-memory node in Dom0
  xen/arm: create another /memory node for static shm

 docs/misc/arm/device-tree/booting.txt   |  52 +-
 xen/arch/arm/dom0less-build.c   |  11 +-
 xen/arch/arm/domain_build.c | 177 +-
 xen/arch/arm/include/asm/domain_build.h |   7 +
 xen/arch/arm/include/asm/kernel.h   |  11 +-
 xen/arch/arm/include/asm/setup.h|  69 ++-
 xen/arch/arm/include/asm/static-shmem.h |  48 +-
 xen/arch/arm/mmu/p2m.c  |  58 +-
 xen/arch/arm/static-shmem.c | 742 ++--
 9 files changed, 929 insertions(+), 246 deletions(-)

-- 
2.25.1




[PATCH v5 03/11] xen/arm: re-define a set of data structures for static shared memory region

2023-12-06 Thread Penny Zheng
This commit introduces a set of separate data structures to deal with
static shared memory at different stages.

In boot-time host device tree parsing, we introduce a new structure
"struct shm_node" and a new field "shminfo" in bootinfo to describe and
store parsed shm info.

In acquire_nr_borrower_domain, it is better to use SHMID as unique identifier
to iterate "shminfo", other than address and size.

In the last, a new anonymized structure "shminfo", which is a array of
compound structure that contains SHMID and a "struct membank membank"
describing shared memory regions in guest address space, is created in "kinfo"
when dealing with domain information.

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- As the original "struct shm_membank" was making reserving memory more
complex and actually memory information could be still got from host Device\
Tree when dealing with domain construction, we introduce a new simple structure
"struct shm_node" in bootinfo to only store SHMID and "nr_borrowers"
- Further restrict the scope of the local variable
"struct meminfo *mem = &bootinfo.reserved_mem"
- Introduce a new local global data "shm_data" in bootfdt.c. In which, reserved
memory bank is recorded together with the shm node, to assist doing shm node
verification.
- Define a set of local variables that point to
"shm_data.shm_nodes[i].membank->start", etc, to make the code more readable.
- Use SHMID to iterate "shminfo" to find requested shm node, as we no
longer store host memory bank info in shm node.
- A new anonymized structure, which is a array of compound structure that
contains SHMID and a "struct membank membank", describing shared memory region
in guest, is introduced in "kinfo".
---
v2 -> v3:
- rebase and no changes
---
v3 -> v4:
rebase and no change
---
v4 -> v5:
- With all shm-related functions classified into static-shmem.c, there
is no need to import local global data "shm_data".
---
 xen/arch/arm/dom0less-build.c   |   3 +-
 xen/arch/arm/domain_build.c |   3 +-
 xen/arch/arm/include/asm/kernel.h   |   9 +-
 xen/arch/arm/include/asm/setup.h|  24 +-
 xen/arch/arm/include/asm/static-shmem.h |   4 +-
 xen/arch/arm/static-shmem.c | 104 ++--
 6 files changed, 92 insertions(+), 55 deletions(-)

diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c
index fb63ec6fd1..ac096fa3fa 100644
--- a/xen/arch/arm/dom0less-build.c
+++ b/xen/arch/arm/dom0less-build.c
@@ -645,8 +645,7 @@ static int __init prepare_dtb_domU(struct domain *d, struct 
kernel_info *kinfo)
 if ( ret )
 goto err;
 
-ret = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells,
-&kinfo->shm_mem);
+ret = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells, kinfo);
 if ( ret )
 goto err;
 
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 613b2885ce..64ae944431 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1767,8 +1767,7 @@ static int __init handle_node(struct domain *d, struct 
kernel_info *kinfo,
 return res;
 }
 
-res = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells,
-&kinfo->shm_mem);
+res = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells, 
kinfo);
 if ( res )
 return res;
 }
diff --git a/xen/arch/arm/include/asm/kernel.h 
b/xen/arch/arm/include/asm/kernel.h
index 0a23e86c2d..db3d8232fa 100644
--- a/xen/arch/arm/include/asm/kernel.h
+++ b/xen/arch/arm/include/asm/kernel.h
@@ -39,7 +39,14 @@ struct kernel_info {
 void *fdt; /* flat device tree */
 paddr_t unassigned_mem; /* RAM not (yet) assigned to a bank */
 struct meminfo mem;
-struct meminfo shm_mem;
+/* Static shared memory banks */
+struct {
+unsigned int nr_banks;
+struct {
+char shm_id[MAX_SHM_ID_LENGTH];
+struct membank membank;
+} bank[NR_MEM_BANKS];
+} shminfo;
 
 /* kernel entry point */
 paddr_t entry;
diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/setup.h
index d15a88d2e0..3a2b35ea46 100644
--- a/xen/arch/arm/include/asm/setup.h
+++ b/xen/arch/arm/include/asm/setup.h
@@ -50,10 +50,6 @@ struct membank {
 paddr_t start;
 paddr_t size;
 enum membank_type type;
-#ifdef CONFIG_STATIC_SHM
-char shm_id[MAX_SHM_ID_LENGTH];
-unsigned int nr_shm_borrowers;
-#endif
 };
 
 struct meminfo {
@@ -95,6 +91,17 @@ struct bootcmdlines {
 struct bootcmdline cmdline[MAX_MODULES];
 };
 
+#ifdef CONFIG_STATIC_SHM
+/*
+ * struct shm_node represents a static shared memory node shared between
+ * multiple domains, identified by the unique

[PATCH v5 01/11] xen/arm: remove stale addr_cells/size_cells in assign_shared_memory

2023-12-06 Thread Penny Zheng
Function parameters {addr_cells,size_cells} are stale parameters in
assign_shared_memory, so we shall remove them.

Signed-off-by: Penny Zheng 
Reviewed-by: Michal Orzel 
---
v1 -> v2:
- new commit
---
v2 -> v3:
rebase and no change
---
v3 -> v4:
rebase and no change
---
v4 -> v5:
rebase and no change
---
 xen/arch/arm/static-shmem.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/xen/arch/arm/static-shmem.c b/xen/arch/arm/static-shmem.c
index 9097bc8b15..cb268cd2ed 100644
--- a/xen/arch/arm/static-shmem.c
+++ b/xen/arch/arm/static-shmem.c
@@ -90,7 +90,6 @@ static mfn_t __init acquire_shared_memory_bank(struct domain 
*d,
 }
 
 static int __init assign_shared_memory(struct domain *d,
-   uint32_t addr_cells, uint32_t 
size_cells,
paddr_t pbase, paddr_t psize,
paddr_t gbase)
 {
@@ -252,7 +251,6 @@ int __init process_shm(struct domain *d, struct kernel_info 
*kinfo,
  * specified, so they should be assigned to dom_io.
  */
 ret = assign_shared_memory(owner_dom_io ? dom_io : d,
-   addr_cells, size_cells,
pbase, psize, gbase);
 if ( ret )
 return ret;
-- 
2.25.1




Re: [PATCH v4 00/10] Follow-up static shared memory PART I

2023-11-30 Thread Penny Zheng
Thanks for the reminder!
I’ll send the updated version ASAP :)

Thanks,
Penny

> 在 2023年11月30日,18:09,Michal Orzel  写道:
> 
> Hi Penny,
> 
>> On 11/09/2023 12:04, Penny Zheng wrote:
>> 
>> 
>> Hi Michal
>> 
>>> On 2023/9/11 17:01, Michal Orzel wrote:
>>> Hi Penny,
>>> 
>>> On 11/09/2023 06:04, Penny Zheng wrote:
>>>> 
>>>> 
>>>> There are some unsolving issues on current 4.17 static shared memory
>>>> feature[1], including:
>>>> - In order to avoid keeping growing 'membank', having the shared memory
>>>> info in separate structures is preferred.
>>>> - Missing implementation on having the host address optional in
>>>> "xen,shared-mem" property
>>>> - Removing static shared memory from extended regions
>>>> - Missing reference release on foreign superpage
>>>> - Fix duplicated /reserved-memory node on Dom0
>>>> - Missing static shm node declaration on guest /memory node
>>>> - Missing "xen,offset" feature, which is introduced in Linux DOC[2]
>>>> 
>>>> All above objects have been divided into two parts to complete. And this
>>>> patch serie is PART I.
>>> 
>>> Just like I pointed out in the previous revision, there is a gitlab CI 
>>> failure on shared-memory jobs:
>>> https://gitlab.com/xen-project/patchew/xen/-/pipelines/999098293
>>> Did you change the interface that could lead to this (I cannot spot any 
>>> change in the docs refinment) ?
>>> No Xen logs meaning the early boot failure. Please check.
>>> 
>> 
>> Soo sorry. I miss-looked that comment. I found that bug exists in
>> bootfdt.c.
>> ```
>> diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
>> index 7d86dffd45..290dd27bf4 100644
>> --- a/xen/arch/arm/bootfdt.c
>> +++ b/xen/arch/arm/bootfdt.c
>> @@ -532,6 +532,8 @@ static int __init process_shm_node(const void *fdt,
>> int node,
>> size, tot_size);
>>  return -EINVAL;
>>  }
>> +
>> +break;
>>  }
>>  else if ( paddr_assigned )
>>  {
>> ```
>> I accidentally delete a `break;` here, and I will also comment in the
>> related commit and fix in next version!
>> 
> While searching for the pending series, I noticed this one.
> If you have time and want us to review the series, please send an updated 
> version
> based on the recent Luca's dom0less features modularization.
> 
> ~Michal


Re: [XEN v1 4/4] xen/arm: traps.c: Enclose VMSA specific registers within CONFIG_MMU

2023-09-13 Thread Penny Zheng

Hi, Ayan

On 2023/9/11 21:59, Ayan Kumar Halder wrote:

The VMSA specific registers (ie TCR, TTBR0, TTBR1, VTTBR, etc) are valid when
MMU is used, thus we can enclose them with CONFIG_MMU.

Signed-off-by: Ayan Kumar Halder 
---
  xen/arch/arm/traps.c | 17 +++--
  1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 46c9a4031b..83522fcc5a 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -698,8 +698,10 @@ static void __do_trap_serror(struct cpu_user_regs *regs, 
bool guest)
  struct reg_ctxt {
  /* Guest-side state */
  register_t sctlr_el1;
+#ifdef CONFIG_MMU
  register_t tcr_el1;
  uint64_t ttbr0_el1, ttbr1_el1;
+#endif
  #ifdef CONFIG_ARM_32
  uint32_t dfsr, ifsr;
  uint32_t dfar, ifar;
@@ -801,9 +803,11 @@ static void show_registers_32(const struct cpu_user_regs 
*regs,
  if ( guest_mode_on )
  {
  printk(" SCTLR: %"PRIregister"\n", ctxt->sctlr_el1);
+#ifdef CONFIG_MMU
  printk("   TCR: %"PRIregister"\n", ctxt->tcr_el1);
  printk(" TTBR0: %016"PRIx64"\n", ctxt->ttbr0_el1);
  printk(" TTBR1: %016"PRIx64"\n", ctxt->ttbr1_el1);
+#endif


FWIS, on v8R-AArch64, with MPU on EL2, we could still support VMSA on 
EL1, so registers like TTBR0_EL1/TCR_EL1 are valid.
See ARM DDI 0600B.a Table G1-2 Alphabetical index of modified AArch64 
System registers (continued) for detailed info.



  printk("  IFAR: %08"PRIx32", IFSR: %08"PRIx32"\n"
 "  DFAR: %08"PRIx32", DFSR: %08"PRIx32"\n",
  #ifdef CONFIG_ARM_64
@@ -873,9 +877,11 @@ static void show_registers_64(const struct cpu_user_regs 
*regs,
  printk("   FAR_EL1: %016"PRIx64"\n", ctxt->far);
  printk("\n");
  printk(" SCTLR_EL1: %"PRIregister"\n", ctxt->sctlr_el1);
+#ifdef CONFIG_MMU
  printk("   TCR_EL1: %"PRIregister"\n", ctxt->tcr_el1);
  printk(" TTBR0_EL1: %016"PRIx64"\n", ctxt->ttbr0_el1);
  printk(" TTBR1_EL1: %016"PRIx64"\n", ctxt->ttbr1_el1);
+#endif
  printk("\n");
  }
  }
@@ -907,13 +913,15 @@ static void _show_registers(const struct cpu_user_regs 
*regs,
  show_registers_32(regs, ctxt, guest_mode_on, v);
  #endif
  }
+#ifdef CONFIG_MMU
  printk("  VTCR_EL2: %"PRIregister"\n", READ_SYSREG(VTCR_EL2));
  printk(" VTTBR_EL2: %016"PRIx64"\n", ctxt->vttbr_el2);
+printk(" TTBR0_EL2: %016"PRIx64"\n", READ_SYSREG64(TTBR0_EL2));
  printk("\n");
+#endif
  
  printk(" SCTLR_EL2: %"PRIregister"\n", READ_SYSREG(SCTLR_EL2));

  printk("   HCR_EL2: %"PRIregister"\n", READ_SYSREG(HCR_EL2));
-printk(" TTBR0_EL2: %016"PRIx64"\n", READ_SYSREG64(TTBR0_EL2));
  printk("\n");
  printk("   ESR_EL2: %"PRIregister"\n", regs->hsr);
  printk(" HPFAR_EL2: %"PRIregister"\n", READ_SYSREG(HPFAR_EL2));
@@ -931,9 +939,13 @@ void show_registers(const struct cpu_user_regs *regs)
  {
  struct reg_ctxt ctxt;
  ctxt.sctlr_el1 = READ_SYSREG(SCTLR_EL1);
+#ifdef CONFIG_MMU
  ctxt.tcr_el1 = READ_SYSREG(TCR_EL1);
  ctxt.ttbr0_el1 = READ_SYSREG64(TTBR0_EL1);
  ctxt.ttbr1_el1 = READ_SYSREG64(TTBR1_EL1);
+ctxt.vttbr_el2 = READ_SYSREG64(VTTBR_EL2);
+#endif
+
  #ifdef CONFIG_ARM_32
  ctxt.dfar = READ_CP32(DFAR);
  ctxt.ifar = READ_CP32(IFAR);
@@ -945,7 +957,6 @@ void show_registers(const struct cpu_user_regs *regs)
  if ( guest_mode(regs) && is_32bit_domain(current->domain) )
  ctxt.ifsr32_el2 = READ_SYSREG(IFSR32_EL2);
  #endif
-ctxt.vttbr_el2 = READ_SYSREG64(VTTBR_EL2);
  
  _show_registers(regs, &ctxt, guest_mode(regs), current);

  }
@@ -954,9 +965,11 @@ void vcpu_show_registers(const struct vcpu *v)
  {
  struct reg_ctxt ctxt;
  ctxt.sctlr_el1 = v->arch.sctlr;
+#ifdef CONFIG_MMU
  ctxt.tcr_el1 = v->arch.ttbcr;
  ctxt.ttbr0_el1 = v->arch.ttbr0;
  ctxt.ttbr1_el1 = v->arch.ttbr1;
+#endif
  #ifdef CONFIG_ARM_32
  ctxt.dfar = v->arch.dfar;
  ctxt.ifar = v->arch.ifar;




Re: [PATCH v4 00/10] Follow-up static shared memory PART I

2023-09-11 Thread Penny Zheng

Hi Michal

On 2023/9/11 17:01, Michal Orzel wrote:

Hi Penny,

On 11/09/2023 06:04, Penny Zheng wrote:



There are some unsolving issues on current 4.17 static shared memory
feature[1], including:
- In order to avoid keeping growing 'membank', having the shared memory
info in separate structures is preferred.
- Missing implementation on having the host address optional in
"xen,shared-mem" property
- Removing static shared memory from extended regions
- Missing reference release on foreign superpage
- Fix duplicated /reserved-memory node on Dom0
- Missing static shm node declaration on guest /memory node
- Missing "xen,offset" feature, which is introduced in Linux DOC[2]

All above objects have been divided into two parts to complete. And this
patch serie is PART I.


Just like I pointed out in the previous revision, there is a gitlab CI failure 
on shared-memory jobs:
https://gitlab.com/xen-project/patchew/xen/-/pipelines/999098293
Did you change the interface that could lead to this (I cannot spot any change 
in the docs refinment) ?
No Xen logs meaning the early boot failure. Please check.



Soo sorry. I miss-looked that comment. I found that bug exists in 
bootfdt.c.

```
diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
index 7d86dffd45..290dd27bf4 100644
--- a/xen/arch/arm/bootfdt.c
+++ b/xen/arch/arm/bootfdt.c
@@ -532,6 +532,8 @@ static int __init process_shm_node(const void *fdt, 
int node,

size, tot_size);
 return -EINVAL;
 }
+
+break;
 }
 else if ( paddr_assigned )
 {
```
I accidentally delete a `break;` here, and I will also comment in the 
related commit and fix in next version!



~Michal




Re: [PATCH v4 04/10] xen/arm: use paddr_assigned to indicate whether host address is provided

2023-09-11 Thread Penny Zheng

Hi,

On 2023/9/11 12:04, Penny Zheng wrote:

We use paddr_assigned to indicate whether host address is provided, by
checking the length of "xen,shared-mem" property.

The shm matching criteria shall also be adapt to cover the new scenario, by
adding when host address is not provided, if SHMID matches, the region size
must exactly match too.

During domain creation, right now, a static shared memory node could be
banked with a statically configured host memory bank, or a set of arbitrary
host memory banks allocated from heap. To cover both scenarios, we create
a new structure shm_meminfo. It is very alike meminfo, but with the maximum
array size being a smaller number NR_SHM_BANKS(16).
As "shm_meminfo" is also a new member of "enum meminfo_type", we shall implement
its own callback "retrieve_shm_meminfo" to have access to all MACRO
helpers, e.g. GET_MEMBANK(...).

Also, to make codes tidy and clear, we extract codes about parsing
"xen,shared-mem" property from function "process_shm" and move them into
a new helper "parse_shm_property".

Signed-off-by: Penny Zheng 
---
v1 -> v2
- In order to get allocated banked host memory info during domain creation,
we create a new structure shm_meminfo. It is very alike meminfo, with
the maximum array size being NR_SHM_BANKS. As shm_meminfo is a new
member of type meminfo_type, we shall implement its own callback
retrieve_shm_meminfo to have access to all MACRO helpers, e.g.
GET_MEMBANK(...)
- rename "acquire_shm_memnode" to "find_shm_memnode"
---
v2 -> v3
- rebase and no changes
---
v3 -> v4:
rebase and no change
---
  xen/arch/arm/bootfdt.c   | 100 ++-
  xen/arch/arm/domain_build.c  | 207 +--
  xen/arch/arm/include/asm/setup.h |   3 +
  3 files changed, 243 insertions(+), 67 deletions(-)

diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
index 66ad3ab3db..7d86dffd45 100644
--- a/xen/arch/arm/bootfdt.c
+++ b/xen/arch/arm/bootfdt.c
@@ -21,7 +21,15 @@ static __initdata struct {
  unsigned int nr_nodes;
  struct {
  const struct shm_node *node;
-const struct membank *membank;
+/*
+ * For a static shared memory node, it is either banked with a reserved
+ * host memory bank, or arbitrary host memory which shall
+ * be allocated by Xen with a specified total size(tot_size).
+ */
+union {
+const struct membank *membank;
+paddr_t tot_size;
+};
  } shm_nodes[NR_MEM_BANKS];
  } shm_data;
  #endif
@@ -421,7 +429,7 @@ static int __init process_shm_node(const void *fdt, int 
node,
  paddr_t paddr, gaddr, size;
  unsigned int i;
  int len;
-bool owner = false;
+bool owner = false, paddr_assigned = true;
  const char *shm_id;
  
  if ( address_cells < 1 || size_cells < 1 )

@@ -462,7 +470,7 @@ static int __init process_shm_node(const void *fdt, int 
node,
  }
  
  /*

- * xen,shared-mem = ;
+ * xen,shared-mem = , and paddr could be optional
   * Memory region starting from physical address #paddr of #size shall
   * be mapped to guest physical address #gaddr as static shared memory
   * region.
@@ -473,16 +481,24 @@ static int __init process_shm_node(const void *fdt, int 
node,
  
  if ( len != dt_cells_to_size(address_cells + size_cells + address_cells) )

  {
+/* paddr is not provided in "xen,shared-mem" */
  if ( len == dt_cells_to_size(size_cells + address_cells) )
-printk("fdt: host physical address must be chosen by users at the 
moment.\n");
-
-printk("fdt: invalid `xen,shared-mem` property.\n");
-return -EINVAL;
+paddr_assigned = false;
+else
+{
+printk("fdt: invalid `xen,shared-mem` property.\n");
+return -EINVAL;
+}
  }
  
  cell = (const __be32 *)prop->data;

-device_tree_get_reg(&cell, address_cells, address_cells, &paddr, &gaddr);
-size = dt_next_cell(size_cells, &cell);
+if ( !paddr_assigned )
+device_tree_get_reg(&cell, address_cells, size_cells, &gaddr, &size);
+else
+{
+device_tree_get_reg(&cell, address_cells, address_cells, &paddr, 
&gaddr);
+size = dt_next_cell(size_cells, &cell);
+}
  
  if ( !size )

  {
@@ -495,23 +511,37 @@ static int __init process_shm_node(const void *fdt, int 
node,
  paddr_t bank_start = shm_data.shm_nodes[i].membank->start;
  paddr_t bank_size = shm_data.shm_nodes[i].membank->size;
  const char *bank_id = shm_data.shm_nodes[i].node->shm_id;
+paddr_t tot_size = shm_data.shm_nodes[i].tot_size;
  
  /*

   * Meet the following check:
+ * when host address is provided:
   * 1

Re: [PATCH v4 09/10] xen/arm: fix duplicate /reserved-memory node in Dom0

2023-09-11 Thread Penny Zheng

Hi Michal

On 2023/9/11 17:40, Michal Orzel wrote:

Hi Penny,

On 11/09/2023 06:04, Penny Zheng wrote:



In case there is a /reserved-memory node already present in the host dtb,
current Xen codes would create yet another /reserved-memory node specially

s/codes/code/


for the static shm in Dom0 Device Tree.

Xen will use write_properties() to copy the reserved memory nodes from host dtb
to Dom0 FDT, so we want to insert the shm node along with the copying.
And avoiding duplication, we add a checking before make_resv_memory_node().

Signed-off-by: Penny Zheng 

---
v3 -> v4:
new commit
---
  xen/arch/arm/domain_build.c   | 31 ---
  xen/arch/arm/include/asm/kernel.h |  2 ++
  2 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 02d903be78..dad234e4b5 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1401,6 +1401,10 @@ static int __init handle_linux_pci_domain(struct 
kernel_info *kinfo,
  return fdt_property_cell(kinfo->fdt, "linux,pci-domain", segment);
  }

+static int __init make_shm_memory_node(const struct domain *d,
+   void *fdt,
+   int addrcells, int sizecells,
+   const struct kernel_info *kinfo);
  static int __init write_properties(struct domain *d, struct kernel_info 
*kinfo,
 const struct dt_device_node *node)
  {
@@ -1549,6 +1553,23 @@ static int __init write_properties(struct domain *d, 
struct kernel_info *kinfo,
  }
  }

+if ( dt_node_path_is_equal(node, "/reserved-memory") )
+{
+kinfo->resv_mem = true;

kinfo structure is used to store per-domain parameters and presence of reserved 
memory in host dtb
does not fit into this. Moreover, there is no need to introduce yet another 
flag for that given
that in other parts of the code in Xen we use bootinfo.reserved_mem.nr_banks to 
check if there are
reserved regions.


+
+/* shared memory provided. */
+if ( kinfo->shminfo.nr_banks != 0 )
+{
+uint32_t addrcells = dt_n_addr_cells(node),
+ sizecells = dt_n_size_cells(node);
+
+res = make_shm_memory_node(d, kinfo->fdt,
+   addrcells, sizecells, kinfo);

I haven't yet looked at previous patches but does it make sense to request passing 
both kinfo->fdt and kinfo?
IMO, the latter would be sufficient. This would apply to other functions you 
modified.



yes, the latter would be sufficient. I'll fix it in next version.



+if ( res )
+return res;
+}
+}
+
  return 0;
  }

@@ -2856,9 +2877,13 @@ static int __init handle_node(struct domain *d, struct 
kernel_info *kinfo,
  return res;
  }

-res = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells, 
kinfo);
-if ( res )
-return res;
+/* Avoid duplicate /reserved-memory nodes in Device Tree */
+if ( !kinfo->resv_mem )

No need for a new flag as mentioned above. Just before this line of code there 
is a check:
if ( bootinfo.reserved_mem.nr_banks > 0 )
{
 res = make_memory_node(d, kinfo->fdt, addrcells, sizecells,
 &bootinfo.reserved_mem);
 if ( res )
 return res;
}
so you can just append the following:
else
{
 res = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells, kinfo);
 if ( res )
 return res;
}
to achieve the same without a need for a new flag.



Right now, bootinfo.reserved_mem is not only containing reserved regions 
described in host FDT /reserved-memory, but also the reserved ones for 
domain only, like in xen,static-mem = .

So simply with non-zero bootinfo.reserved_mem.nr_banks, we couldn't tell
whether we had a /reserved-memory node in host FDT.

I agree that kinfo is not a good place to store whether host FDT has a
/reserved-memory node. Maybe bootinfo.has_resv_memory_node?



~Michal




Re: [PATCH v3 0/8] Follow-up static shared memory PART I

2023-09-10 Thread Penny Zheng

Hi Michal

Sorry for the delayed response, caught up in internal release lately. :\

On 2023/8/22 16:57, Michal Orzel wrote:

Hi Penny,

On 22/08/2023 07:32, Penny Zheng wrote:



Hi, michal

On 2023/8/21 18:49, Michal Orzel wrote:

Hi Penny,

On 21/08/2023 06:00, Penny Zheng wrote:



There are some unsolving issues on current 4.17 static shared memory
feature[1], including:
- In order to avoid keeping growing 'membank', having the shared memory
info in separate structures is preferred.
- Missing implementation on having the host address optional in
"xen,shared-mem" property
- Removing static shared memory from extended regions
- Missing reference release on foreign superpage
- Missing "xen,offset" feature, which is introduced in Linux DOC[2]

All above objects have been divided into two parts to complete. And this
patch serie is PART I.

[1] https://lore.kernel.org/all/20220908135513.1800511-1-penny.zh...@arm.com/
[2] 
https://www.kernel.org/doc/Documentation/devicetree/bindings/reserved-memory/xen%2Cshared-memory.txt


It looks like there is a problem with the changes introduced in this series.
The gitlab static shared memory tests failed:
https://gitlab.com/xen-project/patchew/xen/-/pipelines/973985190
No Xen logs meaning the failure occurred before serial console initialization.

Now, I would like to share some observations after playing around with the 
current static shared mem code today.
1) Static shared memory region is advertised to a domain by creating a child 
node under reserved-memory.
/reserved-memory is nothing but a way to carve out a region from the normal 
memory specified in /memory node.
For me, such regions should be described in domain's /memory node as well. This 
is not the case at the moment
for static shm unlike to other sub-nodes of /reserved-memory (present in host 
dtb) for which Xen creates separate
/memory nodes.



Hmm, correct me if I'm wrong,
If we describe twice in domain's /memory node too, it will be treated as
normal memory, then any application could use it. The reason why we put
static shm under /reserved-memory is that we only hope special driver,
like static shm linux driver, could access it.

If you track down in make_memory_node(), only memory range that is
reserved for device (or firmware) will be described twice as normal
memory in Dom0. Memory like static shm, will get passed.


Reserved memory is a region of RAM (not MMIO) carved out for a special purpose 
which can be used by a driver for e.g. shared dma pool.
Therefore, such region shall be described both under /memory (used to present 
the total RAM and reserved memory is in RAM)
and under /reserved-memory. The OS parses /memory and then parses 
/reserved-memory to exclude the regions from normal usage
(there is also no-map property to tell OS not to create virtual mapping). So 
you do not need to worry about OS making use of something we marked as reserved.
This is exactly what Xen does if there are regions described as reserved in the 
host dtb:
1. Xen parses host dtb, adds reserved regions into bootinfo.reserved_mem so 
that it will not be used e.g. for allocator
2. While copying nodes from host dtb, Xen copies reserved memory nodes to dom0 
dtb and only maps the regions in p2m without permitting iomem access
3. Xen creates another /memory node to contain the reserved memory ranges

I guess static shm is not exception to this flow. It is part of RAM suited for 
memory sharing.



Understood!!! thanks for the detailed explanation.
I've created a new commit "xen/arm: fix duplicate /reserved-memory node 
in Dom0" to fix this problem in v4[1], plz feel free to review.





2) Domain dtb parsing issue with two /reserved-memory nodes present.
In case there is a /reserved-memory node already present in the host dtb, Xen 
would create yet another /reserved-memory
node for the static shm (to be observed in case of dom0). This is a bug as 
there can be only one /reserved-memory node.
This leads to an error when dumping with dtc and leads to a shm node not being 
visible to a domain (guest OS relies on
a presence of a single /reserved-memory node). The issue is because in 
make_resv_memory_node(), you are not checking if
such node already exists.


Yes, you're true.
In Dom0, we could see two /reserved-memory nodes. I think, if there is a
/reserved-memory node already present in the host dtb, we shall reserve
it in kinfo for make_resv_memory_node().

This way you will only take the reference of a region but what about all the 
properties, node names, etc. that you need to copy?
This is why Xen first copies the reserved memory nodes from host dtb and then 
adds ranges to /memory.
In our shm case, we would need to insert the shm node into existing reserved 
memory node. This is a bit tricky as you can no longer
make use of fdt_{begin,end}_node and instead use the helpers operating on 
offsets.



I've also created a new commit "xen/arm: cr

[PATCH v4 08/10] xen/docs: refine docs about static shared memory

2023-09-10 Thread Penny Zheng
This commit amends docs(docs/misc/arm/device-tree/booting.txt) to include the
new scenario where host address is not provided in "xen,shared-mem" property,
and we also add a new example to explain in detail.

We also fix some buggy info in the docs, like SHMID is "my-shared-mem-1",
not "0x1".

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- no new changes
---
v2 -> v3
- rebase and no change
---
v3 -> v4:
rebase and no change
---
 docs/misc/arm/device-tree/booting.txt | 52 ---
 1 file changed, 39 insertions(+), 13 deletions(-)

diff --git a/docs/misc/arm/device-tree/booting.txt 
b/docs/misc/arm/device-tree/booting.txt
index bbd955e9c2..ac4bad6fe5 100644
--- a/docs/misc/arm/device-tree/booting.txt
+++ b/docs/misc/arm/device-tree/booting.txt
@@ -590,7 +590,7 @@ communication.
 An array takes a physical address, which is the base address of the
 shared memory region in host physical address space, a size, and a guest
 physical address, as the target address of the mapping.
-e.g. xen,shared-mem = < [host physical address] [guest address] [size] >
+e.g. xen,shared-mem = < [host physical address] [guest address] [size] >;
 
 It shall also meet the following criteria:
 1) If the SHM ID matches with an existing region, the address range of the
@@ -601,8 +601,8 @@ communication.
 The number of cells for the host address (and size) is the same as the
 guest pseudo-physical address and they are inherited from the parent node.
 
-Host physical address is optional, when missing Xen decides the location
-(currently unimplemented).
+Host physical address is optional, when missing Xen decides the location.
+e.g. xen,shared-mem = < [guest address] [size] >;
 
 - role (Optional)
 
@@ -629,7 +629,7 @@ chosen {
 role = "owner";
 xen,shm-id = "my-shared-mem-0";
 xen,shared-mem = <0x1000 0x1000 0x1000>;
-}
+};
 
 domU1 {
 compatible = "xen,domain";
@@ -640,25 +640,36 @@ chosen {
 vpl011;
 
 /*
- * shared memory region identified as 0x0(xen,shm-id = <0x0>)
- * is shared between Dom0 and DomU1.
+ * shared memory region "my-shared-mem-0" is shared
+ * between Dom0 and DomU1.
  */
 domU1-shared-mem@1000 {
 compatible = "xen,domain-shared-memory-v1";
 role = "borrower";
 xen,shm-id = "my-shared-mem-0";
 xen,shared-mem = <0x1000 0x5000 0x1000>;
-}
+};
 
 /*
- * shared memory region identified as 0x1(xen,shm-id = <0x1>)
- * is shared between DomU1 and DomU2.
+ * shared memory region "my-shared-mem-1" is shared between
+ * DomU1 and DomU2.
  */
 domU1-shared-mem@5000 {
 compatible = "xen,domain-shared-memory-v1";
 xen,shm-id = "my-shared-mem-1";
 xen,shared-mem = <0x5000 0x6000 0x2000>;
-}
+};
+
+/*
+ * shared memory region "my-shared-mem-2" is shared between
+ * DomU1 and DomU2.
+ */
+domU1-shared-mem-2 {
+compatible = "xen,domain-shared-memory-v1";
+xen,shm-id = "my-shared-mem-2";
+role = "owner";
+xen,shared-mem = <0x8000 0x2000>;
+};
 
 ..
 
@@ -672,14 +683,21 @@ chosen {
 cpus = <1>;
 
 /*
- * shared memory region identified as 0x1(xen,shm-id = <0x1>)
- * is shared between domU1 and domU2.
+ * shared memory region "my-shared-mem-1" is shared between
+ * domU1 and domU2.
  */
 domU2-shared-mem@5000 {
 compatible = "xen,domain-shared-memory-v1";
 xen,shm-id = "my-shared-mem-1";
 xen,shared-mem = <0x5000 0x7000 0x2000>;
-}
+};
+
+domU2-shared-mem-2 {
+compatible = "xen,domain-shared-memory-v1";
+xen,shm-id = "my-shared-mem-2";
+role = "borrower";
+xen,shared-mem = <0x9000 0x2000>;
+};
 
 ..
 };
@@ -699,3 +717,11 @@ shared between DomU1 and DomU2. It will get mapped at 
0x6000 in DomU1 guest
 physical address space, and at 0x7000 in DomU2 guest physical address 
space.
 DomU1 and DomU2 are both the borrower domain, the owner domain is the default
 owner domain DOMID_IO.
+
+For the static shared memory region "my-shared-mem-2", since host physical
+address is not provided by user, Xen will automatically allocate 512MB
+from heap as static shared memory to be shared between DomU1 and DomU2.
+The automatically allocated static shared memory will get mapped at
+0x8000 in DomU1 guest physical address space, and at 0x9000 in DomU2
+guest physical address space. DomU1 is explicitly defined as the owner domain,
+and DomU2 is the borrower domain.
-- 
2.25.1




[PATCH v4 09/10] xen/arm: fix duplicate /reserved-memory node in Dom0

2023-09-10 Thread Penny Zheng
In case there is a /reserved-memory node already present in the host dtb,
current Xen codes would create yet another /reserved-memory node specially
for the static shm in Dom0 Device Tree.

Xen will use write_properties() to copy the reserved memory nodes from host dtb
to Dom0 FDT, so we want to insert the shm node along with the copying.
And avoiding duplication, we add a checking before make_resv_memory_node().

Signed-off-by: Penny Zheng 

---
v3 -> v4:
new commit
---
 xen/arch/arm/domain_build.c   | 31 ---
 xen/arch/arm/include/asm/kernel.h |  2 ++
 2 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 02d903be78..dad234e4b5 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1401,6 +1401,10 @@ static int __init handle_linux_pci_domain(struct 
kernel_info *kinfo,
 return fdt_property_cell(kinfo->fdt, "linux,pci-domain", segment);
 }
 
+static int __init make_shm_memory_node(const struct domain *d,
+   void *fdt,
+   int addrcells, int sizecells,
+   const struct kernel_info *kinfo);
 static int __init write_properties(struct domain *d, struct kernel_info *kinfo,
const struct dt_device_node *node)
 {
@@ -1549,6 +1553,23 @@ static int __init write_properties(struct domain *d, 
struct kernel_info *kinfo,
 }
 }
 
+if ( dt_node_path_is_equal(node, "/reserved-memory") )
+{
+kinfo->resv_mem = true;
+
+/* shared memory provided. */
+if ( kinfo->shminfo.nr_banks != 0 )
+{
+uint32_t addrcells = dt_n_addr_cells(node),
+ sizecells = dt_n_size_cells(node);
+
+res = make_shm_memory_node(d, kinfo->fdt,
+   addrcells, sizecells, kinfo);
+if ( res )
+return res;
+}
+}
+
 return 0;
 }
 
@@ -2856,9 +2877,13 @@ static int __init handle_node(struct domain *d, struct 
kernel_info *kinfo,
 return res;
 }
 
-res = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells, 
kinfo);
-if ( res )
-return res;
+/* Avoid duplicate /reserved-memory nodes in Device Tree */
+if ( !kinfo->resv_mem )
+{
+res = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells, 
kinfo);
+if ( res )
+return res;
+}
 }
 
 res = fdt_end_node(kinfo->fdt);
diff --git a/xen/arch/arm/include/asm/kernel.h 
b/xen/arch/arm/include/asm/kernel.h
index 590bc56f6c..d20c8bc2a8 100644
--- a/xen/arch/arm/include/asm/kernel.h
+++ b/xen/arch/arm/include/asm/kernel.h
@@ -38,6 +38,8 @@ struct kernel_info {
 void *fdt; /* flat device tree */
 paddr_t unassigned_mem; /* RAM not (yet) assigned to a bank */
 struct meminfo mem;
+/* Whether we have /reserved-memory node in host Device Tree */
+bool resv_mem;
 /* Static shared memory banks */
 struct {
 unsigned int nr_banks;
-- 
2.25.1




[PATCH v4 10/10] xen/arm: create another /memory node for static shm

2023-09-10 Thread Penny Zheng
Static shared memory region shall be described both under /memory and
/reserved-memory.

We introduce export_shm_memory_node() to create another /memory node to
contain the static shared memory ranges.

Signed-off-by: Penny Zheng 

---
v3 -> v4:
new commit
---
 xen/arch/arm/domain_build.c | 43 +
 1 file changed, 43 insertions(+)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index dad234e4b5..21e5c622a3 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1714,6 +1714,25 @@ static int __init make_memory_node(const struct domain 
*d,
 }
 
 #ifdef CONFIG_STATIC_SHM
+static int __init export_shm_memory_node(const struct domain *d,
+ const struct kernel_info *kinfo,
+ int addrcells, int sizecells)
+{
+unsigned int i = 0;
+struct meminfo shm_meminfo;
+
+/* Extract meminfo from kinfo.shminfo */
+for ( ; i < kinfo->shminfo.nr_banks; i++ )
+{
+shm_meminfo.bank[i].start = kinfo->shminfo.bank[i].membank.start;
+shm_meminfo.bank[i].size = kinfo->shminfo.bank[i].membank.size;
+shm_meminfo.bank[i].type = MEMBANK_DEFAULT;
+}
+shm_meminfo.nr_banks = kinfo->shminfo.nr_banks;
+
+return make_memory_node(d, kinfo->fdt, addrcells, sizecells, &shm_meminfo);
+}
+
 static int __init make_shm_memory_node(const struct domain *d,
void *fdt,
int addrcells, int sizecells,
@@ -1782,6 +1801,14 @@ static int __init make_shm_memory_node(const struct 
domain *d,
 return res;
 }
 #else
+static int __init export_shm_memory_node(const struct domain *d,
+ const struct kernel_info *kinfo,
+ int addrcells, int sizecells)
+{
+ASSERT_UNREACHABLE();
+return -EOPNOTSUPP;
+}
+
 static int __init make_shm_memory_node(const struct domain *d,
void *fdt,
int addrcells, int sizecells,
@@ -2877,6 +2904,14 @@ static int __init handle_node(struct domain *d, struct 
kernel_info *kinfo,
 return res;
 }
 
+/* Create a memory node to store the static shared memory regions */
+if ( kinfo->shminfo.nr_banks != 0 )
+{
+res = export_shm_memory_node(d, kinfo, addrcells, sizecells);
+if ( res )
+return res;
+}
+
 /* Avoid duplicate /reserved-memory nodes in Device Tree */
 if ( !kinfo->resv_mem )
 {
@@ -3437,6 +3472,14 @@ static int __init prepare_dtb_domU(struct domain *d, 
struct kernel_info *kinfo)
 if ( ret )
 goto err;
 
+/* Create a memory node to store the static shared memory regions */
+if ( kinfo->shminfo.nr_banks != 0 )
+{
+ret = export_shm_memory_node(d, kinfo, addrcells, sizecells);
+if ( ret )
+goto err;
+}
+
 ret = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells, kinfo);
 if ( ret )
 goto err;
-- 
2.25.1




[PATCH v4 06/10] xen/arm: remove shm holes for extended regions

2023-09-10 Thread Penny Zheng
Static shared memory acts as reserved memory in guest, so it shall be
excluded from extended regions.

Extended regions are taken care of under three different scenarios:
normal DomU, direct-map domain with iommu on, and direct-map domain
with iommu off.

For normal DomU, we create a new function "remove_shm_holes_for_domU", to
firstly transfer original outputs into the format of "struct rangeset",
then use "remove_shm_from_rangeset" to remove static shm from them.

For direct-map domain with iommu on, after we get guest shm info from "kinfo",
we use "remove_shm_from_rangeset" to remove static shm.

For direct-map domain with iommu off, as static shm has already been taken
care of through reserved memory banks, we do nothing.

Signed-off-by: Penny Zheng 

---
v1 -> v2:
- new commit
---
v2 -> v3:
- error out non-zero res before remove_shm_holes_for_domU
- rebase
---
v3 -> v4:
rebase and no change
---
 xen/arch/arm/domain_build.c | 97 -
 1 file changed, 96 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 2eae50d78b..02d903be78 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1974,6 +1974,32 @@ static int __init handle_pci_range(const struct 
dt_device_node *dev,
 return 0;
 }
 
+static int __init remove_shm_from_rangeset(const struct kernel_info *kinfo,
+   struct rangeset *rangeset)
+{
+unsigned int i;
+
+/* Remove static shared memory regions */
+for ( i = 0; i < kinfo->shminfo.nr_banks; i++ )
+{
+struct membank membank = kinfo->shminfo.bank[i].membank;
+paddr_t start, end;
+int res;
+
+start = membank.start;
+end = membank.start + membank.size - 1;
+res = rangeset_remove_range(rangeset, start, end);
+if ( res )
+{
+printk(XENLOG_ERR "Failed to remove: %#"PRIpaddr"->%#"PRIpaddr"\n",
+   start, end);
+return -EINVAL;
+}
+}
+
+return 0;
+}
+
 /*
  * Find the holes in the Host DT which can be exposed to Dom0 as extended
  * regions for the special memory mappings. In order to calculate regions
@@ -1982,6 +2008,8 @@ static int __init handle_pci_range(const struct 
dt_device_node *dev,
  * - MMIO
  * - Host RAM
  * - PCI aperture
+ * - Static shared memory regions, which are described by special property
+ *   "xen,static-shm"
  */
 static int __init find_memory_holes(const struct kernel_info *kinfo,
 struct meminfo *ext_regions)
@@ -2058,6 +2086,14 @@ static int __init find_memory_holes(const struct 
kernel_info *kinfo,
 }
 }
 
+/* Remove static shared memory regions */
+if ( kinfo->shminfo.nr_banks != 0 )
+{
+res = remove_shm_from_rangeset(kinfo, mem_holes);
+if ( res )
+goto out;
+}
+
 start = 0;
 end = (1ULL << p2m_ipa_bits) - 1;
 res = rangeset_report_ranges(mem_holes, PFN_DOWN(start), PFN_DOWN(end),
@@ -2073,6 +2109,62 @@ out:
 return res;
 }
 
+static int __init remove_shm_holes_for_domU(const struct kernel_info *kinfo,
+struct meminfo *orig_ext)
+{
+struct rangeset *guest_holes;
+unsigned int i = 0, tail;
+int res;
+paddr_t start, end;
+
+/* No static shared memory region. */
+if ( kinfo->shminfo.nr_banks == 0 )
+return 0;
+
+dt_dprintk("Remove static shared memory holes for extended regions of 
DomU\n");
+
+guest_holes = rangeset_new(NULL, NULL, 0);
+if ( !guest_holes )
+return -ENOMEM;
+
+for ( ; i < orig_ext->nr_banks; i++ )
+{
+start = orig_ext->bank[i].start;
+end = start + orig_ext->bank[i].size - 1;
+
+res = rangeset_add_range(guest_holes, start, end);
+if ( res )
+{
+printk(XENLOG_ERR "Failed to add: %#"PRIpaddr"->%#"PRIpaddr"\n",
+   start, end);
+goto out;
+}
+}
+
+/* Remove static shared memory regions */
+res = remove_shm_from_rangeset(kinfo, guest_holes);
+if ( res )
+goto out;
+
+tail = orig_ext->nr_banks - 1;
+start = orig_ext->bank[0].start;
+end = orig_ext->bank[tail].start + orig_ext->bank[tail].size - 1;
+
+/* Reset original extended regions to hold new value */
+orig_ext->nr_banks = 0;
+res = rangeset_report_ranges(guest_holes, start, end,
+ add_ext_regions, orig_ext);
+if ( res )
+orig_ext->nr_banks = 0;
+else if ( !orig_ext->nr_banks )
+res = -ENOENT;
+
+out:
+rangeset_destroy(guest_holes);
+
+return res;
+}
+
 static int __init find_domU_holes(const struct kernel_info *kinfo,
 

[PATCH v4 07/10] xen/p2m: put reference for superpage

2023-09-10 Thread Penny Zheng
We are doing foreign memory mapping for static shared memory, and
there is a great possibility that it could be super mapped.
But today, p2m_put_l3_page could not handle superpages.

This commits implements a new function p2m_put_superpage to handle superpages,
specifically for helping put extra references for foreign superpages.

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- new commit
---
v2 -> v3:
- rebase and no change
---
v3 -> v4:
rebase and no change
---
 xen/arch/arm/p2m.c | 58 ++
 1 file changed, 43 insertions(+), 15 deletions(-)

diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index de32a2d638..b7b3db005e 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -851,17 +851,9 @@ static int p2m_mem_access_radix_set(struct p2m_domain 
*p2m, gfn_t gfn,
 return rc;
 }
 
-/*
- * Put any references on the single 4K page referenced by pte.
- * TODO: Handle superpages, for now we only take special references for leaf
- * pages (specifically foreign ones, which can't be super mapped today).
- */
-static void p2m_put_l3_page(const lpae_t pte)
+/* Put any references on the single 4K page referenced by mfn. */
+static void p2m_put_l3_page(mfn_t mfn, unsigned type)
 {
-mfn_t mfn = lpae_get_mfn(pte);
-
-ASSERT(p2m_is_valid(pte));
-
 /*
  * TODO: Handle other p2m types
  *
@@ -869,16 +861,53 @@ static void p2m_put_l3_page(const lpae_t pte)
  * flush the TLBs if the page is reallocated before the end of
  * this loop.
  */
-if ( p2m_is_foreign(pte.p2m.type) )
+if ( p2m_is_foreign(type) )
 {
 ASSERT(mfn_valid(mfn));
 put_page(mfn_to_page(mfn));
 }
 /* Detect the xenheap page and mark the stored GFN as invalid. */
-else if ( p2m_is_ram(pte.p2m.type) && is_xen_heap_mfn(mfn) )
+else if ( p2m_is_ram(type) && is_xen_heap_mfn(mfn) )
 page_set_xenheap_gfn(mfn_to_page(mfn), INVALID_GFN);
 }
 
+/* Put any references on the superpage referenced by mfn. */
+static void p2m_put_superpage(mfn_t mfn, unsigned int next_level, unsigned 
type)
+{
+unsigned int i;
+unsigned int level_order = XEN_PT_LEVEL_ORDER(next_level);
+
+for ( i = 0; i < XEN_PT_LPAE_ENTRIES; i++ )
+{
+if ( next_level == 3 )
+p2m_put_l3_page(mfn, type);
+else
+p2m_put_superpage(mfn, next_level + 1, type);
+
+mfn = mfn_add(mfn, 1 << level_order);
+}
+}
+
+/* Put any references on the page referenced by pte. */
+static void p2m_put_page(const lpae_t pte, unsigned int level)
+{
+mfn_t mfn = lpae_get_mfn(pte);
+
+ASSERT(p2m_is_valid(pte));
+
+/*
+ * We are either having a first level 1G superpage or a
+ * second level 2M superpage.
+ */
+if ( p2m_is_superpage(pte, level) )
+return p2m_put_superpage(mfn, level + 1, pte.p2m.type);
+else
+{
+ASSERT(level == 3);
+return p2m_put_l3_page(mfn, pte.p2m.type);
+}
+}
+
 /* Free lpae sub-tree behind an entry */
 static void p2m_free_entry(struct p2m_domain *p2m,
lpae_t entry, unsigned int level)
@@ -907,9 +936,8 @@ static void p2m_free_entry(struct p2m_domain *p2m,
 #endif
 
 p2m->stats.mappings[level]--;
-/* Nothing to do if the entry is a super-page. */
-if ( level == 3 )
-p2m_put_l3_page(entry);
+p2m_put_page(entry, level);
+
 return;
 }
 
-- 
2.25.1




[PATCH v4 05/10] xen/arm: support static shared memory when host address not provided

2023-09-10 Thread Penny Zheng
In order to support static shared memory when host address not provided,
we shall do the following modification:
- we shall let Xen allocate memory from heap for static shared memory
at first domain, no matter it is owner or borrower.
- In acquire_shared_memory_bank, as static shared memory has already
been allocated from heap, we shall assign them to the owner domain
using function "assign_pages".
- Function get_shm_pages_reference is created to add as many
additional reference as the number of borrowers.
- We implement a new helper "add_foreign_mapping_for_borrower" to set
up foreign memory mapping for borrower.

Instead of using multiple function parameters to deliver various shm-related
info, like host physical address, SHMID, etc, and with the introduction
of new struct "shm_memnode" to include banked host memory info, we switch to
use "shm_memnode" as function parameter to replace them all, to make codes more
clear and tidy.

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- combine commits 4 - 6 in Serie 1
- Adapt to changes of introducing "struct shm_memnode"
---
v2 -> v3
- fix infinite loop bug and bad indentation
- rebase
---
v3 -> v4:
rebase and no change
---
 xen/arch/arm/domain_build.c | 223 +---
 1 file changed, 155 insertions(+), 68 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 0116bacc2f..2eae50d78b 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -891,6 +891,11 @@ static void __init assign_static_memory_11(struct domain 
*d,
 }
 
 #ifdef CONFIG_STATIC_SHM
+static bool __init is_shm_allocated_from_heap(struct shm_memnode *node)
+{
+return (node->meminfo.nr_banks != 0);
+}
+
 static int __init acquire_nr_borrower_domain(const char *shm_id,
  unsigned long *nr_borrowers)
 {
@@ -934,12 +939,12 @@ static struct shm_memnode * __init find_shm_memnode(const 
char *shm_id)
  * This function checks whether the static shared memory region is
  * already allocated to dom_io.
  */
-static bool __init is_shm_allocated_to_domio(paddr_t pbase)
+static bool __init is_shm_allocated_to_domio(struct shm_memnode *node)
 {
 struct page_info *page;
 struct domain *d;
 
-page = maddr_to_page(pbase);
+page = maddr_to_page(node->meminfo.bank[0].start);
 d = page_get_owner_and_reference(page);
 if ( d == NULL )
 return false;
@@ -957,67 +962,128 @@ static bool __init is_shm_allocated_to_domio(paddr_t 
pbase)
 }
 
 static mfn_t __init acquire_shared_memory_bank(struct domain *d,
-   paddr_t pbase, paddr_t psize)
+   struct shm_meminfo *meminfo,
+   bool paddr_assigned)
 {
-mfn_t smfn;
-unsigned long nr_pfns;
-int res;
+int res, i = 0;
 
-/*
- * Pages of statically shared memory shall be included
- * into domain_tot_pages().
- */
-nr_pfns = PFN_DOWN(psize);
-if ( (UINT_MAX - d->max_pages) < nr_pfns )
+for ( ; i < meminfo->nr_banks; i++ )
 {
-printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages: %lu.\n",
-   d, nr_pfns);
-return INVALID_MFN;
+paddr_t pbase = meminfo->bank[i].start, psize = meminfo->bank[i].size;
+unsigned long nr_pfns;
+
+/*
+ * Pages of statically shared memory shall be included
+ * into domain_tot_pages().
+ */
+nr_pfns = PFN_DOWN(psize);
+if ( (UINT_MAX - d->max_pages) < nr_pfns )
+{
+printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages: %lu.\n",
+   d, nr_pfns);
+return INVALID_MFN;
+}
+d->max_pages += nr_pfns;
+
+if ( paddr_assigned )
+{
+res = acquire_domstatic_pages(d, maddr_to_mfn(pbase), nr_pfns, 0);
+if ( res )
+{
+printk(XENLOG_ERR
+   "%pd: failed to acquire static memory: %d.\n", d, res);
+goto fail;
+}
+}
+else
+/*
+ * When host address is not provided, static shared memory is
+ * allocated from heap and shall be assigned to owner domain.
+ */
+if ( assign_pages(maddr_to_page(pbase), nr_pfns, d, 0) )
+goto fail;
 }
-d->max_pages += nr_pfns;
 
-smfn = maddr_to_mfn(pbase);
-res = acquire_domstatic_pages(d, smfn, nr_pfns, 0);
-if ( res )
+return maddr_to_mfn(meminfo->bank[0].start);
+
+ fail:
+while( --i >= 0 )
+d->max_pages -= PFN_DOWN(meminfo->bank[i].size);
+return INVALID_MFN;
+}
+
+static int __init get_shm_pages_reference(struct domain *d,
+ 

[PATCH v4 04/10] xen/arm: use paddr_assigned to indicate whether host address is provided

2023-09-10 Thread Penny Zheng
We use paddr_assigned to indicate whether host address is provided, by
checking the length of "xen,shared-mem" property.

The shm matching criteria shall also be adapt to cover the new scenario, by
adding when host address is not provided, if SHMID matches, the region size
must exactly match too.

During domain creation, right now, a static shared memory node could be
banked with a statically configured host memory bank, or a set of arbitrary
host memory banks allocated from heap. To cover both scenarios, we create
a new structure shm_meminfo. It is very alike meminfo, but with the maximum
array size being a smaller number NR_SHM_BANKS(16).
As "shm_meminfo" is also a new member of "enum meminfo_type", we shall implement
its own callback "retrieve_shm_meminfo" to have access to all MACRO
helpers, e.g. GET_MEMBANK(...).

Also, to make codes tidy and clear, we extract codes about parsing
"xen,shared-mem" property from function "process_shm" and move them into
a new helper "parse_shm_property".

Signed-off-by: Penny Zheng 
---
v1 -> v2
- In order to get allocated banked host memory info during domain creation,
we create a new structure shm_meminfo. It is very alike meminfo, with
the maximum array size being NR_SHM_BANKS. As shm_meminfo is a new
member of type meminfo_type, we shall implement its own callback
retrieve_shm_meminfo to have access to all MACRO helpers, e.g.
GET_MEMBANK(...)
- rename "acquire_shm_memnode" to "find_shm_memnode"
---
v2 -> v3
- rebase and no changes
---
v3 -> v4:
rebase and no change
---
 xen/arch/arm/bootfdt.c   | 100 ++-
 xen/arch/arm/domain_build.c  | 207 +--
 xen/arch/arm/include/asm/setup.h |   3 +
 3 files changed, 243 insertions(+), 67 deletions(-)

diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
index 66ad3ab3db..7d86dffd45 100644
--- a/xen/arch/arm/bootfdt.c
+++ b/xen/arch/arm/bootfdt.c
@@ -21,7 +21,15 @@ static __initdata struct {
 unsigned int nr_nodes;
 struct {
 const struct shm_node *node;
-const struct membank *membank;
+/*
+ * For a static shared memory node, it is either banked with a reserved
+ * host memory bank, or arbitrary host memory which shall
+ * be allocated by Xen with a specified total size(tot_size).
+ */
+union {
+const struct membank *membank;
+paddr_t tot_size;
+};
 } shm_nodes[NR_MEM_BANKS];
 } shm_data;
 #endif
@@ -421,7 +429,7 @@ static int __init process_shm_node(const void *fdt, int 
node,
 paddr_t paddr, gaddr, size;
 unsigned int i;
 int len;
-bool owner = false;
+bool owner = false, paddr_assigned = true;
 const char *shm_id;
 
 if ( address_cells < 1 || size_cells < 1 )
@@ -462,7 +470,7 @@ static int __init process_shm_node(const void *fdt, int 
node,
 }
 
 /*
- * xen,shared-mem = ;
+ * xen,shared-mem = , and paddr could be optional
  * Memory region starting from physical address #paddr of #size shall
  * be mapped to guest physical address #gaddr as static shared memory
  * region.
@@ -473,16 +481,24 @@ static int __init process_shm_node(const void *fdt, int 
node,
 
 if ( len != dt_cells_to_size(address_cells + size_cells + address_cells) )
 {
+/* paddr is not provided in "xen,shared-mem" */
 if ( len == dt_cells_to_size(size_cells + address_cells) )
-printk("fdt: host physical address must be chosen by users at the 
moment.\n");
-
-printk("fdt: invalid `xen,shared-mem` property.\n");
-return -EINVAL;
+paddr_assigned = false;
+else
+{
+printk("fdt: invalid `xen,shared-mem` property.\n");
+return -EINVAL;
+}
 }
 
 cell = (const __be32 *)prop->data;
-device_tree_get_reg(&cell, address_cells, address_cells, &paddr, &gaddr);
-size = dt_next_cell(size_cells, &cell);
+if ( !paddr_assigned )
+device_tree_get_reg(&cell, address_cells, size_cells, &gaddr, &size);
+else
+{
+device_tree_get_reg(&cell, address_cells, address_cells, &paddr, 
&gaddr);
+size = dt_next_cell(size_cells, &cell);
+}
 
 if ( !size )
 {
@@ -495,23 +511,37 @@ static int __init process_shm_node(const void *fdt, int 
node,
 paddr_t bank_start = shm_data.shm_nodes[i].membank->start;
 paddr_t bank_size = shm_data.shm_nodes[i].membank->size;
 const char *bank_id = shm_data.shm_nodes[i].node->shm_id;
+paddr_t tot_size = shm_data.shm_nodes[i].tot_size;
 
 /*
  * Meet the following check:
+ * when host address is provided:
  * 1) The shm ID matches and the region exactly match
  * 2) The shm ID doesn't match and t

[PATCH v4 03/10] xen/arm: introduce allocate_domheap_memory and guest_physmap_memory

2023-09-10 Thread Penny Zheng
We split the code of allocate_bank_memory into two parts,
allocate_domheap_memory and guest_physmap_memory.

One is about allocating guest RAM from heap, which could be re-used later for
allocating static shared memory from heap when host address is not provided.
The other is building up guest P2M mapping.

We also define a set of MACRO helpers to access common fields in data
structure of "meminfo" type, e.g. "struct meminfo" is one of them, and
later new "struct shm_meminfo" is also one of them.
This kind of structures must have the following characteristics:
- an array of "struct membank"
- a member called "nr_banks" indicating current array size
- a field indicating the maximum array size
When introducing a new data structure, according callbacks with function type
"retrieve_fn" shall be defined for using MACRO helpers.
This commit defines callback "retrieve_meminfo" for data structure
"struct meminfo".

Signed-off-by: Penny Zheng 
---
v1 -> v2:
-  define a set of MACRO helpers to access common fields in data structure of
"meminfo" type. "struct meminfo" is one of them, and according callback
"retrieve_meminfo" is also introduced here.
- typo of changing 1ULL to 1UL
---
v2 -> v3
- rebase and no changes
---
v3 -> v4:
rebase and no change
---
 xen/arch/arm/domain_build.c  | 119 ---
 xen/arch/arm/include/asm/setup.h |  33 +
 2 files changed, 127 insertions(+), 25 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 4901664682..d5945e421d 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -99,6 +99,26 @@ int __init parse_arch_dom0_param(const char *s, const char 
*e)
  */
 #define DOM0_FDT_EXTRA_SIZE (128 + sizeof(struct fdt_reserve_entry))
 
+static void __init retrieve_meminfo(void *mem, unsigned int *max_mem_banks,
+struct membank **bank,
+unsigned int **nr_banks)
+{
+struct meminfo *meminfo = (struct meminfo *)mem;
+
+if ( max_mem_banks )
+*max_mem_banks = NR_MEM_BANKS;
+
+if ( nr_banks )
+*nr_banks = &(meminfo->nr_banks);
+
+if ( bank )
+*bank = meminfo->bank;
+}
+
+retrieve_fn __initdata retrievers[MAX_MEMINFO_TYPE] = {
+[NORMAL_MEMINFO] = retrieve_meminfo,
+};
+
 unsigned int __init dom0_max_vcpus(void)
 {
 if ( opt_dom0_max_vcpus == 0 )
@@ -413,34 +433,20 @@ static void __init allocate_memory_11(struct domain *d,
 }
 }
 
-static bool __init allocate_bank_memory(struct domain *d,
-struct kernel_info *kinfo,
-gfn_t sgfn,
-paddr_t tot_size)
+static bool __init allocate_domheap_memory(struct domain *d,
+   paddr_t tot_size,
+   void *mem, enum meminfo_type type)
 {
-int res;
 struct page_info *pg;
-struct membank *bank;
 unsigned int max_order = ~0;
-
-/*
- * allocate_bank_memory can be called with a tot_size of zero for
- * the second memory bank. It is not an error and we can safely
- * avoid creating a zero-size memory bank.
- */
-if ( tot_size == 0 )
-return true;
-
-bank = &kinfo->mem.bank[kinfo->mem.nr_banks];
-bank->start = gfn_to_gaddr(sgfn);
-bank->size = tot_size;
+unsigned int *nr_banks = GET_NR_BANKS(mem, type);
 
 while ( tot_size > 0 )
 {
 unsigned int order = get_allocation_size(tot_size);
+struct membank *membank;
 
 order = min(max_order, order);
-
 pg = alloc_domheap_pages(d, order, 0);
 if ( !pg )
 {
@@ -460,15 +466,78 @@ static bool __init allocate_bank_memory(struct domain *d,
 continue;
 }
 
-res = guest_physmap_add_page(d, sgfn, page_to_mfn(pg), order);
-if ( res )
-{
-dprintk(XENLOG_ERR, "Failed map pages to DOMU: %d", res);
+if ( *nr_banks == MAX_MEM_BANKS(type) )
 return false;
-}
+
+membank = GET_MEMBANK(mem, type, *nr_banks);
+membank->start = mfn_to_maddr(page_to_mfn(pg));
+membank->size = 1ULL << (PAGE_SHIFT + order);
+(*nr_banks)++;
+tot_size -= membank->size;
+}
+
+return true;
+}
+
+static int __init guest_physmap_memory(struct domain *d,
+   void *mem, enum meminfo_type type,
+   gfn_t sgfn)
+{
+unsigned int i;
+int res;
+unsigned int *nr_banks = GET_NR_BANKS(mem, type);
+
+for ( i = 0; i < *nr_banks; i++ )
+{
+struct membank *membank = GET_MEMBANK(mem, type, i);
+paddr_t start = membank->start;
+paddr_t siz

[PATCH v4 00/10] Follow-up static shared memory PART I

2023-09-10 Thread Penny Zheng
There are some unsolving issues on current 4.17 static shared memory
feature[1], including:
- In order to avoid keeping growing 'membank', having the shared memory
info in separate structures is preferred.
- Missing implementation on having the host address optional in
"xen,shared-mem" property
- Removing static shared memory from extended regions
- Missing reference release on foreign superpage
- Fix duplicated /reserved-memory node on Dom0
- Missing static shm node declaration on guest /memory node
- Missing "xen,offset" feature, which is introduced in Linux DOC[2]

All above objects have been divided into two parts to complete. And this
patch serie is PART I.

[1] https://lore.kernel.org/all/20220908135513.1800511-1-penny.zh...@arm.com/
[2] 
https://www.kernel.org/doc/Documentation/devicetree/bindings/reserved-memory/xen%2Cshared-memory.txt

Penny Zheng (10):
  xen/arm: remove stale addr_cells/size_cells in assign_shared_memory
  xen/arm: re-define a set of data structures for static shared memory
region
  xen/arm: introduce allocate_domheap_memory and guest_physmap_memory
  xen/arm: use paddr_assigned to indicate whether host address is
provided
  xen/arm: support static shared memory when host address not provided
  xen/arm: remove shm holes for extended regions
  xen/p2m: put reference for superpage
  xen/docs: refine docs about static shared memory
  xen/arm: fix duplicate /reserved-memory node in Dom0
  xen/arm: reate another /memory node for static shm

 docs/misc/arm/device-tree/booting.txt |  52 +-
 xen/arch/arm/bootfdt.c| 125 -
 xen/arch/arm/domain_build.c   | 780 --
 xen/arch/arm/include/asm/kernel.h |  11 +-
 xen/arch/arm/include/asm/setup.h  |  57 +-
 xen/arch/arm/p2m.c|  58 +-
 6 files changed, 856 insertions(+), 227 deletions(-)

-- 
2.25.1




[PATCH v4 01/10] xen/arm: remove stale addr_cells/size_cells in assign_shared_memory

2023-09-10 Thread Penny Zheng
Function parameters {addr_cells,size_cells} are stale parameters in
assign_shared_memory, so we shall remove them.

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- new commit
---
v2 -> v3:
rebase and no change
---
v3 -> v4:
rebase and no change
---
 xen/arch/arm/domain_build.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 29dcbb8a2e..c532fa882c 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -858,7 +858,6 @@ static mfn_t __init acquire_shared_memory_bank(struct 
domain *d,
 }
 
 static int __init assign_shared_memory(struct domain *d,
-   uint32_t addr_cells, uint32_t 
size_cells,
paddr_t pbase, paddr_t psize,
paddr_t gbase)
 {
@@ -1020,7 +1019,6 @@ static int __init process_shm(struct domain *d, struct 
kernel_info *kinfo,
  * specified, so they should be assigned to dom_io.
  */
 ret = assign_shared_memory(owner_dom_io ? dom_io : d,
-   addr_cells, size_cells,
pbase, psize, gbase);
 if ( ret )
 return ret;
-- 
2.25.1




[PATCH v4 02/10] xen/arm: re-define a set of data structures for static shared memory region

2023-09-10 Thread Penny Zheng
This commit introduces a set of separate data structures to deal with
static shared memory at different stages.

In boot-time host device tree parsing, we introduce a new structure
"struct shm_node" and a new field "shm_info" in bootinfo to describe and
store parsed shm info.
only SHMID and "nr_borrowers", which describes the number of borrower domain,
are considered here for per shm node.
We also introduce a new local global data "shm_data" in bootfdt.c, in which,
reserved memory bank is recorded together with shm node, to assist doing
shm node verification.

In order to apply above changes in acquire_nr_borrower_domain, we now use SHMID
to iterate "shminfo" to find requested shm node, then acquiring the information
of "nr_borrowers".

In the last, a new anonymized structure "shminfo", which is a array of
compound structure that contains SHMID and a "struct membank membank"
describing shared memory regions in guest address space, is created in "kinfo"
when dealing with domain information.

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- As the original "struct shm_membank" was making reserving memory more
complex and actually memory information could be still got from host Device\
Tree when dealing with domain construction, we introduce a new simple structure
"struct shm_node" in bootinfo to only store SHMID and "nr_borrowers"
- Further restrict the scope of the local variable
"struct meminfo *mem = &bootinfo.reserved_mem"
- Introduce a new local global data "shm_data" in bootfdt.c. In which, reserved
memory bank is recorded together with the shm node, to assist doing shm node
verification.
- Define a set of local variables that point to
"shm_data.shm_nodes[i].membank->start", etc, to make the code more readable.
- Use SHMID to iterate "shminfo" to find requested shm node, as we no
longer store host memory bank info in shm node.
- A new anonymized structure, which is a array of compound structure that
contains SHMID and a "struct membank membank", describing shared memory region
in guest, is introduced in "kinfo".
---
v2 -> v3:
- rebase and no changes
---
v3 -> v4:
rebase and no change
---
 xen/arch/arm/bootfdt.c| 57 ++--
 xen/arch/arm/domain_build.c   | 74 +++
 xen/arch/arm/include/asm/kernel.h |  9 +++-
 xen/arch/arm/include/asm/setup.h  | 21 +++--
 4 files changed, 104 insertions(+), 57 deletions(-)

diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
index 2673ad17a1..66ad3ab3db 100644
--- a/xen/arch/arm/bootfdt.c
+++ b/xen/arch/arm/bootfdt.c
@@ -16,6 +16,16 @@
 #include 
 #include 
 
+#ifdef CONFIG_STATIC_SHM
+static __initdata struct {
+unsigned int nr_nodes;
+struct {
+const struct shm_node *node;
+const struct membank *membank;
+} shm_nodes[NR_MEM_BANKS];
+} shm_data;
+#endif
+
 static bool __init device_tree_node_matches(const void *fdt, int node,
 const char *match)
 {
@@ -409,7 +419,6 @@ static int __init process_shm_node(const void *fdt, int 
node,
 const struct fdt_property *prop, *prop_id, *prop_role;
 const __be32 *cell;
 paddr_t paddr, gaddr, size;
-struct meminfo *mem = &bootinfo.reserved_mem;
 unsigned int i;
 int len;
 bool owner = false;
@@ -481,17 +490,21 @@ static int __init process_shm_node(const void *fdt, int 
node,
 return -EINVAL;
 }
 
-for ( i = 0; i < mem->nr_banks; i++ )
+for ( i = 0; i < shm_data.nr_nodes; i++ )
 {
+paddr_t bank_start = shm_data.shm_nodes[i].membank->start;
+paddr_t bank_size = shm_data.shm_nodes[i].membank->size;
+const char *bank_id = shm_data.shm_nodes[i].node->shm_id;
+
 /*
  * Meet the following check:
  * 1) The shm ID matches and the region exactly match
  * 2) The shm ID doesn't match and the region doesn't overlap
  * with an existing one
  */
-if ( paddr == mem->bank[i].start && size == mem->bank[i].size )
+if ( paddr == bank_start && size == bank_size )
 {
-if ( strncmp(shm_id, mem->bank[i].shm_id, MAX_SHM_ID_LENGTH) == 0 )
+if ( strncmp(shm_id, bank_id, MAX_SHM_ID_LENGTH) == 0 )
 break;
 else
 {
@@ -503,9 +516,9 @@ static int __init process_shm_node(const void *fdt, int 
node,
 else
 {
 paddr_t end = paddr + size;
-paddr_t bank_end = mem->bank[i].start + mem->bank[i].size;
+paddr_t bank_end = bank_start + bank_size;
 
-if ( (end <= paddr) || (bank_end <= mem->bank[i].start) )
+if ( (end <= paddr) || (bank_end <= bank_start) )
 {
   

Re: [PATCH v6 01/13] xen/arm64: head.S: Introduce enable_{boot,secondary}_cpu_mm()

2023-09-07 Thread Penny Zheng

Hi Ayan

On 2023/9/7 17:44, Ayan Kumar Halder wrote:

Hi Henry,

On 28/08/2023 02:32, Henry Wang wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



From: Wei Chen 

At the moment, on MMU system, enable_mmu() will return to an
address in the 1:1 mapping, then each path is responsible to
switch to virtual runtime mapping. Then remove_identity_mapping()
is called on the boot CPU to remove all 1:1 mapping.

Since remove_identity_mapping() is not necessary on Non-MMU system,
and we also avoid creating empty function for Non-MMU system, trying
to keep only one codeflow in arm64/head.S, we move path switch and
remove_identity_mapping() in enable_mmu() on MMU system.

As the remove_identity_mapping should only be called for the boot
CPU only, so we introduce enable_boot_cpu_mm() for boot CPU and
enable_secondary_cpu_mm() for secondary CPUs in this patch.

Signed-off-by: Wei Chen 
Signed-off-by: Penny Zheng 
Signed-off-by: Henry Wang 
Reviewed-by: Julien Grall 
---
v6:
- Add Julien's Reviewed-by tag.
v5:
- Add missing "()" in title.
- Use more generic comment in enable_{boot,secondary}_cpu_mm() to
   mention function will return to the vaddr requested by the caller.
- Move 'mov lr, x5' closer to 'b remove_identity_mapping'.
- Drop the 'b fail' for unreachable code in enable_boot_cpu_mm().
v4:
- Clarify remove_identity_mapping() is called on boot CPU and keep
   the function/proc format consistent in commit msg.
- Drop inaccurate (due to the refactor) in-code comment.
- Rename enable_{boot,runtime}_mmu to enable_{boot,secondary}_cpu_mm.
- Reword the in-code comment on top of enable_{boot,secondary}_cpu_mm.
- Call "fail" for unreachable code.
v3:
- new patch
---
  xen/arch/arm/arm64/head.S | 83 ++-
  1 file changed, 64 insertions(+), 19 deletions(-)

diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
index 5029013a14..f25a41d36c 100644
--- a/xen/arch/arm/arm64/head.S
+++ b/xen/arch/arm/arm64/head.S
@@ -325,21 +325,11 @@ real_start_efi:

  bl    check_cpu_mode
  bl    cpu_init
-    bl    create_page_tables
-    load_paddr x0, boot_pgtable
-    bl    enable_mmu

-    /* We are still in the 1:1 mapping. Jump to the runtime 
Virtual Address. */

-    ldr   x0, =primary_switched
-    br    x0
+    ldr   lr, =primary_switched
+    b enable_boot_cpu_mm
+
  primary_switched:
-    /*
- * The 1:1 map may clash with other parts of the Xen virtual 
memory

- * layout. As it is not used anymore, remove it completely to
- * avoid having to worry about replacing existing mapping
- * afterwards.
- */
-    bl    remove_identity_mapping
  bl    setup_fixmap
  #ifdef CONFIG_EARLY_PRINTK
  /* Use a virtual address to access the UART. */
@@ -384,13 +374,10 @@ GLOBAL(init_secondary)
  #endif
  bl    check_cpu_mode
  bl    cpu_init
-    load_paddr x0, init_ttbr
-    ldr   x0, [x0]
-    bl    enable_mmu

-    /* We are still in the 1:1 mapping. Jump to the runtime 
Virtual Address. */

-    ldr   x0, =secondary_switched
-    br    x0
+    ldr   lr, =secondary_switched
+    b enable_secondary_cpu_mm
+
  secondary_switched:
  #ifdef CONFIG_EARLY_PRINTK
  /* Use a virtual address to access the UART. */
@@ -748,6 +735,64 @@ enable_mmu:
  ret
  ENDPROC(enable_mmu)

+/*
+ * Enable mm (turn on the data cache and the MMU) for secondary CPUs.
+ * The function will return to the virtual address provided in LR 
(e.g. the

+ * runtime mapping).
+ *
+ * Inputs:
+ *   lr : Virtual address to return to.
+ *
+ * Clobbers x0 - x5
+ */
+enable_secondary_cpu_mm:
+    mov   x5, lr
+
+    load_paddr x0, init_ttbr
+    ldr   x0, [x0]
+
+    bl    enable_mmu
+    mov   lr, x5
+
+    /* Return to the virtual address requested by the caller. */
+    ret
+ENDPROC(enable_secondary_cpu_mm)
+
+/*
+ * Enable mm (turn on the data cache and the MMU) for the boot CPU.
+ * The function will return to the virtual address provided in LR 
(e.g. the

+ * runtime mapping).
+ *
+ * Inputs:
+ *   lr : Virtual address to return to.
+ *
+ * Clobbers x0 - x5
+ */
+enable_boot_cpu_mm:
+    mov   x5, lr
+
+    bl    create_page_tables
+    load_paddr x0, boot_pgtable
+
+    bl    enable_mmu
+
+    /*
+ * The MMU is turned on and we are in the 1:1 mapping. Switch
+ * to the runtime mapping.
+ */
+    ldr   x0, =1f
+    br    x0
+1:
+    mov   lr, x5
+    /*
+ * The 1:1 map may clash with other parts of the Xen virtual 
memory
+ * layout. As it is not used anymore, remove it completely to 
avoid

+ * having to worry about replacing existing mapping afte

Re: [PATCH v5 11/13] xen/arm: mmu: move MMU specific P2M code to mmu/p2m.{c,h}

2023-08-22 Thread Penny Zheng

Hi Julien

On 2023/8/23 02:01, Julien Grall wrote:

Hi Henry,

On 14/08/2023 05:25, Henry Wang wrote:

From: Penny Zheng 

Current P2M implementation is designed for MMU system only.
We move the MMU-specific codes into mmu/p2m.c, and only keep generic
codes in p2m.c, like VMID allocator, etc. We also move MMU-specific
definitions and declarations to mmu/p2m.h, such as p2m_tlb_flush_sync().
Also expose previously static functions p2m_vmid_allocator_init(),
p2m_alloc_vmid(), __p2m_set_entry() and setup_virt_paging_one()


Looking at the code, it seemsm that you need to keep expose 
__p2m_set_entry() because of p2m_relinquish_mapping(). However, it is 
not clear how this code is supposed to work for the MPU. So should we 
instead from p2m_relinquish_mapping() to mmu/p2m.c?




p2m->root stores per-domain P2M table, which is actually an array of MPU
region(pr_t). So maybe we should relinquish mapping region by region,
instead of page by page. Nevertheless, p2m_relinquish_mapping() shall be
moved to mmu/p2m.c and we need MPU version of it.


Other functions which doesn't seem to make sense in p2m.c are:
   * p2m_clear_root_pages(): AFAIU there is no concept of root in the 
MPU. This also means that we possibly want to move out anything specific 
to the MMU from 'struct p2m'. This could be done separately.


Current MPU implementation is re-using p2m->root to store P2M table.
Do you agree on this, or should we create a new variable, like 
p2m->mpu_table, for MPU P2M table only?
How we treat p2m_clear_root_pages also decides how we destroy P2M at 
domain destruction stage, current MPU flow is as follows:

```
PROGRESS(mapping):
ret = relinquish_p2m_mapping(d);
if ( ret )
return ret;

PROGRESS(p2m_root):
/*
 * We are about to free the intermediate page-tables, so clear the
 * root to prevent any walk to use them.
 */
p2m_clear_root_pages(&d->arch.p2m);

#ifdef CONFIG_HAS_PAGING_MEMPOOL
PROGRESS(p2m):
ret = p2m_teardown(d);
if ( ret )
return ret;

PROGRESS(p2m_pool):
ret = p2m_teardown_allocation(d);
if( ret )
return ret;
#endif
```
We guard MMU-specific intermediate page-tables destroy with the new 
Kconfig CONFIG_HAS_PAGING_MEMPOOL, check 
https://gitlab.com/xen-project/people/henryw/xen/-/commit/7ff6d351e65f43fc34ea694adea0e030a51b1576

for more details.

If we destroy MPU P2M table in relinquish_p2m_mapping, region by region,
we could provide empty stub for p2m_clear_root_pages, and move it to 
mmu/p2m.c


   * p2m_flush_vm(): This is built with MMU in mind as we can use the 
page-table to track access pages. You don't have that fine granularity 
in the MPU.




Understood


for futher MPU usage.


typo: futher/further/



With the code movement, global variable max_vmid is used in multiple
files instead of a single file (and will be used in MPU P2M
implementation), declare it in the header and remove the "static" of
this variable.

Add #ifdef CONFIG_HAS_MMU to p2m_write_unlock() since future MPU
work does not need p2m_tlb_flush_sync().


And there are no specific barrier required? Overall, I am not sure I 
like the #ifdef rather than providing a stub helper.


If the other like the idea of the #ifdef. I think a comment on top would 
be necessary to explain why there is nothing to do in the context of the 
MPU.


Cheers,





Re: [PATCH v3 0/8] Follow-up static shared memory PART I

2023-08-22 Thread Penny Zheng

Hi, michal

On 2023/8/21 18:49, Michal Orzel wrote:

Hi Penny,

On 21/08/2023 06:00, Penny Zheng wrote:



There are some unsolving issues on current 4.17 static shared memory
feature[1], including:
- In order to avoid keeping growing 'membank', having the shared memory
info in separate structures is preferred.
- Missing implementation on having the host address optional in
"xen,shared-mem" property
- Removing static shared memory from extended regions
- Missing reference release on foreign superpage
- Missing "xen,offset" feature, which is introduced in Linux DOC[2]

All above objects have been divided into two parts to complete. And this
patch serie is PART I.

[1] https://lore.kernel.org/all/20220908135513.1800511-1-penny.zh...@arm.com/
[2] 
https://www.kernel.org/doc/Documentation/devicetree/bindings/reserved-memory/xen%2Cshared-memory.txt


It looks like there is a problem with the changes introduced in this series.
The gitlab static shared memory tests failed:
https://gitlab.com/xen-project/patchew/xen/-/pipelines/973985190
No Xen logs meaning the failure occurred before serial console initialization.

Now, I would like to share some observations after playing around with the 
current static shared mem code today.
1) Static shared memory region is advertised to a domain by creating a child 
node under reserved-memory.
/reserved-memory is nothing but a way to carve out a region from the normal 
memory specified in /memory node.
For me, such regions should be described in domain's /memory node as well. This 
is not the case at the moment
for static shm unlike to other sub-nodes of /reserved-memory (present in host 
dtb) for which Xen creates separate
/memory nodes.



Hmm, correct me if I'm wrong,
If we describe twice in domain's /memory node too, it will be treated as 
normal memory, then any application could use it. The reason why we put 
static shm under /reserved-memory is that we only hope special driver, 
like static shm linux driver, could access it.


If you track down in make_memory_node(), only memory range that is 
reserved for device (or firmware) will be described twice as normal 
memory in Dom0. Memory like static shm, will get passed.



2) Domain dtb parsing issue with two /reserved-memory nodes present.
In case there is a /reserved-memory node already present in the host dtb, Xen 
would create yet another /reserved-memory
node for the static shm (to be observed in case of dom0). This is a bug as 
there can be only one /reserved-memory node.
This leads to an error when dumping with dtc and leads to a shm node not being 
visible to a domain (guest OS relies on
a presence of a single /reserved-memory node). The issue is because in 
make_resv_memory_node(), you are not checking if
such node already exists.


Yes, you're true.
In Dom0, we could see two /reserved-memory nodes. I think, if there is a 
/reserved-memory node already present in the host dtb, we shall reserve 
it in kinfo for make_resv_memory_node().




I haven't looked closely at this series yet. It might be that these issues are 
fixed. If not, I would definitely
suggest to fix them in the first place.

~Michal




[PATCH v3 7/8] xen/p2m: put reference for superpage

2023-08-20 Thread Penny Zheng
We are doing foreign memory mapping for static shared memory, and
there is a great possibility that it could be super mapped.
But today, p2m_put_l3_page could not handle superpages.

This commits implements a new function p2m_put_superpage to handle superpages,
specifically for helping put extra references for foreign superpages.

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- new commit
---
v2 -> v3:
- rebase and no change
---
 xen/arch/arm/p2m.c | 58 ++
 1 file changed, 43 insertions(+), 15 deletions(-)

diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index de32a2d638..b7b3db005e 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -851,17 +851,9 @@ static int p2m_mem_access_radix_set(struct p2m_domain 
*p2m, gfn_t gfn,
 return rc;
 }
 
-/*
- * Put any references on the single 4K page referenced by pte.
- * TODO: Handle superpages, for now we only take special references for leaf
- * pages (specifically foreign ones, which can't be super mapped today).
- */
-static void p2m_put_l3_page(const lpae_t pte)
+/* Put any references on the single 4K page referenced by mfn. */
+static void p2m_put_l3_page(mfn_t mfn, unsigned type)
 {
-mfn_t mfn = lpae_get_mfn(pte);
-
-ASSERT(p2m_is_valid(pte));
-
 /*
  * TODO: Handle other p2m types
  *
@@ -869,16 +861,53 @@ static void p2m_put_l3_page(const lpae_t pte)
  * flush the TLBs if the page is reallocated before the end of
  * this loop.
  */
-if ( p2m_is_foreign(pte.p2m.type) )
+if ( p2m_is_foreign(type) )
 {
 ASSERT(mfn_valid(mfn));
 put_page(mfn_to_page(mfn));
 }
 /* Detect the xenheap page and mark the stored GFN as invalid. */
-else if ( p2m_is_ram(pte.p2m.type) && is_xen_heap_mfn(mfn) )
+else if ( p2m_is_ram(type) && is_xen_heap_mfn(mfn) )
 page_set_xenheap_gfn(mfn_to_page(mfn), INVALID_GFN);
 }
 
+/* Put any references on the superpage referenced by mfn. */
+static void p2m_put_superpage(mfn_t mfn, unsigned int next_level, unsigned 
type)
+{
+unsigned int i;
+unsigned int level_order = XEN_PT_LEVEL_ORDER(next_level);
+
+for ( i = 0; i < XEN_PT_LPAE_ENTRIES; i++ )
+{
+if ( next_level == 3 )
+p2m_put_l3_page(mfn, type);
+else
+p2m_put_superpage(mfn, next_level + 1, type);
+
+mfn = mfn_add(mfn, 1 << level_order);
+}
+}
+
+/* Put any references on the page referenced by pte. */
+static void p2m_put_page(const lpae_t pte, unsigned int level)
+{
+mfn_t mfn = lpae_get_mfn(pte);
+
+ASSERT(p2m_is_valid(pte));
+
+/*
+ * We are either having a first level 1G superpage or a
+ * second level 2M superpage.
+ */
+if ( p2m_is_superpage(pte, level) )
+return p2m_put_superpage(mfn, level + 1, pte.p2m.type);
+else
+{
+ASSERT(level == 3);
+return p2m_put_l3_page(mfn, pte.p2m.type);
+}
+}
+
 /* Free lpae sub-tree behind an entry */
 static void p2m_free_entry(struct p2m_domain *p2m,
lpae_t entry, unsigned int level)
@@ -907,9 +936,8 @@ static void p2m_free_entry(struct p2m_domain *p2m,
 #endif
 
 p2m->stats.mappings[level]--;
-/* Nothing to do if the entry is a super-page. */
-if ( level == 3 )
-p2m_put_l3_page(entry);
+p2m_put_page(entry, level);
+
 return;
 }
 
-- 
2.25.1




[PATCH v3 8/8] xen/docs: refine docs about static shared memory

2023-08-20 Thread Penny Zheng
This commit amends docs(docs/misc/arm/device-tree/booting.txt) to include the
new scenario where host address is not provided in "xen,shared-mem" property,
and we also add a new example to explain in detail.

We also fix some buggy info in the docs, like SHMID is "my-shared-mem-1",
not "0x1".

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- no new changes
---
v2 -> v3
- rebase and no change
---
 docs/misc/arm/device-tree/booting.txt | 52 ---
 1 file changed, 39 insertions(+), 13 deletions(-)

diff --git a/docs/misc/arm/device-tree/booting.txt 
b/docs/misc/arm/device-tree/booting.txt
index bbd955e9c2..ac4bad6fe5 100644
--- a/docs/misc/arm/device-tree/booting.txt
+++ b/docs/misc/arm/device-tree/booting.txt
@@ -590,7 +590,7 @@ communication.
 An array takes a physical address, which is the base address of the
 shared memory region in host physical address space, a size, and a guest
 physical address, as the target address of the mapping.
-e.g. xen,shared-mem = < [host physical address] [guest address] [size] >
+e.g. xen,shared-mem = < [host physical address] [guest address] [size] >;
 
 It shall also meet the following criteria:
 1) If the SHM ID matches with an existing region, the address range of the
@@ -601,8 +601,8 @@ communication.
 The number of cells for the host address (and size) is the same as the
 guest pseudo-physical address and they are inherited from the parent node.
 
-Host physical address is optional, when missing Xen decides the location
-(currently unimplemented).
+Host physical address is optional, when missing Xen decides the location.
+e.g. xen,shared-mem = < [guest address] [size] >;
 
 - role (Optional)
 
@@ -629,7 +629,7 @@ chosen {
 role = "owner";
 xen,shm-id = "my-shared-mem-0";
 xen,shared-mem = <0x1000 0x1000 0x1000>;
-}
+};
 
 domU1 {
 compatible = "xen,domain";
@@ -640,25 +640,36 @@ chosen {
 vpl011;
 
 /*
- * shared memory region identified as 0x0(xen,shm-id = <0x0>)
- * is shared between Dom0 and DomU1.
+ * shared memory region "my-shared-mem-0" is shared
+ * between Dom0 and DomU1.
  */
 domU1-shared-mem@1000 {
 compatible = "xen,domain-shared-memory-v1";
 role = "borrower";
 xen,shm-id = "my-shared-mem-0";
 xen,shared-mem = <0x1000 0x5000 0x1000>;
-}
+};
 
 /*
- * shared memory region identified as 0x1(xen,shm-id = <0x1>)
- * is shared between DomU1 and DomU2.
+ * shared memory region "my-shared-mem-1" is shared between
+ * DomU1 and DomU2.
  */
 domU1-shared-mem@5000 {
 compatible = "xen,domain-shared-memory-v1";
 xen,shm-id = "my-shared-mem-1";
 xen,shared-mem = <0x5000 0x6000 0x2000>;
-}
+};
+
+/*
+ * shared memory region "my-shared-mem-2" is shared between
+ * DomU1 and DomU2.
+ */
+domU1-shared-mem-2 {
+compatible = "xen,domain-shared-memory-v1";
+xen,shm-id = "my-shared-mem-2";
+role = "owner";
+xen,shared-mem = <0x8000 0x2000>;
+};
 
 ..
 
@@ -672,14 +683,21 @@ chosen {
 cpus = <1>;
 
 /*
- * shared memory region identified as 0x1(xen,shm-id = <0x1>)
- * is shared between domU1 and domU2.
+ * shared memory region "my-shared-mem-1" is shared between
+ * domU1 and domU2.
  */
 domU2-shared-mem@5000 {
 compatible = "xen,domain-shared-memory-v1";
 xen,shm-id = "my-shared-mem-1";
 xen,shared-mem = <0x5000 0x7000 0x2000>;
-}
+};
+
+domU2-shared-mem-2 {
+compatible = "xen,domain-shared-memory-v1";
+xen,shm-id = "my-shared-mem-2";
+role = "borrower";
+xen,shared-mem = <0x9000 0x2000>;
+};
 
 ..
 };
@@ -699,3 +717,11 @@ shared between DomU1 and DomU2. It will get mapped at 
0x6000 in DomU1 guest
 physical address space, and at 0x7000 in DomU2 guest physical address 
space.
 DomU1 and DomU2 are both the borrower domain, the owner domain is the default
 owner domain DOMID_IO.
+
+For the static shared memory region "my-shared-mem-2", since host physical
+address is not provided by user, Xen will automatically allocate 512MB
+from heap as static shared memory to be shared between DomU1 and DomU2.
+The automatically allocated static shared memory will get mapped at
+0x8000 in DomU1 guest physical address space, and at 0x9000 in DomU2
+guest physical address space. DomU1 is explicitly defined as the owner domain,
+and DomU2 is the borrower domain.
-- 
2.25.1




[PATCH v3 6/8] xen/arm: remove shm holes for extended regions

2023-08-20 Thread Penny Zheng
Static shared memory acts as reserved memory in guest, so it shall be
excluded from extended regions.

Extended regions are taken care of under three different scenarios:
normal DomU, direct-map domain with iommu on, and direct-map domain
with iommu off.

For normal DomU, we create a new function "remove_shm_holes_for_domU", to
firstly transfer original outputs into the format of "struct rangeset",
then use "remove_shm_from_rangeset" to remove static shm from them.

For direct-map domain with iommu on, after we get guest shm info from "kinfo",
we use "remove_shm_from_rangeset" to remove static shm.

For direct-map domain with iommu off, as static shm has already been taken
care of through reserved memory banks, we do nothing.

Signed-off-by: Penny Zheng 

---
v1 -> v2:
- new commit
---
v2 -> v3:
- error out non-zero res before remove_shm_holes_for_domU
- rebase
---
 xen/arch/arm/domain_build.c | 97 -
 1 file changed, 96 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 687420956f..1ab41f823e 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1974,6 +1974,32 @@ static int __init handle_pci_range(const struct 
dt_device_node *dev,
 return 0;
 }
 
+static int __init remove_shm_from_rangeset(const struct kernel_info *kinfo,
+   struct rangeset *rangeset)
+{
+unsigned int i;
+
+/* Remove static shared memory regions */
+for ( i = 0; i < kinfo->shminfo.nr_banks; i++ )
+{
+struct membank membank = kinfo->shminfo.bank[i].membank;
+paddr_t start, end;
+int res;
+
+start = membank.start;
+end = membank.start + membank.size - 1;
+res = rangeset_remove_range(rangeset, start, end);
+if ( res )
+{
+printk(XENLOG_ERR "Failed to remove: %#"PRIpaddr"->%#"PRIpaddr"\n",
+   start, end);
+return -EINVAL;
+}
+}
+
+return 0;
+}
+
 /*
  * Find the holes in the Host DT which can be exposed to Dom0 as extended
  * regions for the special memory mappings. In order to calculate regions
@@ -1982,6 +2008,8 @@ static int __init handle_pci_range(const struct 
dt_device_node *dev,
  * - MMIO
  * - Host RAM
  * - PCI aperture
+ * - Static shared memory regions, which are described by special property
+ *   "xen,static-shm"
  */
 static int __init find_memory_holes(const struct kernel_info *kinfo,
 struct meminfo *ext_regions)
@@ -2058,6 +2086,14 @@ static int __init find_memory_holes(const struct 
kernel_info *kinfo,
 }
 }
 
+/* Remove static shared memory regions */
+if ( kinfo->shminfo.nr_banks != 0 )
+{
+res = remove_shm_from_rangeset(kinfo, mem_holes);
+if ( res )
+goto out;
+}
+
 start = 0;
 end = (1ULL << p2m_ipa_bits) - 1;
 res = rangeset_report_ranges(mem_holes, PFN_DOWN(start), PFN_DOWN(end),
@@ -2073,6 +2109,62 @@ out:
 return res;
 }
 
+static int __init remove_shm_holes_for_domU(const struct kernel_info *kinfo,
+struct meminfo *orig_ext)
+{
+struct rangeset *guest_holes;
+unsigned int i = 0, tail;
+int res;
+paddr_t start, end;
+
+/* No static shared memory region. */
+if ( kinfo->shminfo.nr_banks == 0 )
+return 0;
+
+dt_dprintk("Remove static shared memory holes for extended regions of 
DomU\n");
+
+guest_holes = rangeset_new(NULL, NULL, 0);
+if ( !guest_holes )
+return -ENOMEM;
+
+for ( ; i < orig_ext->nr_banks; i++ )
+{
+start = orig_ext->bank[i].start;
+end = start + orig_ext->bank[i].size - 1;
+
+res = rangeset_add_range(guest_holes, start, end);
+if ( res )
+{
+printk(XENLOG_ERR "Failed to add: %#"PRIpaddr"->%#"PRIpaddr"\n",
+   start, end);
+goto out;
+}
+}
+
+/* Remove static shared memory regions */
+res = remove_shm_from_rangeset(kinfo, guest_holes);
+if ( res )
+goto out;
+
+tail = orig_ext->nr_banks - 1;
+start = orig_ext->bank[0].start;
+end = orig_ext->bank[tail].start + orig_ext->bank[tail].size - 1;
+
+/* Reset original extended regions to hold new value */
+orig_ext->nr_banks = 0;
+res = rangeset_report_ranges(guest_holes, start, end,
+ add_ext_regions, orig_ext);
+if ( res )
+orig_ext->nr_banks = 0;
+else if ( !orig_ext->nr_banks )
+res = -ENOENT;
+
+out:
+rangeset_destroy(guest_holes);
+
+return res;
+}
+
 static int __init find_domU_holes(const struct kernel_info *kinfo,
   struct

[PATCH v3 5/8] xen/arm: support static shared memory when host address not provided

2023-08-20 Thread Penny Zheng
In order to support static shared memory when host address not provided,
we shall do the following modification:
- we shall let Xen allocate memory from heap for static shared memory
at first domain, no matter it is owner or borrower.
- In acquire_shared_memory_bank, as static shared memory has already
been allocated from heap, we shall assign them to the owner domain
using function "assign_pages".
- Function get_shm_pages_reference is created to add as many
additional reference as the number of borrowers.
- We implement a new helper "add_foreign_mapping_for_borrower" to set
up foreign memory mapping for borrower.

Instead of using multiple function parameters to deliver various shm-related
info, like host physical address, SHMID, etc, and with the introduction
of new struct "shm_memnode" to include banked host memory info, we switch to
use "shm_memnode" as function parameter to replace them all, to make codes more
clear and tidy.

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- combine commits 4 - 6 in Serie 1
- Adapt to changes of introducing "struct shm_memnode"
---
v2 -> v3
- fix infinite loop bug and bad indentation
- rebase
---
 xen/arch/arm/domain_build.c | 223 +---
 1 file changed, 155 insertions(+), 68 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index e37f3376a1..687420956f 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -891,6 +891,11 @@ static void __init assign_static_memory_11(struct domain 
*d,
 }
 
 #ifdef CONFIG_STATIC_SHM
+static bool __init is_shm_allocated_from_heap(struct shm_memnode *node)
+{
+return (node->meminfo.nr_banks != 0);
+}
+
 static int __init acquire_nr_borrower_domain(const char *shm_id,
  unsigned long *nr_borrowers)
 {
@@ -934,12 +939,12 @@ static struct shm_memnode * __init find_shm_memnode(const 
char *shm_id)
  * This function checks whether the static shared memory region is
  * already allocated to dom_io.
  */
-static bool __init is_shm_allocated_to_domio(paddr_t pbase)
+static bool __init is_shm_allocated_to_domio(struct shm_memnode *node)
 {
 struct page_info *page;
 struct domain *d;
 
-page = maddr_to_page(pbase);
+page = maddr_to_page(node->meminfo.bank[0].start);
 d = page_get_owner_and_reference(page);
 if ( d == NULL )
 return false;
@@ -957,67 +962,128 @@ static bool __init is_shm_allocated_to_domio(paddr_t 
pbase)
 }
 
 static mfn_t __init acquire_shared_memory_bank(struct domain *d,
-   paddr_t pbase, paddr_t psize)
+   struct shm_meminfo *meminfo,
+   bool paddr_assigned)
 {
-mfn_t smfn;
-unsigned long nr_pfns;
-int res;
+int res, i = 0;
 
-/*
- * Pages of statically shared memory shall be included
- * into domain_tot_pages().
- */
-nr_pfns = PFN_DOWN(psize);
-if ( (UINT_MAX - d->max_pages) < nr_pfns )
+for ( ; i < meminfo->nr_banks; i++ )
 {
-printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages: %lu.\n",
-   d, nr_pfns);
-return INVALID_MFN;
+paddr_t pbase = meminfo->bank[i].start, psize = meminfo->bank[i].size;
+unsigned long nr_pfns;
+
+/*
+ * Pages of statically shared memory shall be included
+ * into domain_tot_pages().
+ */
+nr_pfns = PFN_DOWN(psize);
+if ( (UINT_MAX - d->max_pages) < nr_pfns )
+{
+printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages: %lu.\n",
+   d, nr_pfns);
+return INVALID_MFN;
+}
+d->max_pages += nr_pfns;
+
+if ( paddr_assigned )
+{
+res = acquire_domstatic_pages(d, maddr_to_mfn(pbase), nr_pfns, 0);
+if ( res )
+{
+printk(XENLOG_ERR
+   "%pd: failed to acquire static memory: %d.\n", d, res);
+goto fail;
+}
+}
+else
+/*
+ * When host address is not provided, static shared memory is
+ * allocated from heap and shall be assigned to owner domain.
+ */
+if ( assign_pages(maddr_to_page(pbase), nr_pfns, d, 0) )
+goto fail;
 }
-d->max_pages += nr_pfns;
 
-smfn = maddr_to_mfn(pbase);
-res = acquire_domstatic_pages(d, smfn, nr_pfns, 0);
-if ( res )
+return maddr_to_mfn(meminfo->bank[0].start);
+
+ fail:
+while( --i >= 0 )
+d->max_pages -= PFN_DOWN(meminfo->bank[i].size);
+return INVALID_MFN;
+}
+
+static int __init get_shm_pages_reference(struct domain *d,
+  struct shm_meminfo *meminfo,
+ 

[PATCH v3 4/8] xen/arm: use paddr_assigned to indicate whether host address is provided

2023-08-20 Thread Penny Zheng
We use paddr_assigned to indicate whether host address is provided, by
checking the length of "xen,shared-mem" property.

The shm matching criteria shall also be adapt to cover the new scenario, by
adding when host address is not provided, if SHMID matches, the region size
must exactly match too.

During domain creation, right now, a static shared memory node could be
banked with a statically configured host memory bank, or a set of arbitrary
host memory banks allocated from heap. To cover both scenarios, we create
a new structure shm_meminfo. It is very alike meminfo, but with the maximum
array size being a smaller number NR_SHM_BANKS(16).
As "shm_meminfo" is also a new member of "enum meminfo_type", we shall implement
its own callback "retrieve_shm_meminfo" to have access to all MACRO
helpers, e.g. GET_MEMBANK(...).

Also, to make codes tidy and clear, we extract codes about parsing
"xen,shared-mem" property from function "process_shm" and move them into
a new helper "parse_shm_property".

Signed-off-by: Penny Zheng 
---
v1 -> v2
- In order to get allocated banked host memory info during domain creation,
we create a new structure shm_meminfo. It is very alike meminfo, with
the maximum array size being NR_SHM_BANKS. As shm_meminfo is a new
member of type meminfo_type, we shall implement its own callback
retrieve_shm_meminfo to have access to all MACRO helpers, e.g.
GET_MEMBANK(...)
- rename "acquire_shm_memnode" to "find_shm_memnode"
---
v2 -> v3
- rebase and no changes
---
 xen/arch/arm/bootfdt.c   | 100 ++-
 xen/arch/arm/domain_build.c  | 207 +--
 xen/arch/arm/include/asm/setup.h |   3 +
 3 files changed, 243 insertions(+), 67 deletions(-)

diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
index 66ad3ab3db..7d86dffd45 100644
--- a/xen/arch/arm/bootfdt.c
+++ b/xen/arch/arm/bootfdt.c
@@ -21,7 +21,15 @@ static __initdata struct {
 unsigned int nr_nodes;
 struct {
 const struct shm_node *node;
-const struct membank *membank;
+/*
+ * For a static shared memory node, it is either banked with a reserved
+ * host memory bank, or arbitrary host memory which shall
+ * be allocated by Xen with a specified total size(tot_size).
+ */
+union {
+const struct membank *membank;
+paddr_t tot_size;
+};
 } shm_nodes[NR_MEM_BANKS];
 } shm_data;
 #endif
@@ -421,7 +429,7 @@ static int __init process_shm_node(const void *fdt, int 
node,
 paddr_t paddr, gaddr, size;
 unsigned int i;
 int len;
-bool owner = false;
+bool owner = false, paddr_assigned = true;
 const char *shm_id;
 
 if ( address_cells < 1 || size_cells < 1 )
@@ -462,7 +470,7 @@ static int __init process_shm_node(const void *fdt, int 
node,
 }
 
 /*
- * xen,shared-mem = ;
+ * xen,shared-mem = , and paddr could be optional
  * Memory region starting from physical address #paddr of #size shall
  * be mapped to guest physical address #gaddr as static shared memory
  * region.
@@ -473,16 +481,24 @@ static int __init process_shm_node(const void *fdt, int 
node,
 
 if ( len != dt_cells_to_size(address_cells + size_cells + address_cells) )
 {
+/* paddr is not provided in "xen,shared-mem" */
 if ( len == dt_cells_to_size(size_cells + address_cells) )
-printk("fdt: host physical address must be chosen by users at the 
moment.\n");
-
-printk("fdt: invalid `xen,shared-mem` property.\n");
-return -EINVAL;
+paddr_assigned = false;
+else
+{
+printk("fdt: invalid `xen,shared-mem` property.\n");
+return -EINVAL;
+}
 }
 
 cell = (const __be32 *)prop->data;
-device_tree_get_reg(&cell, address_cells, address_cells, &paddr, &gaddr);
-size = dt_next_cell(size_cells, &cell);
+if ( !paddr_assigned )
+device_tree_get_reg(&cell, address_cells, size_cells, &gaddr, &size);
+else
+{
+device_tree_get_reg(&cell, address_cells, address_cells, &paddr, 
&gaddr);
+size = dt_next_cell(size_cells, &cell);
+}
 
 if ( !size )
 {
@@ -495,23 +511,37 @@ static int __init process_shm_node(const void *fdt, int 
node,
 paddr_t bank_start = shm_data.shm_nodes[i].membank->start;
 paddr_t bank_size = shm_data.shm_nodes[i].membank->size;
 const char *bank_id = shm_data.shm_nodes[i].node->shm_id;
+paddr_t tot_size = shm_data.shm_nodes[i].tot_size;
 
 /*
  * Meet the following check:
+ * when host address is provided:
  * 1) The shm ID matches and the region exactly match
  * 2) The shm ID doesn't match and the region doesn't overlap
   

[PATCH v3 3/8] xen/arm: introduce allocate_domheap_memory and guest_physmap_memory

2023-08-20 Thread Penny Zheng
We split the code of allocate_bank_memory into two parts,
allocate_domheap_memory and guest_physmap_memory.

One is about allocating guest RAM from heap, which could be re-used later for
allocating static shared memory from heap when host address is not provided.
The other is building up guest P2M mapping.

We also define a set of MACRO helpers to access common fields in data
structure of "meminfo" type, e.g. "struct meminfo" is one of them, and
later new "struct shm_meminfo" is also one of them.
This kind of structures must have the following characteristics:
- an array of "struct membank"
- a member called "nr_banks" indicating current array size
- a field indicating the maximum array size
When introducing a new data structure, according callbacks with function type
"retrieve_fn" shall be defined for using MACRO helpers.
This commit defines callback "retrieve_meminfo" for data structure
"struct meminfo".

Signed-off-by: Penny Zheng 
---
v1 -> v2:
-  define a set of MACRO helpers to access common fields in data structure of
"meminfo" type. "struct meminfo" is one of them, and according callback
"retrieve_meminfo" is also introduced here.
- typo of changing 1ULL to 1UL
---
v2 -> v3
- rebase and no changes
---
 xen/arch/arm/domain_build.c  | 119 ---
 xen/arch/arm/include/asm/setup.h |  33 +
 2 files changed, 127 insertions(+), 25 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index b639d3dc78..97f9db1175 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -99,6 +99,26 @@ int __init parse_arch_dom0_param(const char *s, const char 
*e)
  */
 #define DOM0_FDT_EXTRA_SIZE (128 + sizeof(struct fdt_reserve_entry))
 
+static void __init retrieve_meminfo(void *mem, unsigned int *max_mem_banks,
+struct membank **bank,
+unsigned int **nr_banks)
+{
+struct meminfo *meminfo = (struct meminfo *)mem;
+
+if ( max_mem_banks )
+*max_mem_banks = NR_MEM_BANKS;
+
+if ( nr_banks )
+*nr_banks = &(meminfo->nr_banks);
+
+if ( bank )
+*bank = meminfo->bank;
+}
+
+retrieve_fn __initdata retrievers[MAX_MEMINFO_TYPE] = {
+[NORMAL_MEMINFO] = retrieve_meminfo,
+};
+
 unsigned int __init dom0_max_vcpus(void)
 {
 if ( opt_dom0_max_vcpus == 0 )
@@ -413,34 +433,20 @@ static void __init allocate_memory_11(struct domain *d,
 }
 }
 
-static bool __init allocate_bank_memory(struct domain *d,
-struct kernel_info *kinfo,
-gfn_t sgfn,
-paddr_t tot_size)
+static bool __init allocate_domheap_memory(struct domain *d,
+   paddr_t tot_size,
+   void *mem, enum meminfo_type type)
 {
-int res;
 struct page_info *pg;
-struct membank *bank;
 unsigned int max_order = ~0;
-
-/*
- * allocate_bank_memory can be called with a tot_size of zero for
- * the second memory bank. It is not an error and we can safely
- * avoid creating a zero-size memory bank.
- */
-if ( tot_size == 0 )
-return true;
-
-bank = &kinfo->mem.bank[kinfo->mem.nr_banks];
-bank->start = gfn_to_gaddr(sgfn);
-bank->size = tot_size;
+unsigned int *nr_banks = GET_NR_BANKS(mem, type);
 
 while ( tot_size > 0 )
 {
 unsigned int order = get_allocation_size(tot_size);
+struct membank *membank;
 
 order = min(max_order, order);
-
 pg = alloc_domheap_pages(d, order, 0);
 if ( !pg )
 {
@@ -460,15 +466,78 @@ static bool __init allocate_bank_memory(struct domain *d,
 continue;
 }
 
-res = guest_physmap_add_page(d, sgfn, page_to_mfn(pg), order);
-if ( res )
-{
-dprintk(XENLOG_ERR, "Failed map pages to DOMU: %d", res);
+if ( *nr_banks == MAX_MEM_BANKS(type) )
 return false;
-}
+
+membank = GET_MEMBANK(mem, type, *nr_banks);
+membank->start = mfn_to_maddr(page_to_mfn(pg));
+membank->size = 1ULL << (PAGE_SHIFT + order);
+(*nr_banks)++;
+tot_size -= membank->size;
+}
+
+return true;
+}
+
+static int __init guest_physmap_memory(struct domain *d,
+   void *mem, enum meminfo_type type,
+   gfn_t sgfn)
+{
+unsigned int i;
+int res;
+unsigned int *nr_banks = GET_NR_BANKS(mem, type);
+
+for ( i = 0; i < *nr_banks; i++ )
+{
+struct membank *membank = GET_MEMBANK(mem, type, i);
+paddr_t start = membank->start;
+paddr_t size = membank->size;
+unsig

[PATCH v3 2/8] xen/arm: re-define a set of data structures for static shared memory region

2023-08-20 Thread Penny Zheng
This commit introduces a set of separate data structures to deal with
static shared memory at different stages.

In boot-time host device tree parsing, we introduce a new structure
"struct shm_node" and a new field "shm_info" in bootinfo to describe and
store parsed shm info.
only SHMID and "nr_borrowers", which describes the number of borrower domain,
are considered here for per shm node.
We also introduce a new local global data "shm_data" in bootfdt.c, in which,
reserved memory bank is recorded together with shm node, to assist doing
shm node verification.

In order to apply above changes in acquire_nr_borrower_domain, we now use SHMID
to iterate "shminfo" to find requested shm node, then acquiring the information
of "nr_borrowers".

In the last, a new anonymized structure "shminfo", which is a array of
compound structure that contains SHMID and a "struct membank membank"
describing shared memory regions in guest address space, is created in "kinfo"
when dealing with domain information.

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- As the original "struct shm_membank" was making reserving memory more
complex and actually memory information could be still got from host Device\
Tree when dealing with domain construction, we introduce a new simple structure
"struct shm_node" in bootinfo to only store SHMID and "nr_borrowers"
- Further restrict the scope of the local variable
"struct meminfo *mem = &bootinfo.reserved_mem"
- Introduce a new local global data "shm_data" in bootfdt.c. In which, reserved
memory bank is recorded together with the shm node, to assist doing shm node
verification.
- Define a set of local variables that point to
"shm_data.shm_nodes[i].membank->start", etc, to make the code more readable.
- Use SHMID to iterate "shminfo" to find requested shm node, as we no
longer store host memory bank info in shm node.
- A new anonymized structure, which is a array of compound structure that
contains SHMID and a "struct membank membank", describing shared memory region
in guest, is introduced in "kinfo".
---
v2 -> v3:
- rebase and no changes
---
 xen/arch/arm/bootfdt.c| 57 ++--
 xen/arch/arm/domain_build.c   | 74 +++
 xen/arch/arm/include/asm/kernel.h |  9 +++-
 xen/arch/arm/include/asm/setup.h  | 21 +++--
 4 files changed, 104 insertions(+), 57 deletions(-)

diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
index 2673ad17a1..66ad3ab3db 100644
--- a/xen/arch/arm/bootfdt.c
+++ b/xen/arch/arm/bootfdt.c
@@ -16,6 +16,16 @@
 #include 
 #include 
 
+#ifdef CONFIG_STATIC_SHM
+static __initdata struct {
+unsigned int nr_nodes;
+struct {
+const struct shm_node *node;
+const struct membank *membank;
+} shm_nodes[NR_MEM_BANKS];
+} shm_data;
+#endif
+
 static bool __init device_tree_node_matches(const void *fdt, int node,
 const char *match)
 {
@@ -409,7 +419,6 @@ static int __init process_shm_node(const void *fdt, int 
node,
 const struct fdt_property *prop, *prop_id, *prop_role;
 const __be32 *cell;
 paddr_t paddr, gaddr, size;
-struct meminfo *mem = &bootinfo.reserved_mem;
 unsigned int i;
 int len;
 bool owner = false;
@@ -481,17 +490,21 @@ static int __init process_shm_node(const void *fdt, int 
node,
 return -EINVAL;
 }
 
-for ( i = 0; i < mem->nr_banks; i++ )
+for ( i = 0; i < shm_data.nr_nodes; i++ )
 {
+paddr_t bank_start = shm_data.shm_nodes[i].membank->start;
+paddr_t bank_size = shm_data.shm_nodes[i].membank->size;
+const char *bank_id = shm_data.shm_nodes[i].node->shm_id;
+
 /*
  * Meet the following check:
  * 1) The shm ID matches and the region exactly match
  * 2) The shm ID doesn't match and the region doesn't overlap
  * with an existing one
  */
-if ( paddr == mem->bank[i].start && size == mem->bank[i].size )
+if ( paddr == bank_start && size == bank_size )
 {
-if ( strncmp(shm_id, mem->bank[i].shm_id, MAX_SHM_ID_LENGTH) == 0 )
+if ( strncmp(shm_id, bank_id, MAX_SHM_ID_LENGTH) == 0 )
 break;
 else
 {
@@ -503,9 +516,9 @@ static int __init process_shm_node(const void *fdt, int 
node,
 else
 {
 paddr_t end = paddr + size;
-paddr_t bank_end = mem->bank[i].start + mem->bank[i].size;
+paddr_t bank_end = bank_start + bank_size;
 
-if ( (end <= paddr) || (bank_end <= mem->bank[i].start) )
+if ( (end <= paddr) || (bank_end <= bank_start) )
 {
 printk("fdt: static s

[PATCH v3 1/8] xen/arm: remove stale addr_cells/size_cells in assign_shared_memory

2023-08-20 Thread Penny Zheng
Function parameters {addr_cells,size_cells} are stale parameters in
assign_shared_memory, so we shall remove them.

Signed-off-by: Penny Zheng 
---
v1 -> v2:
- new commit
---
v2 -> v3:
rebase and no change
---
 xen/arch/arm/domain_build.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 54bf5623c8..ac78597bde 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -858,7 +858,6 @@ static mfn_t __init acquire_shared_memory_bank(struct 
domain *d,
 }
 
 static int __init assign_shared_memory(struct domain *d,
-   uint32_t addr_cells, uint32_t 
size_cells,
paddr_t pbase, paddr_t psize,
paddr_t gbase)
 {
@@ -1020,7 +1019,6 @@ static int __init process_shm(struct domain *d, struct 
kernel_info *kinfo,
  * specified, so they should be assigned to dom_io.
  */
 ret = assign_shared_memory(owner_dom_io ? dom_io : d,
-   addr_cells, size_cells,
pbase, psize, gbase);
 if ( ret )
 return ret;
-- 
2.25.1




[PATCH v3 0/8] Follow-up static shared memory PART I

2023-08-20 Thread Penny Zheng
There are some unsolving issues on current 4.17 static shared memory
feature[1], including:
- In order to avoid keeping growing 'membank', having the shared memory
info in separate structures is preferred.
- Missing implementation on having the host address optional in
"xen,shared-mem" property
- Removing static shared memory from extended regions
- Missing reference release on foreign superpage
- Missing "xen,offset" feature, which is introduced in Linux DOC[2]

All above objects have been divided into two parts to complete. And this
patch serie is PART I.

[1] https://lore.kernel.org/all/20220908135513.1800511-1-penny.zh...@arm.com/
[2] 
https://www.kernel.org/doc/Documentation/devicetree/bindings/reserved-memory/xen%2Cshared-memory.txt

Penny Zheng (8):
  xen/arm: remove stale addr_cells/size_cells in assign_shared_memory
  xen/arm: re-define a set of data structures for static shared memory
region
  xen/arm: introduce allocate_domheap_memory and guest_physmap_memory
  xen/arm: use paddr_assigned to indicate whether host address is
provided
  xen/arm: support static shared memory when host address not provided
  xen/arm: remove shm holes for extended regions
  xen/p2m: put reference for superpage
  xen/docs: refine docs about static shared memory

 docs/misc/arm/device-tree/booting.txt |  52 +-
 xen/arch/arm/bootfdt.c| 125 +++--
 xen/arch/arm/domain_build.c   | 708 --
 xen/arch/arm/include/asm/kernel.h |   9 +-
 xen/arch/arm/include/asm/setup.h  |  57 ++-
 xen/arch/arm/p2m.c|  58 ++-
 6 files changed, 784 insertions(+), 225 deletions(-)

-- 
2.25.1




Re: [PATCH v3 44/52] xen/mpu: P2M initialization in MPU system

2023-07-13 Thread Penny Zheng

Hi, Ayan

On 2023/7/5 23:35, Ayan Kumar Halder wrote:

Hi Penny,

On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



We inherit p2m_init() to do P2M initialization in MPU system, including
VMID assignment, setting up P2M MPU region mapping table, etc.

p2m_alloc_table() is responsible for allocating per-domain P2M MPU memory
region mapping table. As a MPU memory region structure(pr_t) takes 16 
bytes,
even with maximum supported MPU memory regions, 255, MPU memory 
mapping table

at most takes up less than 4KB.

VSCTLR_EL2, Virtualization System Control Register, provides 
configuration

information for VMSAv8-64 and PMSAv8-64 virtualization using stage 2
of EL1&0 translation regime, bit[63:48] of which determines VMID for the
EL1-Guest-OS.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
  xen/arch/arm/include/asm/mpu/mm.h |  3 ++
  xen/arch/arm/include/asm/p2m.h    |  5 +++
  xen/arch/arm/mpu/mm.c | 22 ++
  xen/arch/arm/mpu/p2m.c    | 69 +++
  4 files changed, 99 insertions(+)

diff --git a/xen/arch/arm/include/asm/mpu/mm.h 
b/xen/arch/arm/include/asm/mpu/mm.h

index a83519ad13..4df69245c6 100644
--- a/xen/arch/arm/include/asm/mpu/mm.h
+++ b/xen/arch/arm/include/asm/mpu/mm.h
@@ -2,6 +2,8 @@
  #ifndef __ARCH_ARM_MM_MPU__
  #define __ARCH_ARM_MM_MPU__

#ifdef CONFIG_ARM_64

+#include 

#endif

+
  extern struct page_info *frame_table;
  extern unsigned long frametable_pdx_end;

@@ -11,6 +13,7 @@ extern uint8_t is_mm_range_mapped(paddr_t pa, 
paddr_t len);
  extern void *map_mm_range(paddr_t pa, size_t len, unsigned int 
attributes);

  extern void unmap_mm_range(paddr_t pa);
  extern bool is_mm_range_mapped_transient(paddr_t pa, paddr_t len);
+extern pr_t *alloc_mpumap(void);

  #endif /* __ARCH_ARM_MM_MPU__ */

diff --git a/xen/arch/arm/include/asm/p2m.h 
b/xen/arch/arm/include/asm/p2m.h

index d9c91d4a98..c3598d514e 100644
--- a/xen/arch/arm/include/asm/p2m.h
+++ b/xen/arch/arm/include/asm/p2m.h
@@ -61,8 +61,13 @@ struct p2m_domain {
  /* Current VMID in use */
  uint16_t vmid;

+#ifndef CONFIG_HAS_MPU
  /* Current Translation Table Base Register for the p2m */
  uint64_t vttbr;
+#else
+    /* Current Virtualization System Control Register for the p2m */
+    uint64_t vsctlr;


register_t vsctlr;

So that it is 64-bit for ARM_64 and 32-bit for ARM_32.



Understood, will fix


+#endif

  /* Highest guest frame that's ever been mapped in the p2m */
  gfn_t max_mapped_gfn;
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index 27d924e449..de5da96b80 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -872,6 +872,28 @@ void __init remove_early_mappings(paddr_t dtb_paddr)
  panic("Unable to destroy early Device-Tree mapping.\n");
  }

+/*
+ * Standard entry to dynamically allocate MPU memory region mapping 
table.

+ * A 4KB page is enough for holding the maximum supported MPU memory
+ * regions.
+ */
+pr_t *alloc_mpumap(void)
+{
+    pr_t *map;
+
+    /*
+ * A MPU memory region structure(pr_t) takes 16 bytes, even with 
maximum
+ * supported MPU memory regions, 255, MPU memory mapping table at 
most

+ * takes up less than 4KB.
+ */
+    map = alloc_xenheap_pages(0, 0);
+    if ( map == NULL )
+    return NULL;
+
+    clear_page(map);
+    return map;
+}
+
  /*
   * Local variables:
   * mode: C
diff --git a/xen/arch/arm/mpu/p2m.c b/xen/arch/arm/mpu/p2m.c
index a7a3912a9a..8f728f8957 100644
--- a/xen/arch/arm/mpu/p2m.c
+++ b/xen/arch/arm/mpu/p2m.c
@@ -4,6 +4,7 @@
  #include 
  #include 

+#include 
  #include 
  #include 
  #include 
@@ -97,6 +98,74 @@ fault:
  panic("Hardware with no PMSAv8-64 support in any translation 
regime.\n");

  }

+static uint64_t __init generate_vsctlr(uint16_t vmid)
+{
+    return ((uint64_t)vmid << 48);
+}


Please move ^^^ to ./xen/arch/arm/include/asm/arm64/mpu.h as it differs 
between R82 and R52




Sure, will do


- Ayan


+
+static int __init p2m_alloc_table(struct domain *d)
+{
+    struct p2m_domain *p2m = p2m_get_hostp2m(d);
+    pr_t* p2m_map;
+
+    p2m_map = alloc_mpumap();
+    if ( !p2m_map )
+    {
+    printk(XENLOG_G_ERR "DOM%pd: p2m: unable to allocate P2M MPU 
mapping table\n", d);

+    return -ENOMEM;
+    }
+
+    p2m->root = virt_to_page((const void *)p2m_map);
+
+    return 0;
+}
+
+int p2m_init(struct domain *d)
+{
+    struct p2m_domain *p2m = p2m_get_hostp2m(d);
+    int rc = 0;
+    unsigned int cpu;
+
+    rwlock_init(&p2m->lock);
+    spin_lock_init(&d->arch.paging.lock);
+
+    p2m->vmid = INVALID_VMID;
+    p2m->max_mapped_gfn = _gfn(0);
+    p2m->lowest_mapped_gfn = _gfn(ULONG_MAX);
+
+    p2m->default_access = p2m_

Re: [PATCH v3 33/52] xen/mpu: initialize frametable in MPU system

2023-07-13 Thread Penny Zheng

Hi,

On 2023/7/5 21:52, Julien Grall wrote:

Hi,

On 05/07/2023 10:53, Penny Zheng wrote:
Since if not and when anyone wants to update map_pages_to_xen(), 
destroy_xen_mappings() and modify_xen_mappings() in the future, it 
is possible for them to leave changes in only one file.


The helpers are just wrappers. I doubt they will change in the 
future. So I think it would be OK to duplicate.


The alternative would to have a common prototype for xen_pt_update() 
and xen_mpumap_update() and avoid any #ifdery. That said, this is not 
my preference at least if they are not static inline.




Correct me if I'm wrong, you are suggesting something like this:
A more-generic wrapper like xen_mm_update, and we introduce static 
inline implementation in mmu/mm.h with xen_pt_update(), and static

inline implementation in mpu/mm.h with xen_mpumap_update().


Yes as an alternative proposal. But my preference here is to duplicate 
the helpers in mm-mmu.c and mm-mpu.c.




Understood, I'll do the duplication.


Cheers,





Re: [PATCH v3 43/52] xen/mpu: configure VSTCR_EL2 in MPU system

2023-07-13 Thread Penny Zheng

Hi Ayan

On 2023/7/5 22:21, Ayan Kumar Halder wrote:


On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



VSTCR_EL2, Virtualization Secure Translation Control Register,is
the control register for stage 2 of the Secure EL1&0 translation regime.

VSTCR_EL2.SA defines secure stage 2 translation output address space.
To make sure that all stage 2 translations for the Secure PA space
access the Secure PA space, we keep SA bit as 0.
VSTCR_EL2.SC is NS check enable bit.
To make sure that Stage 2 NS configuration is checked against stage 1
NS configuration in EL1&0 translation regime for the given address, and
generates a fault if they are different, we set SC bit 1.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
  xen/arch/arm/include/asm/arm64/sysregs.h |  6 ++
  xen/arch/arm/mpu/p2m.c   | 17 -
  2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/include/asm/arm64/sysregs.h 
b/xen/arch/arm/include/asm/arm64/sysregs.h

index ab0e6a97d3..35d7da411d 100644
--- a/xen/arch/arm/include/asm/arm64/sysregs.h
+++ b/xen/arch/arm/include/asm/arm64/sysregs.h
@@ -512,6 +512,12 @@
  /* MPU Protection Region Enable Register encode */
  #define PRENR_EL2   S3_4_C6_C1_1

+/* Virtualization Secure Translation Control Register */
+#define VSTCR_EL2    S3_4_C2_C6_2
+#define VSTCR_EL2_RES1_SHIFT 31
+#define VSTCR_EL2_SA ~(_AC(0x1,UL)<<30)
+#define VSTCR_EL2_SC (_AC(0x1,UL)<<20)
+
  #endif

  #ifdef CONFIG_ARM_SECURE_STATE
diff --git a/xen/arch/arm/mpu/p2m.c b/xen/arch/arm/mpu/p2m.c
index 04c44825cb..a7a3912a9a 100644
--- a/xen/arch/arm/mpu/p2m.c
+++ b/xen/arch/arm/mpu/p2m.c
@@ -10,7 +10,7 @@

  void __init setup_virt_paging(void)
  {
-    uint64_t val = 0;
+    uint64_t val = 0, val2 = 0;
  bool p2m_vmsa = true;

  /* PA size */
@@ -76,6 +76,21 @@ void __init setup_virt_paging(void)

  WRITE_SYSREG(val, VTCR_EL2);

#ifdef CONFIG_ARM_64


+    /*
+ * VSTCR_EL2.SA defines secure stage 2 translation output address 
space.
+ * To make sure that all stage 2 translations for the Secure PA 
space

+ * access the Secure PA space, we keep SA bit as 0.
+ *
+ * VSTCR_EL2.SC is NS check enable bit.
+ * To make sure that Stage 2 NS configuration is checked against 
stage 1
+ * NS configuration in EL1&0 translation regime for the given 
address, and

+ * generates a fault if they are different, we set SC bit 1.
+ */
+    val2 = 1 << VSTCR_EL2_RES1_SHIFT;
+    val2 &= VSTCR_EL2_SA;
+    val2 |= VSTCR_EL2_SC;
+    WRITE_SYSREG(val2, VSTCR_EL2);

#endif


Understood, will fix.


+
  return;

  fault:
--
2.25.1






Re: [PATCH v3 36/52] xen/mpu: implememt ioremap_xxx in MPU

2023-07-13 Thread Penny Zheng

Hi Ayan

On 2023/7/5 22:01, Ayan Kumar Halder wrote:

Hi Penny,

On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



A set of function ioremap_xxx are designed to map deivce memory or
remap part of memory temporarily for short-time special purpose, like
using ioremap_wc to temporarily remap guest kernel non-cacheable, for
copying it to guest memory.

As virtual translation is not supported in MPU, and we always follow the
rule of "map in demand" in MPU, we implement MPU version of ioremap_xxx,
through mapping the memory with a transient MPU memory region.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- adapt to the new rule of "map in demand"
---
  xen/arch/arm/include/asm/arm64/mpu.h |   4 +
  xen/arch/arm/include/asm/mm.h    |   6 +
  xen/arch/arm/mpu/mm.c    | 185 +++
  3 files changed, 195 insertions(+)

diff --git a/xen/arch/arm/include/asm/arm64/mpu.h 
b/xen/arch/arm/include/asm/arm64/mpu.h

index aee7947223..c5e69f239a 100644
--- a/xen/arch/arm/include/asm/arm64/mpu.h
+++ b/xen/arch/arm/include/asm/arm64/mpu.h
@@ -121,6 +121,10 @@ static inline bool region_is_valid(pr_t *pr)
  return pr->prlar.reg.en;
  }

+static inline bool region_is_transient(pr_t *pr)
+{
+    return pr->prlar.reg.tran;
+}
  #endif /* __ASSEMBLY__ */

  #endif /* __ARM64_MPU_H__ */
diff --git a/xen/arch/arm/include/asm/mm.h 
b/xen/arch/arm/include/asm/mm.h

index cffbf8a595..0352182d99 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -227,6 +227,7 @@ void __iomem *ioremap_attr(paddr_t start, size_t 
len, unsigned int attributes);

  extern int map_staticmem_pages_to_xen(paddr_t start, paddr_t end);
  extern int unmap_staticmem_pages_to_xen(paddr_t start, paddr_t end);

+#ifndef CONFIG_HAS_MPU
  static inline void __iomem *ioremap_nocache(paddr_t start, size_t len)
  {
  return ioremap_attr(start, len, PAGE_HYPERVISOR_NOCACHE);
@@ -241,6 +242,11 @@ static inline void __iomem *ioremap_wc(paddr_t 
start, size_t len)

  {
  return ioremap_attr(start, len, PAGE_HYPERVISOR_WC);
  }
+#else
+extern void __iomem *ioremap_nocache(paddr_t start, size_t len);
+extern void __iomem *ioremap_cache(paddr_t start, size_t len);
+extern void __iomem *ioremap_wc(paddr_t start, size_t len);
+#endif

  /* XXX -- account for base */
  #define mfn_valid(mfn)
({  \

diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index 9d5c1da39c..3bb1a5c7c4 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -624,6 +624,191 @@ int __init unmap_staticmem_pages_to_xen(paddr_t 
start, paddr_t end)

  return xen_mpumap_update(start, end, 0);
  }

+/*
+ * Check whether memory range [pa, pa + len) is mapped in Xen MPU
+ * memory mapping table xen_mpumap.
+ *
+ * If it is mapped, the associated index will be returned.
+ * If it is not mapped, INVALID_REGION_IDX will be returned.
+ */
+static uint8_t is_mm_range_mapped(paddr_t pa, paddr_t len)
+{
+    int rc;
+    uint8_t idx;
+
+    rc = mpumap_contain_region(xen_mpumap, max_xen_mpumap, pa, pa + 
len - 1,

+   &idx);
+    if ( (rc == MPUMAP_REGION_FOUND) || (rc == 
MPUMAP_REGION_INCLUSIVE) )

+    return idx;
+
+    if ( rc == MPUMAP_REGION_OVERLAP )
+ panic("mpu: can not deal with overlapped MPU memory region\n");
+    /* Not mapped */
+    return INVALID_REGION_IDX;
+}
+
+static bool is_mm_attr_match(pr_t *region, unsigned int attributes)
+{
+    if ( region->prbar.reg.ap != PAGE_AP_MASK(attributes) )
+    {
+    printk(XENLOG_WARNING "region permission is not matched (0x%x 
-> 0x%x)\n",

+   region->prbar.reg.ap, PAGE_AP_MASK(attributes));
+    return false;
+    }
+
+    if ( region->prbar.reg.xn != PAGE_XN_MASK(attributes) )
+    {
+    printk(XENLOG_WARNING "region execution permission is not 
matched (0x%x -> 0x%x)\n",

+   region->prbar.reg.xn, PAGE_XN_MASK(attributes));
+    return false;
+    }
+
+    if ( region->prlar.reg.ai != PAGE_AI_MASK(attributes) )
+    {
+    printk(XENLOG_WARNING "region memory attributes is not 
matched (0x%x -> 0x%x)\n",

+   region->prlar.reg.ai, PAGE_AI_MASK(attributes));
+    return false;
+    }
+
+    return true;
+}
+
+/*
+ * Check whether memory range [pa, pa + len) is mapped with memory
+ * attributes #attr in Xen MPU memory mapping table xen_mpumap.
+ *
+ * If it is mapped but with different memory attributes, Errno -EINVAL
+ * will be returned.
+ * If it is not mapped at all, Errno -ENOENT will be returned.
+ */
+static int is_mm_range_mapped_with_attr(paddr_t pa, paddr_t len,
+    unsigned int attr)
+

Re: [PATCH v3 35/52] xen/arm: map static memory on demand

2023-07-12 Thread Penny Zheng

Hi Ayan

On 2023/7/5 21:33, Ayan Kumar Halder wrote:


On 05/07/2023 11:16, Penny Zheng wrote:

Hi Ayan

Hi Penny,


On 2023/7/4 23:10, Ayan Kumar Halder wrote:

Hi Penny,

On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



In function init_staticmem_pages, we need the access to static memory
for proper initialization.
It is not a problem in MMU system, as Xen map the whole RAM in
setup_mm(). However, with limited MPU memory regions, it is too luxury
to map the whole RAM.
As a result, we follow the rule of "map on demand", to map static 
memory

temporarily before its initialization, and unmap immediately after its
initialization.


I could see that you are using _PAGE_TRANSIENT  to map memory 
temporarily. However, I don't see this being translated to any of the 
MPU hardware features (ie _PAGE_TRANSIENT does not seem to translate 
to any of the attributes in PRBAR, PRLAR, PRENR, etc). Thus, how is 
it different from mapping the memory in "non temporary" way ?




It is only software feature.
It is designed for implementing functions like ioremap_xxx(), or 
map_staticmem_pages_to_xen() here, which are always occuring with its 
reverse unmapping function nearby like iounmap(), or 
unmap_staticmem_pages_to_xen(), to map a chunk of memory 
*temporarily*, for a very short time.
I understand that it is a software only feature. But why does the 
software need to know if the memory is mapped temporarily or not ? What 
difference does it make ?


See this pair map_domain_page()/unmap_domain_page(), which is used to 
map/unmap page of guest RAM. vcpu in different mode is facing different 
scenario.


Taking usage in copy_guest() as example:
When vcpu in guest mode trying to access its own memory(e.g. copy
hypercall param), there is no need to do the mapping/unmapping in MPU,
as page is already mapped at both EL1/EL2. Checking if it is transient
region in unmap_domain_page() is definitely necessary to help avoid 
unmapping it here.

When vcpu in hypervisor mode at boot time copying kernel image to guest
memory, we need to map page as transient MPU region to do the copying 
and pasting.


I want to check this flag in the unmapping function, to ensure that we 
are unmapping the proper MPU region.


I had a look at unmap_staticmem_pages_to_xen() --> xen_mpumap_update() 
--> control_mpu_region_from_index() and I don't see this flag used 
anywhere.

>

- Ayan



Fixed MPU regions are like Xen text section, Xen data section, etc.


Please let me know what I am missing.

- Ayan



Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
  xen/arch/arm/include/asm/mm.h |  2 ++
  xen/arch/arm/mmu/mm.c | 10 ++
  xen/arch/arm/mpu/mm.c | 10 ++
  xen/arch/arm/setup.c  | 21 +
  4 files changed, 43 insertions(+)

diff --git a/xen/arch/arm/include/asm/mm.h 
b/xen/arch/arm/include/asm/mm.h

index 66d98b9a29..cffbf8a595 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -224,6 +224,8 @@ extern void mm_init_secondary_cpu(void);
  extern void setup_frametable_mappings(paddr_t ps, paddr_t pe);
  /* map a physical range in virtual memory */
  void __iomem *ioremap_attr(paddr_t start, size_t len, unsigned int 
attributes);

+extern int map_staticmem_pages_to_xen(paddr_t start, paddr_t end);
+extern int unmap_staticmem_pages_to_xen(paddr_t start, paddr_t end);

  static inline void __iomem *ioremap_nocache(paddr_t start, size_t 
len)

  {
diff --git a/xen/arch/arm/mmu/mm.c b/xen/arch/arm/mmu/mm.c
index 2f29cb53fe..4196a55c32 100644
--- a/xen/arch/arm/mmu/mm.c
+++ b/xen/arch/arm/mmu/mm.c
@@ -1113,6 +1113,16 @@ int populate_pt_range(unsigned long virt, 
unsigned long nr_mfns)

  return xen_pt_update(virt, INVALID_MFN, nr_mfns, _PAGE_POPULATE);
  }

+int __init map_staticmem_pages_to_xen(paddr_t start, paddr_t end)
+{
+    return 0;
+}
+
+int __init unmap_staticmem_pages_to_xen(paddr_t start, paddr_t end)
+{
+    return 0;
+}
+
  /*
   * Local variables:
   * mode: C
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index a40055ae5e..9d5c1da39c 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -614,6 +614,16 @@ void __init setup_frametable_mappings(paddr_t 
ps, paddr_t pe)

 frametable_size - (nr_pdxs * sizeof(struct page_info)));
  }

+int __init map_staticmem_pages_to_xen(paddr_t start, paddr_t end)
+{
+    return xen_mpumap_update(start, end, PAGE_HYPERVISOR | 
_PAGE_TRANSIENT);

+}
+
+int __init unmap_staticmem_pages_to_xen(paddr_t start, paddr_t end)
+{
+    return xen_mpumap_update(start, end, 0);
+}
+
  /*
   * Local variables:
   * mode: C
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index f42b53d17b..c21d1db763 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/se

Re: [PATCH v3 31/52] xen/mpu: make early_fdt_map support in MPU systems

2023-07-12 Thread Penny Zheng

Hi Julien

On 2023/7/3 17:20, Julien Grall wrote:

Hi,

On 03/07/2023 06:12, Penny Zheng wrote:

Hi,


On 2023/6/30 23:02, Julien Grall wrote:

Hi,

On 30/06/2023 15:42, Ayan Kumar Halder wrote:

Hi Julien,

On 30/06/2023 12:22, Julien Grall wrote:



On 30/06/2023 11:49, Ayan Kumar Halder wrote:


On 30/06/2023 05:07, Penny Zheng wrote:

Hi,

Hi Penny,



On 2023/6/30 01:22, Ayan Kumar Halder wrote:


On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. 
Please use proper judgment and caution when opening 
attachments, clicking links, or responding to this email.



In MPU system, MPU memory region is always mapped PAGE_ALIGN, 
so in order to
not access unexpected memory area, dtb section in xen.lds.S 
should be made

page-aligned too.
We add . = ALIGN(PAGE_SIZE); in the head of dtb section to make 
it happen.


In this commit, we map early FDT with a transient MPU memory 
region, as

it will be relocated into heap and unmapped at the end of boot.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- map the first 2MB. Check the size and then re-map with an 
extra 2MB if needed

---
  xen/arch/arm/include/asm/arm64/mpu.h |  3 ++-
  xen/arch/arm/include/asm/page.h  |  5 +
  xen/arch/arm/mm.c    | 26 
--

  xen/arch/arm/mpu/mm.c    |  1 +
  xen/arch/arm/xen.lds.S   |  5 -
  5 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/xen/arch/arm/include/asm/arm64/mpu.h 
b/xen/arch/arm/include/asm/arm64/mpu.h

index a6b07bab02..715ea69884 100644
--- a/xen/arch/arm/include/asm/arm64/mpu.h
+++ b/xen/arch/arm/include/asm/arm64/mpu.h
@@ -72,7 +72,8 @@ typedef union {
  unsigned long ns:1; /* Not-Secure */
  unsigned long res:1;    /* Reserved 0 by hardware */
  unsigned long limit:42; /* Limit Address */
-    unsigned long pad:16;
+    unsigned long pad:15;
+    unsigned long tran:1;   /* Transient region */
  } reg;
  uint64_t bits;
  } prlar_t;
diff --git a/xen/arch/arm/include/asm/page.h 
b/xen/arch/arm/include/asm/page.h

index 85ecd5e4de..a434e2205a 100644
--- a/xen/arch/arm/include/asm/page.h
+++ b/xen/arch/arm/include/asm/page.h
@@ -97,19 +97,24 @@
   * [3:4] Execute Never
   * [5:6] Access Permission
   * [7]   Region Present
+ * [8]   Transient Region, e.g. MPU memory region is temproraily
+ *  mapped for a short time
   */
  #define _PAGE_AI_BIT    0
  #define _PAGE_XN_BIT    3
  #define _PAGE_AP_BIT    5
  #define _PAGE_PRESENT_BIT   7
+#define _PAGE_TRANSIENT_BIT 8
I don't think this is related to MPU. At least when I look at 
the bit representation of PRBAR_EL1/2,


This set of _PAGE_xxx flags aren't compliant with PRBAR_EL1/2 
register map.
It is a flag passed to function map_pages_to_xen() to indicate 
memory

attributes and permission.


But aren't you writing these flags to PRBAR_EL1/EL2 when you call 
xen_mpumap_update_entry().


In the below snippet of xen_mpumap_update_entry(), IIUC, you are 
writing these flags.


 xen_mpumap[idx].prbar.reg.ap = PAGE_AP_MASK(flags);
 xen_mpumap[idx].prbar.reg.xn = PAGE_XN_MASK(flags);

 write_protection_region((const pr_t*)(&xen_mpumap[idx]), 
idx);


Please clarify here.

In this case, I don't prefer mixing hardware specific bits with 
software only representation for these reasons :-


1. It makes it confusing and hard to differentiate the hardware 
specific attrbutes from software only.


Penny's approach matches what we are doing in the MMU code. We want 
to have a way for the caller to pass just set of flags and let the 
callee to decide what to do with them.


This may be flags converted for HW fields or just used by the logic.

If you disagree with this approach, then can you propose a 
different way that we can discuss?


Thanks ayan for pointing out that RES0 is not suitable for storing 
software-only flags, agreed.


Then, maybe we should refine the existing "struct pr_t" to store these
sw bits, like:
```
typedef union {
 struct {
    uint8_t tran:1; /* Transient region */
    uint8_t p2m_type:4; /* Used to store p2m types.*/


Why do you need the p2m_type?



I inherited the usage from MMU. Right now, in commit "[PATCH v3 46/52] 
xen/mpu: look up entry in p2m table", we introduce the first usage to

tell whether it is a valid P2M MPU memory region. In the future,
we may also use it to check whether it works as RAM region(p2m_ram_rw).


 };
 uint8_t bits;
} pr_flags;

/* MPU Protection Region */
typedef struct {
 prbar_t prbar;
 prlar_t prlar;
 pr_flags flags;
} pr_t;
```
The drawback is that, considering the padding, "struct pr_t" expands 
from 16 bytes to 24 bytes.


For clarifications, pr_t is going to be used to create an array in Xen, 
right? If so, what's the expected

Re: [PATCH v3 12/52] xen/mmu: extract early uart mapping from setup_fixmap

2023-07-06 Thread Penny Zheng

Hi Julien

On 2023/7/5 18:35, Julien Grall wrote:

Hi Penny,

On 05/07/2023 10:03, Penny Zheng wrote:

On 2023/7/5 06:25, Julien Grall wrote:

Hi Penny,

Title: You want to clarify that this change is arm64 only. So:

xen/arm64: mmu: ...

On 26/06/2023 04:34, Penny Zheng wrote:
Original setup_fixmap is actually doing two seperate tasks, one is 
enabling
the early UART when earlyprintk on, and the other is to set up the 
fixmap

even when earlyprintk is not configured.

To be more dedicated and precise, the old function shall be split 
into two

functions, setup_early_uart and new setup_fixmap.
While some of the split before would be warrant even without the MPU 
support. This one is not because there is limited point to have 3 
lines function. So I think you want to justify based on what you plan 
to do with the MPU code.


That said, I don't think we need to introduce setup_fixmap. See below.




Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new patch
---
  xen/arch/arm/arm64/head.S |  3 +++
  xen/arch/arm/arm64/mmu/head.S | 24 +---
  2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
index e63886b037..55a4cfe69e 100644
--- a/xen/arch/arm/arm64/head.S
+++ b/xen/arch/arm/arm64/head.S
@@ -258,7 +258,10 @@ real_start_efi:
  b enable_boot_mm
  primary_switched:
+    bl    setup_early_uart
+#ifdef CONFIG_HAS_FIXMAP
  bl    setup_fixmap
+#endif
  #ifdef CONFIG_EARLY_PRINTK
  /* Use a virtual address to access the UART. */
  ldr   x23, =EARLY_UART_VIRTUAL_ADDRESS
diff --git a/xen/arch/arm/arm64/mmu/head.S 
b/xen/arch/arm/arm64/mmu/head.S

index 2b209fc3ce..295596aca1 100644
--- a/xen/arch/arm/arm64/mmu/head.S
+++ b/xen/arch/arm/arm64/mmu/head.S
@@ -367,24 +367,34 @@ identity_mapping_removed:
  ENDPROC(remove_identity_mapping)
  /*
- * Map the UART in the fixmap (when earlyprintk is used) and hook the
- * fixmap table in the page tables.
- *
- * The fixmap cannot be mapped in create_page_tables because it may
- * clash with the 1:1 mapping.


Since commit 9d267c049d92 ("xen/arm64: Rework the memory layout"), 
there is no chance that the fixmap will clash with the 1:1 mapping. 
So rather than introducing a new function, I would move the creation 
of the fixmap in create_pagetables().




Understood. I'll move the creation of the fixmap in create_pagetables().


This would avoid the #ifdef CONFIG_HAS_FIXMAP in head.S.


+ * Map the UART in the fixmap (when earlyprintk is used)
   *
   * Inputs:
- *   x20: Physical offset
   *   x23: Early UART base physical address
   *
   * Clobbers x0 - x3
   */
-ENTRY(setup_fixmap)
+ENTRY(setup_early_uart)
  #ifdef CONFIG_EARLY_PRINTK
  /* Add UART to the fixmap table */
  ldr   x0, =EARLY_UART_VIRTUAL_ADDRESS
  create_mapping_entry xen_fixmap, x0, x23, x1, x2, x3, 
type=PT_DEV_L3

+    /* Ensure any page table updates made above have occurred. */
+    dsb   nshst
+
+    ret


The 'ret' needs to be outside of the '#ifdef' block. But, in this 
case, I would prefer if we don't call setup_early_uart() when 
!CONFIG_EARLY_PRINTK in head.S




okay. I'll move the #ifdef to the caller in head.S.


Thinking about this again. I think you can actually move the mapping of 
the UART in create_pagetables() because it will also not clash with the 
1:1.


For the MPU, the mapping could then be moved in prepare_early_mappings().

This would reduce the number of functions exposed.


Understood! will do.



Cheers,





Re: [PATCH v3 11/52] xen/arm: mmu: fold FIXMAP into MMU system

2023-07-06 Thread Penny Zheng

Hi Julien

On 2023/7/5 18:31, Julien Grall wrote:

Hi Penny,

On 05/07/2023 09:19, Penny Zheng wrote:

On 2023/7/5 06:12, Julien Grall wrote:

On 26/06/2023 04:34, Penny Zheng wrote:

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index fb77392b82..22b28b8ba2 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -15,7 +15,6 @@ config ARM
  select HAS_DEVICE_TREE
  select HAS_PASSTHROUGH
  select HAS_PDX
-    select HAS_PMAP
  select IOMMU_FORCE_PT_SHARE
  config ARCH_DEFCONFIG
@@ -63,11 +62,17 @@ source "arch/Kconfig"
  config HAS_MMU
  bool "Memory Management Unit support in a VMSA system"
  default y
+    select HAS_PMAP
  help
    In a VMSA system, a Memory Management Unit (MMU) provides 
fine-grained control of
    a memory system through a set of virtual to physical address 
mappings and associated memory
    properties held in memory-mapped tables known as translation 
tables.

+config HAS_FIXMAP
+    bool "Provide special-purpose 4K mapping slots in a VMSA"



Regardless what I wrote above, I don't think a developer should be 
able to disable HAS_FIXMAP when the HAS_MMU is used. So the 3 lines 
should be replaced with:


def_bool HAS_MMU


Understood, will fix


Do you still need HAS_FIXMAP if this patch is dropped?


Right now, this patch only contains:
1) wrap PMAP into MMU
2) change static inline virt_to_fix() to declaration in fixmap.h and
definition in mmu/mm.c.
HAS_FIXMAP is not needed anymore.



Cheers,





Re: [PATCH v3 10/52] xen/arm: Move MMU related definitions from config.h to mmu/layout.h

2023-07-06 Thread Penny Zheng

Hi Julien

On 2023/7/5 18:30, Julien Grall wrote:

Hi Penny,

On 05/07/2023 07:51, Penny Zheng wrote:

On 2023/7/5 05:54, Julien Grall wrote:

Hi Penny,

On 26/06/2023 04:34, Penny Zheng wrote:

From: Wei Chen 

Xen defines some global configuration macros for Arm in config.h.
We still want to use it for MMU systems, but there are some address


Did you mean MPU?



yes, typo


layout related definitions that are defined for MMU systems only.
These definitions could not be used by MPU systems, but adding
ifdefery with CONFIG_HAS_MPU to gate these definitions will result
in a messy and hard-to-read/maintain code.

So we keep some common definitions still in config.h, but move MMU
related definitions to a new file - mmu/layout.h to avoid spreading
"#ifdef" everywhere.


Just to ease the review, can you add some details which one are 
considered common?




Sure,
IMO, the only part left in common is as follows:
```
#ifdef CONFIG_ARM_64

#define FRAMETABLE_SIZE    GB(32)
#define FRAMETABLE_NR  (FRAMETABLE_SIZE / sizeof(*frame_table))

#endif
```


Hmmm... Looking at the result of the patch, you moved FRAMETABLE_SIZE 
and FRAMETABLE_NR in layout.h. Also, I can't find any layout specific 
define in config.h. So I think the paragraph could be dropped.




That's because I define this same snippet in both mmu/layout.h and
mpu/layout.h, see [PATCH v3 23/52] xen/arm: create mpu/layout.h for MPU 
related address definitions.

So it is common for both mmu/layout.h and mpu/layout.h.
We could leave it later for discussion.


I couldn't figure a proper way to remove the limit for MPU system.

when calculating variable "pdx_group_valid", which is defined as
```
unsigned long __read_mostly pdx_group_valid[BITS_TO_LONGS(
 (FRAMETABLE_NR + PDX_GROUP_COUNT - 1)/PDX_GROUP_COUNT)] = {[0] = 1}
'''

It relies on FRAMETABLE_NR to limit array length. If we are trying to
get rid of the limit for the MPU, it may bring a lot of changes in pdx 
common codes, like, variable "pdx_group_valid" needs to be allocated 
in runtime, according actual frametable size, at least for MPU case.


The main problem is that, at least on Arm, the PDX is initialized before 
you can allocate any memory. You should be able to re-order the code so 
we populate the boot allocator first.


But I don't think this is worth it right now as, if I am not mistaken, 
the pdx_group_valid is only 256 bytes on Arm64.


Cheers,





Re: [PATCH v3 09/52] xen/arm: use PA == VA for EARLY_UART_VIRTUAL_ADDRESS on MPU systems

2023-07-06 Thread Penny Zheng

Hi Julien

On 2023/7/5 03:25, Julien Grall wrote:

Hi Penny,

On 26/06/2023 04:34, Penny Zheng wrote:

From: Wei Chen 

There is no VMSA support on MPU systems, so we can not map early
UART to FIXMAP_CONSOLE. In stead, we can use PA == VA for early
UART on MPU systems.

Signed-off-by: Wei Chen 
Signed-off-by: Penny Zheng 


Is this change necessary for the MMU split? If not, I will skip the 
review for now.




It is not necessary. I will not include it in next series focusing on 
MMU split.



Cheers,





Re: [PATCH v3 08/52] xen/arm64: move MMU related code from head.S to mmu/head.S

2023-07-05 Thread Penny Zheng

Hi Julien

On 2023/7/5 18:43, Julien Grall wrote:

Hi Penny,

One more remark.

On 26/06/2023 04:33, Penny Zheng wrote:

From: Wei Chen 

There are lots of MMU specific code in head.S. This code will not
be used in MPU systems. If we use #ifdef to gate them, the code
will become messy and hard to maintain. So we move MMU related
code to mmu/head.S, and keep common code still in head.S. We also
add .text.idmap in mmu/head.S to make all code in this new file
are still in identity map page but will be linked after head.S.

As "fail" in head.S is very simple and this name is too easy to
be conflicted, so duplicate it in mmu/head.S instead of exporting
it.

And some assembly macros that will be shared by MMU and MPU later,
we move them to macros.h.

Rename enable_boot_mmu()/enable_runtime_mmu() to a more generic name
enable_boot_mm()/enable_runtime_mm(), in order to make them common 
interfaces

to be used for both MMU and later MPU system.

Signed-off-by: Wei Chen 
Signed-off-by: Penny Zheng 
---
v1 -> v2:
1. Move macros to macros.h
2. Remove the indention modification
3. Duplicate "fail" instead of exporting it.
---
v3:
- Rename enable_boot_mmu()/enable_runtime_mmu() to a more generic name
enable_boot_mm()/enable_runtime_mm()
---
  xen/arch/arm/arm64/Makefile |   3 +
  xen/arch/arm/arm64/head.S   | 469 +---
  xen/arch/arm/arm64/mmu/head.S   | 453 +++
  xen/arch/arm/include/asm/arm64/macros.h |  51 +++
  4 files changed, 509 insertions(+), 467 deletions(-)
  create mode 100644 xen/arch/arm/arm64/mmu/head.S

diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile
index 54ad55c75c..0c4b177be9 100644
--- a/xen/arch/arm/arm64/Makefile
+++ b/xen/arch/arm/arm64/Makefile
@@ -8,6 +8,9 @@ obj-y += domctl.o
  obj-y += domain.o
  obj-y += entry.o
  obj-y += head.o
+ifeq ($(CONFIG_HAS_MMU),y)
+obj-y += mmu/head.o
+endif


You could use obj-$(CONFIG_HAS_MMU) += mmu/head.o.

But in this case, I would rather prefer if we match how other 
subdirectory are added. I.e. on the parent's directory Makefile you add:


obj-$(CONFIG_MMU) += mmu/

And in the directory you add a Makefile which list the files to compile.



Understood. thanks for the instruction.


Cheers,





Re: [PATCH v3 03/52] xen/arm: add an option to define Xen start address for Armv8-R

2023-07-05 Thread Penny Zheng

Hi Julien

On 2023/7/5 03:21, Julien Grall wrote:

Hi,

On 26/06/2023 04:33, Penny Zheng wrote:

From: Wei Chen 

On Armv8-A, Xen has a fixed virtual start address (link address
too) for all Armv8-A platforms. In an MMU based system, Xen can
map its loaded address to this virtual start address. So, on
Armv8-A platforms, the Xen start address does not need to be
configurable. But on Armv8-R platforms, there is no MMU to map
loaded address to a fixed virtual address and different platforms
will have very different address space layout. So Xen cannot use
a fixed physical address on MPU based system and need to have it
configurable.

In this patch we introduce one Kconfig option for users to define
the default Xen start address for Armv8-R. Users can enter the
address in config time, or select the tailored platform config
file from arch/arm/configs.

And as we introduced Armv8-R to Xen, that means the existed Arm64
MMU based platforms should not be listed in Armv8-R platform
list, so we add !HAS_MPU dependency for these platforms.


 From a brief look, this patch doesn't seem to be necessary in order to 
move the MMU code in separate files. Can you confirm?


If so can this be moved latter in the series? This is to allow the 
reviewers to focus on the MMU split as we discussed on the call today.




Sure,it will be not included in the next serie focusing on MMU split.


Cheers,





Re: [PATCH v3 03/52] xen/arm: add an option to define Xen start address for Armv8-R

2023-07-05 Thread Penny Zheng




On 2023/7/4 19:47, Julien Grall wrote:



On 04/07/2023 11:36, Ayan Kumar Halder wrote:

Hi Penny,


Hi Ayan,


On 26/06/2023 04:33, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



From: Wei Chen 

On Armv8-A, Xen has a fixed virtual start address (link address
too) for all Armv8-A platforms. In an MMU based system, Xen can
map its loaded address to this virtual start address. So, on
Armv8-A platforms, the Xen start address does not need to be
configurable. But on Armv8-R platforms, there is no MMU to map
loaded address to a fixed virtual address and different platforms
will have very different address space layout. So Xen cannot use
a fixed physical address on MPU based system and need to have it
configurable.

In this patch we introduce one Kconfig option for users to define
the default Xen start address for Armv8-R. Users can enter the
address in config time, or select the tailored platform config
file from arch/arm/configs.

And as we introduced Armv8-R to Xen, that means the existed Arm64
MMU based platforms should not be listed in Armv8-R platform
list, so we add !HAS_MPU dependency for these platforms.

Signed-off-by: Wei Chen 
Signed-off-by: Penny Zheng 
---
v1 -> v2:
1. Remove the platform header fvp_baser.h.
2. Remove the default start address for fvp_baser64.
3. Remove the description of default address from commit log.
4. Change HAS_MPU to ARM_V8R for Xen start address dependency.
    No matter Arm-v8r board has MPU or not, it always need to
    specify the start address.
---
v3:
1. Remove unrelated change of "CONFIG_FVP_BASER"
2. Change ARM_V8R to HAS_MPU for Xen start address dependency
---
  xen/arch/arm/Kconfig   | 8 
  xen/arch/arm/platforms/Kconfig | 8 +---
  2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index 70fdc2ba63..ff17345cdb 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -181,6 +181,14 @@ config TEE
   This option enables generic TEE mediators support. It 
allows guests
   to access real TEE via one of TEE mediators implemented in 
XEN.


+config XEN_START_ADDRESS
+   hex "Xen start address: keep default to use platform defined 
address"

+   default 0
+   depends on HAS_MPU
+   help
+ This option allows to set the customized address at which 
Xen will be
+ linked on MPU systems. This address must be aligned to a 
page size.

+
  source "arch/arm/tee/Kconfig"

  config STATIC_SHM
diff --git a/xen/arch/arm/platforms/Kconfig 
b/xen/arch/arm/platforms/Kconfig

index c93a6b2756..75af48b5f9 100644
--- a/xen/arch/arm/platforms/Kconfig
+++ b/xen/arch/arm/platforms/Kconfig
@@ -1,6 +1,7 @@
  choice
 prompt "Platform Support"
 default ALL_PLAT
+   default NO_PLAT if HAS_MPU


I am a bit concerned about this as we will be introducing R52 specific 
platform in xen/arch/arm/platforms/


(For eg 
https://github.com/Xilinx/xen/blob/xlnx_rebase_4.17/xen/arch/arm_mpu/platforms/amd-versal-net.c )


Thus, we will have to remove this line at that time.

Can you remove this line, please if it does not cause any issue ?


 From my understanding of the discussion at Xen Summit, most of the 
platform specific code would be moved to something similar to bootwrapper.


So do you still actually need to have code in Xen for setting up the timer?

Cheers,





Re: [PATCH v3 42/52] xen/mpu: implement setup_virt_paging for MPU system

2023-07-05 Thread Penny Zheng

Hi Ayan

On 2023/7/5 01:49, Ayan Kumar Halder wrote:

Hi Penny,

Most of these are specific to ARM_64, thus we can add "#ifdef 
CONFIG_ARM_64" as follows :-


Yes, you're right.



On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



For MMU system, setup_virt_paging is used to configure stage 2 address
translation regime, like IPA bits, VMID allocator set up, etc.
Some could be inherited in MPU system, like VMID allocator set up, etc.

For MPU system, we could have the following memory translation regime:
- PMSAv8-64 at both EL1/EL0 and EL2
- VMSAv8-64 at EL1/EL0 and PMSAv8-64 at EL2
The default option will be the second, unless the platform could not 
support,
which could be checked against MSA_frac bit in Memory Model Feature 
Register 0(

ID_AA64MMFR0_EL1).

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- no change
---
  xen/arch/arm/Makefile |  1 +
  xen/arch/arm/include/asm/cpufeature.h |  7 ++
  xen/arch/arm/include/asm/p2m.h    |  8 +++
  xen/arch/arm/include/asm/processor.h  | 13 
  xen/arch/arm/mpu/p2m.c    | 92 +++
  5 files changed, 121 insertions(+)
  create mode 100644 xen/arch/arm/mpu/p2m.c

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index feb49640a0..9f4b11b069 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -47,6 +47,7 @@ obj-y += mmu/p2m.o
  else
  obj-y += mpu/mm.o
  obj-y += mpu/setup.o
+obj-y += mpu/p2m.o
  endif
  obj-y += mm.o
  obj-y += monitor.o
diff --git a/xen/arch/arm/include/asm/cpufeature.h 
b/xen/arch/arm/include/asm/cpufeature.h

index 894f278a4a..cbaf41881b 100644
--- a/xen/arch/arm/include/asm/cpufeature.h
+++ b/xen/arch/arm/include/asm/cpufeature.h
@@ -250,6 +250,12 @@ struct cpuinfo_arm {
  unsigned long tgranule_16K:4;
  unsigned long tgranule_64K:4;
  unsigned long tgranule_4K:4;
+#ifdef CONFIG_HAS_MPU
+    unsigned long __res:16;
+    unsigned long msa:4;
+    unsigned long msa_frac:4;
+    unsigned long __res0:8;
+#else
  unsigned long tgranule_16k_2:4;
  unsigned long tgranule_64k_2:4;
  unsigned long tgranule_4k_2:4;
@@ -257,6 +263,7 @@ struct cpuinfo_arm {
  unsigned long __res0:8;
  unsigned long fgt:4;
  unsigned long ecv:4;
+#endif

  /* MMFR1 */
  unsigned long hafdbs:4;
diff --git a/xen/arch/arm/include/asm/p2m.h 
b/xen/arch/arm/include/asm/p2m.h

index f62d632830..d9c91d4a98 100644
--- a/xen/arch/arm/include/asm/p2m.h
+++ b/xen/arch/arm/include/asm/p2m.h
@@ -16,8 +16,16 @@ extern unsigned int p2m_ipa_bits;

  extern unsigned int p2m_root_order;
  extern unsigned int p2m_root_level;
+#ifdef CONFIG_HAS_MPU
+/*
+ * A 4KB Page is enough for stage 2 translation in MPU system, which 
could

+ * store at most 255 EL2 MPU memory regions.
+ */
+#define P2M_ROOT_ORDER 0
+#else
  #define P2M_ROOT_ORDER    p2m_root_order
  #define P2M_ROOT_LEVEL p2m_root_level
+#endif

  #define MAX_VMID_8_BIT  (1UL << 8)
  #define MAX_VMID_16_BIT (1UL << 16)
diff --git a/xen/arch/arm/include/asm/processor.h 
b/xen/arch/arm/include/asm/processor.h

index 685f9b18fd..fe761ce50f 100644
--- a/xen/arch/arm/include/asm/processor.h
+++ b/xen/arch/arm/include/asm/processor.h
@@ -389,6 +389,12 @@

  #define VTCR_RES1   (_AC(1,UL)<<31)

+#ifdef CONFIG_HAS_MPU

&& ARM_64 /* As these are specific to ID_AA64MMFR0EL1 */


Will do


+#define VTCR_MSA_VMSA   (_AC(0x1,UL)<<31)
+#define VTCR_MSA_PMSA   ~(_AC(0x1,UL)<<31)
+#define NSA_SEL2    ~(_AC(0x1,UL)<<30)
+#endif
+
  /* HCPTR Hyp. Coprocessor Trap Register */
  #define HCPTR_TAM   ((_AC(1,U)<<30))
  #define HCPTR_TTA   ((_AC(1,U)<<20))    /* Trap trace 
registers */

@@ -449,6 +455,13 @@
  #define MM64_VMID_16_BITS_SUPPORT   0x2
  #endif

+#ifdef CONFIG_HAS_MPU

&& ARM_64 /* As these are specific to ID_AA64MMFR0EL1 */


Will do


+#define MM64_MSA_PMSA_SUPPORT   0xf
+#define MM64_MSA_FRAC_NONE_SUPPORT  0x0
+#define MM64_MSA_FRAC_PMSA_SUPPORT  0x1
+#define MM64_MSA_FRAC_VMSA_SUPPORT  0x2
+#endif
+
  #ifndef __ASSEMBLY__

  extern register_t __cpu_logical_map[];
diff --git a/xen/arch/arm/mpu/p2m.c b/xen/arch/arm/mpu/p2m.c
new file mode 100644
index 00..04c44825cb
--- /dev/null
+++ b/xen/arch/arm/mpu/p2m.c
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+void __init setup_virt_paging(void)
+{
+    uint64_t val = 0;
+    bool p2m_vmsa = true;
+
+    /* PA size */
+    const unsigned int pa_range_info[] = { 32, 36, 40, 42, 44, 48, 
52, 0, /* Invalid */ };


As this file is common between ARM_32 and ARM_64 and th

Re: [PATCH v3 35/52] xen/arm: map static memory on demand

2023-07-05 Thread Penny Zheng

Hi Ayan

On 2023/7/4 23:10, Ayan Kumar Halder wrote:

Hi Penny,

On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



In function init_staticmem_pages, we need the access to static memory
for proper initialization.
It is not a problem in MMU system, as Xen map the whole RAM in
setup_mm(). However, with limited MPU memory regions, it is too luxury
to map the whole RAM.
As a result, we follow the rule of "map on demand", to map static memory
temporarily before its initialization, and unmap immediately after its
initialization.


I could see that you are using _PAGE_TRANSIENT  to map memory 
temporarily. However, I don't see this being translated to any of the 
MPU hardware features (ie _PAGE_TRANSIENT does not seem to translate to 
any of the attributes in PRBAR, PRLAR, PRENR, etc). Thus, how is it 
different from mapping the memory in "non temporary" way ?




It is only software feature.
It is designed for implementing functions like ioremap_xxx(), or 
map_staticmem_pages_to_xen() here, which are always occuring with its 
reverse unmapping function nearby like iounmap(), or 
unmap_staticmem_pages_to_xen(), to map a chunk of memory *temporarily*, 
for a very short time.
I want to check this flag in the unmapping function, to ensure that we 
are unmapping the proper MPU region.


Fixed MPU regions are like Xen text section, Xen data section, etc.


Please let me know what I am missing.

- Ayan



Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
  xen/arch/arm/include/asm/mm.h |  2 ++
  xen/arch/arm/mmu/mm.c | 10 ++
  xen/arch/arm/mpu/mm.c | 10 ++
  xen/arch/arm/setup.c  | 21 +
  4 files changed, 43 insertions(+)

diff --git a/xen/arch/arm/include/asm/mm.h 
b/xen/arch/arm/include/asm/mm.h

index 66d98b9a29..cffbf8a595 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -224,6 +224,8 @@ extern void mm_init_secondary_cpu(void);
  extern void setup_frametable_mappings(paddr_t ps, paddr_t pe);
  /* map a physical range in virtual memory */
  void __iomem *ioremap_attr(paddr_t start, size_t len, unsigned int 
attributes);

+extern int map_staticmem_pages_to_xen(paddr_t start, paddr_t end);
+extern int unmap_staticmem_pages_to_xen(paddr_t start, paddr_t end);

  static inline void __iomem *ioremap_nocache(paddr_t start, size_t len)
  {
diff --git a/xen/arch/arm/mmu/mm.c b/xen/arch/arm/mmu/mm.c
index 2f29cb53fe..4196a55c32 100644
--- a/xen/arch/arm/mmu/mm.c
+++ b/xen/arch/arm/mmu/mm.c
@@ -1113,6 +1113,16 @@ int populate_pt_range(unsigned long virt, 
unsigned long nr_mfns)

  return xen_pt_update(virt, INVALID_MFN, nr_mfns, _PAGE_POPULATE);
  }

+int __init map_staticmem_pages_to_xen(paddr_t start, paddr_t end)
+{
+    return 0;
+}
+
+int __init unmap_staticmem_pages_to_xen(paddr_t start, paddr_t end)
+{
+    return 0;
+}
+
  /*
   * Local variables:
   * mode: C
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index a40055ae5e..9d5c1da39c 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -614,6 +614,16 @@ void __init setup_frametable_mappings(paddr_t ps, 
paddr_t pe)

 frametable_size - (nr_pdxs * sizeof(struct page_info)));
  }

+int __init map_staticmem_pages_to_xen(paddr_t start, paddr_t end)
+{
+    return xen_mpumap_update(start, end, PAGE_HYPERVISOR | 
_PAGE_TRANSIENT);

+}
+
+int __init unmap_staticmem_pages_to_xen(paddr_t start, paddr_t end)
+{
+    return xen_mpumap_update(start, end, 0);
+}
+
  /*
   * Local variables:
   * mode: C
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index f42b53d17b..c21d1db763 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -637,12 +637,33 @@ void __init init_staticmem_pages(void)
  mfn_t bank_start = 
_mfn(PFN_UP(bootinfo.reserved_mem.bank[bank].start));
  unsigned long bank_pages = 
PFN_DOWN(bootinfo.reserved_mem.bank[bank].size);

  mfn_t bank_end = mfn_add(bank_start, bank_pages);
+    int res;

  if ( mfn_x(bank_end) <= mfn_x(bank_start) )
  return;

+    /* Map temporarily before initialization */
+    res = map_staticmem_pages_to_xen(mfn_to_maddr(bank_start),
+ mfn_to_maddr(bank_end));
+    if ( res )
+    {
+    printk(XENLOG_ERR "Failed to map static memory to 
Xen: %d\n",

+   res);
+    return;
+    }
+
  unprepare_staticmem_pages(mfn_to_page(bank_start),
    bank_pages, false);
+
+    /* Unmap immediately after initialization */
+    res = unmap_staticmem_pages_to_xen(mfn_to_maddr(bank_start),
+ 

Re: [PATCH v3 33/52] xen/mpu: initialize frametable in MPU system

2023-07-05 Thread Penny Zheng

Hi,

On 2023/7/3 17:31, Julien Grall wrote:

Hi,

On 03/07/2023 07:10, Penny Zheng wrote:

On 2023/6/30 23:19, Ayan Kumar Halder wrote:

Hi Penny,

On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



Xen is using page as the smallest granularity for memory managment.
And we want to follow the same concept in MPU system.
That is, structure page_info and the frametable which is used for 
storing
and managing the smallest memory managment unit is also required in 
MPU system.


In MPU system, since we can not use a fixed VA 
address(FRAMETABLE_VIRT_START)
to map frametable like MMU system does and everything is 1:1 
mapping, we

instead define a variable "struct page_info *frame_table" as frametable
pointer, and ask boot allocator to allocate appropriate memory for 
frametable.


As frametable is successfully initialized, the convertion between 
machine frame

number/machine address/"virtual address" and page-info structure is
ready too, like mfn_to_page/maddr_to_page/virt_to_page, etc

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- add ASSERT() to confirm the MFN you pass is covered by the 
frametable.

---
  xen/arch/arm/include/asm/mm.h | 14 ++
  xen/arch/arm/include/asm/mpu/mm.h |  3 +++
  xen/arch/arm/mpu/mm.c | 27 +++
  3 files changed, 44 insertions(+)

diff --git a/xen/arch/arm/include/asm/mm.h 
b/xen/arch/arm/include/asm/mm.h

index daa6329505..66d98b9a29 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -341,6 +341,19 @@ static inline uint64_t gvirt_to_maddr(vaddr_t 
va, paddr_t *pa,

  #define virt_to_mfn(va) __virt_to_mfn(va)
  #define mfn_to_virt(mfn)    __mfn_to_virt(mfn)

+#ifdef CONFIG_HAS_MPU
+/* Convert between virtual address to page-info structure. */
+static inline struct page_info *virt_to_page(const void *v)
+{
+    unsigned long pdx;
+
+    pdx = paddr_to_pdx(virt_to_maddr(v));
+    ASSERT(pdx >= frametable_base_pdx);
+    ASSERT(pdx < frametable_pdx_end);
+
+    return frame_table + pdx - frametable_base_pdx;
+}
This should go in xen/arch/arm/include/asm/mpu/mm.h. Then you don't 
need ifdef

+#else
  /* Convert between Xen-heap virtual addresses and page-info 
structures. */

  static inline struct page_info *virt_to_page(const void *v)
  {
@@ -354,6 +367,7 @@ static inline struct page_info 
*virt_to_page(const void *v)

  pdx += mfn_to_pdx(directmap_mfn_start);
  return frame_table + pdx - frametable_base_pdx;
  }

Consequently, this should be in xen/arch/arm/include/asm/mmu/mm.h


The reason why I don't put virt_to_page()/page_to_virt() in specific 
header is that we are using some helpers, which are defined just

a few lines before, like mfn_to_virt(), etc.
If you are moving mfn_to_virt() to specific header too, that will
result in a lot dulplication.


+#endif

  static inline void *page_to_virt(const struct page_info *pg)
  {
diff --git a/xen/arch/arm/include/asm/mpu/mm.h 
b/xen/arch/arm/include/asm/mpu/mm.h

index e26bd4f975..98f6df65b8 100644
--- a/xen/arch/arm/include/asm/mpu/mm.h
+++ b/xen/arch/arm/include/asm/mpu/mm.h
@@ -2,6 +2,9 @@
  #ifndef __ARCH_ARM_MM_MPU__
  #define __ARCH_ARM_MM_MPU__

+extern struct page_info *frame_table;
If you define frame_table in xen/arch/arm/include/asm/mm.h , then you 
don't need the above declaration.


It is a variable only in MPU. In MMU, it is a fixed value.
"#define frame_table ((struct page_info *)FRAMETABLE_VIRT_START)"


+extern unsigned long frametable_pdx_end;
Also you don't need extern as this is only used by 
xen/arch/arm/mpu/mm.c.


sure.


+
  extern int xen_mpumap_update(paddr_t base, paddr_t limit, unsigned 
int flags);


You don't need extern here as it should be used only in 
xen/arch/arm/mpu/mm.c


Currently, I see the following in xen/arch/arm/mm.c,

int map_pages_to_xen(unsigned long virt,
  mfn_t mfn,
  unsigned long nr_mfns,
  unsigned int flags)
{
#ifndef CONFIG_HAS_MPU
 return xen_pt_update(virt, mfn, nr_mfns, flags);
#else
 return xen_mpumap_update(mfn_to_maddr(mfn),
  mfn_to_maddr(mfn_add(mfn, nr_mfns)), 
You are ignoring 'virt' here. Shouldn't you at least check that 'virt == 
mfn_to_maddr(mfn)'?




Sure, I'll do the check.


flags);
#endif
}

int destroy_xen_mappings(unsigned long s, unsigned long e)
{
 ASSERT(IS_ALIGNED(s, PAGE_SIZE));
 ASSERT(IS_ALIGNED(e, PAGE_SIZE));
 ASSERT(s <= e);
#ifndef CONFIG_HAS_MPU
 return xen_pt_update(s, INVALID_MFN, (e - s) >> PAGE_SHIFT, 0);
#else
 return xen_mpumap_update(virt_to_maddr((void *)s),
  virt_to_maddr((void *)e), 0);
#endif
}

int modify_xen_ma

Re: [PATCH v3 12/52] xen/mmu: extract early uart mapping from setup_fixmap

2023-07-05 Thread Penny Zheng

Hi Julien

On 2023/7/5 06:25, Julien Grall wrote:

Hi Penny,

Title: You want to clarify that this change is arm64 only. So:

xen/arm64: mmu: ...

On 26/06/2023 04:34, Penny Zheng wrote:
Original setup_fixmap is actually doing two seperate tasks, one is 
enabling

the early UART when earlyprintk on, and the other is to set up the fixmap
even when earlyprintk is not configured.

To be more dedicated and precise, the old function shall be split into 
two

functions, setup_early_uart and new setup_fixmap.
While some of the split before would be warrant even without the MPU 
support. This one is not because there is limited point to have 3 lines 
function. So I think you want to justify based on what you plan to do 
with the MPU code.


That said, I don't think we need to introduce setup_fixmap. See below.




Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new patch
---
  xen/arch/arm/arm64/head.S |  3 +++
  xen/arch/arm/arm64/mmu/head.S | 24 +---
  2 files changed, 20 insertions(+), 7 deletions(-)

diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
index e63886b037..55a4cfe69e 100644
--- a/xen/arch/arm/arm64/head.S
+++ b/xen/arch/arm/arm64/head.S
@@ -258,7 +258,10 @@ real_start_efi:
  b enable_boot_mm
  primary_switched:
+    bl    setup_early_uart
+#ifdef CONFIG_HAS_FIXMAP
  bl    setup_fixmap
+#endif
  #ifdef CONFIG_EARLY_PRINTK
  /* Use a virtual address to access the UART. */
  ldr   x23, =EARLY_UART_VIRTUAL_ADDRESS
diff --git a/xen/arch/arm/arm64/mmu/head.S 
b/xen/arch/arm/arm64/mmu/head.S

index 2b209fc3ce..295596aca1 100644
--- a/xen/arch/arm/arm64/mmu/head.S
+++ b/xen/arch/arm/arm64/mmu/head.S
@@ -367,24 +367,34 @@ identity_mapping_removed:
  ENDPROC(remove_identity_mapping)
  /*
- * Map the UART in the fixmap (when earlyprintk is used) and hook the
- * fixmap table in the page tables.
- *
- * The fixmap cannot be mapped in create_page_tables because it may
- * clash with the 1:1 mapping.


Since commit 9d267c049d92 ("xen/arm64: Rework the memory layout"), there 
is no chance that the fixmap will clash with the 1:1 mapping. So rather 
than introducing a new function, I would move the creation of the fixmap 
in create_pagetables().




Understood. I'll move the creation of the fixmap in create_pagetables().


This would avoid the #ifdef CONFIG_HAS_FIXMAP in head.S.


+ * Map the UART in the fixmap (when earlyprintk is used)
   *
   * Inputs:
- *   x20: Physical offset
   *   x23: Early UART base physical address
   *
   * Clobbers x0 - x3
   */
-ENTRY(setup_fixmap)
+ENTRY(setup_early_uart)
  #ifdef CONFIG_EARLY_PRINTK
  /* Add UART to the fixmap table */
  ldr   x0, =EARLY_UART_VIRTUAL_ADDRESS
  create_mapping_entry xen_fixmap, x0, x23, x1, x2, x3, 
type=PT_DEV_L3

+    /* Ensure any page table updates made above have occurred. */
+    dsb   nshst
+
+    ret


The 'ret' needs to be outside of the '#ifdef' block. But, in this case, 
I would prefer if we don't call setup_early_uart() when 
!CONFIG_EARLY_PRINTK in head.S




okay. I'll move the #ifdef to the caller in head.S.


  #endif
+ENDPROC(setup_early_uart)
+
+/*
+ * Map the fixmap table in the page tables.
+ *
+ * The fixmap cannot be mapped in create_page_tables because it may
+ * clash with the 1:1 mapping.
+ *
+ * Clobbers x0 - x3
+ */
+ENTRY(setup_fixmap)
  /* Map fixmap into boot_second */
  ldr   x0, =FIXMAP_ADDR(0)
  create_table_entry boot_second, xen_fixmap, x0, 2, x1, x2, x3


Cheeers,





Re: [PATCH v3 11/52] xen/arm: mmu: fold FIXMAP into MMU system

2023-07-05 Thread Penny Zheng

Hi,

On 2023/7/5 06:12, Julien Grall wrote:

Hi,

On 26/06/2023 04:34, Penny Zheng wrote:

FIXMAP in MMU system is used to do special-purpose 4K mapping, like
mapping early UART, temporarily mapping source codes for copy and paste
(copy_from_paddr), etc.

As FIXMAP feature is highly dependent on virtual address translation, we
introduce a new Kconfig CONFIG_HAS_FIXMAP to wrap all releated codes, 
then

we fold it into MMU system.
Since PMAP relies on FIXMAP, so we fold it too into MMU system.

Under !CONFIG_HAS_FIXMAP, we provide empty stubbers for not breaking
compilation.


Looking at the end result, I can't find any use of set_fixmap() in the 
common code. So I am not sure this is warrant to provide any stubs (see 
above).




Yes, you're rignt.

I think we do not need to provide stubs for set_fixmap/clear_fixmap, or
even for virt_to_fix(), if we change the static inline virt_to_fix()
to the definition in mmu/mm.c



Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v1 -> v2
- new patch
---
v3:
- fold CONFIG_HAS_FIXMAP into CONFIG_HAS_MMU
- change CONFIG_HAS_FIXMAP to an Arm-specific Kconfig
---
  xen/arch/arm/Kconfig  |  7 ++-
  xen/arch/arm/include/asm/fixmap.h | 31 ---
  2 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index fb77392b82..22b28b8ba2 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -15,7 +15,6 @@ config ARM
  select HAS_DEVICE_TREE
  select HAS_PASSTHROUGH
  select HAS_PDX
-    select HAS_PMAP
  select IOMMU_FORCE_PT_SHARE
  config ARCH_DEFCONFIG
@@ -63,11 +62,17 @@ source "arch/Kconfig"
  config HAS_MMU
  bool "Memory Management Unit support in a VMSA system"
  default y
+    select HAS_PMAP
  help
    In a VMSA system, a Memory Management Unit (MMU) provides 
fine-grained control of
    a memory system through a set of virtual to physical address 
mappings and associated memory
    properties held in memory-mapped tables known as translation 
tables.

+config HAS_FIXMAP
+    bool "Provide special-purpose 4K mapping slots in a VMSA"



Regardless what I wrote above, I don't think a developer should be able 
to disable HAS_FIXMAP when the HAS_MMU is used. So the 3 lines should be 
replaced with:


def_bool HAS_MMU


Understood, will fix




+    depends on HAS_MMU
+    default y
+
  config ACPI
  bool "ACPI (Advanced Configuration and Power Interface) Support 
(UNSUPPORTED)" if UNSUPPORTED

  depends on ARM_64
diff --git a/xen/arch/arm/include/asm/fixmap.h 
b/xen/arch/arm/include/asm/fixmap.h

index d0c9a52c8c..1b5b62866b 100644
--- a/xen/arch/arm/include/asm/fixmap.h
+++ b/xen/arch/arm/include/asm/fixmap.h
@@ -4,9 +4,6 @@
  #ifndef __ASM_FIXMAP_H
  #define __ASM_FIXMAP_H
-#include 
-#include 
-
  /* Fixmap slots */
  #define FIXMAP_CONSOLE  0  /* The primary UART */
  #define FIXMAP_MISC 1  /* Ephemeral mappings of hardware */
@@ -22,6 +19,11 @@
  #ifndef __ASSEMBLY__
+#ifdef CONFIG_HAS_FIXMAP
+
+#include 
+#include 
+
  /*
   * Direct access to xen_fixmap[] should only happen when {set,
   * clear}_fixmap() is unusable (e.g. where we would end up to
@@ -43,6 +45,29 @@ static inline unsigned int virt_to_fix(vaddr_t vaddr)
  return ((vaddr - FIXADDR_START) >> PAGE_SHIFT);
  }
+#else /* !CONFIG_HAS_FIXMAP */
+
+#include 
+#include 


I think they should be included outside of #ifdef.


+
+static inline void set_fixmap(unsigned int map, mfn_t mfn,
+  unsigned int attributes)
+{
+    ASSERT_UNREACHABLE();
+}


If there is an interest to have a stub, then I think we should be using 
BUG() because if this gets call, then it would likely crash right after 
when the user tries to access it.



+
+static inline void clear_fixmap(unsigned int map)
+{
+    ASSERT_UNREACHABLE();


This one might be OK with ASSERT_UNREACHABLE(). Yet, it might be best to 
use BUG() as nobody should use it.



+}
+
+static inline unsigned int virt_to_fix(vaddr_t vaddr)
+{
+    ASSERT_UNREACHABLE();
+    return -EINVAL;


This is a bit of a random value. This may or may not be mapped. And 
therefore any user of the return may or may not crash.


Overall, it feels like we are trying to just please the compiler by 
writing bogus stubs. It is going to be hard to get them correct. So it 
would be better if we have no use of the 3 helpers in the common code.




Agree.




+}
+#endif /* !CONFIG_HAS_FIXMAP */
+
  #endif /* __ASSEMBLY__ */
  #endif /* __ASM_FIXMAP_H */


Cheers,





Re: [PATCH v3 10/52] xen/arm: Move MMU related definitions from config.h to mmu/layout.h

2023-07-04 Thread Penny Zheng

Hi Julien

On 2023/7/5 05:54, Julien Grall wrote:

Hi Penny,

On 26/06/2023 04:34, Penny Zheng wrote:

From: Wei Chen 

Xen defines some global configuration macros for Arm in config.h.
We still want to use it for MMU systems, but there are some address


Did you mean MPU?



yes, typo


layout related definitions that are defined for MMU systems only.
These definitions could not be used by MPU systems, but adding
ifdefery with CONFIG_HAS_MPU to gate these definitions will result
in a messy and hard-to-read/maintain code.

So we keep some common definitions still in config.h, but move MMU
related definitions to a new file - mmu/layout.h to avoid spreading
"#ifdef" everywhere.


Just to ease the review, can you add some details which one are 
considered common?




Sure,
IMO, the only part left in common is as follows:
```
#ifdef CONFIG_ARM_64

#define FRAMETABLE_SIZEGB(32)
#define FRAMETABLE_NR  (FRAMETABLE_SIZE / sizeof(*frame_table))

#endif
```
I couldn't figure a proper way to remove the limit for MPU system.

when calculating variable "pdx_group_valid", which is defined as
```
unsigned long __read_mostly pdx_group_valid[BITS_TO_LONGS(
(FRAMETABLE_NR + PDX_GROUP_COUNT - 1)/PDX_GROUP_COUNT)] = {[0] = 1}
'''

It relies on FRAMETABLE_NR to limit array length. If we are trying to
get rid of the limit for the MPU, it may bring a lot of changes in pdx 
common codes, like, variable "pdx_group_valid" needs to be allocated in 
runtime, according actual frametable size, at least for MPU case.




Also, this patch will need to be rebased on top of the latest staging.


sure,





Signed-off-by: Wei Chen 
Signed-off-by: Penny Zheng 
---
v1 -> v2:
1. Remove duplicated FIXMAP definitions from config_mmu.h
---
v3:
1. name the new header layout.h
---
  xen/arch/arm/include/asm/config.h | 127 +--
  xen/arch/arm/include/asm/mmu/layout.h | 141 ++
  2 files changed, 143 insertions(+), 125 deletions(-)
  create mode 100644 xen/arch/arm/include/asm/mmu/layout.h

diff --git a/xen/arch/arm/include/asm/config.h 
b/xen/arch/arm/include/asm/config.h

index 30f4665ba9..204b3dec13 100644
--- a/xen/arch/arm/include/asm/config.h
+++ b/xen/arch/arm/include/asm/config.h
@@ -71,131 +71,8 @@
  #include 
  #include 
-/*
- * ARM32 layout:
- *   0  -   2M   Unmapped
- *   2M -   4M   Xen text, data, bss
- *   4M -   6M   Fixmap: special-purpose 4K mapping slots
- *   6M -  10M   Early boot mapping of FDT
- *   10M - 12M   Livepatch vmap (if compiled in)
- *
- *  32M - 128M   Frametable: 32 bytes per page for 12GB of RAM
- * 256M -   1G   VMAP: ioremap and early_ioremap use this virtual 
address

- *    space
- *
- *   1G -   2G   Xenheap: always-mapped memory
- *   2G -   4G   Domheap: on-demand-mapped
- *
- * ARM64 layout:
- * 0x - 0x01ff (2TB, L0 slots [0..3])
- *
- *  Reserved to identity map Xen
- *
- * 0x0200 - 0x027f (512GB, L0 slot [4])
- *  (Relative offsets)
- *   0  -   2M   Unmapped
- *   2M -   4M   Xen text, data, bss
- *   4M -   6M   Fixmap: special-purpose 4K mapping slots
- *   6M -  10M   Early boot mapping of FDT
- *  10M -  12M   Livepatch vmap (if compiled in)
- *
- *   1G -   2G   VMAP: ioremap and early_ioremap
- *
- *  32G -  64G   Frametable: 56 bytes per page for 2TB of RAM
- *
- * 0x0280 - 0x7fff (125TB, L0 slots [5..255])
- *  Unused
- *
- * 0x8000 - 0x84ff (5TB, L0 slots [256..265])
- *  1:1 mapping of RAM
- *
- * 0x8500 - 0x (123TB, L0 slots [266..511])
- *  Unused
- */
-
-#ifdef CONFIG_ARM_32
-#define XEN_VIRT_START  _AT(vaddr_t, MB(2))
-#else
-
-#define SLOT0_ENTRY_BITS  39
-#define SLOT0(slot) (_AT(vaddr_t,slot) << SLOT0_ENTRY_BITS)
-#define SLOT0_ENTRY_SIZE  SLOT0(1)
-
-#define XEN_VIRT_START  (SLOT0(4) + _AT(vaddr_t, MB(2)))
-#endif
-
-#define XEN_VIRT_SIZE   _AT(vaddr_t, MB(2))
-
-#define FIXMAP_VIRT_START   (XEN_VIRT_START + XEN_VIRT_SIZE)
-#define FIXMAP_VIRT_SIZE    _AT(vaddr_t, MB(2))
-
-#define FIXMAP_ADDR(n)  (FIXMAP_VIRT_START + (n) * PAGE_SIZE)
-
-#define BOOT_FDT_VIRT_START (FIXMAP_VIRT_START + FIXMAP_VIRT_SIZE)
-#define BOOT_FDT_VIRT_SIZE  _AT(vaddr_t, MB(4))
-
-#ifdef CONFIG_LIVEPATCH
-#define LIVEPATCH_VMAP_START    (BOOT_FDT_VIRT_START + 
BOOT_FDT_VIRT_SIZE)

-#define LIVEPATCH_VMAP_SIZE    _AT(vaddr_t, MB(2))
-#endif
-
-#define HYPERVISOR_VIRT_START  XEN_VIRT_START
-
-#ifdef CONFIG_ARM_32
-
-#define CONFIG_SEPARATE_XENHEAP 1
-
-#define FRAMETABLE_VIRT_START  _AT(vaddr_t, MB(32))
-#define FRAMETABLE_SIZE    MB(128-32)
-#define FRAMETABLE_NR  (FRAMETABLE_SIZE / sizeof(*frame_table))
-
-#define VMAP_VIRT_START    _AT(vaddr_t, MB(256))
-#define VMAP_VIRT_SIZE _AT(vaddr_t, GB(1) - MB(256))
-
-#define XENHEAP_VIRT_START _AT(vaddr_t, GB(1))
-#d

Re: [PATCH v3 08/52] xen/arm64: move MMU related code from head.S to mmu/head.S

2023-07-04 Thread Penny Zheng

Hi Julien

On 2023/7/5 05:46, Julien Grall wrote:

Hi Penny,

On 26/06/2023 04:33, Penny Zheng wrote:

From: Wei Chen 

There are lots of MMU specific code in head.S. This code will not
be used in MPU systems. If we use #ifdef to gate them, the code
will become messy and hard to maintain. So we move MMU related
code to mmu/head.S, and keep common code still in head.S. We also
add .text.idmap in mmu/head.S to make all code in this new file
are still in identity map page but will be linked after head.S.

As "fail" in head.S is very simple and this name is too easy to
be conflicted, so duplicate it in mmu/head.S instead of exporting
it.

And some assembly macros that will be shared by MMU and MPU later,
we move them to macros.h.


Aren't those macros already shared between head.S and mmu/head.S?



Correct me if I understand wrongly, so you want to remove the mention of 
MPU, and rephrase it to

"
As some assembly macros need to be shared by head.S and mmu/head.S,
we will move them to macros.h.
"



Rename enable_boot_mmu()/enable_runtime_mmu() to a more generic name
enable_boot_mm()/enable_runtime_mm(), in order to make them common 
interfaces

to be used for both MMU and later MPU system.


As mentionned in an earlier patch, I would prefer if the name was 
correct from the beginning. So this patch will be merely code movement.




Sure. will fix.




Signed-off-by: Wei Chen 
Signed-off-by: Penny Zheng 


I think this will need a rebase on top of the recent changes in head.S.



Will do in the next version.


diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile
index 54ad55c75c..0c4b177be9 100644
--- a/xen/arch/arm/arm64/Makefile
+++ b/xen/arch/arm/arm64/Makefile
@@ -8,6 +8,9 @@ obj-y += domctl.o


[...]


-/*
- * Macro to print the value of register \xb
- *
- * Clobbers x0 - x4
- */
-.macro print_reg xb
-    mov   x0, \xb
-    mov   x4, lr
-    bl    putn
-    mov   lr, x4
-.endm


I can't find any use of print_reg() in mmu/head.S. So is it necessary to 
move right now?




True, it is only used in head.S. I'll leave it here.


[...]

diff --git a/xen/arch/arm/arm64/mmu/head.S 
b/xen/arch/arm/arm64/mmu/head.S

new file mode 100644
index 00..2b209fc3ce
--- /dev/null
+++ b/xen/arch/arm/arm64/mmu/head.S
@@ -0,0 +1,453 @@
+/*
+ * xen/arch/arm/mmu/head.S
+ *
+ * Start-of-day code for an ARMv8.
+ *
+ * Ian Campbell 
+ * Copyright (c) 2012 Citrix Systems.
+ *
+ * Based on ARMv7-A head.S by
+ * Tim Deegan 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.


For new file (even split code), please use the SPDX tag. In this case, 
the following line should be added at the top of the file:


/* SPDX-License-Identifier: GPL-2.0-or-later */



Sure.


Cheers,





Re: [PATCH v3 07/52] xen/arm64: prepare for moving MMU related code from head.S

2023-07-04 Thread Penny Zheng

Hi Julien

On 2023/7/5 05:35, Julien Grall wrote:

Hi Penny,

On 26/06/2023 04:33, Penny Zheng wrote:

From: Wei Chen 

We want to reuse head.S for MPU systems, but there are some
code are implemented for MMU systems only. We will move such
code to another MMU specific file. But before that we will
do some indentations fix in this patch to make them be easier
for reviewing:
1. Fix the indentations of code comments.
2. Fix the indentations for .text.header section.
3. Rename puts() to asm_puts() for global export

Signed-off-by: Wei Chen 
Signed-off-by: Penny Zheng 
---
v1 -> v2:
1. New patch.
---
v3:
1. fix commit message
2. Rename puts() to asm_puts() for global export
---
  xen/arch/arm/arm64/head.S | 42 +++
  1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
index 4dfbe0bc6f..66347eedcc 100644
--- a/xen/arch/arm/arm64/head.S
+++ b/xen/arch/arm/arm64/head.S
@@ -94,7 +94,7 @@
  #define PRINT(_s)  \
  mov   x3, lr ; \
  adr   x0, 98f ;    \


This was recently changed to adr_l in staging. So you will need to 
rebase this patch.


Sure, I'll rebase.




-    bl    puts    ;    \
+    bl    asm_puts ;   \
  mov   lr, x3 ; \
  RODATA_STR(98, _s)
@@ -136,22 +136,22 @@
  add \xb, \xb, x20
  .endm
-    .section .text.header, "ax", %progbits
-    /*.aarch64*/
+.section .text.header, "ax", %progbits
+/*.aarch64*/
-    /*
- * Kernel startup entry point.
- * ---
- *
- * The requirements are:
- *   MMU = off, D-cache = off, I-cache = on or off,
- *   x0 = physical address to the FDT blob.
- *
- * This must be the very first address in the loaded image.
- * It should be linked at XEN_VIRT_START, and loaded at any
- * 4K-aligned address.  All of text+data+bss must fit in 2MB,
- * or the initial pagetable code below will need adjustment.
- */
+/*
+ * Kernel startup entry point.
+ * ---
+ *
+ * The requirements are:
+ *   MMU = off, D-cache = off, I-cache = on or off,
+ *   x0 = physical address to the FDT blob.
+ *
+ * This must be the very first address in the loaded image.
+ * It should be linked at XEN_VIRT_START, and loaded at any
+ * 4K-aligned address.  All of text+data+bss must fit in 2MB,
+ * or the initial pagetable code below will need adjustment.
+ */
  GLOBAL(start)
  /*
@@ -520,7 +520,7 @@ ENDPROC(cpu_init)
   * Macro to create a mapping entry in \tbl to \phys. Only mapping in 
3rd

   * level table (i.e page granularity) is supported.
   *
- * ptbl: table symbol where the entry will be created
+ * ptbl:    table symbol where the entry will be created
   * virt:    virtual address
   * phys:    physical address (should be page aligned)
   * tmp1:    scratch register
@@ -928,15 +928,15 @@ ENDPROC(init_uart)
   * x0: Nul-terminated string to print.
   * x23: Early UART base address
   * Clobbers x0-x1 */
-puts:
+ENTRY(asm_puts)


Can you mention in the comment that this function is only supposed to be 
called from assembly?


While you are at it, can you update the comment coding style to:

/*
  * Foo
  * Bar
  */



Sure,


  early_uart_ready x23, 1
  ldrb  w1, [x0], #1   /* Load next char */
  cbz   w1, 1f /* Exit on nul */
  early_uart_transmit x23, w1
-    b puts
+    b asm_puts
  1:
  ret
-ENDPROC(puts)
+ENDPROC(asm_puts)
  /*
   * Print a 64-bit number in hex.
@@ -966,7 +966,7 @@ hex:    .ascii "0123456789abcdef"
  ENTRY(early_puts)
  init_uart:
-puts:
+asm_puts:


I find odd that you add ENTRY() to the asm_puts() above but not here. 
However... I can't find any use of asm_puts() outside #ifdef 
CONFIG_EARLY_PRINTK. So maybe it can be dropped?




True. It is only used under #ifdef CONFIG_EARLY_PRINTK.
I'll drop.




  putn:   ret
  #endif /* !CONFIG_EARLY_PRINTK */


Cheers,





Re: [PATCH v3 06/52] xen/arm: introduce CONFIG_HAS_MMU

2023-07-04 Thread Penny Zheng

Hi Julien and Ayan

On 2023/7/4 20:04, Ayan Kumar Halder wrote:


On 04/07/2023 12:44, Julien Grall wrote:

Hi,

On 04/07/2023 12:14, Ayan Kumar Halder wrote:

On 26/06/2023 04:33, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



This commit wants to introduce a new Kconfig CONFIG_HAS_MMU to guard
MMU-related codes, to tell two different memory management 
architecture:

VMAS and PMSA.

In a VMSA system, a Memory Management Unit (MMU) provides fine-grained
control of a memory system through a set of virtual to physical address
mappings and associated memory properties held in memory-mapped tables
known as translation tables.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new patch
---
  xen/arch/arm/Kconfig | 8 
  1 file changed, 8 insertions(+)

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index ff17345cdb..fb77392b82 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -60,6 +60,14 @@ config PADDR_BITS

  source "arch/Kconfig"

+config HAS_MMU
+   bool "Memory Management Unit support in a VMSA system"
+   default y


I don't think you can disable HAS_MMU right now. So you want to drop 
the description to prevent a user to select it. This could then be 
combined to


"def_bool y".


+   help
+ In a VMSA system, a Memory Management Unit (MMU) provides 
fine-grained control of
+ a memory system through a set of virtual to physical 
address mappings and associated memory
+ properties held in memory-mapped tables known as 
translation tables.

+
  config ACPI
 bool "ACPI (Advanced Configuration and Power Interface) 
Support (UNSUPPORTED)" if UNSUPPORTED

 depends on ARM_64


I don't think you need this option.


I think we want to introduce a 'choice' where the user can select 
either the MPU or MMU. But not both.


+1 (I like this approach).


+1 from me

I will introduce the choice "ARM Memory Management Architecture" and 
default HAS_MMU







This would be similar to how we select the Physical address space size.

Cheers,





Re: [PATCH v3 05/52] xen/arm64: head: Introduce enable_boot_mmu and enable_runtime_mmu

2023-07-04 Thread Penny Zheng

Hi Julien

On 2023/7/5 05:24, Julien Grall wrote:

Hi Penny,

On 26/06/2023 04:33, Penny Zheng wrote:

From: Wei Chen 

At the moment, on MMU system, enable_mmu() will return to an
address in the 1:1 mapping, then each path is responsible to
switch to virtual runtime mapping. Then remove_identity_mapping()
is called to remove all 1:1 mapping.


The identity mapping is only removed for the boot CPU. You mention it 
correctly below but here it lead to think it may be called on the 
secondary CPU. So I would add 'on the boot CPU'.




Since remove_identity_mapping() is not necessary on Non-MMU system,
and we also avoid creating empty function for Non-MMU system, trying
to keep only one codeflow in arm64/head.S, we move path switch and
remove_identity_mapping() in enable_mmu() on MMU system.

As the remove_identity_mapping should only be called for the boot
CPU only, so we introduce enable_boot_mmu for boot CPU and
enable_runtime_mmu for secondary CPUs in this patch.


NIT: Add () after enable_runtime_mmu to be consistent with the rest of 
commit message. Same for the title.




sure.

Also, I would prefer if we name the functions properly from the start. 
So we don't have to rename them when they are moved in patch 7.




ok. change them to enable_runtime_mm() and enable_boot_mm() at the beginning



Signed-off-by: Wei Chen 
Signed-off-by: Penny Zheng 
---
v3:
- new patch
---
  xen/arch/arm/arm64/head.S | 87 +++
  1 file changed, 70 insertions(+), 17 deletions(-)

diff --git a/xen/arch/arm/arm64/head.S b/xen/arch/arm/arm64/head.S
index 10a07db428..4dfbe0bc6f 100644
--- a/xen/arch/arm/arm64/head.S
+++ b/xen/arch/arm/arm64/head.S
@@ -314,21 +314,12 @@ real_start_efi:
  bl    check_cpu_mode
  bl    cpu_init
-    bl    create_page_tables
-    load_paddr x0, boot_pgtable
-    bl    enable_mmu
  /* We are still in the 1:1 mapping. Jump to the runtime 
Virtual Address. */


This comment is not accurate anymore given that the MMU is off.



I'll remove.


-    ldr   x0, =primary_switched
-    br    x0
+    ldr   lr, =primary_switched
+    b enable_boot_mmu
+
  primary_switched:
-    /*
- * The 1:1 map may clash with other parts of the Xen virtual 
memory

- * layout. As it is not used anymore, remove it completely to
- * avoid having to worry about replacing existing mapping
- * afterwards.
- */
-    bl    remove_identity_mapping
  bl    setup_fixmap
  #ifdef CONFIG_EARLY_PRINTK
  /* Use a virtual address to access the UART. */
@@ -373,13 +364,11 @@ GLOBAL(init_secondary)
  #endif
  bl    check_cpu_mode
  bl    cpu_init
-    load_paddr x0, init_ttbr
-    ldr   x0, [x0]
-    bl    enable_mmu
  /* We are still in the 1:1 mapping. Jump to the runtime 
Virtual Address. */


Note: Remove this too.


-    ldr   x0, =secondary_switched
-    br    x0
+    ldr   lr, =secondary_switched
+    b enable_runtime_mmu
+
  secondary_switched:
  #ifdef CONFIG_EARLY_PRINTK
  /* Use a virtual address to access the UART. */
@@ -694,6 +683,70 @@ enable_mmu:
  ret
  ENDPROC(enable_mmu)
+/*
+ * Turn on the Data Cache and the MMU. The function will return
+ * to the virtual address provided in LR (e.g. the runtime mapping).


The description here is exactly the same as below. However, there is a 
different between the two functions. One is to deal with the secondary 
CPUs whilst the second is for the boot CPUs.




I'll add-on: This function deals with the secondary CPUs.


+ *
+ * Inputs:
+ *   lr : Virtual address to return to.
+ *
+ * Clobbers x0 - x5
+ */
+enable_runtime_mmu:


I find "runtime" confusing in this case. How about 
"enable_secondary_cpu_mm"?




Sure, will do.


+    mov   x5, lr
+
+    load_paddr x0, init_ttbr
+    ldr   x0, [x0]
+
+    bl    enable_mmu
+    mov   lr, x5
+
+    /* return to secondary_switched */
+    ret
+ENDPROC(enable_runtime_mmu)
+
+/*
+ * Turn on the Data Cache and the MMU. The function will return
+ * to the virtual address provided in LR (e.g. the runtime mapping).


Similar remark as for the comment above.


I'll add-on: This function deals with the boot CPUs.




+ *
+ * Inputs:
+ *   lr : Virtual address to return to.
+ *
+ * Clobbers x0 - x5
+ */
+enable_boot_mmu:


Based on my comment above, I would sugesst to call it "enable_boot_cpu_mm"


sure,




+    mov   x5, lr
+
+    bl    create_page_tables
+    load_paddr x0, boot_pgtable
+
+    bl    enable_mmu
+    mov   lr, x5
+
+    /*
+ * The MMU is turned on and we are in the 1:1 mapping. Switch
+ * to the runtime mapping.
+ */
+    ldr   x0, =1f
+    br    x0
+1:
+    /*
+ * The 1:1 map may clash with other parts of the Xen virtual 
memory

+ 

Re: [PATCH v3 34/52] xen/mpu: destroy an existing entry in Xen MPU memory mapping table

2023-07-03 Thread Penny Zheng

Hi Ayan

On 2023/7/1 00:17, Ayan Kumar Halder wrote:


On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



This commit expands xen_mpumap_update/xen_mpumap_update_entry to include
destroying an existing entry.

We define a new helper "control_xen_mpumap_region_from_index" to 
enable/disable
the MPU region based on index. If region is within [0, 31], we could 
quickly
disable the MPU region through PRENR_EL2 which provides direct access 
to the

PRLAR_EL2.EN bits of EL2 MPU regions.

Rignt now, we only support destroying a *WHOLE* MPU memory region,
part-region removing is not supported, as in worst case, it will
leave two fragments behind.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- make pr_get_base()/pr_get_limit() static inline
- need an isb to ensure register write visible before zeroing the entry
---
  xen/arch/arm/include/asm/arm64/mpu.h |  2 +
  xen/arch/arm/include/asm/arm64/sysregs.h |  3 +
  xen/arch/arm/mm.c    |  5 ++
  xen/arch/arm/mpu/mm.c    | 74 
  4 files changed, 84 insertions(+)

diff --git a/xen/arch/arm/include/asm/arm64/mpu.h 
b/xen/arch/arm/include/asm/arm64/mpu.h

index 715ea69884..aee7947223 100644
--- a/xen/arch/arm/include/asm/arm64/mpu.h
+++ b/xen/arch/arm/include/asm/arm64/mpu.h
@@ -25,6 +25,8 @@
  #define REGION_UART_SEL    0x07
  #define MPUIR_REGION_MASK  ((_AC(1, UL) << 8) - 1)

+#define MPU_PRENR_BITS 32


This is common to R52 and R82.

Thus, you can put it in the common file (may be 
xen/arch/arm/include/asm/mpu/mm.h)




Will do.


+
  /* Access permission attributes. */
  /* Read/Write at EL2, No Access at EL1/EL0. */
  #define AP_RW_EL2 0x0
diff --git a/xen/arch/arm/include/asm/arm64/sysregs.h 
b/xen/arch/arm/include/asm/arm64/sysregs.h

index c8a679afdd..96c025053b 100644
--- a/xen/arch/arm/include/asm/arm64/sysregs.h
+++ b/xen/arch/arm/include/asm/arm64/sysregs.h
@@ -509,6 +509,9 @@
  /* MPU Type registers encode */
  #define MPUIR_EL2   S3_4_C0_C0_4

+/* MPU Protection Region Enable Register encode */
+#define PRENR_EL2   S3_4_C6_C1_1
+
  #endif

  /* Access to system registers */
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index 8625066256..247d17cfa1 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -164,7 +164,12 @@ int destroy_xen_mappings(unsigned long s, 
unsigned long e)

  ASSERT(IS_ALIGNED(s, PAGE_SIZE));
  ASSERT(IS_ALIGNED(e, PAGE_SIZE));
  ASSERT(s <= e);
+#ifndef CONFIG_HAS_MPU
  return xen_pt_update(s, INVALID_MFN, (e - s) >> PAGE_SHIFT, 0);
+#else
+    return xen_mpumap_update(virt_to_maddr((void *)s),
+ virt_to_maddr((void *)e), 0);
+#endif
  }


Refer my comment in previous patch.

You can have two implementations of this function 1) 
xen/arch/arm/mmu/mm.c 2) xen/arch/arm/mpu/mm.h




Refer my comment in previous patch.

I prefer #ifdef in destroy_xen_mappings()



  int modify_xen_mappings(unsigned long s, unsigned long e, unsigned 
int flags)

diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index 0a65b58dc4..a40055ae5e 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -425,6 +425,59 @@ static int mpumap_contain_region(pr_t *table, 
uint8_t nr_regions,

  return MPUMAP_REGION_FAILED;
  }

+/* Disable or enable EL2 MPU memory region at index #index */
+static void control_mpu_region_from_index(uint8_t index, bool enable)
+{
+    pr_t region;
+
+    read_protection_region(®ion, index);
+    if ( !region_is_valid(®ion) ^ enable )
+    {
+    printk(XENLOG_WARNING
+   "mpu: MPU memory region[%u] is already %s\n", index,
+   enable ? "enabled" : "disabled");
+    return;
+    }
+
+    /*
+ * ARM64v8R provides PRENR_EL2 to have direct access to the
+ * PRLAR_EL2.EN bits of EL2 MPU regions from 0 to 31.
+ */
+    if ( index < MPU_PRENR_BITS )
+    {
+    uint64_t orig, after;
+
+    orig = READ_SYSREG(PRENR_EL2);
+    if ( enable )
+    /* Set respective bit */
+    after = orig | (1UL << index);
+    else
+    /* Clear respective bit */
+    after = orig & (~(1UL << index));
+    WRITE_SYSREG(after, PRENR_EL2);
+    }
+    else
+    {
+    region.prlar.reg.en = enable ? 1 : 0;
+    write_protection_region((const pr_t*)®ion, index);
+    }
+    /* Ensure the write before zeroing the entry */

dsb(); /* to ensure write completes */

+    isb();
+
+    /* Update according bitfield in xen_mpumap_mask */
+    spin_lock(&xen_mpumap_alloc_lock);
+
+    if ( enable )
+    set_bit(index, xen_mpumap_mask);
+    else
+    {
+    clear_bit(index, xen_mpumap_mask);
+    memset(&xen_mpumap[index], 0, sizeof(p

Re: [PATCH v3 33/52] xen/mpu: initialize frametable in MPU system

2023-07-02 Thread Penny Zheng

Hi Ayan

On 2023/6/30 23:19, Ayan Kumar Halder wrote:

Hi Penny,

On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



Xen is using page as the smallest granularity for memory managment.
And we want to follow the same concept in MPU system.
That is, structure page_info and the frametable which is used for storing
and managing the smallest memory managment unit is also required in 
MPU system.


In MPU system, since we can not use a fixed VA 
address(FRAMETABLE_VIRT_START)

to map frametable like MMU system does and everything is 1:1 mapping, we
instead define a variable "struct page_info *frame_table" as frametable
pointer, and ask boot allocator to allocate appropriate memory for 
frametable.


As frametable is successfully initialized, the convertion between 
machine frame

number/machine address/"virtual address" and page-info structure is
ready too, like mfn_to_page/maddr_to_page/virt_to_page, etc

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- add ASSERT() to confirm the MFN you pass is covered by the frametable.
---
  xen/arch/arm/include/asm/mm.h | 14 ++
  xen/arch/arm/include/asm/mpu/mm.h |  3 +++
  xen/arch/arm/mpu/mm.c | 27 +++
  3 files changed, 44 insertions(+)

diff --git a/xen/arch/arm/include/asm/mm.h 
b/xen/arch/arm/include/asm/mm.h

index daa6329505..66d98b9a29 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -341,6 +341,19 @@ static inline uint64_t gvirt_to_maddr(vaddr_t va, 
paddr_t *pa,

  #define virt_to_mfn(va) __virt_to_mfn(va)
  #define mfn_to_virt(mfn)    __mfn_to_virt(mfn)

+#ifdef CONFIG_HAS_MPU
+/* Convert between virtual address to page-info structure. */
+static inline struct page_info *virt_to_page(const void *v)
+{
+    unsigned long pdx;
+
+    pdx = paddr_to_pdx(virt_to_maddr(v));
+    ASSERT(pdx >= frametable_base_pdx);
+    ASSERT(pdx < frametable_pdx_end);
+
+    return frame_table + pdx - frametable_base_pdx;
+}
This should go in xen/arch/arm/include/asm/mpu/mm.h. Then you don't need 
ifdef

+#else
  /* Convert between Xen-heap virtual addresses and page-info 
structures. */

  static inline struct page_info *virt_to_page(const void *v)
  {
@@ -354,6 +367,7 @@ static inline struct page_info *virt_to_page(const 
void *v)

  pdx += mfn_to_pdx(directmap_mfn_start);
  return frame_table + pdx - frametable_base_pdx;
  }

Consequently, this should be in xen/arch/arm/include/asm/mmu/mm.h


The reason why I don't put virt_to_page()/page_to_virt() in specific 
header is that we are using some helpers, which are defined just

a few lines before, like mfn_to_virt(), etc.
If you are moving mfn_to_virt() to specific header too, that will
result in a lot dulplication.


+#endif

  static inline void *page_to_virt(const struct page_info *pg)
  {
diff --git a/xen/arch/arm/include/asm/mpu/mm.h 
b/xen/arch/arm/include/asm/mpu/mm.h

index e26bd4f975..98f6df65b8 100644
--- a/xen/arch/arm/include/asm/mpu/mm.h
+++ b/xen/arch/arm/include/asm/mpu/mm.h
@@ -2,6 +2,9 @@
  #ifndef __ARCH_ARM_MM_MPU__
  #define __ARCH_ARM_MM_MPU__

+extern struct page_info *frame_table;
If you define frame_table in xen/arch/arm/include/asm/mm.h , then you 
don't need the above declaration.


It is a variable only in MPU. In MMU, it is a fixed value.
"#define frame_table ((struct page_info *)FRAMETABLE_VIRT_START)"


+extern unsigned long frametable_pdx_end;

Also you don't need extern as this is only used by xen/arch/arm/mpu/mm.c.


sure.


+
  extern int xen_mpumap_update(paddr_t base, paddr_t limit, unsigned 
int flags);


You don't need extern here as it should be used only in 
xen/arch/arm/mpu/mm.c


Currently, I see the following in xen/arch/arm/mm.c,

int map_pages_to_xen(unsigned long virt,
  mfn_t mfn,
  unsigned long nr_mfns,
  unsigned int flags)
{
#ifndef CONFIG_HAS_MPU
     return xen_pt_update(virt, mfn, nr_mfns, flags);
#else
     return xen_mpumap_update(mfn_to_maddr(mfn),
  mfn_to_maddr(mfn_add(mfn, nr_mfns)), flags);
#endif
}

int destroy_xen_mappings(unsigned long s, unsigned long e)
{
     ASSERT(IS_ALIGNED(s, PAGE_SIZE));
     ASSERT(IS_ALIGNED(e, PAGE_SIZE));
     ASSERT(s <= e);
#ifndef CONFIG_HAS_MPU
     return xen_pt_update(s, INVALID_MFN, (e - s) >> PAGE_SHIFT, 0);
#else
     return xen_mpumap_update(virt_to_maddr((void *)s),
  virt_to_maddr((void *)e), 0);
#endif
}

int modify_xen_mappings(unsigned long s, unsigned long e, unsigned int 
flags)

{
     ASSERT(IS_ALIGNED(s, PAGE_SIZE));
     ASSERT(IS_ALIGNED(e, PAGE_SIZE));
     ASSERT(s <= e);
#ifndef CONFIG_HAS_MPU
     return xen_pt_update(s, INVALID_MFN, (e - s) >> 

Re: [PATCH v3 31/52] xen/mpu: make early_fdt_map support in MPU systems

2023-07-02 Thread Penny Zheng

Hi,


On 2023/6/30 23:02, Julien Grall wrote:

Hi,

On 30/06/2023 15:42, Ayan Kumar Halder wrote:

Hi Julien,

On 30/06/2023 12:22, Julien Grall wrote:



On 30/06/2023 11:49, Ayan Kumar Halder wrote:


On 30/06/2023 05:07, Penny Zheng wrote:

Hi,

Hi Penny,



On 2023/6/30 01:22, Ayan Kumar Halder wrote:


On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. 
Please use proper judgment and caution when opening attachments, 
clicking links, or responding to this email.



In MPU system, MPU memory region is always mapped PAGE_ALIGN, so 
in order to
not access unexpected memory area, dtb section in xen.lds.S 
should be made

page-aligned too.
We add . = ALIGN(PAGE_SIZE); in the head of dtb section to make 
it happen.


In this commit, we map early FDT with a transient MPU memory 
region, as

it will be relocated into heap and unmapped at the end of boot.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- map the first 2MB. Check the size and then re-map with an extra 
2MB if needed

---
  xen/arch/arm/include/asm/arm64/mpu.h |  3 ++-
  xen/arch/arm/include/asm/page.h  |  5 +
  xen/arch/arm/mm.c    | 26 
--

  xen/arch/arm/mpu/mm.c    |  1 +
  xen/arch/arm/xen.lds.S   |  5 -
  5 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/xen/arch/arm/include/asm/arm64/mpu.h 
b/xen/arch/arm/include/asm/arm64/mpu.h

index a6b07bab02..715ea69884 100644
--- a/xen/arch/arm/include/asm/arm64/mpu.h
+++ b/xen/arch/arm/include/asm/arm64/mpu.h
@@ -72,7 +72,8 @@ typedef union {
  unsigned long ns:1; /* Not-Secure */
  unsigned long res:1;    /* Reserved 0 by hardware */
  unsigned long limit:42; /* Limit Address */
-    unsigned long pad:16;
+    unsigned long pad:15;
+    unsigned long tran:1;   /* Transient region */
  } reg;
  uint64_t bits;
  } prlar_t;
diff --git a/xen/arch/arm/include/asm/page.h 
b/xen/arch/arm/include/asm/page.h

index 85ecd5e4de..a434e2205a 100644
--- a/xen/arch/arm/include/asm/page.h
+++ b/xen/arch/arm/include/asm/page.h
@@ -97,19 +97,24 @@
   * [3:4] Execute Never
   * [5:6] Access Permission
   * [7]   Region Present
+ * [8]   Transient Region, e.g. MPU memory region is temproraily
+ *  mapped for a short time
   */
  #define _PAGE_AI_BIT    0
  #define _PAGE_XN_BIT    3
  #define _PAGE_AP_BIT    5
  #define _PAGE_PRESENT_BIT   7
+#define _PAGE_TRANSIENT_BIT 8
I don't think this is related to MPU. At least when I look at the 
bit representation of PRBAR_EL1/2,


This set of _PAGE_xxx flags aren't compliant with PRBAR_EL1/2 
register map.

It is a flag passed to function map_pages_to_xen() to indicate memory
attributes and permission.


But aren't you writing these flags to PRBAR_EL1/EL2 when you call 
xen_mpumap_update_entry().


In the below snippet of xen_mpumap_update_entry(), IIUC, you are 
writing these flags.


 xen_mpumap[idx].prbar.reg.ap = PAGE_AP_MASK(flags);
 xen_mpumap[idx].prbar.reg.xn = PAGE_XN_MASK(flags);

 write_protection_region((const pr_t*)(&xen_mpumap[idx]), idx);

Please clarify here.

In this case, I don't prefer mixing hardware specific bits with 
software only representation for these reasons :-


1. It makes it confusing and hard to differentiate the hardware 
specific attrbutes from software only.


Penny's approach matches what we are doing in the MMU code. We want 
to have a way for the caller to pass just set of flags and let the 
callee to decide what to do with them.


This may be flags converted for HW fields or just used by the logic.

If you disagree with this approach, then can you propose a different 
way that we can discuss?


Thanks ayan for pointing out that RES0 is not suitable for storing 
software-only flags, agreed.


Then, maybe we should refine the existing "struct pr_t" to store these
sw bits, like:
```
typedef union {
struct {
   uint8_t tran:1; /* Transient region */
   uint8_t p2m_type:4; /* Used to store p2m types.*/
};
uint8_t bits;
} pr_flags;

/* MPU Protection Region */
typedef struct {
prbar_t prbar;
prlar_t prlar;
pr_flags flags; 
} pr_t;
```
The drawback is that, considering the padding, "struct pr_t" expands 
from 16 bytes to 24 bytes.


Wdyt?



In MMU, I could see "struct lpae_pt_t{ .avail }" is used for reference 
count.


Something like this might look better (where the hardware specific 
bits are not reused for sw logic)


struct {

   struct __packed {

  ... /* the existing bits as they are */

           } lpae_pt_t;

   unsigned int ref_count;

} p2m_entry
 > And use "p2m_entry.ref_count" for the reference counting.


So where would you store 'ref_count'? In the existing approach, this is 
stor

Re: [PATCH v3 31/52] xen/mpu: make early_fdt_map support in MPU systems

2023-06-29 Thread Penny Zheng

Hi,


On 2023/6/30 01:22, Ayan Kumar Halder wrote:


On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



In MPU system, MPU memory region is always mapped PAGE_ALIGN, so in 
order to
not access unexpected memory area, dtb section in xen.lds.S should be 
made

page-aligned too.
We add . = ALIGN(PAGE_SIZE); in the head of dtb section to make it 
happen.


In this commit, we map early FDT with a transient MPU memory region, as
it will be relocated into heap and unmapped at the end of boot.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- map the first 2MB. Check the size and then re-map with an extra 2MB 
if needed

---
  xen/arch/arm/include/asm/arm64/mpu.h |  3 ++-
  xen/arch/arm/include/asm/page.h  |  5 +
  xen/arch/arm/mm.c    | 26 --
  xen/arch/arm/mpu/mm.c    |  1 +
  xen/arch/arm/xen.lds.S   |  5 -
  5 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/xen/arch/arm/include/asm/arm64/mpu.h 
b/xen/arch/arm/include/asm/arm64/mpu.h

index a6b07bab02..715ea69884 100644
--- a/xen/arch/arm/include/asm/arm64/mpu.h
+++ b/xen/arch/arm/include/asm/arm64/mpu.h
@@ -72,7 +72,8 @@ typedef union {
  unsigned long ns:1; /* Not-Secure */
  unsigned long res:1;    /* Reserved 0 by hardware */
  unsigned long limit:42; /* Limit Address */
-    unsigned long pad:16;
+    unsigned long pad:15;
+    unsigned long tran:1;   /* Transient region */
  } reg;
  uint64_t bits;
  } prlar_t;
diff --git a/xen/arch/arm/include/asm/page.h 
b/xen/arch/arm/include/asm/page.h

index 85ecd5e4de..a434e2205a 100644
--- a/xen/arch/arm/include/asm/page.h
+++ b/xen/arch/arm/include/asm/page.h
@@ -97,19 +97,24 @@
   * [3:4] Execute Never
   * [5:6] Access Permission
   * [7]   Region Present
+ * [8]   Transient Region, e.g. MPU memory region is temproraily
+ *  mapped for a short time
   */
  #define _PAGE_AI_BIT    0
  #define _PAGE_XN_BIT    3
  #define _PAGE_AP_BIT    5
  #define _PAGE_PRESENT_BIT   7
+#define _PAGE_TRANSIENT_BIT 8
I don't think this is related to MPU. At least when I look at the bit 
representation of PRBAR_EL1/2,


This set of _PAGE_xxx flags aren't compliant with PRBAR_EL1/2 register map.
It is a flag passed to function map_pages_to_xen() to indicate memory
attributes and permission.
This bit _PAGE_TRANSIENT is to tell whether the new adding MPU region is 
a fixed one, or a temporary one.

The MPU region created for early FDT is a temporary one, as it will be
unmapped at the end of boot.



bits [47:6] are for the base address.

If my understanding is correct, then please take it out of this patch 
and put it in a separate MMU related patch.



  #define _PAGE_AI    (7U << _PAGE_AI_BIT)
  #define _PAGE_XN    (2U << _PAGE_XN_BIT)
  #define _PAGE_RO    (2U << _PAGE_AP_BIT)
  #define _PAGE_PRESENT   (1U << _PAGE_PRESENT_BIT)
+#define _PAGE_TRANSIENT (1U << _PAGE_TRANSIENT_BIT)
  #define PAGE_AI_MASK(x) (((x) >> _PAGE_AI_BIT) & 0x7U)
  #define PAGE_XN_MASK(x) (((x) >> _PAGE_XN_BIT) & 0x3U)
  #define PAGE_AP_MASK(x) (((x) >> _PAGE_AP_BIT) & 0x3U)
  #define PAGE_RO_MASK(x) (((x) >> _PAGE_AP_BIT) & 0x2U)
+#define PAGE_TRANSIENT_MASK(x)  (((x) >> _PAGE_TRANSIENT_BIT) & 0x1U)
  #endif /* CONFIG_HAS_MPU */

  /*
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index d35e7e280f..8625066256 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -61,8 +61,17 @@ void flush_page_to_ram(unsigned long mfn, bool 
sync_icache)


  void * __init early_fdt_map(paddr_t fdt_paddr)
  {
+#ifndef CONFIG_HAS_MPU
  /* We are using 2MB superpage for mapping the FDT */
  paddr_t base_paddr = fdt_paddr & SECOND_MASK;
+    unsigned int flags = PAGE_HYPERVISOR_RO | _PAGE_BLOCK;
+    unsigned long base_virt = BOOT_FDT_VIRT_START;
+#else
+    /* MPU region must be PAGE aligned */
+    paddr_t base_paddr = fdt_paddr & PAGE_MASK;
+    unsigned int flags = PAGE_HYPERVISOR_RO | _PAGE_TRANSIENT;
+    unsigned long base_virt = ~0UL;
+#endif
  paddr_t offset;
  void *fdt_virt;
  uint32_t size;
@@ -79,18 +88,24 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
  if ( !fdt_paddr || fdt_paddr % MIN_FDT_ALIGN )
  return NULL;

+#ifndef CONFIG_HAS_MPU
  /* The FDT is mapped using 2MB superpage */
  BUILD_BUG_ON(BOOT_FDT_VIRT_START % SZ_2M);
+#endif

-    rc = map_pages_to_xen(BOOT_FDT_VIRT_START, maddr_to_mfn(base_paddr),
-  SZ_2M >> PAGE_SHIFT,
-  PAGE_HYPERVISOR_RO | _PAGE_BLOCK);
+    rc = map_pages_to_xen(ba

Re: [PATCH v3 27/52] xen/mpu: introduce setup_mm_mappings

2023-06-29 Thread Penny Zheng

Hi,


On 2023/6/29 22:50, Ayan Kumar Halder wrote:


On 29/06/2023 15:29, Julien Grall wrote:

Hi,

On 29/06/2023 15:05, Ayan Kumar Halder wrote:

On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



Function setup_pagetables is responsible for boot-time pagetable setup
in MMU system at C world.
In MPU system, as we have already built up start-of-day Xen MPU memory
region mapping in assembly boot-time, here we only need to do a few
memory management data initializtion, including reading the number of
maximum MPU regions supported by the EL2 MPU, and setting the according
bitfield for regions enabled in assembly boot-time, in bitmap 
xen_mpumap_mask.
This bitmap xen_mpumap_mask is responsible for recording the usage 
of EL2 MPU

memory regions.

In order to keep only one codeflow in arm/setup.c, setup_mm_mappings
, with a more generic name, is introduced to replace setup_pagetables.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- introduce bitmap xen_mpumap_mask for dynamic allocation on MPU 
regions

---
  xen/arch/arm/include/asm/arm64/mpu.h |  1 +
  xen/arch/arm/include/asm/arm64/sysregs.h |  3 +++
  xen/arch/arm/include/asm/mm.h    |  4 ++--
  xen/arch/arm/mmu/mm.c    |  7 +-
  xen/arch/arm/mpu/mm.c    | 30 


  xen/arch/arm/setup.c |  2 +-
  6 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/include/asm/arm64/mpu.h 
b/xen/arch/arm/include/asm/arm64/mpu.h

index 6ec2c10b14..407fec66c9 100644
--- a/xen/arch/arm/include/asm/arm64/mpu.h
+++ b/xen/arch/arm/include/asm/arm64/mpu.h
@@ -19,6 +19,7 @@
   * or it needs adjustment.
   */
  #define REGION_UART_SEL    0x07
+#define MPUIR_REGION_MASK  ((_AC(1, UL) << 8) - 1)


May be this is simpler to read

#define MPUIR_REGION_MASK _AC(0xFF, UL)

Also, you can move it to xen/arch/arm/include/asm/mpu.h as it is 
common between R52 and R82.


I would actually prefer if we use GENMASK(...).

[...]


Sure, I'll switch to use GENMASK(...).




diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index fb6bb721b1..e06a6e5810 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -20,6 +20,7 @@
   */

  #include 
+#include 
  #include 
  #include 

@@ -27,6 +28,35 @@
  pr_t __aligned(PAGE_SIZE) __section(".data.page_aligned")
   xen_mpumap[ARM_MAX_MPU_MEMORY_REGIONS];

+/* Maximum number of supported MPU memory regions by the EL2 MPU. */
+uint8_t __ro_after_init max_xen_mpumap;
+
+/*
+ * Bitmap xen_mpumap_mask is to record the usage of EL2 MPU memory 
regions.

+ * Bit 0 represents MPU memory region 0, bit 1 represents MPU memory
+ * region 1, ..., and so on.
+ * If a MPU memory region gets enabled, set the according bit to 1.
+ */
+static DECLARE_BITMAP(xen_mpumap_mask, ARM_MAX_MPU_MEMORY_REGIONS);
+
+void __init setup_mm_mappings(unsigned long boot_phys_offset)
+{
+    unsigned int nr_regions = REGION_UART_SEL, i = 0;
+
+    /*
+ * MPUIR_EL2.Region[0:7] identifies the number of regions 
supported by

+ * the EL2 MPU.
+ */
+    max_xen_mpumap = (uint8_t)(READ_SYSREG(MPUIR_EL2) & 
MPUIR_REGION_MASK);


NIT:- You may dop "& MPUIR_REGION_MASK " as the other bits are RES0


From the Arm Arm (look for the definition of RES0 in the glossary):

"
To preserve forward compatibility, software:
• Must not rely on the bit reading as 0.
• Must use an SBZP policy to write to the bit.
"

So we should not drop "& MPUIR_REGION_MASK".


Yes, you are correct.

Penny, please disregard my NIT.

- Ayan



Cheers,





Re: [PATCH v3 28/52] xen/mpu: plump virt/maddr conversion in MPU system

2023-06-29 Thread Penny Zheng

Hi,

On 2023/6/29 23:14, Julien Grall wrote:

Hi,

On 29/06/2023 15:44, Ayan Kumar Halder wrote:


On 29/06/2023 15:23, Andrew Cooper wrote:

On 29/06/2023 3:20 pm, Ayan Kumar Halder wrote:

On 26/06/2023 04:34, Penny Zheng wrote:

diff --git a/xen/arch/arm/include/asm/mm.h
b/xen/arch/arm/include/asm/mm.h
index eb520b49e3..ea4847c12b 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -292,6 +301,12 @@ static inline void *maddr_to_virt(paddr_t ma)
    ((ma & ma_top_mask) >> pfn_pdx_hole_shift)));
   }
   #endif
+#else /* CONFIG_HAS_MPU */
+static inline void *maddr_to_virt(paddr_t ma)
+{
+    return (void *)(unsigned long)ma;

Why do you need "(unsigned long)ma" ? Both "unsigned long" and
"paddr_t" are u64.

For when paddr_t really isn't u64.


Sorry, I am missing something

 From 
https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=xen/arch/arm/include/asm/types.h;h=fb6618ef247fe8e3abe472e50b4877e11cc8a96c;hb=refs/heads/staging


In CONFIG_ARM_64

typedef unsigned long u64;

typedef u64 paddr_t;

So, why do we need to typecast "paddr_t" to "unsigned long" as they 
are the same ?

We may decide to restrict paddr_t to 32-bit in the future on Arm64.

Also, when CONFIG_PHYS_ADDR_T_32=n, paddr_t is 64-bit on 32-bit Xen. So 
casting directly to (void *) is not possible. Although, this is not a 
problem here because for the MPU on 32-bit, you would select 
CONFIG_PHYS_ADDR_T_32.


On a side note, I agree with Andrew that we should switch to _p().


Sure. I'll switch to _p().



Cheers,





Re: [PATCH v3 30/52] xen/mpu: populate a new region in Xen MPU mapping table

2023-06-28 Thread Penny Zheng

Hi Ayan

On 2023/6/28 18:08, Ayan Kumar Halder wrote:

(Forgot to cc)

On 28/06/2023 11:05, Ayan Kumar Halder wrote:

Hi Penny,

On 26/06/2023 04:34, Penny Zheng wrote:
CAUTION: This message has originated from an External Source. Please 
use proper judgment and caution when opening attachments, clicking 
links, or responding to this email.



The new helper xen_mpumap_update() is responsible for updating Xen 
MPU memory

mapping table(xen_mpumap), including creating a new entry, updating
or destroying an existing one. It is equivalent to xen_pt_update in MMU.
This commit only talks about populating a new entry in Xen MPU memory 
mapping

table(xen_mpumap). Others will be introduced in the following commits.

When populating a new entry in Xen MPU memory mapping table(xen_mpumap),
firstly, we shall check if requested address range [base, limit) is 
mapped.
If not, we shall find a free slot in xen_mpumap to insert, based on 
bitmap
xen_mpumap_mask, and use standard entry pr_of_xenaddr() to build up 
MPU memory

region structure(pr_t)
In the last, we set memory attribute and permission based on variable 
@flags.


To summarize all region attributes in one variable @flags, layout of the
flags is elaborated as follows:
[0:2] Memory attribute Index
[3:4] Execute Never
[5:6] Access Permission
[7]   Region Present
Also, we provide a set of definitions(REGION_HYPERVISOR_RW, etc) that 
combine

the memory attribute and permission for common combinations.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- implement pr_set_base/pr_set_limit/region_is_valid using static
inline.
- define index uint8_t to limit its size
- stay the same major entry map_pages_to_xen, then go different path
in different context(xen_pt_update in MMU, and xen_mpumap_update in MPU)
---
  xen/arch/arm/include/asm/arm64/mpu.h |  64 +++
  xen/arch/arm/include/asm/mm.h    |   3 +
  xen/arch/arm/include/asm/mpu/mm.h    |  16 ++
  xen/arch/arm/include/asm/page.h  |  22 +++
  xen/arch/arm/mm.c    |  20 +++
  xen/arch/arm/mmu/mm.c    |   9 +-
  xen/arch/arm/mpu/mm.c    | 255 +++
  7 files changed, 381 insertions(+), 8 deletions(-)
  create mode 100644 xen/arch/arm/include/asm/mpu/mm.h

diff --git a/xen/arch/arm/include/asm/arm64/mpu.h 
b/xen/arch/arm/include/asm/arm64/mpu.h

index 407fec66c9..a6b07bab02 100644
--- a/xen/arch/arm/include/asm/arm64/mpu.h
+++ b/xen/arch/arm/include/asm/arm64/mpu.h
@@ -6,6 +6,10 @@
  #ifndef __ARM64_MPU_H__
  #define __ARM64_MPU_H__

+#define MPU_REGION_SHIFT  6


You are using this macro in patch 24/52 and you are defining it here.

Please consider moving the definition to patch 24/52.



Thanks for pointing out. I'll move.


+#define MPU_REGION_ALIGN  (_AC(1, UL) << MPU_REGION_SHIFT)
+#define MPU_REGION_MASK   (~(MPU_REGION_ALIGN - 1))
+
  /*
   * MPUIR_EL2.Region identifies the number of regions supported by 
the EL2 MPU.

   * It is a 8-bit field, so 255 MPU memory regions at most.
@@ -21,8 +25,33 @@
  #define REGION_UART_SEL    0x07
  #define MPUIR_REGION_MASK  ((_AC(1, UL) << 8) - 1)


...

+static inline bool region_is_valid(pr_t *pr)
+{
+    return pr->prlar.reg.en;
+}


A lot of these macros and inlines can be reused on arm32 as well. I 
have split them as follows :-


Refer 
https://github.com/Xilinx/xen/blob/xlnx_rebase_4.17/xen/arch/arm_mpu/include/asm/armv8r/mpu.h for the common definitions.


Refer 
https://github.com/Xilinx/xen/blob/xlnx_rebase_4.17/xen/arch/arm_mpu/include/asm/armv8r/arm64/mpu.h for the 64 bit specific definitions


Refer 
https://github.com/Xilinx/xen/blob/xlnx_rebase_4.17/xen/arch/arm_mpu/include/asm/armv8r/arm32/mpu.h for the 32 bit specific definitions (This I can add later as part of R52 port).


Please consider splitting the definitions so that R52 can reuse the 
common ones.




Sure. I'll try to split.


- Ayan






Re: [PATCH v3 15/52] xen: make VMAP only support in MMU system

2023-06-28 Thread Penny Zheng

Hi Julien

On 2023/6/28 15:59, Julien Grall wrote:

Hi,

On 28/06/2023 06:38, Penny Zheng wrote:

On 2023/6/26 14:00, Jan Beulich wrote:

On 26.06.2023 05:34, Penny Zheng wrote:

--- a/xen/common/vmap.c
+++ b/xen/common/vmap.c
@@ -331,4 +331,11 @@ void vfree(void *va)
  while ( (pg = page_list_remove_head(&pg_list)) != NULL )
  free_domheap_page(pg);
  }
+
+void iounmap(void __iomem *va)
+{
+    unsigned long addr = (unsigned long)(void __force *)va;
+
+    vunmap((void *)(addr & PAGE_MASK));
+}


Why does this move here?


ioremap/iounmap is using vmap, at least in ARM. So for this more
generic interface, I was intending to implement it on MPU system.
In commit "[PATCH v3 19/52] xen/arm: switch to use ioremap_xxx in 
common file", I'm trying to replace all direct vmap interface with 
ioremap_xxx in common files.


While the implementation of ioremap() is based on vmap(), the intended 
usage is not the same. ioremap() is for MMIO regions while vmap() is for 
RAM.


So I don't think this is correct to replace vmap() with ioremap().



Sure, understood now.
So then the current usage of ioremap_xxx in xen/arch/arm/kernel.c, like
```
kernel_zimage_load()
...
kernel = ioremap_wc(paddr, len);
...
```
ioremap_wc() is used for remapping and then copying guest kernel image 
to guest memory. Since ioremap_xxx is for MMIO regions, maybe we shall 
provide a new pair of interfaces for RAM, like ramremap_xxx, to replace 
the ioremap_xxx here?



Cheers,




Re: [PATCH v3 21/52] xen: introduce CONFIG_HAS_PAGING_MEMPOOL

2023-06-27 Thread Penny Zheng

Hi Jan

On 2023/6/26 15:01, Jan Beulich wrote:

On 26.06.2023 05:34, Penny Zheng wrote:

--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -54,6 +54,9 @@ config HAS_IOPORTS
  config HAS_KEXEC
bool
  
+config HAS_PAGING_MEMPOOL

+   bool
+
  config HAS_PDX
bool
  
--- a/xen/common/domctl.c

+++ b/xen/common/domctl.c
@@ -844,6 +844,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
u_domctl)
  ret = iommu_do_domctl(op, d, u_domctl);
  break;
  
+#ifdef CONFIG_HAS_PAGING_MEMPOOL

  case XEN_DOMCTL_get_paging_mempool_size:
  ret = arch_get_paging_mempool_size(d, &op->u.paging_mempool.size);
  if ( !ret )
@@ -857,6 +858,7 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) 
u_domctl)
  ret = hypercall_create_continuation(
  __HYPERVISOR_domctl, "h", u_domctl);
  break;
+#endif


While I'm not outright opposed to doing it this way, I wonder
whether it wouldn't be better to leave common code untouched by
making arch_get_paging_mempool_size() do what you want done.
That's part of what arch hooks are for, after all.



Sure, I'll try.


Jan




Re: [PATCH v3 15/52] xen: make VMAP only support in MMU system

2023-06-27 Thread Penny Zheng

Hi Jan

On 2023/6/26 14:00, Jan Beulich wrote:

On 26.06.2023 05:34, Penny Zheng wrote:

--- a/xen/arch/x86/Kconfig
+++ b/xen/arch/x86/Kconfig
@@ -27,6 +27,7 @@ config X86
select HAS_PDX
select HAS_SCHED_GRANULARITY
select HAS_UBSAN
+   select HAS_VMAP


With this being unconditional, ...


--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -1750,12 +1750,14 @@ void __init noreturn __start_xen(unsigned long mbi_p)
  end_boot_allocator();
  
  system_state = SYS_STATE_boot;

+#ifdef CONFIG_HAS_VMAP
  /*
   * No calls involving ACPI code should go between the setting of
   * SYS_STATE_boot and vm_init() (or else acpi_os_{,un}map_memory()
   * will break).
   */
  vm_init();
+#endif


... there's no need to make this code less readable by adding #ifdef.
Even for the Arm side I question the #ifdef-ary - it likely would be
better to have an empty stub in the header for that case.



I may misunderstand what you said in last serie and thought #ifdef-ary 
is preferred compared with inline stubs, referring here to recall

'''
Do you really need this and all other inline stubs? Imo the goal ought
to be to have as few of them as possible: The one above won't be
referenced if you further make LIVEPATCH depend on HAS_VMAP (which I
think you need to do anyway), and the only other call to the function
is visible in context above (i.e. won't be used either when !HAS_VMAP).
In other cases merely having a declaration (but no definition) may be
sufficient, as the compiler may be able to eliminate calls.
'''
So maybe the preferring order is "declaration > empty inline stubs > 
#ifdef-ary" ? As having a declaration is not enough for vm_init()(when

!HAS_VMAP), we provide static inline empty stub here.


--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -15,6 +15,7 @@ config CORE_PARKING
  config GRANT_TABLE
bool "Grant table support" if EXPERT
default y
+   depends on HAS_VMAP


Looking back at the commit which added use of vmap.h there, I can't
seem to be bale to spot why it did. Where's the dependency there?


vzalloc() is used in grant_table_init() in xen/common/grantable.c:2023


And even if there is one, I think you don't want to unconditionally
turn off a core, guest-visible feature. Instead you would want to
identify a way to continue to support the feature in perhaps
slightly less efficient a way.



We have discussed in MPU design, normally, xen guest in MPU system
will be a linux guest with no pv(with CONFIG_XEN=n), so advanced 
features like grant table is in no use there.



--- a/xen/common/vmap.c
+++ b/xen/common/vmap.c
@@ -331,4 +331,11 @@ void vfree(void *va)
  while ( (pg = page_list_remove_head(&pg_list)) != NULL )
  free_domheap_page(pg);
  }
+
+void iounmap(void __iomem *va)
+{
+unsigned long addr = (unsigned long)(void __force *)va;
+
+vunmap((void *)(addr & PAGE_MASK));
+}


Why does this move here?


ioremap/iounmap is using vmap, at least in ARM. So for this more
generic interface, I was intending to implement it on MPU system.
In commit "[PATCH v3 19/52] xen/arm: switch to use ioremap_xxx in common 
file", I'm trying to replace all direct vmap interface with ioremap_xxx 
in common files.
Then I, in commit "[PATCH v3 36/52] xen/mpu: implememt ioremap_xxx in 
MPU", will implement MPU version of ioremap_xxx.





--- a/xen/include/xen/vmap.h
+++ b/xen/include/xen/vmap.h
@@ -1,4 +1,4 @@
-#if !defined(__XEN_VMAP_H__) && defined(VMAP_VIRT_START)
+#if !defined(__XEN_VMAP_H__) && (defined(VMAP_VIRT_START) || 
!defined(CONFIG_HAS_VMAP))
  #define __XEN_VMAP_H__
  
  #include 

@@ -25,17 +25,14 @@ void vfree(void *va);
  
  void __iomem *ioremap(paddr_t, size_t);
  
-static inline void iounmap(void __iomem *va)

-{
-unsigned long addr = (unsigned long)(void __force *)va;
-
-vunmap((void *)(addr & PAGE_MASK));
-}
+void iounmap(void __iomem *va);
  
  void *arch_vmap_virt_end(void);

  static inline void vm_init(void)
  {
+#if defined(VMAP_VIRT_START)
  vm_init_type(VMAP_DEFAULT, (void *)VMAP_VIRT_START, arch_vmap_virt_end());
+#endif
  }


Why the (seemingly unrelated) #ifdef-ary here? You've eliminated
the problematic caller already. Didn't you mean to add wider scope
#ifdef CONFIG_HAS_VMAP to this header?



plz correct me if I'm wrong, in MPU system with !HAS_VMAP, if we don't
#ifdef-ary here, we will have the following compilation error, I guess
it's because that vm_init() is a static inline stub:
```
./include/xen/vmap.h: In function ‘vm_init’:
./include/xen/vmap.h:33:40: error: ‘VMAP_VIRT_START’ undeclared (first 
use in this function); did you mean ‘XEN_VIRT_START’?
   33 | vm_init_type(VMAP_DEFAULT, (void *)VMAP_VIRT_START, 
arch_vmap_virt_end());

  |^~~
  |XEN_VIRT_START
```


Jan





[PATCH v3 32/52] xen/mpu: implement MPU version of setup_mm in mpu/setup.c

2023-06-25 Thread Penny Zheng
In MPU system, resource, like Xenheap, must be statically configured to
meet the requirement of static system with expected behavior.
Then, in MPU version of setup_mm, we introduce setup_staticheap_mappings to
map fixed MPU memory region for static Xenheap.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- move the changes to mpu/setup.c
---
 xen/arch/arm/Makefile |  1 +
 xen/arch/arm/include/asm/mpu/mm.h |  1 +
 xen/arch/arm/mpu/mm.c | 27 
 xen/arch/arm/mpu/setup.c  | 70 +++
 4 files changed, 99 insertions(+)
 create mode 100644 xen/arch/arm/mpu/setup.c

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 3bd193ee32..5f6ee817ad 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -42,6 +42,7 @@ obj-y += mmu/setup.o
 obj-y += mmu/p2m.o
 else
 obj-y += mpu/mm.o
+obj-y += mpu/setup.o
 endif
 obj-y += mm.o
 obj-y += monitor.o
diff --git a/xen/arch/arm/include/asm/mpu/mm.h 
b/xen/arch/arm/include/asm/mpu/mm.h
index eec572ecfc..e26bd4f975 100644
--- a/xen/arch/arm/include/asm/mpu/mm.h
+++ b/xen/arch/arm/include/asm/mpu/mm.h
@@ -3,6 +3,7 @@
 #define __ARCH_ARM_MM_MPU__
 
 extern int xen_mpumap_update(paddr_t base, paddr_t limit, unsigned int flags);
+extern void setup_staticheap_mappings(void);
 
 #endif /* __ARCH_ARM_MM_MPU__ */
 
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index f4ce19d36a..7bd5609102 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -22,8 +22,10 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
+#include 
 
 #ifdef NDEBUG
 static inline void __attribute__ ((__format__ (__printf__, 1, 2)))
@@ -486,6 +488,31 @@ int xen_mpumap_update(paddr_t base, paddr_t limit, 
unsigned int flags)
 return rc;
 }
 
+/*
+ * Heap must be statically configured in Device Tree through
+ * "xen,static-heap" in MPU system.
+ */
+void __init setup_staticheap_mappings(void)
+{
+unsigned int bank = 0;
+
+for ( ; bank < bootinfo.reserved_mem.nr_banks; bank++ )
+{
+if ( bootinfo.reserved_mem.bank[bank].type == MEMBANK_STATIC_HEAP )
+{
+paddr_t bank_start = round_pgup(
+ bootinfo.reserved_mem.bank[bank].start);
+paddr_t bank_size = round_pgdown(
+bootinfo.reserved_mem.bank[bank].size);
+paddr_t bank_end = bank_start + bank_size;
+
+/* Map static heap with fixed MPU memory region */
+if ( xen_mpumap_update(bank_start, bank_end, PAGE_HYPERVISOR) )
+panic("mpu: failed to map static heap\n");
+}
+}
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/mpu/setup.c b/xen/arch/arm/mpu/setup.c
new file mode 100644
index 00..31f412957c
--- /dev/null
+++ b/xen/arch/arm/mpu/setup.c
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * xen/arch/arm/mpu/setup.c
+ *
+ * Early bringup code for an Armv8-R with virt extensions.
+ *
+ * Copyright (C) 2023 Arm Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+void __init setup_mm(void)
+{
+paddr_t ram_start = ~0, ram_end = 0, ram_size = 0;
+unsigned int bank;
+
+if ( !bootinfo.mem.nr_banks )
+panic("No memory bank\n");
+
+init_pdx();
+
+populate_boot_allocator();
+
+total_pages = 0;
+for ( bank = 0 ; bank < bootinfo.mem.nr_banks; bank++ )
+{
+paddr_t bank_start = round_pgup(bootinfo.mem.bank[bank].start);
+paddr_t bank_size = bootinfo.mem.bank[bank].size;
+paddr_t bank_end = round_pgdown(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_staticheap_mappings();
+
+total_pages += ram_size >> PAGE_SHIFT;
+max_page = PFN_DOWN(ram_end);
+
+setup_frametable_mappings(ram_start, ram_end);
+
+init_staticmem_pages();
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.25.1




[PATCH v3 24/52] xen/mpu: build up start-of-day Xen MPU memory region map

2023-06-25 Thread Penny Zheng
The start-of-day Xen MPU memory region layout shall be like
as follows:

xen_mpumap[0] : Xen text
xen_mpumap[1] : Xen read-only data
xen_mpumap[2] : Xen read-only after init data
xen_mpumap[3] : Xen read-write data
xen_mpumap[4] : Xen BSS
xen_mpumap[5] : Xen init text
xen_mpumap[6] : Xen init data

The layout shall be compliant with what we describe in xen.lds.S,
or the codes need adjustment.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- cache maintanence for safety when modifying MPU memory mapping table
- Hardcode index for all data/text sections
- To make sure that alternative instructions are included, use "_einitext"
as the start of the "Init data" section.
---
 xen/arch/arm/Makefile|   2 +
 xen/arch/arm/arm64/Makefile  |   2 +
 xen/arch/arm/arm64/mpu/head.S| 178 +++
 xen/arch/arm/include/asm/arm64/mpu.h |  59 
 xen/arch/arm/include/asm/arm64/sysregs.h |  14 ++
 xen/arch/arm/mpu/mm.c|  37 +
 6 files changed, 292 insertions(+)
 create mode 100644 xen/arch/arm/arm64/mpu/head.S
 create mode 100644 xen/arch/arm/include/asm/arm64/mpu.h
 create mode 100644 xen/arch/arm/mpu/mm.c

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index a83a535cd7..3bd193ee32 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -40,6 +40,8 @@ ifeq ($(CONFIG_HAS_MMU), y)
 obj-y += mmu/mm.o
 obj-y += mmu/setup.o
 obj-y += mmu/p2m.o
+else
+obj-y += mpu/mm.o
 endif
 obj-y += mm.o
 obj-y += monitor.o
diff --git a/xen/arch/arm/arm64/Makefile b/xen/arch/arm/arm64/Makefile
index 55895ecb53..2641fb13ba 100644
--- a/xen/arch/arm/arm64/Makefile
+++ b/xen/arch/arm/arm64/Makefile
@@ -11,6 +11,8 @@ obj-y += head.o
 ifeq ($(CONFIG_HAS_MMU),y)
 obj-y += mmu/head.o
 obj-y += mmu/mm.o
+else
+obj-y += mpu/head.o
 endif
 obj-y += insn.o
 obj-$(CONFIG_LIVEPATCH) += livepatch.o
diff --git a/xen/arch/arm/arm64/mpu/head.S b/xen/arch/arm/arm64/mpu/head.S
new file mode 100644
index 00..93a7a75029
--- /dev/null
+++ b/xen/arch/arm/arm64/mpu/head.S
@@ -0,0 +1,178 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Start-of-day code for an Armv8-R AArch64 MPU system.
+ *
+ * Copyright (C) 2023 Arm Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include 
+#include 
+
+/*
+ * One entry in Xen MPU memory region mapping table(xen_mpumap) is a structure
+ * of pr_t, which is 16-bytes size, so the entry offset is the order of 4.
+ */
+#define MPU_ENTRY_SHIFT 0x4
+
+#define REGION_TEXT_PRBAR   0x38/* SH=11 AP=10 XN=00 */
+#define REGION_RO_PRBAR 0x3A/* SH=11 AP=10 XN=10 */
+#define REGION_DATA_PRBAR   0x32/* SH=11 AP=00 XN=10 */
+
+#define REGION_NORMAL_PRLAR 0x0f/* NS=0 ATTR=111 EN=1 */
+
+/*
+ * Macro to round up the section address to be PAGE_SIZE aligned
+ * Each section(e.g. .text, .data, etc) in xen.lds.S is page-aligned,
+ * which is usually guarded with ". = ALIGN(PAGE_SIZE)" in the head,
+ * or in the end
+ */
+.macro roundup_section, xb
+add   \xb, \xb, #(PAGE_SIZE-1)
+and   \xb, \xb, #PAGE_MASK
+.endm
+
+/*
+ * Macro to prepare and configure a particular EL2 MPU memory region with
+ * base address as \base and limit address as \limit.
+ * We will also create an according MPU memory region entry, which
+ * is a structure of pr_t, in Xen EL2 mpu memory region mapping table
+ * xen_mpumap.
+ *
+ * Inputs:
+ * base:reg storing base address (should be page-aligned)
+ * limit:   reg storing limit address
+ * sel: region selector
+ * prbar:   store computed PRBAR_EL2 value
+ * prlar:   store computed PRLAR_EL2 value
+ * attr_prbar:  PRBAR_EL2-related memory attributes. If not specified it will 
be REGION_DATA_PRBAR
+ * attr_prlar:  PRLAR_EL2-related memory attributes. If not specified it will 
be REGION_NORMAL_PRLAR
+ *
+ * Clobber \tmp1, \tmp2
+ *
+ */
+.macro prepare_xen_region, sel, base, limit, prbar, prlar, tmp1, tmp2, 
attr_prbar=REGION_DATA_PRBAR, attr_prlar=REGION_NORMAL_PRLAR
+/* Prepare value for PRBAR_EL2 reg and preserve it in \prbar.*/
+and   \base, \base, #MPU_REGION_MASK
+mov   \prbar, #\attr_prbar
+orr   \prbar, \prbar, \base
+
+/* Prepare value for PRLAR_EL2 reg and preserve it in \prlar.*/
+/* Round up limit address to be PAGE_SIZE aligned */
+roundup_section \limit
+/* Limit address shou

[PATCH v3 38/52] xen/mpu: map domain page in MPU system

2023-06-25 Thread Penny Zheng
In MPU system, we implement map_domain_page()/unmap_domain_page()
through mapping the domain page with a transient MPU region on demand.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new patch
---
 xen/arch/arm/Makefile |  4 ++
 xen/arch/arm/include/asm/mpu/mm.h |  1 +
 xen/arch/arm/mpu/domain_page.c| 68 +++
 xen/arch/arm/mpu/mm.c | 17 
 4 files changed, 90 insertions(+)
 create mode 100644 xen/arch/arm/mpu/domain_page.c

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 5f6ee817ad..feb49640a0 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -17,7 +17,11 @@ obj-y += device.o
 obj-$(CONFIG_IOREQ_SERVER) += dm.o
 obj-y += domain.o
 obj-y += domain_build.init.o
+ifneq ($(CONFIG_HAS_MPU),y)
 obj-$(CONFIG_ARCH_MAP_DOMAIN_PAGE) += domain_page.o
+else
+obj-$(CONFIG_ARCH_MAP_DOMAIN_PAGE) += mpu/domain_page.o
+endif
 obj-y += domctl.o
 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
 obj-y += efi/
diff --git a/xen/arch/arm/include/asm/mpu/mm.h 
b/xen/arch/arm/include/asm/mpu/mm.h
index 452fe20c5f..a83519ad13 100644
--- a/xen/arch/arm/include/asm/mpu/mm.h
+++ b/xen/arch/arm/include/asm/mpu/mm.h
@@ -10,6 +10,7 @@ extern void setup_staticheap_mappings(void);
 extern uint8_t is_mm_range_mapped(paddr_t pa, paddr_t len);
 extern void *map_mm_range(paddr_t pa, size_t len, unsigned int attributes);
 extern void unmap_mm_range(paddr_t pa);
+extern bool is_mm_range_mapped_transient(paddr_t pa, paddr_t len);
 
 #endif /* __ARCH_ARM_MM_MPU__ */
 
diff --git a/xen/arch/arm/mpu/domain_page.c b/xen/arch/arm/mpu/domain_page.c
new file mode 100644
index 00..da408bb9e0
--- /dev/null
+++ b/xen/arch/arm/mpu/domain_page.c
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include 
+#include 
+
+/* Override macros from asm/mm.h to make them work with mfn_t */
+#undef mfn_to_virt
+#define mfn_to_virt(mfn) __mfn_to_virt(mfn_x(mfn))
+
+void *map_domain_page_global(mfn_t mfn)
+{
+/* TODO: map shared domain page globally */
+printk(XENLOG_ERR
+   "mpu: mapping shared domain page not SUPPORTED right now!\n");
+return NULL;
+}
+
+void unmap_domain_page_global(const void *va)
+{
+/* TODO: map shared domain page globally */
+printk(XENLOG_ERR
+   "mpu: mapping shared domain page not SUPPORTED right now!\n");
+return;
+}
+
+/* Map a page of domain memory */
+void *map_domain_page(mfn_t mfn)
+{
+uint8_t idx;
+paddr_t pa = mfn_to_maddr(mfn);
+
+idx = is_mm_range_mapped(pa, PAGE_SIZE);
+if ( idx != INVALID_REGION_IDX )
+/* Already mapped */
+return mfn_to_virt(mfn);
+else
+/*
+ * Map it temporarily with a transient MPU region.
+ * And it is caller's responsibity to unmap it
+ * through unmap_domain_page.
+ */
+return map_mm_range(pa, PAGE_SIZE, PAGE_HYPERVISOR_RW);
+}
+
+/* Release a mapping taken with map_domain_page() */
+void unmap_domain_page(const void *va)
+{
+paddr_t pa = (paddr_t)(unsigned long)(va);
+
+/* Only unmap transient page */
+if ( is_mm_range_mapped_transient(pa, PAGE_SIZE) )
+unmap_mm_range(pa);
+}
+
+mfn_t domain_page_map_to_mfn(const void *ptr)
+{
+printk(XENLOG_ERR
+   "mpu: domain_page_map_to_mfn() not SUPPORTED right now!\n");
+return INVALID_MFN;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index 21276d6de9..b2419f0603 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -809,6 +809,23 @@ void iounmap(void __iomem *va)
 unmap_mm_range(virt_to_maddr(va));
 }
 
+bool is_mm_range_mapped_transient(paddr_t pa, paddr_t len)
+{
+uint8_t idx;
+
+idx = is_mm_range_mapped(pa, len);
+if ( idx != INVALID_REGION_IDX )
+{
+pr_t *region;
+
+region = &xen_mpumap[idx];
+if ( region_is_transient(region) )
+return true;
+}
+
+return false;
+}
+
 /*
  * Local variables:
  * mode: C
-- 
2.25.1




[PATCH v3 49/52] xen/mpu: enable device passthrough in MPU system

2023-06-25 Thread Penny Zheng
In order to enable device passthrough in MPU system, we only need to
provide p2m_mmio_direct_dev permission set up.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
 xen/arch/arm/mpu/p2m.c | 11 ++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/mpu/p2m.c b/xen/arch/arm/mpu/p2m.c
index e21b76813d..a68a06105f 100644
--- a/xen/arch/arm/mpu/p2m.c
+++ b/xen/arch/arm/mpu/p2m.c
@@ -185,11 +185,15 @@ static void p2m_set_permission(pr_t *region, p2m_type_t t)
 region->prbar.reg.ap = AP_RO_ALL;
 break;
 
+case p2m_mmio_direct_dev:
+region->prbar.reg.xn = XN_P2M_ENABLED;
+region->prbar.reg.ap = AP_RW_ALL;
+break;
+
 case p2m_max_real_type:
 BUG();
 break;
 
-case p2m_mmio_direct_dev:
 case p2m_mmio_direct_nc:
 case p2m_mmio_direct_c:
 case p2m_iommu_map_ro:
@@ -233,6 +237,11 @@ static inline pr_t region_to_p2m_entry(mfn_t smfn, 
unsigned long nr_mfn,
 prlar.reg.ai = MT_NORMAL;
 break;
 
+case p2m_mmio_direct_dev:
+prbar.reg.sh = LPAE_SH_OUTER;
+prlar.reg.ai = MT_DEVICE_nGnRE;
+break;
+
 default:
 panic(XENLOG_G_ERR "p2m: UNIMPLEMENTED p2m type in MPU system\n");
 break;
-- 
2.25.1




[PATCH v3 31/52] xen/mpu: make early_fdt_map support in MPU systems

2023-06-25 Thread Penny Zheng
In MPU system, MPU memory region is always mapped PAGE_ALIGN, so in order to
not access unexpected memory area, dtb section in xen.lds.S should be made
page-aligned too.
We add . = ALIGN(PAGE_SIZE); in the head of dtb section to make it happen.

In this commit, we map early FDT with a transient MPU memory region, as
it will be relocated into heap and unmapped at the end of boot.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- map the first 2MB. Check the size and then re-map with an extra 2MB if needed
---
 xen/arch/arm/include/asm/arm64/mpu.h |  3 ++-
 xen/arch/arm/include/asm/page.h  |  5 +
 xen/arch/arm/mm.c| 26 --
 xen/arch/arm/mpu/mm.c|  1 +
 xen/arch/arm/xen.lds.S   |  5 -
 5 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/xen/arch/arm/include/asm/arm64/mpu.h 
b/xen/arch/arm/include/asm/arm64/mpu.h
index a6b07bab02..715ea69884 100644
--- a/xen/arch/arm/include/asm/arm64/mpu.h
+++ b/xen/arch/arm/include/asm/arm64/mpu.h
@@ -72,7 +72,8 @@ typedef union {
 unsigned long ns:1; /* Not-Secure */
 unsigned long res:1;/* Reserved 0 by hardware */
 unsigned long limit:42; /* Limit Address */
-unsigned long pad:16;
+unsigned long pad:15;
+unsigned long tran:1;   /* Transient region */
 } reg;
 uint64_t bits;
 } prlar_t;
diff --git a/xen/arch/arm/include/asm/page.h b/xen/arch/arm/include/asm/page.h
index 85ecd5e4de..a434e2205a 100644
--- a/xen/arch/arm/include/asm/page.h
+++ b/xen/arch/arm/include/asm/page.h
@@ -97,19 +97,24 @@
  * [3:4] Execute Never
  * [5:6] Access Permission
  * [7]   Region Present
+ * [8]   Transient Region, e.g. MPU memory region is temproraily
+ *  mapped for a short time
  */
 #define _PAGE_AI_BIT0
 #define _PAGE_XN_BIT3
 #define _PAGE_AP_BIT5
 #define _PAGE_PRESENT_BIT   7
+#define _PAGE_TRANSIENT_BIT 8
 #define _PAGE_AI(7U << _PAGE_AI_BIT)
 #define _PAGE_XN(2U << _PAGE_XN_BIT)
 #define _PAGE_RO(2U << _PAGE_AP_BIT)
 #define _PAGE_PRESENT   (1U << _PAGE_PRESENT_BIT)
+#define _PAGE_TRANSIENT (1U << _PAGE_TRANSIENT_BIT)
 #define PAGE_AI_MASK(x) (((x) >> _PAGE_AI_BIT) & 0x7U)
 #define PAGE_XN_MASK(x) (((x) >> _PAGE_XN_BIT) & 0x3U)
 #define PAGE_AP_MASK(x) (((x) >> _PAGE_AP_BIT) & 0x3U)
 #define PAGE_RO_MASK(x) (((x) >> _PAGE_AP_BIT) & 0x2U)
+#define PAGE_TRANSIENT_MASK(x)  (((x) >> _PAGE_TRANSIENT_BIT) & 0x1U)
 #endif /* CONFIG_HAS_MPU */
 
 /*
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index d35e7e280f..8625066256 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -61,8 +61,17 @@ void flush_page_to_ram(unsigned long mfn, bool sync_icache)
 
 void * __init early_fdt_map(paddr_t fdt_paddr)
 {
+#ifndef CONFIG_HAS_MPU
 /* We are using 2MB superpage for mapping the FDT */
 paddr_t base_paddr = fdt_paddr & SECOND_MASK;
+unsigned int flags = PAGE_HYPERVISOR_RO | _PAGE_BLOCK;
+unsigned long base_virt = BOOT_FDT_VIRT_START;
+#else
+/* MPU region must be PAGE aligned */
+paddr_t base_paddr = fdt_paddr & PAGE_MASK;
+unsigned int flags = PAGE_HYPERVISOR_RO | _PAGE_TRANSIENT;
+unsigned long base_virt = ~0UL;
+#endif
 paddr_t offset;
 void *fdt_virt;
 uint32_t size;
@@ -79,18 +88,24 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
 if ( !fdt_paddr || fdt_paddr % MIN_FDT_ALIGN )
 return NULL;
 
+#ifndef CONFIG_HAS_MPU
 /* The FDT is mapped using 2MB superpage */
 BUILD_BUG_ON(BOOT_FDT_VIRT_START % SZ_2M);
+#endif
 
-rc = map_pages_to_xen(BOOT_FDT_VIRT_START, maddr_to_mfn(base_paddr),
-  SZ_2M >> PAGE_SHIFT,
-  PAGE_HYPERVISOR_RO | _PAGE_BLOCK);
+rc = map_pages_to_xen(base_virt, maddr_to_mfn(base_paddr),
+  SZ_2M >> PAGE_SHIFT, flags);
 if ( rc )
 panic("Unable to map the device-tree.\n");
 
 
+#ifndef CONFIG_HAS_MPU
 offset = fdt_paddr % SECOND_SIZE;
 fdt_virt = (void *)BOOT_FDT_VIRT_START + offset;
+#else
+offset = fdt_paddr % PAGE_SIZE;
+fdt_virt = (void *)fdt_paddr;
+#endif
 
 if ( fdt_magic(fdt_virt) != FDT_MAGIC )
 return NULL;
@@ -101,10 +116,9 @@ void * __init early_fdt_map(paddr_t fdt_paddr)
 
 if ( (offset + size) > SZ_2M )
 {
-rc = map_pages_to_xen(BOOT_FDT_VIRT_START + SZ_2M,
+rc = map_pages_to_xen(base_virt + SZ_2M,
   maddr_to_mfn(base_paddr + SZ_2M),
-  SZ_2M >> PAGE_SHIFT,
-  PAGE_HYPERVISOR_RO | _PAGE_BLOCK);
+  SZ_2M >> PAGE_SHIFT, flags);
 if ( rc )
 panic("Unable

[PATCH v3 11/52] xen/arm: mmu: fold FIXMAP into MMU system

2023-06-25 Thread Penny Zheng
FIXMAP in MMU system is used to do special-purpose 4K mapping, like
mapping early UART, temporarily mapping source codes for copy and paste
(copy_from_paddr), etc.

As FIXMAP feature is highly dependent on virtual address translation, we
introduce a new Kconfig CONFIG_HAS_FIXMAP to wrap all releated codes, then
we fold it into MMU system.
Since PMAP relies on FIXMAP, so we fold it too into MMU system.

Under !CONFIG_HAS_FIXMAP, we provide empty stubbers for not breaking
compilation.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v1 -> v2
- new patch
---
v3:
- fold CONFIG_HAS_FIXMAP into CONFIG_HAS_MMU
- change CONFIG_HAS_FIXMAP to an Arm-specific Kconfig
---
 xen/arch/arm/Kconfig  |  7 ++-
 xen/arch/arm/include/asm/fixmap.h | 31 ---
 2 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index fb77392b82..22b28b8ba2 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -15,7 +15,6 @@ config ARM
select HAS_DEVICE_TREE
select HAS_PASSTHROUGH
select HAS_PDX
-   select HAS_PMAP
select IOMMU_FORCE_PT_SHARE
 
 config ARCH_DEFCONFIG
@@ -63,11 +62,17 @@ source "arch/Kconfig"
 config HAS_MMU
bool "Memory Management Unit support in a VMSA system"
default y
+   select HAS_PMAP
help
  In a VMSA system, a Memory Management Unit (MMU) provides 
fine-grained control of
  a memory system through a set of virtual to physical address mappings 
and associated memory
  properties held in memory-mapped tables known as translation tables.
 
+config HAS_FIXMAP
+   bool "Provide special-purpose 4K mapping slots in a VMSA"
+   depends on HAS_MMU
+   default y
+
 config ACPI
bool "ACPI (Advanced Configuration and Power Interface) Support 
(UNSUPPORTED)" if UNSUPPORTED
depends on ARM_64
diff --git a/xen/arch/arm/include/asm/fixmap.h 
b/xen/arch/arm/include/asm/fixmap.h
index d0c9a52c8c..1b5b62866b 100644
--- a/xen/arch/arm/include/asm/fixmap.h
+++ b/xen/arch/arm/include/asm/fixmap.h
@@ -4,9 +4,6 @@
 #ifndef __ASM_FIXMAP_H
 #define __ASM_FIXMAP_H
 
-#include 
-#include 
-
 /* Fixmap slots */
 #define FIXMAP_CONSOLE  0  /* The primary UART */
 #define FIXMAP_MISC 1  /* Ephemeral mappings of hardware */
@@ -22,6 +19,11 @@
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_HAS_FIXMAP
+
+#include 
+#include 
+
 /*
  * Direct access to xen_fixmap[] should only happen when {set,
  * clear}_fixmap() is unusable (e.g. where we would end up to
@@ -43,6 +45,29 @@ static inline unsigned int virt_to_fix(vaddr_t vaddr)
 return ((vaddr - FIXADDR_START) >> PAGE_SHIFT);
 }
 
+#else /* !CONFIG_HAS_FIXMAP */
+
+#include 
+#include 
+
+static inline void set_fixmap(unsigned int map, mfn_t mfn,
+  unsigned int attributes)
+{
+ASSERT_UNREACHABLE();
+}
+
+static inline void clear_fixmap(unsigned int map)
+{
+ASSERT_UNREACHABLE();
+}
+
+static inline unsigned int virt_to_fix(vaddr_t vaddr)
+{
+ASSERT_UNREACHABLE();
+return -EINVAL;
+}
+#endif /* !CONFIG_HAS_FIXMAP */
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_FIXMAP_H */
-- 
2.25.1




[PATCH v3 14/52] xen/mmu: move MMU-specific setup_mm to mmu/setup.c

2023-06-25 Thread Penny Zheng
setup_mm is used for Xen to setup memory management subsystem at boot
time, like boot allocator, direct-mapping, xenheap initialization, frametable
and static memory pages.
We could inherit some components seamlessly in later MPU system like
boot allocator, whilst we need to implement some components differently
in MPU, like xenheap, etc. There are some components that is specific to
MMU only, like direct-mapping.

In the commit, we move MMU-specific components into mmu/setup.c, in preparation
of implementing MPU version of setup_mm later in future commit.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- adapt to the introduction of new directories: mmu/
---
 xen/arch/arm/Makefile|   1 +
 xen/arch/arm/include/asm/setup.h |   5 +
 xen/arch/arm/mmu/setup.c | 352 +++
 xen/arch/arm/setup.c | 326 +---
 4 files changed, 362 insertions(+), 322 deletions(-)
 create mode 100644 xen/arch/arm/mmu/setup.c

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index f825d95e29..c1babdba6a 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o
 obj-y += mem_access.o
 ifeq ($(CONFIG_HAS_MMU), y)
 obj-y += mmu/mm.o
+obj-y += mmu/setup.o
 endif
 obj-y += mm.o
 obj-y += monitor.o
diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/setup.h
index f0f64d228c..0922549631 100644
--- a/xen/arch/arm/include/asm/setup.h
+++ b/xen/arch/arm/include/asm/setup.h
@@ -156,6 +156,11 @@ struct bootcmdline 
*boot_cmdline_find_by_kind(bootmodule_kind kind);
 struct bootcmdline * boot_cmdline_find_by_name(const char *name);
 const char *boot_module_kind_as_string(bootmodule_kind kind);
 
+extern void init_pdx(void);
+extern void init_staticmem_pages(void);
+extern void populate_boot_allocator(void);
+extern void setup_mm(void);
+
 extern uint32_t hyp_traps_vector[];
 void init_traps(void);
 
diff --git a/xen/arch/arm/mmu/setup.c b/xen/arch/arm/mmu/setup.c
new file mode 100644
index 00..f4de0cb29d
--- /dev/null
+++ b/xen/arch/arm/mmu/setup.c
@@ -0,0 +1,352 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * xen/arch/arm/mmu/setup.c
+ *
+ * Early bringup code for an ARMv7-A with virt extensions.
+ *
+ * Tim Deegan 
+ * Copyright (c) 2011 Citrix Systems.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#ifdef CONFIG_ARM_32
+static unsigned long opt_xenheap_megabytes __initdata;
+integer_param("xenheap_megabytes", opt_xenheap_megabytes);
+
+/*
+ * Returns the end address of the highest region in the range s..e
+ * with required size and alignment that does not conflict with the
+ * modules from first_mod to nr_modules.
+ *
+ * For non-recursive callers first_mod should normally be 0 (all
+ * modules and Xen itself) or 1 (all modules but not Xen).
+ */
+static paddr_t __init consider_modules(paddr_t s, paddr_t e,
+   uint32_t size, paddr_t align,
+   int first_mod)
+{
+const struct bootmodules *mi = &bootinfo.modules;
+int i;
+int nr;
+
+s = (s+align-1) & ~(align-1);
+e = e & ~(align-1);
+
+if ( s > e ||  e - s < size )
+return 0;
+
+/* First check the boot modules */
+for ( i = first_mod; i < mi->nr_mods; i++ )
+{
+paddr_t mod_s = mi->module[i].start;
+paddr_t mod_e = mod_s + mi->module[i].size;
+
+if ( s < mod_e && mod_s < e )
+{
+mod_e = consider_modules(mod_e, e, size, align, i+1);
+if ( mod_e )
+return mod_e;
+
+return consider_modules(s, mod_s, size, align, i+1);
+}
+}
+
+/* Now check any fdt reserved areas. */
+
+nr = fdt_num_mem_rsv(device_tree_flattened);
+
+for ( ; i < mi->nr_mods + nr; i++ )
+{
+paddr_t mod_s, mod_e;
+
+if ( fdt_get_mem_rsv_paddr(device_tree_flattened,
+   i - mi->nr_mods,
+   &mod_s, &mod_e ) < 0 )
+/* If we can't read it, pretend it doesn't exist... */
+continue;
+
+/* fdt_get_mem_rsv_paddr returns length */
+mod_e += mod_s;
+
+if ( s < mod_e && mod_s < e )
+{
+mod_e = consider_modules(mod_e, e,

[PATCH v3 27/52] xen/mpu: introduce setup_mm_mappings

2023-06-25 Thread Penny Zheng
Function setup_pagetables is responsible for boot-time pagetable setup
in MMU system at C world.
In MPU system, as we have already built up start-of-day Xen MPU memory
region mapping in assembly boot-time, here we only need to do a few
memory management data initializtion, including reading the number of
maximum MPU regions supported by the EL2 MPU, and setting the according
bitfield for regions enabled in assembly boot-time, in bitmap xen_mpumap_mask.
This bitmap xen_mpumap_mask is responsible for recording the usage of EL2 MPU
memory regions.

In order to keep only one codeflow in arm/setup.c, setup_mm_mappings
, with a more generic name, is introduced to replace setup_pagetables.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- introduce bitmap xen_mpumap_mask for dynamic allocation on MPU regions
---
 xen/arch/arm/include/asm/arm64/mpu.h |  1 +
 xen/arch/arm/include/asm/arm64/sysregs.h |  3 +++
 xen/arch/arm/include/asm/mm.h|  4 ++--
 xen/arch/arm/mmu/mm.c|  7 +-
 xen/arch/arm/mpu/mm.c| 30 
 xen/arch/arm/setup.c |  2 +-
 6 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/include/asm/arm64/mpu.h 
b/xen/arch/arm/include/asm/arm64/mpu.h
index 6ec2c10b14..407fec66c9 100644
--- a/xen/arch/arm/include/asm/arm64/mpu.h
+++ b/xen/arch/arm/include/asm/arm64/mpu.h
@@ -19,6 +19,7 @@
  * or it needs adjustment.
  */
 #define REGION_UART_SEL0x07
+#define MPUIR_REGION_MASK  ((_AC(1, UL) << 8) - 1)
 
 #ifndef __ASSEMBLY__
 
diff --git a/xen/arch/arm/include/asm/arm64/sysregs.h 
b/xen/arch/arm/include/asm/arm64/sysregs.h
index c41d805fde..a249a660a8 100644
--- a/xen/arch/arm/include/asm/arm64/sysregs.h
+++ b/xen/arch/arm/include/asm/arm64/sysregs.h
@@ -474,6 +474,9 @@
 /* MPU Protection Region Selection Register encode */
 #define PRSELR_EL2  S3_4_C6_C2_1
 
+/* MPU Type registers encode */
+#define MPUIR_EL2   S3_4_C0_C0_4
+
 #endif
 
 /* Access to system registers */
diff --git a/xen/arch/arm/include/asm/mm.h b/xen/arch/arm/include/asm/mm.h
index 5d890a6a45..eb520b49e3 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -201,8 +201,8 @@ extern unsigned long total_pages;
 
 extern uint64_t init_mm;
 
-/* Boot-time pagetable setup */
-extern void setup_pagetables(unsigned long boot_phys_offset);
+/* Boot-time memory mapping setup */
+extern void setup_mm_mappings(unsigned long boot_phys_offset);
 /* Map FDT in boot pagetable */
 extern void *early_fdt_map(paddr_t fdt_paddr);
 /* Remove early mappings */
diff --git a/xen/arch/arm/mmu/mm.c b/xen/arch/arm/mmu/mm.c
index 43c19fa914..d7d5bf7287 100644
--- a/xen/arch/arm/mmu/mm.c
+++ b/xen/arch/arm/mmu/mm.c
@@ -398,7 +398,7 @@ static void clear_table(void *table)
 
 /* Boot-time pagetable setup.
  * Changes here may need matching changes in head.S */
-void __init setup_pagetables(unsigned long boot_phys_offset)
+static void __init setup_pagetables(unsigned long boot_phys_offset)
 {
 uint64_t ttbr;
 lpae_t pte, *p;
@@ -470,6 +470,11 @@ void __init setup_pagetables(unsigned long 
boot_phys_offset)
 #endif
 }
 
+void setup_mm_mappings(unsigned long boot_phys_offset)
+{
+setup_pagetables(boot_phys_offset);
+}
+
 static void clear_boot_pagetables(void)
 {
 /*
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index fb6bb721b1..e06a6e5810 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -20,6 +20,7 @@
  */
 
 #include 
+#include 
 #include 
 #include 
 
@@ -27,6 +28,35 @@
 pr_t __aligned(PAGE_SIZE) __section(".data.page_aligned")
  xen_mpumap[ARM_MAX_MPU_MEMORY_REGIONS];
 
+/* Maximum number of supported MPU memory regions by the EL2 MPU. */
+uint8_t __ro_after_init max_xen_mpumap;
+
+/*
+ * Bitmap xen_mpumap_mask is to record the usage of EL2 MPU memory regions.
+ * Bit 0 represents MPU memory region 0, bit 1 represents MPU memory
+ * region 1, ..., and so on.
+ * If a MPU memory region gets enabled, set the according bit to 1.
+ */
+static DECLARE_BITMAP(xen_mpumap_mask, ARM_MAX_MPU_MEMORY_REGIONS);
+
+void __init setup_mm_mappings(unsigned long boot_phys_offset)
+{
+unsigned int nr_regions = REGION_UART_SEL, i = 0;
+
+/*
+ * MPUIR_EL2.Region[0:7] identifies the number of regions supported by
+ * the EL2 MPU.
+ */
+max_xen_mpumap = (uint8_t)(READ_SYSREG(MPUIR_EL2) & MPUIR_REGION_MASK);
+
+/* Set the bitfield for regions enabled in assembly boot-time. */
+#ifdef CONFIG_EARLY_PRINTK
+nr_regions = REGION_UART_SEL + 1;
+#endif
+for ( ; i < nr_regions; i++ )
+set_bit(i, xen_mpumap_mask);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 6f8dd98d6b..f42b53d17b 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -781,7 +781,7 @@ void __init start_xen(unsigned long boot_phys_offset,
 /* Initialize traps early al

[PATCH v3 45/52] xen/mpu: insert an new entry into guest physmap in MPU system

2023-06-25 Thread Penny Zheng
Function p2m_set_entry/__p2m_set_entry is responsible for inserting an entry
in the p2m. In MPU system, it includes the following steps:
- checking whether mapping already exists(sgfn -> mfn)
- constituting a new P2M MPU memory region structure(pr_t) through
standard entry region_to_p2m_entry()
- insert the new entry into domain P2M table(p2m->root)

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
 xen/arch/arm/include/asm/arm64/mpu.h |   3 +-
 xen/arch/arm/include/asm/mpu/mm.h|   6 +
 xen/arch/arm/include/asm/p2m.h   |   3 +
 xen/arch/arm/mpu/mm.c|   4 +-
 xen/arch/arm/mpu/p2m.c   | 172 +++
 5 files changed, 185 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/include/asm/arm64/mpu.h 
b/xen/arch/arm/include/asm/arm64/mpu.h
index c5e69f239a..444ca716b8 100644
--- a/xen/arch/arm/include/asm/arm64/mpu.h
+++ b/xen/arch/arm/include/asm/arm64/mpu.h
@@ -61,7 +61,8 @@ typedef union {
 unsigned long ap:2;   /* Acess Permission */
 unsigned long sh:2;   /* Sharebility */
 unsigned long base:42;/* Base Address */
-unsigned long pad:16;
+unsigned long pad:12;
+unsigned long p2m_type:4; /* Ignore by hardware. Used to store p2m 
types.*/
 } reg;
 uint64_t bits;
 } prbar_t;
diff --git a/xen/arch/arm/include/asm/mpu/mm.h 
b/xen/arch/arm/include/asm/mpu/mm.h
index 4df69245c6..0abb0a6c92 100644
--- a/xen/arch/arm/include/asm/mpu/mm.h
+++ b/xen/arch/arm/include/asm/mpu/mm.h
@@ -14,6 +14,12 @@ extern void *map_mm_range(paddr_t pa, size_t len, unsigned 
int attributes);
 extern void unmap_mm_range(paddr_t pa);
 extern bool is_mm_range_mapped_transient(paddr_t pa, paddr_t len);
 extern pr_t *alloc_mpumap(void);
+#define MPUMAP_REGION_FAILED0
+#define MPUMAP_REGION_FOUND 1
+#define MPUMAP_REGION_INCLUSIVE 2
+#define MPUMAP_REGION_OVERLAP   3
+extern int mpumap_contain_region(pr_t *table, uint8_t nr_regions,
+ paddr_t base, paddr_t limit, uint8_t *index);
 
 #endif /* __ARCH_ARM_MM_MPU__ */
 
diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h
index c3598d514e..68837b6df7 100644
--- a/xen/arch/arm/include/asm/p2m.h
+++ b/xen/arch/arm/include/asm/p2m.h
@@ -67,6 +67,9 @@ struct p2m_domain {
 #else
 /* Current Virtualization System Control Register for the p2m */
 uint64_t vsctlr;
+
+/* Number of MPU memory regions in P2M MPU memory mapping table. */
+uint8_t nr_regions;
 #endif
 
 /* Highest guest frame that's ever been mapped in the p2m */
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index de5da96b80..8cdb7d7219 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -378,8 +378,8 @@ out:
  *  MPUMAP_REGION_INCLUSIVE: find an inclusive match in #table
  *  MPUMAP_REGION_OVERLAP: overlap with the existing mapping
  */
-static int mpumap_contain_region(pr_t *table, uint8_t nr_regions,
- paddr_t base, paddr_t limit, uint8_t *index)
+int mpumap_contain_region(pr_t *table, uint8_t nr_regions,
+  paddr_t base, paddr_t limit, uint8_t *index)
 {
 uint8_t i = 0, _index = INVALID_REGION_IDX;
 
diff --git a/xen/arch/arm/mpu/p2m.c b/xen/arch/arm/mpu/p2m.c
index 8f728f8957..4838d5b625 100644
--- a/xen/arch/arm/mpu/p2m.c
+++ b/xen/arch/arm/mpu/p2m.c
@@ -166,6 +166,178 @@ int p2m_init(struct domain *d)
 return rc;
 }
 
+static void p2m_set_permission(pr_t *region, p2m_type_t t)
+{
+switch ( t )
+{
+case p2m_ram_rw:
+region->prbar.reg.xn = XN_DISABLED;
+region->prbar.reg.ap = AP_RW_ALL;
+break;
+
+case p2m_ram_ro:
+region->prbar.reg.xn = XN_DISABLED;
+region->prbar.reg.ap = AP_RO_ALL;
+break;
+
+case p2m_invalid:
+region->prbar.reg.xn = XN_P2M_ENABLED;
+region->prbar.reg.ap = AP_RO_ALL;
+break;
+
+case p2m_max_real_type:
+BUG();
+break;
+
+case p2m_mmio_direct_dev:
+case p2m_mmio_direct_nc:
+case p2m_mmio_direct_c:
+case p2m_iommu_map_ro:
+case p2m_iommu_map_rw:
+case p2m_map_foreign_ro:
+case p2m_map_foreign_rw:
+case p2m_grant_map_ro:
+case p2m_grant_map_rw:
+panic(XENLOG_G_ERR "p2m: UNIMPLEMENTED p2m permission in MPU 
system\n");
+break;
+}
+}
+
+static inline pr_t region_to_p2m_entry(mfn_t smfn, unsigned long nr_mfn,
+   p2m_type_t t)
+{
+prbar_t prbar;
+prlar_t prlar;
+pr_t region;
+
+prbar = (prbar_t) {
+.reg = {
+.p2m_type = t,  /* P2M Type */
+}};
+
+prlar = (prlar_t) {
+.reg = {
+.ns = 0,/* Hyp mode is in secure world */
+.en = 1,/* Region enabled */
+}};
+
+BUILD_BUG_ON(p2m_max_real_type > (1 << 4));
+
+switch ( t )
+{
+case p2m_inv

[PATCH v3 47/52] xen/mpu: support vcpu context switch in MPU system

2023-06-25 Thread Penny Zheng
When vcpu switching into guest mode, in MMU system, we update VTTBR_EL2
with the incoming guest's P2M table, simple and fast.
While in MPU system, we have MPU register PRBAR_EL2/PRLAR_EL2 for
both stage 1 EL2 address translation and stage 2 EL1&EL0 address
translation. That is, MPU memory region mapping table(xen_mpumap) shall be
also updated with P2M regions during context switch.

In p2m_save_state(), we need to manually disable all P2M MPU memory regions
from last-running vcpu, and in p2m_restore_state(), we need to manually
enable incoming guest's P2M MPU memory regions.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
 xen/arch/arm/include/asm/arm64/sysregs.h |  3 ++
 xen/arch/arm/include/asm/page.h  |  4 ++
 xen/arch/arm/mpu/mm.c|  6 ++-
 xen/arch/arm/mpu/p2m.c   | 61 
 4 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/include/asm/arm64/sysregs.h 
b/xen/arch/arm/include/asm/arm64/sysregs.h
index 35d7da411d..aa6c07cd4f 100644
--- a/xen/arch/arm/include/asm/arm64/sysregs.h
+++ b/xen/arch/arm/include/asm/arm64/sysregs.h
@@ -512,6 +512,9 @@
 /* MPU Protection Region Enable Register encode */
 #define PRENR_EL2   S3_4_C6_C1_1
 
+/* Virtualization System Control Register */
+#define VSCTLR_EL2  S3_4_C2_C0_0
+
 /* Virtualization Secure Translation Control Register */
 #define VSTCR_EL2S3_4_C2_C6_2
 #define VSTCR_EL2_RES1_SHIFT 31
diff --git a/xen/arch/arm/include/asm/page.h b/xen/arch/arm/include/asm/page.h
index a434e2205a..e28c3d59c5 100644
--- a/xen/arch/arm/include/asm/page.h
+++ b/xen/arch/arm/include/asm/page.h
@@ -99,22 +99,26 @@
  * [7]   Region Present
  * [8]   Transient Region, e.g. MPU memory region is temproraily
  *  mapped for a short time
+ * [9]   P2M Region for stage 2 translation
  */
 #define _PAGE_AI_BIT0
 #define _PAGE_XN_BIT3
 #define _PAGE_AP_BIT5
 #define _PAGE_PRESENT_BIT   7
 #define _PAGE_TRANSIENT_BIT 8
+#define _PAGE_P2M_BIT   9
 #define _PAGE_AI(7U << _PAGE_AI_BIT)
 #define _PAGE_XN(2U << _PAGE_XN_BIT)
 #define _PAGE_RO(2U << _PAGE_AP_BIT)
 #define _PAGE_PRESENT   (1U << _PAGE_PRESENT_BIT)
 #define _PAGE_TRANSIENT (1U << _PAGE_TRANSIENT_BIT)
+#define _PAGE_P2M   (1U << _PAGE_P2M_BIT)
 #define PAGE_AI_MASK(x) (((x) >> _PAGE_AI_BIT) & 0x7U)
 #define PAGE_XN_MASK(x) (((x) >> _PAGE_XN_BIT) & 0x3U)
 #define PAGE_AP_MASK(x) (((x) >> _PAGE_AP_BIT) & 0x3U)
 #define PAGE_RO_MASK(x) (((x) >> _PAGE_AP_BIT) & 0x2U)
 #define PAGE_TRANSIENT_MASK(x)  (((x) >> _PAGE_TRANSIENT_BIT) & 0x1U)
+#define PAGE_P2M_MASK(x)(((x) >> _PAGE_P2M_BIT) & 0x1U)
 #endif /* CONFIG_HAS_MPU */
 
 /*
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index 8cdb7d7219..c6b287b3aa 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -580,7 +580,11 @@ int xen_mpumap_update(paddr_t base, paddr_t limit, 
unsigned int flags)
 {
 int rc;
 
-if ( flags_has_rwx(flags) )
+/*
+ * Mappings should not be both Writeable and Executable, unless
+ * it is for guest P2M mapping.
+ */
+if ( flags_has_rwx(flags) && !PAGE_P2M_MASK(flags) )
 {
 region_printk("Mappings should not be both Writeable and 
Executable\n");
 return -EINVAL;
diff --git a/xen/arch/arm/mpu/p2m.c b/xen/arch/arm/mpu/p2m.c
index d403479229..e21b76813d 100644
--- a/xen/arch/arm/mpu/p2m.c
+++ b/xen/arch/arm/mpu/p2m.c
@@ -411,6 +411,67 @@ mfn_t p2m_get_entry(struct p2m_domain *p2m, gfn_t gfn,
 return p2m_get_mpu_region(p2m, gfn, 1, t, valid);
 }
 
+static unsigned int build_p2m_memory_region_flags(pr_t *p2m_region)
+{
+return (p2m_region->prlar.reg.ai << _PAGE_AI_BIT |
+p2m_region->prbar.reg.ap << _PAGE_AP_BIT |
+p2m_region->prbar.reg.xn << _PAGE_XN_BIT);
+}
+
+static int p2m_xenmpu_update(struct p2m_domain *p2m, bool online)
+{
+pr_t *p2m_table;
+unsigned int i = 0;
+unsigned int flags = online ? (_PAGE_PRESENT | _PAGE_P2M) : 0;
+
+p2m_table = (pr_t *)page_to_virt(p2m->root);
+if ( !p2m_table )
+return -EINVAL;
+
+for ( ; i < p2m->nr_regions; i++ )
+{
+paddr_t base = pr_get_base(&p2m_table[i]);
+paddr_t limit = pr_get_limit(&p2m_table[i]);
+unsigned int region_flags;
+
+region_flags = build_p2m_memory_region_flags(&p2m_table[i]) | flags;
+if ( xen_mpumap_update(base, limit + 1, region_flags) )
+{
+printk(XENLOG_G_ERR "p2m: unable to update MPU memory mapping with 
P2M region 0x%"PRIpaddr"-0x%"PRIpaddr"\n",
+   base, 

[PATCH v3 17/52] xen/arm: do not give memory back to static heap

2023-06-25 Thread Penny Zheng
If Xenheap is statically configured in Device Tree, its size is
definite. So, we shall not give memory back into static heap, like
we normally do in free_init_memory, etc, once it finishes initialization.

We extract static_heap flag from init data bootinfo, as we also need it
after we destroy init data section. we introduce a new helper
xen_is_using_staticheap to tell whether Xenheap is statically configured in
Device Tree. It is always returning false when !CONFIG_STATIC_MEMORY,
since static heap depends on static memory feature.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
 xen/arch/arm/bootfdt.c   |  2 +-
 xen/arch/arm/include/asm/setup.h |  8 +++-
 xen/arch/arm/kernel.c|  3 ++-
 xen/arch/arm/mm.c|  8 ++--
 xen/arch/arm/mmu/setup.c |  4 ++--
 xen/arch/arm/setup.c | 29 +
 6 files changed, 35 insertions(+), 19 deletions(-)

diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
index 2673ad17a1..c4497e3b31 100644
--- a/xen/arch/arm/bootfdt.c
+++ b/xen/arch/arm/bootfdt.c
@@ -341,7 +341,7 @@ static int __init process_chosen_node(const void *fdt, int 
node,
 if ( rc )
 return rc;
 
-bootinfo.static_heap = true;
+static_heap = true;
 }
 
 printk("Checking for initrd in /chosen\n");
diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/setup.h
index 0922549631..d691f6bf93 100644
--- a/xen/arch/arm/include/asm/setup.h
+++ b/xen/arch/arm/include/asm/setup.h
@@ -104,9 +104,15 @@ struct bootinfo {
 #ifdef CONFIG_ACPI
 struct meminfo acpi;
 #endif
-bool static_heap;
 };
 
+extern bool static_heap;
+#ifdef CONFIG_STATIC_MEMORY
+#define xen_is_using_staticheap() (static_heap)
+#else
+#define xen_is_using_staticheap() (false)
+#endif
+
 struct map_range_data
 {
 struct domain *d;
diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
index 2e64612ab3..d13ef0330b 100644
--- a/xen/arch/arm/kernel.c
+++ b/xen/arch/arm/kernel.c
@@ -246,7 +246,8 @@ static __init int kernel_decompress(struct bootmodule *mod, 
uint32_t offset)
  * Free the original kernel, update the pointers to the
  * decompressed kernel
  */
-fw_unreserved_regions(addr, addr + size, init_domheap_pages, 0);
+if ( !xen_is_using_staticheap() )
+fw_unreserved_regions(addr, addr + size, init_domheap_pages, 0);
 
 return 0;
 }
diff --git a/xen/arch/arm/mm.c b/xen/arch/arm/mm.c
index e665d1f97a..4b174f4d08 100644
--- a/xen/arch/arm/mm.c
+++ b/xen/arch/arm/mm.c
@@ -177,8 +177,12 @@ void free_init_memory(void)
 if ( rc )
 panic("Unable to remove the init section (rc = %d)\n", rc);
 
-init_domheap_pages(pa, pa + len);
-printk("Freed %ldkB init memory.\n", (long)(__init_end-__init_begin)>>10);
+if ( !xen_is_using_staticheap() )
+{
+init_domheap_pages(pa, pa + len);
+printk("Freed %ldkB init memory.\n",
+   (long)(__init_end-__init_begin)>>10);
+}
 }
 
 void arch_dump_shared_mem_info(void)
diff --git a/xen/arch/arm/mmu/setup.c b/xen/arch/arm/mmu/setup.c
index a7590a2443..cf7018b190 100644
--- a/xen/arch/arm/mmu/setup.c
+++ b/xen/arch/arm/mmu/setup.c
@@ -196,7 +196,7 @@ void __init setup_mm(void)
 
 total_pages = ram_size >> PAGE_SHIFT;
 
-if ( bootinfo.static_heap )
+if ( xen_is_using_staticheap() )
 {
 for ( i = 0 ; i < bootinfo.reserved_mem.nr_banks; i++ )
 {
@@ -241,7 +241,7 @@ void __init setup_mm(void)
 
 do
 {
-e = bootinfo.static_heap ?
+e = xen_is_using_staticheap() ?
 fit_xenheap_in_static_heap(pfn_to_paddr(xenheap_pages), MB(32)) :
 consider_modules(ram_start, ram_end,
  pfn_to_paddr(xenheap_pages),
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 34923d9984..6f8dd98d6b 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -59,6 +59,8 @@ bool __read_mostly acpi_disabled;
 
 domid_t __read_mostly max_init_domid;
 
+bool __read_mostly static_heap;
+
 static __used void init_done(void)
 {
 int rc;
@@ -508,22 +510,25 @@ void __init discard_initial_modules(void)
 struct bootmodules *mi = &bootinfo.modules;
 int i;
 
-for ( i = 0; i < mi->nr_mods; i++ )
+if ( !xen_is_using_staticheap() )
 {
-paddr_t s = mi->module[i].start;
-paddr_t e = s + PAGE_ALIGN(mi->module[i].size);
+for ( i = 0; i < mi->nr_mods; i++ )
+{
+paddr_t s = mi->module[i].start;
+paddr_t e = s + PAGE_ALIGN(mi->module[i].size);
 
-if ( mi->module[i].kind == BOOTMOD_XEN )
-continue;
+if ( mi->module[i].kind == BOOTMOD_XEN )
+continue;
 
-if ( !mfn_valid(maddr_to_mfn(s)) ||
- !mfn_valid(maddr_to_mfn(e)) )
-continu

[PATCH v3 29/52] xen/mpu: introduce a pair helper read_protection_region()/write_protection_region()

2023-06-25 Thread Penny Zheng
Each EL2 MPU protection region could be configured using PRBAR_EL2 and
PRLAR_EL2.

This commit introduces a pair helper read_protection_region()/
write_protection_region() to read/write EL2 MPU protection region.

As explained in section G1.3.18 of the reference manual for AArch64v8R,
a set of system register PRBAR_EL2 and PRLAR_EL2 provide access to
the EL2 MPU region which is determined by the value of 'n' and
PRSELR_EL2.REGION as PRSELR_EL2.REGION<7:4>:n(n = 0, 1, 2, ... , 15).
For example to access regions from 16 to 31:
- Set PRSELR_EL2 to 0b1
- Region 16 configuration is accessible through PRBAR0_EL2 and PRLAR0_EL2
- Region 17 configuration is accessible through PRBAR1_EL2 and PRLAR1_EL2
- Region 18 configuration is accessible through PRBAR2_EL2 and PRLAR2_EL2
- ...
- Region 31 configuration is accessible through PRBAR15_EL2 and PRLAR15_EL2

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- use WRITE_SYSREG()/READ_SYSREG() to avoid open-coding
- move the selection part outside of the macro, So it could be outside of the
switch and reduce the code generation.
- introduce two helpers (one for the read operation, the other for the write
operation). This would make the code a bit easier to read.
- error out when the caller pass a number higher than 15
---
 xen/arch/arm/include/asm/arm64/sysregs.h |  32 +
 xen/arch/arm/mpu/mm.c| 173 +++
 2 files changed, 205 insertions(+)

diff --git a/xen/arch/arm/include/asm/arm64/sysregs.h 
b/xen/arch/arm/include/asm/arm64/sysregs.h
index a249a660a8..c8a679afdd 100644
--- a/xen/arch/arm/include/asm/arm64/sysregs.h
+++ b/xen/arch/arm/include/asm/arm64/sysregs.h
@@ -467,9 +467,41 @@
 
 /* EL2 MPU Protection Region Base Address Register encode */
 #define PRBAR_EL2   S3_4_C6_C8_0
+#define PRBAR0_EL2  S3_4_C6_C8_0
+#define PRBAR1_EL2  S3_4_C6_C8_4
+#define PRBAR2_EL2  S3_4_C6_C9_0
+#define PRBAR3_EL2  S3_4_C6_C9_4
+#define PRBAR4_EL2  S3_4_C6_C10_0
+#define PRBAR5_EL2  S3_4_C6_C10_4
+#define PRBAR6_EL2  S3_4_C6_C11_0
+#define PRBAR7_EL2  S3_4_C6_C11_4
+#define PRBAR8_EL2  S3_4_C6_C12_0
+#define PRBAR9_EL2  S3_4_C6_C12_4
+#define PRBAR10_EL2 S3_4_C6_C13_0
+#define PRBAR11_EL2 S3_4_C6_C13_4
+#define PRBAR12_EL2 S3_4_C6_C14_0
+#define PRBAR13_EL2 S3_4_C6_C14_4
+#define PRBAR14_EL2 S3_4_C6_C15_0
+#define PRBAR15_EL2 S3_4_C6_C15_4
 
 /* EL2 MPU Protection Region Limit Address Register encode */
 #define PRLAR_EL2   S3_4_C6_C8_1
+#define PRLAR0_EL2  S3_4_C6_C8_1
+#define PRLAR1_EL2  S3_4_C6_C8_5
+#define PRLAR2_EL2  S3_4_C6_C9_1
+#define PRLAR3_EL2  S3_4_C6_C9_5
+#define PRLAR4_EL2  S3_4_C6_C10_1
+#define PRLAR5_EL2  S3_4_C6_C10_5
+#define PRLAR6_EL2  S3_4_C6_C11_1
+#define PRLAR7_EL2  S3_4_C6_C11_5
+#define PRLAR8_EL2  S3_4_C6_C12_1
+#define PRLAR9_EL2  S3_4_C6_C12_5
+#define PRLAR10_EL2 S3_4_C6_C13_1
+#define PRLAR11_EL2 S3_4_C6_C13_5
+#define PRLAR12_EL2 S3_4_C6_C14_1
+#define PRLAR13_EL2 S3_4_C6_C14_5
+#define PRLAR14_EL2 S3_4_C6_C15_1
+#define PRLAR15_EL2 S3_4_C6_C15_5
 
 /* MPU Protection Region Selection Register encode */
 #define PRSELR_EL2  S3_4_C6_C2_1
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index e06a6e5810..7b1b5d6e27 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -39,6 +39,23 @@ uint8_t __ro_after_init max_xen_mpumap;
  */
 static DECLARE_BITMAP(xen_mpumap_mask, ARM_MAX_MPU_MEMORY_REGIONS);
 
+/* Write a MPU protection region */
+#define WRITE_PROTECTION_REGION(pr, prbar_el2, prlar_el2) ({\
+const pr_t *_pr = pr;   \
+\
+WRITE_SYSREG(_pr->prbar.bits, prbar_el2);   \
+WRITE_SYSREG(_pr->prlar.bits, prlar_el2);   \
+})
+
+/* Read a MPU protection region */
+#define READ_PROTECTION_REGION(prbar_el2, prlar_el2) ({ \
+pr_t _pr;   \
+\
+_pr.prbar.bits = READ_SYSREG(prbar_el2);\
+_pr.prlar.bits = READ_SYSREG(prlar_el2);\
+_pr;\
+})
+
 void __init setup_mm_mappings(unsigned long boot_phys_offset)
 {
 unsigned int nr_regions = REGION_UART_SEL, i = 0;
@@ -57,6 +74,162 @@ void __init setup_mm_mappings(unsigned long 
boot_phys_offset)
 set_bit(i, xen_mpumap_mask);
 }
 
+/*
+ * Armv8-R AArch64 at most supports 255 MPU protection regions.
+ * See section G1.3.18 of the reference manual for Armv8-R AArch64,
+ * PRBAR_EL2 and PRLAR_EL2 provide access to the EL2 MPU region
+ * determined by the value of 'n' and PRSELR_EL2.REGION as
+ * PRSELR_EL2.REGION<7:4>:n(n = 0, 1, 2, ... , 15)
+ * For example to access regions from 16 to 31 (0b1 to 0b1):
+ * - Set PRSELR_EL2 to 0b1
+ * - Region 16 configuration is accessible through PRBAR0_EL2 and PRLAR

[PATCH v3 15/52] xen: make VMAP only support in MMU system

2023-06-25 Thread Penny Zheng
VMAP is widely used in ALTERNATIVE feature, CPUERRATA feature, Grant
Table feature, LIVEPATCH feature etc, to remap a range of memory with new
memory attributes. Since this is highly dependent on virtual address
translation, we choose to fold VMAP in MMU system.

In this patch, we introduce a new Kconfig CONFIG_HAS_VMAP, and make it only
support in MMU system on ARM architecture. And we make features like
ALTERNATIVE, CPUERRATA, LIVEPATCH, Grant Table, etc, now depend on VMAP.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v2:
- new commit
---
v3:
- make LIVEPATCH/ALTERNATIVE/CPUERRATA/Grant Table/LIVEPATCH depend on HAS_VMAP
- function call should be wrapped in context, then we could remove inline stubs
---
 xen/arch/arm/Kconfig   |  3 ++-
 xen/arch/arm/Makefile  |  2 +-
 xen/arch/arm/setup.c   |  7 +++
 xen/arch/arm/smpboot.c |  2 ++
 xen/arch/x86/Kconfig   |  1 +
 xen/arch/x86/setup.c   |  2 ++
 xen/common/Kconfig |  5 +
 xen/common/Makefile|  2 +-
 xen/common/vmap.c  |  7 +++
 xen/include/xen/vmap.h | 11 ---
 10 files changed, 32 insertions(+), 10 deletions(-)

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index 22b28b8ba2..a88500fb50 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -11,7 +11,7 @@ config ARM_64
 
 config ARM
def_bool y
-   select HAS_ALTERNATIVE
+   select HAS_ALTERNATIVE if HAS_VMAP
select HAS_DEVICE_TREE
select HAS_PASSTHROUGH
select HAS_PDX
@@ -63,6 +63,7 @@ config HAS_MMU
bool "Memory Management Unit support in a VMSA system"
default y
select HAS_PMAP
+   select HAS_VMAP
help
  In a VMSA system, a Memory Management Unit (MMU) provides 
fine-grained control of
  a memory system through a set of virtual to physical address mappings 
and associated memory
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index c1babdba6a..d01528cac6 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_HAS_VPCI) += vpci.o
 
 obj-$(CONFIG_HAS_ALTERNATIVE) += alternative.o
 obj-y += bootfdt.init.o
-obj-y += cpuerrata.o
+obj-$(CONFIG_HAS_VMAP) += cpuerrata.o
 obj-y += cpufeature.o
 obj-y += decode.o
 obj-y += device.o
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index 50259552a0..34923d9984 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -812,7 +812,9 @@ void __init start_xen(unsigned long boot_phys_offset,
  */
 system_state = SYS_STATE_boot;
 
+#ifdef CONFIG_HAS_VMAP
 vm_init();
+#endif
 
 if ( acpi_disabled )
 {
@@ -844,11 +846,13 @@ void __init start_xen(unsigned long boot_phys_offset,
 nr_cpu_ids = smp_get_max_cpus();
 printk(XENLOG_INFO "SMP: Allowing %u CPUs\n", nr_cpu_ids);
 
+#ifdef CONFIG_HAS_VMAP
 /*
  * Some errata relies on SMCCC version which is detected by psci_init()
  * (called from smp_init_cpus()).
  */
 check_local_cpu_errata();
+#endif
 
 check_local_cpu_features();
 
@@ -915,12 +919,15 @@ void __init start_xen(unsigned long boot_phys_offset,
 
 do_initcalls();
 
+
+#ifdef CONFIG_HAS_VMAP
 /*
  * It needs to be called after do_initcalls to be able to use
  * stop_machine (tasklets initialized via an initcall).
  */
 apply_alternatives_all();
 enable_errata_workarounds();
+#endif
 enable_cpu_features();
 
 /* Create initial domain 0. */
diff --git a/xen/arch/arm/smpboot.c b/xen/arch/arm/smpboot.c
index 8bcdbea66c..0796e534ec 100644
--- a/xen/arch/arm/smpboot.c
+++ b/xen/arch/arm/smpboot.c
@@ -388,7 +388,9 @@ void start_secondary(void)
 
 local_abort_enable();
 
+#ifdef CONFIG_HAS_VMAP
 check_local_cpu_errata();
+#endif
 check_local_cpu_features();
 
 printk(XENLOG_DEBUG "CPU %u booted.\n", smp_processor_id());
diff --git a/xen/arch/x86/Kconfig b/xen/arch/x86/Kconfig
index 406445a358..033cc2332e 100644
--- a/xen/arch/x86/Kconfig
+++ b/xen/arch/x86/Kconfig
@@ -27,6 +27,7 @@ config X86
select HAS_PDX
select HAS_SCHED_GRANULARITY
select HAS_UBSAN
+   select HAS_VMAP
select HAS_VPCI if HVM
select NEEDS_LIBELF
 
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 74e3915a4d..9f06879225 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -1750,12 +1750,14 @@ void __init noreturn __start_xen(unsigned long mbi_p)
 end_boot_allocator();
 
 system_state = SYS_STATE_boot;
+#ifdef CONFIG_HAS_VMAP
 /*
  * No calls involving ACPI code should go between the setting of
  * SYS_STATE_boot and vm_init() (or else acpi_os_{,un}map_memory()
  * will break).
  */
 vm_init();
+#endif
 
 bsp_stack = cpu_alloc_stack(0);
 if ( !bsp_stack )
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 3d2123a783..2c29e89b75 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -15,6 +15,7 @@ config CORE_PARKING
 config GRANT_TABLE
   

[PATCH v3 35/52] xen/arm: map static memory on demand

2023-06-25 Thread Penny Zheng
In function init_staticmem_pages, we need the access to static memory
for proper initialization.
It is not a problem in MMU system, as Xen map the whole RAM in
setup_mm(). However, with limited MPU memory regions, it is too luxury
to map the whole RAM.
As a result, we follow the rule of "map on demand", to map static memory
temporarily before its initialization, and unmap immediately after its
initialization.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
 xen/arch/arm/include/asm/mm.h |  2 ++
 xen/arch/arm/mmu/mm.c | 10 ++
 xen/arch/arm/mpu/mm.c | 10 ++
 xen/arch/arm/setup.c  | 21 +
 4 files changed, 43 insertions(+)

diff --git a/xen/arch/arm/include/asm/mm.h b/xen/arch/arm/include/asm/mm.h
index 66d98b9a29..cffbf8a595 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -224,6 +224,8 @@ extern void mm_init_secondary_cpu(void);
 extern void setup_frametable_mappings(paddr_t ps, paddr_t pe);
 /* map a physical range in virtual memory */
 void __iomem *ioremap_attr(paddr_t start, size_t len, unsigned int attributes);
+extern int map_staticmem_pages_to_xen(paddr_t start, paddr_t end);
+extern int unmap_staticmem_pages_to_xen(paddr_t start, paddr_t end);
 
 static inline void __iomem *ioremap_nocache(paddr_t start, size_t len)
 {
diff --git a/xen/arch/arm/mmu/mm.c b/xen/arch/arm/mmu/mm.c
index 2f29cb53fe..4196a55c32 100644
--- a/xen/arch/arm/mmu/mm.c
+++ b/xen/arch/arm/mmu/mm.c
@@ -1113,6 +1113,16 @@ int populate_pt_range(unsigned long virt, unsigned long 
nr_mfns)
 return xen_pt_update(virt, INVALID_MFN, nr_mfns, _PAGE_POPULATE);
 }
 
+int __init map_staticmem_pages_to_xen(paddr_t start, paddr_t end)
+{
+return 0;
+}
+
+int __init unmap_staticmem_pages_to_xen(paddr_t start, paddr_t end)
+{
+return 0;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index a40055ae5e..9d5c1da39c 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -614,6 +614,16 @@ void __init setup_frametable_mappings(paddr_t ps, paddr_t 
pe)
frametable_size - (nr_pdxs * sizeof(struct page_info)));
 }
 
+int __init map_staticmem_pages_to_xen(paddr_t start, paddr_t end)
+{
+return xen_mpumap_update(start, end, PAGE_HYPERVISOR | _PAGE_TRANSIENT);
+}
+
+int __init unmap_staticmem_pages_to_xen(paddr_t start, paddr_t end)
+{
+return xen_mpumap_update(start, end, 0);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index f42b53d17b..c21d1db763 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -637,12 +637,33 @@ void __init init_staticmem_pages(void)
 mfn_t bank_start = 
_mfn(PFN_UP(bootinfo.reserved_mem.bank[bank].start));
 unsigned long bank_pages = 
PFN_DOWN(bootinfo.reserved_mem.bank[bank].size);
 mfn_t bank_end = mfn_add(bank_start, bank_pages);
+int res;
 
 if ( mfn_x(bank_end) <= mfn_x(bank_start) )
 return;
 
+/* Map temporarily before initialization */
+res = map_staticmem_pages_to_xen(mfn_to_maddr(bank_start),
+ mfn_to_maddr(bank_end));
+if ( res )
+{
+printk(XENLOG_ERR "Failed to map static memory to Xen: %d\n",
+   res);
+return;
+}
+
 unprepare_staticmem_pages(mfn_to_page(bank_start),
   bank_pages, false);
+
+/* Unmap immediately after initialization */
+res = unmap_staticmem_pages_to_xen(mfn_to_maddr(bank_start),
+   mfn_to_maddr(bank_end));
+if ( res )
+{
+printk(XENLOG_ERR "Failed to unmap static memory to Xen: %d\n",
+   res);
+return;
+}
 }
 }
 #endif
-- 
2.25.1




[PATCH v3 09/52] xen/arm: use PA == VA for EARLY_UART_VIRTUAL_ADDRESS on MPU systems

2023-06-25 Thread Penny Zheng
From: Wei Chen 

There is no VMSA support on MPU systems, so we can not map early
UART to FIXMAP_CONSOLE. In stead, we can use PA == VA for early
UART on MPU systems.

Signed-off-by: Wei Chen 
Signed-off-by: Penny Zheng 
---
v2:
1. New patch
---
v3:
1. fix comment
2. change CONFIG_ARM_V8R to !CONFIG_HAS_MMU
---
 xen/arch/arm/include/asm/early_printk.h | 12 
 1 file changed, 12 insertions(+)

diff --git a/xen/arch/arm/include/asm/early_printk.h 
b/xen/arch/arm/include/asm/early_printk.h
index c5149b2976..ec5bcc343c 100644
--- a/xen/arch/arm/include/asm/early_printk.h
+++ b/xen/arch/arm/include/asm/early_printk.h
@@ -15,10 +15,22 @@
 
 #ifdef CONFIG_EARLY_PRINTK
 
+#ifndef CONFIG_HAS_MMU
+
+/*
+ * For MPU systems, there is no VMSA support in EL2, so we use VA == PA
+ * for EARLY_UART_VIRTUAL_ADDRESS.
+ */
+#define EARLY_UART_VIRTUAL_ADDRESS CONFIG_EARLY_UART_BASE_ADDRESS
+
+#else
+
 /* need to add the uart address offset in page to the fixmap address */
 #define EARLY_UART_VIRTUAL_ADDRESS \
 (FIXMAP_ADDR(FIXMAP_CONSOLE) + (CONFIG_EARLY_UART_BASE_ADDRESS & 
~PAGE_MASK))
 
+#endif /* CONFIG_HAS_MMU */
+
 #endif /* !CONFIG_EARLY_PRINTK */
 
 #endif
-- 
2.25.1




[PATCH v3 43/52] xen/mpu: configure VSTCR_EL2 in MPU system

2023-06-25 Thread Penny Zheng
VSTCR_EL2, Virtualization Secure Translation Control Register,is
the control register for stage 2 of the Secure EL1&0 translation regime.

VSTCR_EL2.SA defines secure stage 2 translation output address space.
To make sure that all stage 2 translations for the Secure PA space
access the Secure PA space, we keep SA bit as 0.
VSTCR_EL2.SC is NS check enable bit.
To make sure that Stage 2 NS configuration is checked against stage 1
NS configuration in EL1&0 translation regime for the given address, and
generates a fault if they are different, we set SC bit 1.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
 xen/arch/arm/include/asm/arm64/sysregs.h |  6 ++
 xen/arch/arm/mpu/p2m.c   | 17 -
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/include/asm/arm64/sysregs.h 
b/xen/arch/arm/include/asm/arm64/sysregs.h
index ab0e6a97d3..35d7da411d 100644
--- a/xen/arch/arm/include/asm/arm64/sysregs.h
+++ b/xen/arch/arm/include/asm/arm64/sysregs.h
@@ -512,6 +512,12 @@
 /* MPU Protection Region Enable Register encode */
 #define PRENR_EL2   S3_4_C6_C1_1
 
+/* Virtualization Secure Translation Control Register */
+#define VSTCR_EL2S3_4_C2_C6_2
+#define VSTCR_EL2_RES1_SHIFT 31
+#define VSTCR_EL2_SA ~(_AC(0x1,UL)<<30)
+#define VSTCR_EL2_SC (_AC(0x1,UL)<<20)
+
 #endif
 
 #ifdef CONFIG_ARM_SECURE_STATE
diff --git a/xen/arch/arm/mpu/p2m.c b/xen/arch/arm/mpu/p2m.c
index 04c44825cb..a7a3912a9a 100644
--- a/xen/arch/arm/mpu/p2m.c
+++ b/xen/arch/arm/mpu/p2m.c
@@ -10,7 +10,7 @@
 
 void __init setup_virt_paging(void)
 {
-uint64_t val = 0;
+uint64_t val = 0, val2 = 0;
 bool p2m_vmsa = true;
 
 /* PA size */
@@ -76,6 +76,21 @@ void __init setup_virt_paging(void)
 
 WRITE_SYSREG(val, VTCR_EL2);
 
+/*
+ * VSTCR_EL2.SA defines secure stage 2 translation output address space.
+ * To make sure that all stage 2 translations for the Secure PA space
+ * access the Secure PA space, we keep SA bit as 0.
+ *
+ * VSTCR_EL2.SC is NS check enable bit.
+ * To make sure that Stage 2 NS configuration is checked against stage 1
+ * NS configuration in EL1&0 translation regime for the given address, and
+ * generates a fault if they are different, we set SC bit 1.
+ */
+val2 = 1 << VSTCR_EL2_RES1_SHIFT;
+val2 &= VSTCR_EL2_SA;
+val2 |= VSTCR_EL2_SC;
+WRITE_SYSREG(val2, VSTCR_EL2);
+
 return;
 
 fault:
-- 
2.25.1




[PATCH v3 16/52] xen/mmu: relocate copy_from_paddr into setup.c

2023-06-25 Thread Penny Zheng
Function copy_from_paddr() is defined in asm/setup.h, so it is better to
be implemented in setup.c.
Current copy_from_paddr() implementation is mmu-specific, so this commit moves
copy_from_paddr() into mmu/setup.c, and it is also benefical for us to
implement MPU version of copy_from_paddr() in later commit.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
 xen/arch/arm/kernel.c| 27 ---
 xen/arch/arm/mmu/setup.c | 27 +++
 2 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
index ca5318515e..2e64612ab3 100644
--- a/xen/arch/arm/kernel.c
+++ b/xen/arch/arm/kernel.c
@@ -41,33 +41,6 @@ struct minimal_dtb_header {
 
 #define DTB_MAGIC 0xd00dfeed
 
-/**
- * copy_from_paddr - copy data from a physical address
- * @dst: destination virtual address
- * @paddr: source physical address
- * @len: length to copy
- */
-void __init copy_from_paddr(void *dst, paddr_t paddr, unsigned long len)
-{
-void *src = (void *)FIXMAP_ADDR(FIXMAP_MISC);
-
-while (len) {
-unsigned long l, s;
-
-s = paddr & (PAGE_SIZE-1);
-l = min(PAGE_SIZE - s, len);
-
-set_fixmap(FIXMAP_MISC, maddr_to_mfn(paddr), PAGE_HYPERVISOR_WC);
-memcpy(dst, src + s, l);
-clean_dcache_va_range(dst, l);
-clear_fixmap(FIXMAP_MISC);
-
-paddr += l;
-dst += l;
-len -= l;
-}
-}
-
 static void __init place_modules(struct kernel_info *info,
  paddr_t kernbase, paddr_t kernend)
 {
diff --git a/xen/arch/arm/mmu/setup.c b/xen/arch/arm/mmu/setup.c
index f4de0cb29d..a7590a2443 100644
--- a/xen/arch/arm/mmu/setup.c
+++ b/xen/arch/arm/mmu/setup.c
@@ -342,6 +342,33 @@ void __init setup_mm(void)
 }
 #endif
 
+/*
+ * copy_from_paddr - copy data from a physical address
+ * @dst: destination virtual address
+ * @paddr: source physical address
+ * @len: length to copy
+ */
+void __init copy_from_paddr(void *dst, paddr_t paddr, unsigned long len)
+{
+void *src = (void *)FIXMAP_ADDR(FIXMAP_MISC);
+
+while (len) {
+unsigned long l, s;
+
+s = paddr & (PAGE_SIZE-1);
+l = min(PAGE_SIZE - s, len);
+
+set_fixmap(FIXMAP_MISC, maddr_to_mfn(paddr), PAGE_HYPERVISOR_WC);
+memcpy(dst, src + s, l);
+clean_dcache_va_range(dst, l);
+clear_fixmap(FIXMAP_MISC);
+
+paddr += l;
+dst += l;
+len -= l;
+}
+}
+
 /*
  * Local variables:
  * mode: C
-- 
2.25.1




[PATCH v3 19/52] xen/arm: switch to use ioremap_xxx in common file

2023-06-25 Thread Penny Zheng
In arm, with the introduction of MPU system, VMAP scheme, taking
advantage of virtual translation, will become a MMU-only feature.
So we want to avoid using direct access to all vmap-related functions,
like __vmap(), in common files, and switch to use more generic eoremap_xxx
instead.
Then later, we also just need to implement MPU version of ioremap_xxx.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
 xen/arch/arm/kernel.c | 12 
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
index d13ef0330b..30f8bc5923 100644
--- a/xen/arch/arm/kernel.c
+++ b/xen/arch/arm/kernel.c
@@ -172,7 +172,6 @@ static __init int kernel_decompress(struct bootmodule *mod, 
uint32_t offset)
 unsigned int kernel_order_out;
 paddr_t output_size;
 struct page_info *pages;
-mfn_t mfn;
 int i;
 paddr_t addr = mod->start;
 paddr_t size = mod->size;
@@ -209,13 +208,18 @@ static __init int kernel_decompress(struct bootmodule 
*mod, uint32_t offset)
 iounmap(input);
 return -ENOMEM;
 }
-mfn = page_to_mfn(pages);
-output = __vmap(&mfn, 1 << kernel_order_out, 1, 1, PAGE_HYPERVISOR, 
VMAP_DEFAULT);
+output = ioremap_cache(page_to_maddr(pages),
+   pfn_to_paddr(1UL << kernel_order_out));
+if ( output == NULL )
+{
+iounmap(output);
+return -EFAULT;
+}
 
 rc = perform_gunzip(output, input, size);
 clean_dcache_va_range(output, output_size);
 iounmap(input);
-vunmap(output);
+iounmap(output);
 
 if ( rc )
 {
-- 
2.25.1




[PATCH v3 28/52] xen/mpu: plump virt/maddr conversion in MPU system

2023-06-25 Thread Penny Zheng
virt_to_maddr and maddr_to_virt are used widely in Xen code. So
even there is no VMSA in MPU system, we keep the interface in MPU to
stay the same code flow.

The MPU version of virt/maddr conversion is simple, and we just return
the input address as the output with type conversion.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- Fix typos
- Move the implementation from mm/mpu.h to mm.h, to share as much as
possible with MMU system.
---
 xen/arch/arm/include/asm/mm.h | 15 +++
 1 file changed, 15 insertions(+)

diff --git a/xen/arch/arm/include/asm/mm.h b/xen/arch/arm/include/asm/mm.h
index eb520b49e3..ea4847c12b 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -267,13 +267,22 @@ static inline void __iomem *ioremap_wc(paddr_t start, 
size_t len)
 /* Page-align address and convert to frame number format */
 #define paddr_to_pfn_aligned(paddr)paddr_to_pfn(PAGE_ALIGN(paddr))
 
+#ifndef CONFIG_HAS_MPU
 static inline paddr_t __virt_to_maddr(vaddr_t va)
 {
 uint64_t par = va_to_par(va);
 return (par & PADDR_MASK & PAGE_MASK) | (va & ~PAGE_MASK);
 }
+#else
+static inline paddr_t __virt_to_maddr(vaddr_t va)
+{
+return (paddr_t)va;
+}
+#endif /* CONFIG_HAS_MPU */
+
 #define virt_to_maddr(va)   __virt_to_maddr((vaddr_t)(va))
 
+#ifndef CONFIG_HAS_MPU
 #ifdef CONFIG_ARM_32
 static inline void *maddr_to_virt(paddr_t ma)
 {
@@ -292,6 +301,12 @@ static inline void *maddr_to_virt(paddr_t ma)
  ((ma & ma_top_mask) >> pfn_pdx_hole_shift)));
 }
 #endif
+#else /* CONFIG_HAS_MPU */
+static inline void *maddr_to_virt(paddr_t ma)
+{
+return (void *)(unsigned long)ma;
+}
+#endif
 
 /*
  * Translate a guest virtual address to a machine address.
-- 
2.25.1




[PATCH v3 50/52] xen/mpu: dump debug message in MPU system

2023-06-25 Thread Penny Zheng
A set of helpers dump_xxx and show_registers are responsible for
dumping memory mapping info and register info when debugging.
In this commit, we implement them all in MPU system too.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new commit
---
 xen/arch/arm/include/asm/mpu/mm.h |  3 +++
 xen/arch/arm/mpu/mm.c | 35 +++
 xen/arch/arm/mpu/p2m.c| 11 ++
 xen/arch/arm/p2m.c|  4 
 xen/arch/arm/traps.c  | 16 ++
 5 files changed, 69 insertions(+)

diff --git a/xen/arch/arm/include/asm/mpu/mm.h 
b/xen/arch/arm/include/asm/mpu/mm.h
index 0abb0a6c92..d3dcf0024a 100644
--- a/xen/arch/arm/include/asm/mpu/mm.h
+++ b/xen/arch/arm/include/asm/mpu/mm.h
@@ -21,6 +21,9 @@ extern pr_t *alloc_mpumap(void);
 extern int mpumap_contain_region(pr_t *table, uint8_t nr_regions,
  paddr_t base, paddr_t limit, uint8_t *index);
 
+/* Print a walk of a MPU memory mapping table */
+void dump_mpu_walk(pr_t *table, uint8_t nr_regions);
+
 #endif /* __ARCH_ARM_MM_MPU__ */
 
 /*
diff --git a/xen/arch/arm/mpu/mm.c b/xen/arch/arm/mpu/mm.c
index c6b287b3aa..ef8a327037 100644
--- a/xen/arch/arm/mpu/mm.c
+++ b/xen/arch/arm/mpu/mm.c
@@ -898,6 +898,41 @@ pr_t *alloc_mpumap(void)
 return map;
 }
 
+void dump_mpu_walk(pr_t *table, uint8_t nr_regions)
+{
+uint8_t i = 0;
+
+for ( ; i < nr_regions; i++ )
+{
+paddr_t base, limit;
+
+if ( region_is_valid(&table[i]) )
+{
+base = pr_get_base(&table[i]);
+limit = pr_get_limit(&table[i]);
+
+printk(XENLOG_INFO
+   "Walking MPU memory mapping table: Region[%u]: 
0x%"PRIpaddr"-0x%"PRIpaddr"\n",
+   i, base, limit);
+}
+}
+}
+
+void dump_hyp_walk(vaddr_t addr)
+{
+uint8_t i = 0;
+pr_t region;
+
+for ( i = 0; i < max_xen_mpumap; i++ )
+{
+read_protection_region(®ion, i);
+if ( region_is_valid(®ion) )
+printk(XENLOG_INFO
+   "Walking hypervisor MPU memory region [%u]: 
0x%"PRIpaddr"-0x%"PRIpaddr"\n",
+   i, pr_get_base(®ion), pr_get_limit(®ion));
+}
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/mpu/p2m.c b/xen/arch/arm/mpu/p2m.c
index a68a06105f..87e350270d 100644
--- a/xen/arch/arm/mpu/p2m.c
+++ b/xen/arch/arm/mpu/p2m.c
@@ -481,6 +481,17 @@ void p2m_restore_state(struct vcpu *n)
 *last_vcpu_ran = n->vcpu_id;
 }
 
+void p2m_dump_info(struct domain *d)
+{
+struct p2m_domain *p2m = p2m_get_hostp2m(d);
+
+p2m_read_lock(p2m);
+printk("p2m mappings for domain %d (vmid %d):\n",
+   d->domain_id, p2m->vmid);
+printk("  Number of P2M Memory Region: %u \n", p2m->nr_regions);
+p2m_read_unlock(p2m);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
index e29b11334e..d3961997d0 100644
--- a/xen/arch/arm/p2m.c
+++ b/xen/arch/arm/p2m.c
@@ -51,8 +51,12 @@ void dump_p2m_lookup(struct domain *d, paddr_t addr)
 printk("P2M @ %p mfn:%#"PRI_mfn"\n",
p2m->root, mfn_x(page_to_mfn(p2m->root)));
 
+#ifndef CONFIG_HAS_MPU
 dump_pt_walk(page_to_maddr(p2m->root), addr,
  P2M_ROOT_LEVEL, P2M_ROOT_PAGES);
+#else
+dump_mpu_walk((pr_t *)page_to_virt(p2m->root), p2m->nr_regions);
+#endif
 }
 
 mfn_t p2m_lookup(struct domain *d, gfn_t gfn, p2m_type_t *t)
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index bffa147c36..0592eee91c 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -710,7 +710,11 @@ struct reg_ctxt {
 #endif
 
 /* Hypervisor-side state */
+#ifdef CONFIG_HAS_MPU
+uint64_t vsctlr_el2;
+#else
 uint64_t vttbr_el2;
+#endif
 };
 
 static const char *mode_string(register_t cpsr)
@@ -908,7 +912,11 @@ static void _show_registers(const struct cpu_user_regs 
*regs,
 #endif
 }
 printk("  VTCR_EL2: %"PRIregister"\n", READ_SYSREG(VTCR_EL2));
+#ifndef CONFIG_HAS_MPU
 printk(" VTTBR_EL2: %016"PRIx64"\n", ctxt->vttbr_el2);
+#else
+printk(" VSCTLR_EL2: %016"PRIx64"\n", ctxt->vsctlr_el2);
+#endif
 printk("\n");
 
 printk(" SCTLR_EL2: %"PRIregister"\n", READ_SYSREG(SCTLR_EL2));
@@ -945,7 +953,11 @@ void show_registers(const struct cpu_user_regs *regs)
 if ( guest_mode(regs) && is_32bit_domain(current->domain) )
 ctxt.ifsr32_el2 = READ_SYSREG(IFSR32_EL2);
 #endif
+#ifndef CONFIG_HAS_MPU
 ctxt.vttbr_el2 = READ_SYSREG64(VTTBR_EL2);
+#else
+ctxt.vsctlr_el2 = READ_SYSREG64(VSCTLR_EL2);
+#endif
 
 _show_registers(regs, &ctxt, guest_mode(regs), current);
 }
@@ -968,7 +980,11 @@ void vcpu_show_registers(const struct vcpu *v)
   

[PATCH v3 23/52] xen/arm: create mpu/layout.h for MPU related address definitions

2023-06-25 Thread Penny Zheng
From: Wei Chen 

As we have done for MMU systems, we instroduce mpu/layout.h for
MPU systems to store their address layout definitions.

To avoid spreading #ifdef everywhere, we keep the same definition
names for MPU systems, like XEN_VIRT_START and HYPERVISOR_VIRT_START,
but the definition contents are MPU specific.

Signed-off-by: Wei Chen 
Signed-off-by: Penny Zheng 
---
v3:
- new commit
---
 xen/arch/arm/include/asm/config.h |  2 ++
 xen/arch/arm/include/asm/mpu/layout.h | 32 +++
 2 files changed, 34 insertions(+)
 create mode 100644 xen/arch/arm/include/asm/mpu/layout.h

diff --git a/xen/arch/arm/include/asm/config.h 
b/xen/arch/arm/include/asm/config.h
index 204b3dec13..bd71cc1373 100644
--- a/xen/arch/arm/include/asm/config.h
+++ b/xen/arch/arm/include/asm/config.h
@@ -73,6 +73,8 @@
 
 #ifndef CONFIG_HAS_MPU
 #include 
+#else
+#include 
 #endif
 
 #define NR_hypercalls 64
diff --git a/xen/arch/arm/include/asm/mpu/layout.h 
b/xen/arch/arm/include/asm/mpu/layout.h
new file mode 100644
index 00..84c55cb2bd
--- /dev/null
+++ b/xen/arch/arm/include/asm/mpu/layout.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __ARM_MPU_LAYOUT_H__
+#define __ARM_MPU_LAYOUT_H__
+
+#define FRAMETABLE_SIZEGB(32)
+#define FRAMETABLE_NR  (FRAMETABLE_SIZE / sizeof(*frame_table))
+
+#define XEN_START_ADDRESS CONFIG_XEN_START_ADDRESS
+
+/*
+ * All MPU platforms need to provide a XEN_START_ADDRESS for linker. This
+ * address indicates where Xen image will be loaded and run from. This
+ * address must be aligned to a PAGE_SIZE.
+ */
+#if (XEN_START_ADDRESS % PAGE_SIZE) != 0
+#error "XEN_START_ADDRESS must be aligned to PAGE_SIZE"
+#endif
+
+#define XEN_VIRT_START _AT(paddr_t, XEN_START_ADDRESS)
+
+#define HYPERVISOR_VIRT_START  XEN_VIRT_START
+
+#endif /* __ARM_MPU_LAYOUT_H__ */
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
-- 
2.25.1




[PATCH v3 20/52] xen/mmu: move MMU specific P2M code to mmu/p2m.c and mmu/p2m.h

2023-06-25 Thread Penny Zheng
Current P2M implementation is designed for MMU system only.
We move the MMU-specific codes into mmu/p2m.c, and only keep generic
codes in p2m.c, like VMID allocator, etc

We also move MMU-specific definitions and declarations to mmu/p2m.h, like
function p2m_tlb_flush_sync, etc

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v2:
- new commit
---
v3:
- remove MPU stubs
- adapt to the introduction of new directories: mmu/
---
 xen/arch/arm/Makefile  |1 +
 xen/arch/arm/include/asm/mmu/p2m.h |   18 +
 xen/arch/arm/include/asm/p2m.h |   30 +-
 xen/arch/arm/mmu/p2m.c | 1612 +
 xen/arch/arm/p2m.c | 1770 ++--
 5 files changed, 1744 insertions(+), 1687 deletions(-)
 create mode 100644 xen/arch/arm/include/asm/mmu/p2m.h
 create mode 100644 xen/arch/arm/mmu/p2m.c

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index d01528cac6..a83a535cd7 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -39,6 +39,7 @@ obj-y += mem_access.o
 ifeq ($(CONFIG_HAS_MMU), y)
 obj-y += mmu/mm.o
 obj-y += mmu/setup.o
+obj-y += mmu/p2m.o
 endif
 obj-y += mm.o
 obj-y += monitor.o
diff --git a/xen/arch/arm/include/asm/mmu/p2m.h 
b/xen/arch/arm/include/asm/mmu/p2m.h
new file mode 100644
index 00..bc108bdc4b
--- /dev/null
+++ b/xen/arch/arm/include/asm/mmu/p2m.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef _XEN_P2M_MMU_H
+#define _XEN_P2M_MMU_H
+
+struct p2m_domain;
+void p2m_force_tlb_flush_sync(struct p2m_domain *p2m);
+void p2m_tlb_flush_sync(struct p2m_domain *p2m);
+
+#endif /* _XEN_P2M_MMU_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h
index 940495d42b..f62d632830 100644
--- a/xen/arch/arm/include/asm/p2m.h
+++ b/xen/arch/arm/include/asm/p2m.h
@@ -19,6 +19,20 @@ extern unsigned int p2m_root_level;
 #define P2M_ROOT_ORDERp2m_root_order
 #define P2M_ROOT_LEVEL p2m_root_level
 
+#define MAX_VMID_8_BIT  (1UL << 8)
+#define MAX_VMID_16_BIT (1UL << 16)
+
+#define INVALID_VMID 0 /* VMID 0 is reserved */
+
+#ifdef CONFIG_ARM_64
+extern unsigned int max_vmid;
+/* VMID is by default 8 bit width on AArch64 */
+#define MAX_VMID   max_vmid
+#else
+/* VMID is always 8 bit width on AArch32 */
+#define MAX_VMIDMAX_VMID_8_BIT
+#endif
+
 struct domain;
 
 extern void memory_type_changed(struct domain *);
@@ -156,6 +170,10 @@ typedef enum {
 #endif
 #include 
 
+#ifdef CONFIG_HAS_MMU
+#include 
+#endif
+
 static inline bool arch_acquire_resource_check(struct domain *d)
 {
 /*
@@ -180,7 +198,11 @@ void p2m_altp2m_check(struct vcpu *v, uint16_t idx)
  */
 void p2m_restrict_ipa_bits(unsigned int ipa_bits);
 
+void p2m_vmid_allocator_init(void);
+int p2m_alloc_vmid(struct domain *d);
+
 /* Second stage paging setup, to be called on all CPUs */
+void setup_virt_paging_one(void *data);
 void setup_virt_paging(void);
 
 /* Init the datastructures for later use by the p2m code */
@@ -242,8 +264,6 @@ static inline int p2m_is_write_locked(struct p2m_domain 
*p2m)
 return rw_is_write_locked(&p2m->lock);
 }
 
-void p2m_tlb_flush_sync(struct p2m_domain *p2m);
-
 /* Look up the MFN corresponding to a domain's GFN. */
 mfn_t p2m_lookup(struct domain *d, gfn_t gfn, p2m_type_t *t);
 
@@ -268,6 +288,12 @@ int p2m_set_entry(struct p2m_domain *p2m,
   mfn_t smfn,
   p2m_type_t t,
   p2m_access_t a);
+int __p2m_set_entry(struct p2m_domain *p2m,
+gfn_t sgfn,
+unsigned int page_order,
+mfn_t smfn,
+p2m_type_t t,
+p2m_access_t a);
 
 bool p2m_resolve_translation_fault(struct domain *d, gfn_t gfn);
 
diff --git a/xen/arch/arm/mmu/p2m.c b/xen/arch/arm/mmu/p2m.c
new file mode 100644
index 00..ad0c7fa30e
--- /dev/null
+++ b/xen/arch/arm/mmu/p2m.c
@@ -0,0 +1,1612 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+unsigned int __read_mostly p2m_root_order;
+unsigned int __read_mostly p2m_root_level;
+
+#define P2M_ROOT_PAGES(1<arch.paging.lock);
+pg = page_list_remove_head(&d->arch.paging.p2m_freelist);
+spin_unlock(&d->arch.paging.lock);
+}
+
+return pg;
+}
+
+static void p2m_free_page(struct domain *d, struct page_info *pg)
+{
+if ( is_hardware_domain(d) )
+free_domheap_page(pg);
+else
+{
+spin_lock(&d->arch.paging.lock);
+page_list_add_tail(pg, &d->arch.paging.p2m_freelist);
+spin_unlock(&d->arch.paging.lock);
+}
+}
+
+/* Return the size of the pool, in bytes. */
+int arch_get_paging_mempool_size(struct domain *d, uint64_t *size)
+{
+*size = (uint64_t

[PATCH v3 25/52] xen/mpu: introduce helpers for MPU enablement

2023-06-25 Thread Penny Zheng
We introduce new helpers for Xen to enable MPU in boot-time.
enable_boot_mm() is implemented to be semantically consistent
with the MMU version.

If the Background region is enabled, then the MPU uses the
default memory map as the Background region for generating
the memory attributes when MPU is disabled.
Since the default memory map of the Armv8-R AArch64
architecture is IMPLEMENTATION DEFINED, we always turn off
the Background region.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- introduce code clearing SCTLR_EL2.BR
- document the reason of isb
---
 xen/arch/arm/arm64/mpu/head.S| 46 
 xen/arch/arm/include/asm/processor.h |  1 +
 2 files changed, 47 insertions(+)

diff --git a/xen/arch/arm/arm64/mpu/head.S b/xen/arch/arm/arm64/mpu/head.S
index 93a7a75029..3cfce126d5 100644
--- a/xen/arch/arm/arm64/mpu/head.S
+++ b/xen/arch/arm/arm64/mpu/head.S
@@ -170,6 +170,52 @@ ENTRY(prepare_early_mappings)
 ret
 ENDPROC(prepare_early_mappings)
 
+/*
+ * Enable EL2 MPU and data cache
+ * If the Background region is enabled, then the MPU uses the default memory
+ * map as the Background region for generating the memory
+ * attributes when MPU is disabled.
+ * Since the default memory map of the Armv8-R AArch64 architecture is
+ * IMPLEMENTATION DEFINED, we intend to turn off the Background region here.
+ *
+ * Clobbers x0
+ *
+ */
+ENTRY(enable_mpu)
+mrs   x0, SCTLR_EL2
+orr   x0, x0, #SCTLR_Axx_ELx_M/* Enable MPU */
+orr   x0, x0, #SCTLR_Axx_ELx_C/* Enable D-cache */
+orr   x0, x0, #SCTLR_Axx_ELx_WXN  /* Enable WXN */
+and   x0, x0, #SCTLR_Axx_ELx_BR   /* Disable Background region */
+msr   SCTLR_EL2, x0   /* now mpu memory mapping is enabled */
+isb   /* Now, flush the icache */
+ret
+ENDPROC(enable_mpu)
+
+/*
+ * Turn on the Data Cache and the MPU. The function will return
+ * to the virtual address provided in LR (e.g. the runtime mapping).
+ *
+ * Inputs:
+ *   lr : Virtual address to return to.
+ *
+ * Clobbers x0 - x7
+ */
+ENTRY(enable_boot_mm)
+/* save return address */
+mov   x7, lr
+
+blprepare_early_mappings
+blenable_mpu
+
+mov   lr, x7
+/*
+ * The "ret" here will use the return address in LR to
+ * return to primary_switched
+ */
+ret
+ENDPROC(enable_boot_mm)
+
 /*
  * Local variables:
  * mode: ASM
diff --git a/xen/arch/arm/include/asm/processor.h 
b/xen/arch/arm/include/asm/processor.h
index 7e42ff8811..685f9b18fd 100644
--- a/xen/arch/arm/include/asm/processor.h
+++ b/xen/arch/arm/include/asm/processor.h
@@ -167,6 +167,7 @@
 /* Common bits for SCTLR_ELx on all architectures */
 #define SCTLR_Axx_ELx_EEBIT(25, UL)
 #define SCTLR_Axx_ELx_WXN   BIT(19, UL)
+#define SCTLR_Axx_ELx_BR(~BIT(17, UL))
 #define SCTLR_Axx_ELx_I BIT(12, UL)
 #define SCTLR_Axx_ELx_C BIT(2, UL)
 #define SCTLR_Axx_ELx_A BIT(1, UL)
-- 
2.25.1




[PATCH v3 30/52] xen/mpu: populate a new region in Xen MPU mapping table

2023-06-25 Thread Penny Zheng
The new helper xen_mpumap_update() is responsible for updating Xen MPU memory
mapping table(xen_mpumap), including creating a new entry, updating
or destroying an existing one. It is equivalent to xen_pt_update in MMU.
This commit only talks about populating a new entry in Xen MPU memory mapping
table(xen_mpumap). Others will be introduced in the following commits.

When populating a new entry in Xen MPU memory mapping table(xen_mpumap),
firstly, we shall check if requested address range [base, limit) is mapped.
If not, we shall find a free slot in xen_mpumap to insert, based on bitmap
xen_mpumap_mask, and use standard entry pr_of_xenaddr() to build up MPU memory
region structure(pr_t)
In the last, we set memory attribute and permission based on variable @flags.

To summarize all region attributes in one variable @flags, layout of the
flags is elaborated as follows:
[0:2] Memory attribute Index
[3:4] Execute Never
[5:6] Access Permission
[7]   Region Present
Also, we provide a set of definitions(REGION_HYPERVISOR_RW, etc) that combine
the memory attribute and permission for common combinations.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- implement pr_set_base/pr_set_limit/region_is_valid using static
inline.
- define index uint8_t to limit its size
- stay the same major entry map_pages_to_xen, then go different path
in different context(xen_pt_update in MMU, and xen_mpumap_update in MPU)
---
 xen/arch/arm/include/asm/arm64/mpu.h |  64 +++
 xen/arch/arm/include/asm/mm.h|   3 +
 xen/arch/arm/include/asm/mpu/mm.h|  16 ++
 xen/arch/arm/include/asm/page.h  |  22 +++
 xen/arch/arm/mm.c|  20 +++
 xen/arch/arm/mmu/mm.c|   9 +-
 xen/arch/arm/mpu/mm.c| 255 +++
 7 files changed, 381 insertions(+), 8 deletions(-)
 create mode 100644 xen/arch/arm/include/asm/mpu/mm.h

diff --git a/xen/arch/arm/include/asm/arm64/mpu.h 
b/xen/arch/arm/include/asm/arm64/mpu.h
index 407fec66c9..a6b07bab02 100644
--- a/xen/arch/arm/include/asm/arm64/mpu.h
+++ b/xen/arch/arm/include/asm/arm64/mpu.h
@@ -6,6 +6,10 @@
 #ifndef __ARM64_MPU_H__
 #define __ARM64_MPU_H__
 
+#define MPU_REGION_SHIFT  6
+#define MPU_REGION_ALIGN  (_AC(1, UL) << MPU_REGION_SHIFT)
+#define MPU_REGION_MASK   (~(MPU_REGION_ALIGN - 1))
+
 /*
  * MPUIR_EL2.Region identifies the number of regions supported by the EL2 MPU.
  * It is a 8-bit field, so 255 MPU memory regions at most.
@@ -21,8 +25,33 @@
 #define REGION_UART_SEL0x07
 #define MPUIR_REGION_MASK  ((_AC(1, UL) << 8) - 1)
 
+/* Access permission attributes. */
+/* Read/Write at EL2, No Access at EL1/EL0. */
+#define AP_RW_EL2 0x0
+/* Read/Write at EL2/EL1/EL0 all levels. */
+#define AP_RW_ALL 0x1
+/* Read-only at EL2, No Access at EL1/EL0. */
+#define AP_RO_EL2 0x2
+/* Read-only at EL2/EL1/EL0 all levels. */
+#define AP_RO_ALL 0x3
+
+/*
+ * Excute never.
+ * Stage 1 EL2 translation regime.
+ * XN[1] determines whether execution of the instruction fetched from the MPU
+ * memory region is permitted.
+ * Stage 2 EL1/EL0 translation regime.
+ * XN[0] determines whether execution of the instruction fetched from the MPU
+ * memory region is permitted.
+ */
+#define XN_DISABLED0x0
+#define XN_P2M_ENABLED 0x1
+#define XN_ENABLED 0x2
+
 #ifndef __ASSEMBLY__
 
+#define INVALID_REGION_IDX 0xff
+
 /* Protection Region Base Address Register */
 typedef union {
 struct __packed {
@@ -54,6 +83,41 @@ typedef struct {
 prlar_t prlar;
 } pr_t;
 
+/* Access to set base address of MPU protection region(pr_t). */
+static inline void pr_set_base(pr_t *pr, paddr_t base)
+{
+pr->prbar.reg.base = (base >> MPU_REGION_SHIFT);
+}
+
+/* Access to set limit address of MPU protection region(pr_t). */
+static inline void pr_set_limit(pr_t *pr, paddr_t limit)
+{
+pr->prlar.reg.limit = (limit >> MPU_REGION_SHIFT);
+}
+
+/*
+ * Access to get base address of MPU protection region(pr_t).
+ * The base address shall be zero extended.
+ */
+static inline paddr_t pr_get_base(pr_t *pr)
+{
+return (paddr_t)(pr->prbar.reg.base << MPU_REGION_SHIFT);
+}
+
+/*
+ * Access to get limit address of MPU protection region(pr_t).
+ * The limit address shall be concatenated with 0x3f.
+ */
+static inline paddr_t pr_get_limit(pr_t *pr)
+{
+return (paddr_t)((pr->prlar.reg.limit << MPU_REGION_SHIFT) | 
~MPU_REGION_MASK);
+}
+
+static inline bool region_is_valid(pr_t *pr)
+{
+return pr->prlar.reg.en;
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ARM64_MPU_H__ */
diff --git a/xen/arch/arm/include/asm/mm.h b/xen/arch/arm/include/asm/mm.h
index ea4847c12b..daa6329505 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -16,6 +16,8 @@
 
 #ifdef CONFIG_HAS_MMU
 #include 
+#else
+#include 
 #endif
 
 /* Align Xen to a 2 MiB boundary. */
@@ -203,6 +205,7 @@ extern uint64_t init_mm;
 
 /* Boot-time memory mapping setup */
 extern vo

[PATCH v3 06/52] xen/arm: introduce CONFIG_HAS_MMU

2023-06-25 Thread Penny Zheng
This commit wants to introduce a new Kconfig CONFIG_HAS_MMU to guard
MMU-related codes, to tell two different memory management architecture:
VMAS and PMSA.

In a VMSA system, a Memory Management Unit (MMU) provides fine-grained
control of a memory system through a set of virtual to physical address
mappings and associated memory properties held in memory-mapped tables
known as translation tables.

Signed-off-by: Penny Zheng 
Signed-off-by: Wei Chen 
---
v3:
- new patch
---
 xen/arch/arm/Kconfig | 8 
 1 file changed, 8 insertions(+)

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index ff17345cdb..fb77392b82 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -60,6 +60,14 @@ config PADDR_BITS
 
 source "arch/Kconfig"
 
+config HAS_MMU
+   bool "Memory Management Unit support in a VMSA system"
+   default y
+   help
+ In a VMSA system, a Memory Management Unit (MMU) provides 
fine-grained control of
+ a memory system through a set of virtual to physical address mappings 
and associated memory
+ properties held in memory-mapped tables known as translation tables.
+
 config ACPI
bool "ACPI (Advanced Configuration and Power Interface) Support 
(UNSUPPORTED)" if UNSUPPORTED
depends on ARM_64
-- 
2.25.1




  1   2   3   4   5   6   7   8   >