RE: [PATCH] xen/arm: Add Cortex-A73 erratum 858921 workaround

2020-11-10 Thread Penny Zheng


> -Original Message-
> From: Julien Grall 
> Sent: Monday, November 9, 2020 8:04 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Andre Przywara ; Bertrand Marquis
> ; Wei Chen ; Kaly Xin
> ; nd 
> Subject: Re: [PATCH] xen/arm: Add Cortex-A73 erratum 858921 workaround
> 
> Hi,
> 
> On 09/11/2020 08:21, Penny Zheng wrote:
> > CNTVCT_EL0 or CNTPCT_EL0 counter read in Cortex-A73 (all versions)
> > might return a wrong value when the counter crosses a 32bit boundary.
> >
> > Until now, there is no case for Xen itself to access CNTVCT_EL0, and
> > it also should be the Guest OS's responsibility to deal with this
> > part.
> >
> > But for CNTPCT, there exists several cases in Xen involving reading
> > CNTPCT, so a possible workaround is that performing the read twice,
> > and to return one or the other depending on whether a transition has
> > taken place.
> >
> > Signed-off-by: Penny Zheng 
> 
> Acked-by: Julien Grall 
>
Thank you. 😉

> On a related topic, do we need a fix similar to Linux commit 75a19a0202db
> "arm64: arch_timer: Ensure counter register reads occur with seqlock held"?
> 
Sure, I'll check this commit and talk with my teams for further work.

Cheers

--
Penny Zheng
> Cheers,
> 
> --
> Julien Grall


RE: [PATCH] design: design doc for shared memory on a dom0less system

2022-03-10 Thread Penny Zheng
Hi Julien

Sorry for the late response, Since I'm considering sending the code together 
for better
understanding.

> -Original Message-
> From: Julien Grall 
> Sent: Wednesday, January 26, 2022 6:58 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Bertrand Marquis ; Wei Chen
> 
> Subject: Re: [PATCH] design: design doc for shared memory on a dom0less
> system
> 
> Hi,
> 
> On 26/01/2022 10:09, Penny Zheng wrote:
> > This commit provides a design doc for static shared memory on a
> > dom0less system.
> >
> > Signed-off-by: Penny Zheng 
> > ---
> >   design/shm-dom0less.md | 182
> +
> >   1 file changed, 182 insertions(+)
> >   create mode 100644 design/shm-dom0less.md
> >
> > diff --git a/design/shm-dom0less.md b/design/shm-dom0less.md new file
> > mode 100644 index 000..b46199d
> > --- /dev/null
> > +++ b/design/shm-dom0less.md
> > @@ -0,0 +1,182 @@
> > +# Static Shared Memory between domains on a dom0less system
> > +
> > +This design aims to provide an overview of the new feature: setting
> > +up static shared memory between domains on a dom0less system, through
> > +device tree configuration.
> > +
> > +The new feature is driven by the need of finding a way to build up
> > +communication channels on dom0less system, since the legacy ways
> > +including grant table, etc are all absent there.
> 
> Stefano has a series to add support for grant-table [2]. So I think you want 
> to
> justify it differently.
> 

The dom0less system I am referring here is that either dom0 is totally missing 
in the system,
or even when dom0 is there, all the other domains are statically configured and 
CONFIG_XEN
is not enabled, so in above scenario, all the legacy ways to communicate 
between domains are
absent. These scenarios are specially applied to ARMv8R, where everything is 
static.

I think Stefano is trying to enable PV drivers on dom0less guest with 
CONFIG_XEN still on.
TBH, I could not find proper nouns for them, sometimes calling these domains 
dom0less guests but
with dom0 still there makes me confused too. ;/

> > +
> > +It was inspired by the patch serie of "xl/libxl-based shared memory",
> > +see [1] for more details.
> > +
> > +# Static Shared Memory Device Tree Configuration
> > +
> > +The static shared memory device tree nodes allow users to statically
> > +set up shared memory among a group of dom0less DomUs and Dom0,
> > +enabling domains to do shm-based communication.
> > +
> > +- compatible
> > +
> > +"xen,domain-shared-memory-v1"
> > +
> > +- xen,shm-id
> 
>  From the document, it is not clear to me what is the purpose of the 
> identifier.
> Could you clarify it?
> 

It is more related to the implementation. 

I've already pushed an RFC patch for reviewing in community for better 
understanding.  For example,
in commit "xen/arm: introduce static shared memory", when parsing shared memory 
node to reserve it
in advance, we notice that a shared memory region could be shared among 
multiple domains, so in order to
prevent iterating over all reserved memory regions each time, we use bitmap 
there and shm-id is used as the
index of the bitmap.

Also, in Linux Doc about xen,shared-memory binding[3], it requires a xen,id 
property that identifies the
shared memory region as specified in the VM config file. 

> > +
> > +An u32 value represents the unique identifier of the shared memory
> region.
> > +User valuing per shared memory region shall follow the ascending order,
> > +starting from xen,shm-id = <0x0>, to the maximum identifier
> > +xen,shm-id = <0x126>.
> 
> Why is it limit to 0x126? And also, why do they have to be allocated in
> ascending order?
> 

In current code, I make it the same number with NR_MEM_BANKS

> > The special xen,shm-id = <0x127> is reserved for
> > +INVALID_SHMID.
> 
> Why do we need to reserve invalid?
> 

It is removed in current codes.

> > +
> > +- xen,shared-mem
> > +
> > +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.
> 
> I think shared memory is useful without static allocation. So I think we want 
> to
> make the host physical address optional.
> 

Hmm,, so later,, you want to make one domain as owner, and parts of its guest 
RAM
is shared with other borrower domains? So only GFN is enough here, right?

> > +

[PATCH v1 00/13] Static shared memory on dom0less system

2022-03-10 Thread Penny Zheng
The static shared memory device tree nodes allow users to statically set up
shared memory on dom0less system, enabling domains to do shm-based
communication.

The new feature is driven by the need of finding a way to build up
communication channels on dom0less system, since the legacy ways including
grant table, etc are all absent there.

It was inspired by the patch serie of ["xl/libxl-based shared mem](
https://marc.info/?l=xen-devel&m=154404821731186ory";).

Looking into related [design link](
https://lore.kernel.org/all/a50d9fde-1d06-7cda-2779-9eea9e1c0...@xen.org/T/)
for more details.

Penny Zheng (13):
  xen/arm: introduce static shared memory
  xen/arm: introduce a special domain DOMID_SHARED
  xen/arm: allocate static shared memory to dom_shared
  xen/arm: add P2M type parameter in guest_physmap_add_pages
  xen/arm: introduce get_pages_from_gfn
  xen/arm: set up shared memory foreign mapping for borrower domain
  xen/arm: create shared memory nodes in guest device tree
  xen/arm: destroy static shared memory when de-construct domain
  xen/arm: enable statically shared memory on Dom0
  xen/arm: allocate static shared memory to a specific owner domain
  xen/arm: store shm-info for deferred foreign memory map
  xen/arm: defer foreign memory map in shm_init_late
  xen/arm: unmap foreign memory mapping when destroyed domain is owner
domain

 docs/misc/arm/device-tree/booting.txt | 118 +++
 xen/arch/arm/Kconfig  |   7 +
 xen/arch/arm/bootfdt.c|  52 +++
 xen/arch/arm/domain.c | 117 ++-
 xen/arch/arm/domain_build.c   | 445 +-
 xen/arch/arm/include/asm/domain.h |  33 ++
 xen/arch/arm/include/asm/p2m.h|  42 ++-
 xen/arch/arm/include/asm/setup.h  |   3 +
 xen/arch/arm/setup.c  |  28 ++
 xen/common/domain.c   |  11 +-
 xen/common/page_alloc.c   |   5 +
 xen/common/vsprintf.c |   9 +-
 xen/include/public/xen.h  |   6 +
 xen/include/xen/sched.h   |   2 +
 14 files changed, 864 insertions(+), 14 deletions(-)

-- 
2.25.1




[PATCH v1 02/13] xen/arm: introduce a special domain DOMID_SHARED

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

In case to own statically shared pages when owner domain is not
explicitly defined, this commits propose a special domain DOMID_SHARED,
and we assign it 0x7FF5, as one of the system domains.

Statically shared memory reuses the same way of initialization with static
memory, hence this commits proposes a new Kconfig CONFIG_STATIC_SHM to wrap
related codes, and this option depends on static memory(CONFIG_STATIC_MEMORY).

We intends to do shared domain creation after setup_virt_paging so shared
domain could successfully do p2m initialization.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/Kconfig  |  7 +++
 xen/arch/arm/domain.c | 12 ++--
 xen/arch/arm/include/asm/domain.h |  6 ++
 xen/arch/arm/setup.c  | 22 ++
 xen/common/domain.c   | 11 +++
 xen/common/page_alloc.c   |  5 +
 xen/common/vsprintf.c |  9 +
 xen/include/public/xen.h  |  6 ++
 xen/include/xen/sched.h   |  2 ++
 9 files changed, 70 insertions(+), 10 deletions(-)

diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index ecfa6822e4..c54accefb1 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -106,6 +106,13 @@ config TEE
 
 source "arch/arm/tee/Kconfig"
 
+config STATIC_SHM
+   bool "Statically shared memory on a dom0less system" if UNSUPPORTED
+   depends on STATIC_MEMORY
+   default n
+   help
+ This option enables statically shared memory on a dom0less system.
+
 endmenu
 
 menu "ARM errata workaround via the alternative framework"
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 8110c1df86..1ff1df5d3f 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -44,6 +44,10 @@
 
 DEFINE_PER_CPU(struct vcpu *, curr_vcpu);
 
+#ifdef CONFIG_STATIC_SHM
+struct domain *__read_mostly dom_shared;
+#endif
+
 static void do_idle(void)
 {
 unsigned int cpu = smp_processor_id();
@@ -703,7 +707,7 @@ int arch_domain_create(struct domain *d,
 if ( is_idle_domain(d) )
 return 0;
 
-ASSERT(config != NULL);
+ASSERT(is_shared_domain(d) ? config == NULL : config != NULL);
 
 #ifdef CONFIG_IOREQ_SERVER
 ioreq_domain_init(d);
@@ -712,12 +716,16 @@ int arch_domain_create(struct domain *d,
 d->arch.directmap = flags & CDF_directmap;
 
 /* p2m_init relies on some value initialized by the IOMMU subsystem */
-if ( (rc = iommu_domain_init(d, config->iommu_opts)) != 0 )
+if ( (rc = iommu_domain_init(d, is_shared_domain(d) ? 0 : 
config->iommu_opts)) != 0 )
 goto fail;
 
 if ( (rc = p2m_init(d)) != 0 )
 goto fail;
 
+/* DOMID_shared is sufficiently constructed after p2m initialization. */
+if ( is_shared_domain(d) )
+return 0;
+
 rc = -ENOMEM;
 if ( (d->shared_info = alloc_xenheap_pages(0, 0)) == NULL )
 goto fail;
diff --git a/xen/arch/arm/include/asm/domain.h 
b/xen/arch/arm/include/asm/domain.h
index c56f6e4398..ea7a7219a3 100644
--- a/xen/arch/arm/include/asm/domain.h
+++ b/xen/arch/arm/include/asm/domain.h
@@ -31,6 +31,12 @@ enum domain_type {
 
 #define is_domain_direct_mapped(d) (d)->arch.directmap
 
+#ifdef CONFIG_STATIC_SHM
+extern struct domain *dom_shared;
+#else
+#define dom_shared NULL
+#endif
+
 /*
  * Is the domain using the host memory layout?
  *
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index d5d0792ed4..f6a3b04958 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -855,6 +855,20 @@ static bool __init is_dom0less_mode(void)
 return ( !dom0found && domUfound );
 }
 
+#ifdef CONFIG_STATIC_SHM
+static void __init setup_shared_domain(void)
+{
+/*
+ * Initialise our DOMID_SHARED domain.
+ * This domain owns statically shared pages when owner domain is not
+ * explicitly defined.
+ */
+dom_shared = domain_create(DOMID_SHARED, NULL, CDF_directmap);
+if ( IS_ERR(dom_shared) )
+panic("Failed to create d[SHARED]: %ld\n", PTR_ERR(dom_shared));
+}
+#endif
+
 size_t __read_mostly dcache_line_bytes;
 
 /* C entry point for boot CPU */
@@ -1022,6 +1036,14 @@ void __init start_xen(unsigned long boot_phys_offset,
 apply_alternatives_all();
 enable_errata_workarounds();
 
+#ifdef CONFIG_STATIC_SHM
+/*
+ * This needs to be called **after** setup_virt_paging so shared
+ * domains could successfully do p2m initialization.
+ */
+setup_shared_domain();
+#endif
+
 /* Create initial domain 0. */
 if ( !is_dom0less_mode() )
 create_dom0();
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 3742322d22..5cdd0b9f5b 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -643,11 +643,14 @@ struct domain *domain_create(domid_t domid,
 
 rangeset_domain_initialise(d);
 
-/* DOMID_{XEN,IO,etc} (other than IDLE) are sufficiently constructed. */
-if ( is_system_

[PATCH v1 04/13] xen/arm: add P2M type parameter in guest_physmap_add_pages

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

In order to cover the scenario where users intend to set up guest
p2m foreign mapping with nr_pages, this commit adds a new P2M type
parameter in guest_physmap_add_pages.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain_build.c| 5 +++--
 xen/arch/arm/include/asm/p2m.h | 5 +++--
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 6e6349caac..984e70e5fc 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -507,7 +507,7 @@ static bool __init append_static_memory_to_bank(struct 
domain *d,
 else
 sgfn = gaddr_to_gfn(mfn_to_maddr(smfn));
 
-res = guest_physmap_add_pages(d, sgfn, smfn, nr_pages);
+res = guest_physmap_add_pages(d, sgfn, smfn, nr_pages, p2m_ram_rw);
 if ( res )
 {
 dprintk(XENLOG_ERR, "Failed to map pages to DOMU: %d", res);
@@ -787,7 +787,8 @@ static int __init allocate_shared_memory(struct domain *d,
 if ( mfn_eq(smfn, INVALID_MFN) )
 return -EINVAL;
 
-ret = guest_physmap_add_pages(d, gaddr_to_gfn(gbase), smfn, 
PFN_DOWN(psize));
+ret = guest_physmap_add_pages(d, gaddr_to_gfn(gbase), smfn, 
PFN_DOWN(psize),
+  p2m_ram_rw);
 if ( ret )
 {
 dprintk(XENLOG_ERR, "Failed to map shared memory to %pd.\n", d);
diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h
index 8cce459b67..58590145b0 100644
--- a/xen/arch/arm/include/asm/p2m.h
+++ b/xen/arch/arm/include/asm/p2m.h
@@ -317,9 +317,10 @@ guest_physmap_add_page(struct domain *d, gfn_t gfn, mfn_t 
mfn,
 static inline int guest_physmap_add_pages(struct domain *d,
   gfn_t gfn,
   mfn_t mfn,
-  unsigned int nr_pages)
+  unsigned int nr_pages,
+  p2m_type_t t)
 {
-return p2m_insert_mapping(d, gfn, nr_pages, mfn, p2m_ram_rw);
+return p2m_insert_mapping(d, gfn, nr_pages, mfn, t);
 }
 
 mfn_t gfn_to_mfn(struct domain *d, gfn_t gfn);
-- 
2.25.1




[PATCH v1 05/13] xen/arm: introduce get_pages_from_gfn

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

In order to getting statically shared pages based on gfn with nr_pages, this
commit introduces a new helper get_pages_from_gfn to acquire a set of pages
based on [gfn, gfn + nr_gfns), with the same P2M type.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/include/asm/p2m.h | 37 ++
 1 file changed, 37 insertions(+)

diff --git a/xen/arch/arm/include/asm/p2m.h b/xen/arch/arm/include/asm/p2m.h
index 58590145b0..b23024b9a1 100644
--- a/xen/arch/arm/include/asm/p2m.h
+++ b/xen/arch/arm/include/asm/p2m.h
@@ -370,6 +370,43 @@ static inline struct page_info *get_page_from_gfn(
 return page;
 }
 
+static inline int get_pages_from_gfn(struct domain *d, unsigned long gfn,
+ unsigned long nr_gfns,
+ struct page_info **pages, p2m_type_t *t,
+ p2m_query_t q)
+{
+p2m_type_t _t;
+unsigned long i = 0;
+int ret = 0;
+
+for ( ; i < nr_gfns; i++ )
+{
+pages[i] = get_page_from_gfn(d, gfn + i, t, q);
+
+if ( !pages[i] )
+{
+ret = -ENOENT;
+goto fail_get;
+}
+
+if ( i == 0 )
+_t = *t;
+/* Check if all pages share the same p2m type. */
+else if ( *t != _t )
+{
+ret = -EINVAL;
+goto fail_get;
+}
+}
+
+return ret;
+
+ fail_get:
+while( --i >= 0 )
+put_page(pages[i]);
+return ret;
+}
+
 int get_page_type(struct page_info *page, unsigned long type);
 bool is_iomem_page(mfn_t mfn);
 static inline int get_page_and_type(struct page_info *page,
-- 
2.25.1




[PATCH v1 06/13] xen/arm: set up shared memory foreign mapping for borrower domain

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

This commits introduces a new helper guest_physmap_add_shm to set up shared
memory foreign mapping for borrower domain.

Firstly it should get and take reference of statically shared pages from
owner dom_shared. Then it will setup P2M foreign memory map of these statically
shared pages for borrower domain.

This commits only considers owner domain is the default dom_shared, the
other scenario will be covered in the following patches.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain_build.c | 52 +
 1 file changed, 52 insertions(+)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 984e70e5fc..8cee5ffbd1 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -798,6 +798,48 @@ static int __init allocate_shared_memory(struct domain *d,
 return ret;
 }
 
+static int __init guest_physmap_add_shm(struct domain *od, struct domain *bd,
+unsigned long o_gfn,
+unsigned long b_gfn,
+unsigned long nr_gfns)
+{
+struct page_info **pages = NULL;
+p2m_type_t p2mt, t;
+int ret = 0;
+
+pages = xmalloc_array(struct page_info *, nr_gfns);
+if ( !pages )
+return -ENOMEM;
+
+/*
+ * Take reference of statically shared pages from owner domain.
+ * Reference will be released when destroying shared memory region.
+ */
+ret = get_pages_from_gfn(od, o_gfn, nr_gfns, pages, &p2mt, P2M_ALLOC);
+if ( ret )
+{
+ret = -EINVAL;
+goto fail_pages;
+}
+
+if ( p2m_is_ram(p2mt) )
+t = (p2mt == p2m_ram_rw) ? p2m_map_foreign_rw : p2m_map_foreign_ro;
+else
+{
+ret = -EINVAL;
+goto fail_pages;
+}
+
+/* Set up guest foreign map. */
+ret = guest_physmap_add_pages(bd, _gfn(b_gfn), page_to_mfn(pages[0]),
+  nr_gfns, t);
+
+ fail_pages:
+xfree(pages);
+
+return ret;
+}
+
 static int __init process_shm(struct domain *d,
   const struct dt_device_node *node)
 {
@@ -855,6 +897,16 @@ static int __init process_shm(struct domain *d,
 
 set_bit(shm_id, shm_mask);
 }
+
+/*
+ * All domains are borrower domains when owner domain is the
+ * default dom_shared, so here we could just set up P2M foreign
+ * mapping for borrower domain immediately.
+ */
+ret = guest_physmap_add_shm(dom_shared, d, PFN_DOWN(pbase),
+PFN_DOWN(gbase), PFN_DOWN(psize));
+if ( ret )
+return ret;
 }
 
 return 0;
-- 
2.25.1




[PATCH v1 03/13] xen/arm: allocate static shared memory to dom_shared

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

This commit introduces process_shm to cope with static shared memory in
domain construction.

This commit only considers allocating static shared memory to dom_shared
when owner domain is not explicitly defined in device tree, the other
scenario will be covered in the following patches.

Static shared memory could reuse acquire_static_memory_bank() to acquire
and allocate static memory.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain_build.c | 116 +++-
 1 file changed, 115 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 8be01678de..6e6349caac 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -527,7 +527,8 @@ static mfn_t __init acquire_static_memory_bank(struct 
domain *d,
 mfn_t smfn;
 int res;
 
-device_tree_get_reg(cell, addr_cells, size_cells, pbase, psize);
+if ( cell )
+device_tree_get_reg(cell, addr_cells, size_cells, pbase, psize);
 ASSERT(IS_ALIGNED(*pbase, PAGE_SIZE) && IS_ALIGNED(*psize, PAGE_SIZE));
 if ( PFN_DOWN(*psize) > UINT_MAX )
 {
@@ -751,6 +752,113 @@ static void __init assign_static_memory_11(struct domain 
*d,
 panic("Failed to assign requested static memory for direct-map domain 
%pd.",
   d);
 }
+
+#ifdef CONFIG_STATIC_SHM
+static __initdata DECLARE_BITMAP(shm_mask, NR_MEM_BANKS);
+
+static mfn_t __init acquire_shared_memory_bank(struct domain *d,
+   u32 addr_cells, u32 size_cells,
+   paddr_t *pbase, paddr_t *psize)
+{
+/*
+ * Pages of statically shared memory shall be included
+ * in domain_tot_pages().
+ */
+d->max_pages += PFN_DOWN(*psize);
+
+return acquire_static_memory_bank(d, NULL, addr_cells, size_cells,
+  pbase, psize);
+
+}
+
+static int __init allocate_shared_memory(struct domain *d,
+ u32 addr_cells, u32 size_cells,
+ paddr_t pbase, paddr_t psize,
+ paddr_t gbase)
+{
+mfn_t smfn;
+int ret = 0;
+
+printk(XENLOG_INFO "Allocate static shared memory BANK 
%#"PRIpaddr"-%#"PRIpaddr"\n",
+   pbase, pbase + psize);
+
+smfn = acquire_shared_memory_bank(d, addr_cells, size_cells, &pbase,
+  &psize);
+if ( mfn_eq(smfn, INVALID_MFN) )
+return -EINVAL;
+
+ret = guest_physmap_add_pages(d, gaddr_to_gfn(gbase), smfn, 
PFN_DOWN(psize));
+if ( ret )
+{
+dprintk(XENLOG_ERR, "Failed to map shared memory to %pd.\n", d);
+return ret;
+}
+
+return ret;
+}
+
+static int __init process_shm(struct domain *d,
+  const struct dt_device_node *node)
+{
+struct dt_device_node *shm_node;
+int ret = 0;
+const struct dt_property *prop;
+const __be32 *cells;
+u32 shm_id;
+u32 addr_cells, size_cells;
+paddr_t gbase, pbase, psize;
+
+dt_for_each_child_node(node, shm_node)
+{
+if ( !dt_device_is_compatible(shm_node, "xen,domain-shared-memory-v1") 
)
+continue;
+
+if ( !dt_property_read_u32(shm_node, "xen,shm-id", &shm_id) )
+{
+printk("Shared memory node does not provide \"xen,shm-id\" 
property.\n");
+return -ENOENT;
+}
+
+addr_cells = dt_n_addr_cells(shm_node);
+size_cells = dt_n_size_cells(shm_node);
+prop = dt_find_property(shm_node, "xen,shared-mem", NULL);
+if ( !prop )
+{
+printk("Shared memory node does not provide \"xen,shared-mem\" 
property.\n");
+return -ENOENT;
+}
+cells = (const __be32 *)prop->value;
+/* xen,shared-mem = ; */
+device_tree_get_reg(&cells, addr_cells, size_cells, &pbase, &psize);
+ASSERT(IS_ALIGNED(pbase, PAGE_SIZE) && IS_ALIGNED(psize, PAGE_SIZE));
+gbase = dt_read_number(cells, addr_cells);
+
+/* TODO: Consider owner domain is not the default dom_shared. */
+/*
+ * Per shared memory region could be shared between multiple domains.
+ * In case re-allocating the same shared memory region, we use bitmask
+ * shm_mask to record whether this shared memory region has ever been
+ * allocated already.
+ */
+if ( !test_bit(shm_id, shm_mask) )
+{
+/*
+ * Allocate statically shared pages to the default dom_shared.
+ * Set up P2M, and dom_shared is a direct-map domain,
+ * so GFN == PFN.
+ */
+ret = allocate_shared_memory(dom_shared, addr_cells, size_cells,
+  

[PATCH v1 08/13] xen/arm: destroy static shared memory when de-construct domain

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

This commit introduces a new helper destroy_domain_shm to destroy static
shared memory at domain de-construction.

This patch only considers the scenario where the owner domain is the
default dom_shared, for user-defined owner domain, it will be covered in
the following patches.

Since all domains are borrower domains, we could simply remove guest P2M
foreign mapping of statically shared memory region and drop the reference
added at guest_physmap_add_shm.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain.c | 48 +++
 1 file changed, 48 insertions(+)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 1ff1df5d3f..f0bfd67fe5 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -34,6 +34,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -993,6 +994,48 @@ static int relinquish_memory(struct domain *d, struct 
page_list_head *list)
 return ret;
 }
 
+#ifdef CONFIG_STATIC_SHM
+static int domain_destroy_shm(struct domain *d)
+{
+int ret = 0;
+unsigned long i = 0UL, j;
+
+if ( d->arch.shm_mem == NULL )
+return ret;
+else
+{
+for ( ; i < d->arch.shm_mem->nr_banks; i++ )
+{
+unsigned long nr_gfns = PFN_DOWN(d->arch.shm_mem->bank[i].size);
+gfn_t gfn = gaddr_to_gfn(d->arch.shm_mem->bank[i].start);
+
+for ( j = 0; j < nr_gfns; j++ )
+{
+mfn_t mfn;
+
+mfn = gfn_to_mfn(d, gfn_add(gfn, j));
+if ( !mfn_valid(mfn) )
+{
+dprintk(XENLOG_ERR,
+"Domain %pd page number %lx invalid.\n",
+d, gfn_x(gfn) + i);
+return -EINVAL;
+}
+
+ret = guest_physmap_remove_page(d, gfn_add(gfn, j), mfn, 0);
+if ( ret )
+return ret;
+
+/* Drop the reference. */
+put_page(mfn_to_page(mfn));
+}
+}
+}
+
+return ret;
+}
+#endif
+
 /*
  * Record the current progress. Subsequent hypercall continuations will
  * logically restart work from this point.
@@ -1039,6 +1082,11 @@ int domain_relinquish_resources(struct domain *d)
  */
 domain_vpl011_deinit(d);
 
+#ifdef CONFIG_STATIC_SHM
+ret = domain_destroy_shm(d);
+if ( ret )
+return ret;
+#endif
 #ifdef CONFIG_IOREQ_SERVER
 ioreq_server_destroy_all(d);
 #endif
-- 
2.25.1




[PATCH v1 07/13] xen/arm: create shared memory nodes in guest device tree

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

We expose the shared memory to the domU using the "xen,shared-memory-v1"
reserved-memory binding. See
Documentation/devicetree/bindings/reserved-memory/xen,shared-memory.txt
in Linux for the corresponding device tree binding.

To save the cost of re-parsing shared memory device tree configuration when
creating shared memory nodes in guest device tree, this commit adds new field
"shm_mem" to store shm-info per domain.

For each shared memory region, a range is exposed under
the /reserved-memory node as a child node. Each range sub-node is
named xen-shmem@ and has the following properties:
- compatible:
compatible = "xen,shared-memory-v1"
- reg:
the base guest physical address and size of the shared memory region
- xen,id:
a string that identifies the shared memory region.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain_build.c   | 144 ++
 xen/arch/arm/include/asm/domain.h |   1 +
 xen/arch/arm/include/asm/setup.h  |   3 +
 3 files changed, 148 insertions(+)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 8cee5ffbd1..997df46ddd 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -840,6 +840,28 @@ static int __init guest_physmap_add_shm(struct domain *od, 
struct domain *bd,
 return ret;
 }
 
+static int __init append_shm_bank_to_domain(struct domain *d,
+paddr_t start, paddr_t size,
+u32 shm_id)
+{
+/* Allocate memory at first insertion. */
+if ( d->arch.shm_mem == NULL )
+{
+d->arch.shm_mem = xmalloc_bytes(sizeof(struct meminfo));
+if ( d->arch.shm_mem == NULL )
+return -ENOMEM;
+
+memset(d->arch.shm_mem, 0, sizeof(struct meminfo));
+}
+
+d->arch.shm_mem->bank[d->arch.shm_mem->nr_banks].start = start;
+d->arch.shm_mem->bank[d->arch.shm_mem->nr_banks].size = size;
+d->arch.shm_mem->bank[d->arch.shm_mem->nr_banks].shm_id = shm_id;
+d->arch.shm_mem->nr_banks++;
+
+return 0;
+}
+
 static int __init process_shm(struct domain *d,
   const struct dt_device_node *node)
 {
@@ -907,6 +929,14 @@ static int __init process_shm(struct domain *d,
 PFN_DOWN(gbase), PFN_DOWN(psize));
 if ( ret )
 return ret;
+
+/*
+ * Record static shared memory region info for later setting
+ * up shm-node in guest device tree.
+ */
+ret = append_shm_bank_to_domain(d, gbase, psize, shm_id);
+if ( ret )
+return ret;
 }
 
 return 0;
@@ -1237,6 +1267,115 @@ static int __init make_memory_node(const struct domain 
*d,
 return res;
 }
 
+#ifdef CONFIG_STATIC_SHM
+static int __init make_shm_memory_node(const struct domain *d,
+   void *fdt,
+   int addrcells, int sizecells,
+   struct meminfo *mem)
+{
+unsigned long i = 0;
+int res = 0;
+int reg_size = addrcells + sizecells;
+
+if ( mem->nr_banks == 0 )
+return -ENOENT;
+
+/*
+ * For each shared memory region, a range is exposed under
+ * the /reserved-memory node as a child node. Each range sub-node is
+ * named xen-shmem@.
+ */
+dt_dprintk("Create xen-shmem node\n");
+
+for ( ; i < mem->nr_banks; i++ )
+{
+u64 start = mem->bank[i].start;
+u64 size = mem->bank[i].size;
+u32 shm_id = mem->bank[i].shm_id;
+/* Placeholder for xen-shmem@ + a 64-bit number + \0 */
+char buf[27];
+const char compat[] = "xen,shared-memory-v1";
+__be32 *reg, *cells;
+   unsigned int len;
+
+snprintf(buf, sizeof(buf), "xen-shmem@%"PRIx64, mem->bank[i].start);
+res = fdt_begin_node(fdt, buf);
+if ( res )
+return res;
+
+res = fdt_property(fdt, "compatible", compat, sizeof(compat));
+if ( res )
+return res;
+
+   len = reg_size * sizeof(__be32);
+reg = xmalloc_bytes(len);
+if ( reg == NULL )
+return -ENOMEM;
+cells = reg;
+
+dt_child_set_range(&cells, addrcells, sizecells, start, size);
+
+res = fdt_property(fdt, "reg", reg, len);
+xfree(reg);
+if (res)
+return res;
+
+dt_dprintk("Shared memory bank %lu: %#"PRIx64"->%#"PRIx64"\n",
+   i, start, start + size);
+
+res = fdt_property_cell(fdt, "xen,id", shm_id);
+if (res)
+return res;
+
+res = fdt_end_node(fdt);
+if (res)
+return res;
+}
+
+ret

[PATCH v1 01/13] xen/arm: introduce static shared memory

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

This patch serie introduces a new feature: setting up static
shared memory on a dom0less system, through device tree configuration.

This commit parses shared memory node at boot-time, and reserve it in
bootinfo.reserved_mem to avoid other use.

Signed-off-by: Penny Zheng 
---
 docs/misc/arm/device-tree/booting.txt | 118 ++
 xen/arch/arm/bootfdt.c|  52 
 2 files changed, 170 insertions(+)

diff --git a/docs/misc/arm/device-tree/booting.txt 
b/docs/misc/arm/device-tree/booting.txt
index a94125394e..f702ade817 100644
--- a/docs/misc/arm/device-tree/booting.txt
+++ b/docs/misc/arm/device-tree/booting.txt
@@ -355,3 +355,121 @@ device-tree:
 
 This will reserve a 512MB region starting at the host physical address
 0x3000 to be exclusively used by DomU1.
+
+Static Shared Memory
+=
+
+The static shared memory device tree nodes allow users to statically set up
+shared memory on dom0less system, enabling domains to do shm-based
+communication.
+
+- compatible
+
+"xen,domain-shared-memory-v1"
+
+- xen,shm-id
+
+An u8 value represents the unique identifier of the shared memory region.
+The maximum identifier shall be "xen,shm-id = <0xff>".
+
+- xen,shared-mem
+
+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.
+
+- role (Optional)
+
+A string property specifying the ownership of a shared memory region,
+the value must be one of the following: "owner", or "borrower"
+A shared memory region could be explicitly backed by one domain, which is
+called "owner domain", and all the other domains who are also sharing
+this region are called "borrower domain".
+If not specified, the default value is "borrower" and owner is
+"dom_shared", a system domain.
+
+As an example:
+
+chosen {
+#address-cells = <0x1>;
+#size-cells = <0x1>;
+xen,xen-bootargs = "console=dtuart dtuart=serial0 bootscrub=0";
+
+..
+
+/* this is for Dom0 */
+dom0-shared-mem@1000 {
+compatible = "xen,domain-shared-memory-v1";
+role = "owner";
+xen,shm-id = <0x0>;
+xen,shared-mem = <0x1000 0x1000 0x1000>;
+}
+
+domU1 {
+compatible = "xen,domain";
+#address-cells = <0x1>;
+#size-cells = <0x1>;
+memory = <0 131072>;
+cpus = <2>;
+vpl011;
+
+/*
+ * shared memory region identified as 0x0(xen,shm-id = <0x0>)
+ * is shared between Dom0 and DomU1.
+ */
+domU1-shared-mem@1000 {
+compatible = "xen,domain-shared-memory-v1";
+role = "borrower";
+xen,shm-id = <0x0>;
+xen,shared-mem = <0x1000 0x1000 0x5000>;
+}
+
+/*
+ * shared memory region identified as 0x1(xen,shm-id = <0x1>)
+ * is shared between DomU1 and DomU2.
+ */
+domU1-shared-mem@5000 {
+compatible = "xen,domain-shared-memory-v1";
+xen,shm-id = <0x1>;
+xen,shared-mem = <0x5000 0x2000 0x6000>;
+}
+
+..
+
+};
+
+domU2 {
+compatible = "xen,domain";
+#address-cells = <0x1>;
+#size-cells = <0x1>;
+memory = <0 65536>;
+cpus = <1>;
+
+/*
+ * shared memory region identified as 0x1(xen,shm-id = <0x1>)
+ * is shared between domU1 and domU2.
+ */
+domU2-shared-mem@5000 {
+compatible = "xen,domain-shared-memory-v1";
+xen,shm-id = <0x1>;
+xen,shared-mem = <0x5000 0x2000 0x7000>;
+}
+
+..
+};
+};
+
+This is an example with two static shared memory regions.
+
+For the static shared memory region identified as 0x0, host physical
+address starting at 0x1000 of 256MB will be reserved to be shared between
+Dom0 and DomU1.It will get mapped at 0x1000 in Dom0 guest physical address
+space, and at 0x5000 in DomU1 guest physical address space. Dom0 is
+explicitly defined as the owner domain, and DomU1 is the borrower domain.
+
+For the static shared memory region identified as 0x1, host physical
+address starting at 0x5000 of 512MB will be reserved to be 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 dom_shared.
diff --git

[PATCH v1 09/13] xen/arm: enable statically shared memory on Dom0

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

To add statically shared memory nodes in Dom0, user shall put according
static shared memory configuration under /chosen node.

This commit adds shm-processing function process_shm in construct_dom0
to enable statically shared memory on Dom0.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain_build.c | 14 ++
 1 file changed, 14 insertions(+)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 997df46ddd..d35f98ff9c 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2561,6 +2561,11 @@ static int __init handle_node(struct domain *d, struct 
kernel_info *kinfo,
 if ( res )
 return res;
 }
+
+res = make_resv_memory_node(d, kinfo->fdt, addrcells, sizecells,
+d->arch.shm_mem);
+if ( res )
+return res;
 }
 
 res = fdt_end_node(kinfo->fdt);
@@ -3572,6 +3577,9 @@ static int __init construct_dom0(struct domain *d)
 {
 struct kernel_info kinfo = {};
 int rc;
+#ifdef CONFIG_STATIC_SHM
+const struct dt_device_node *chosen = dt_find_node_by_path("/chosen");
+#endif
 
 /* Sanity! */
 BUG_ON(d->domain_id != 0);
@@ -3606,6 +3614,12 @@ static int __init construct_dom0(struct domain *d)
 allocate_memory_11(d, &kinfo);
 find_gnttab_region(d, &kinfo);
 
+#ifdef CONFIG_STATIC_SHM
+rc = process_shm(d, chosen);
+if ( rc < 0 )
+return rc;
+#endif
+
 /* Map extra GIC MMIO, irqs and other hw stuffs to dom0. */
 rc = gic_map_hwdom_extra_mappings(d);
 if ( rc < 0 )
-- 
2.25.1




[PATCH v1 10/13] xen/arm: allocate static shared memory to a specific owner domain

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

If owner property is defined, then owner domain of a static shared memory
region is not the default dom_shared anymore, but a specific domain.

This commit implements allocating static shared memory to a specific domain
when owner property is defined.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain_build.c | 63 -
 1 file changed, 48 insertions(+), 15 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index d35f98ff9c..7ee4d33e0b 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -872,6 +872,8 @@ static int __init process_shm(struct domain *d,
 u32 shm_id;
 u32 addr_cells, size_cells;
 paddr_t gbase, pbase, psize;
+const char *role_str;
+bool owner_dom_shared = true;
 
 dt_for_each_child_node(node, shm_node)
 {
@@ -899,6 +901,13 @@ static int __init process_shm(struct domain *d,
 gbase = dt_read_number(cells, addr_cells);
 
 /* TODO: Consider owner domain is not the default dom_shared. */
+/*
+ * "role" property is optional and if it is defined explicitly,
+ * so the owner domain is not the default "dom_shared" domain.
+ */
+if ( dt_property_read_string(shm_node, "role", &role_str) == 0 )
+owner_dom_shared = false;
+
 /*
  * Per shared memory region could be shared between multiple domains.
  * In case re-allocating the same shared memory region, we use bitmask
@@ -907,17 +916,38 @@ static int __init process_shm(struct domain *d,
  */
 if ( !test_bit(shm_id, shm_mask) )
 {
-/*
- * Allocate statically shared pages to the default dom_shared.
- * Set up P2M, and dom_shared is a direct-map domain,
- * so GFN == PFN.
- */
-ret = allocate_shared_memory(dom_shared, addr_cells, size_cells,
- pbase, psize, pbase);
-if ( ret )
-return ret;
-
-set_bit(shm_id, shm_mask);
+if ( !owner_dom_shared )
+{
+if ( strcmp(role_str, "owner") == 0 )
+{
+/*
+ * Allocate statically shared pages to a specific owner
+ * domain.
+ */
+ret = allocate_shared_memory(d, shm_id, addr_cells,
+ size_cells, pbase, psize,
+ gbase);
+if ( ret )
+return ret;
+
+set_bit(shm_id, shm_mask);
+}
+}
+else
+{
+/*
+ * Allocate statically shared pages to the default dom_shared.
+ * Set up P2M, and dom_shared is a direct-map domain,
+ * so GFN == PFN.
+ */
+ret = allocate_shared_memory(dom_shared, shm_id,
+ addr_cells, size_cells, pbase,
+ psize, pbase);
+if ( ret )
+return ret;
+
+set_bit(shm_id, shm_mask);
+}
 }
 
 /*
@@ -925,10 +955,13 @@ static int __init process_shm(struct domain *d,
  * default dom_shared, so here we could just set up P2M foreign
  * mapping for borrower domain immediately.
  */
-ret = guest_physmap_add_shm(dom_shared, d, PFN_DOWN(pbase),
-PFN_DOWN(gbase), PFN_DOWN(psize));
-if ( ret )
-return ret;
+if ( owner_dom_shared )
+{
+ret = guest_physmap_add_shm(dom_shared, d, PFN_DOWN(pbase),
+PFN_DOWN(gbase), PFN_DOWN(psize));
+if ( ret )
+return ret;
+}
 
 /*
  * Record static shared memory region info for later setting
-- 
2.25.1




[PATCH v1 13/13] xen/arm: unmap foreign memory mapping when destroyed domain is owner domain

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

When destroyed domain is an owner domain of a static shared memory
region, then we need to ensure that all according borrower domains
shall not have the access to this static shared memory region too.

This commit covers above scenario through unmapping all borrowers'
according foreign memory mapping when destroyed domain is a owner
domain of a static shared memory region.

NOTE: It will best for users to destroy all borrowers before the owner
domain in case encountering data abort when accidentally accessing
the static shared memory region.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain.c | 88 ++-
 1 file changed, 71 insertions(+), 17 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 73ffbfb918..8f4a8dcbfc 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -998,10 +998,39 @@ static int relinquish_memory(struct domain *d, struct 
page_list_head *list)
 }
 
 #ifdef CONFIG_STATIC_SHM
+static int destroy_shm(struct domain *d, gfn_t gfn, unsigned long nr_gfns)
+{
+unsigned long i = 0;
+int ret = 0;
+
+for ( ; i < nr_gfns; i++ )
+{
+mfn_t mfn;
+
+mfn = gfn_to_mfn(d, gfn_add(gfn, i));
+if ( !mfn_valid(mfn) )
+{
+dprintk(XENLOG_ERR,
+"Domain %pd page number %lx invalid.\n",
+d, gfn_x(gfn) + i);
+return -EINVAL;
+}
+
+ret = guest_physmap_remove_page(d, gfn_add(gfn, i), mfn, 0);
+if ( ret )
+return ret;
+
+/* Drop the reference. */
+put_page(mfn_to_page(mfn));
+}
+
+return ret;
+}
+
 static int domain_destroy_shm(struct domain *d)
 {
 int ret = 0;
-unsigned long i = 0UL, j;
+unsigned long i = 0UL;
 
 if ( d->arch.shm_mem == NULL )
 return ret;
@@ -1009,29 +1038,54 @@ static int domain_destroy_shm(struct domain *d)
 {
 for ( ; i < d->arch.shm_mem->nr_banks; i++ )
 {
+u32 shm_id = d->arch.shm_mem->bank[i].shm_id;
 unsigned long nr_gfns = PFN_DOWN(d->arch.shm_mem->bank[i].size);
 gfn_t gfn = gaddr_to_gfn(d->arch.shm_mem->bank[i].start);
 
-for ( j = 0; j < nr_gfns; j++ )
+if ( test_bit(shm_id, shm_list_mask) )
 {
-mfn_t mfn;
-
-mfn = gfn_to_mfn(d, gfn_add(gfn, j));
-if ( !mfn_valid(mfn) )
+domid_t od = shm_list[shm_id].owner_dom;
+unsigned long j;
+/*
+ * If it is a owner domain, then after it gets destroyed,
+ * static shared memory region shall be unaccessible to all
+ * borrower domains too.
+ */
+if ( d->domain_id == od )
 {
-dprintk(XENLOG_ERR,
-"Domain %pd page number %lx invalid.\n",
-d, gfn_x(gfn) + i);
-return -EINVAL;
+struct domain *bd;
+
+for ( j = 0; j < shm_list[shm_id].nr_borrower; j++ )
+{
+bd = 
get_domain_by_id(shm_list[shm_id].borrower_dom[j]);
+/*
+ * borrower domain could be dead already, in such case
+ * no need to do the unmapping.
+ */
+if ( bd != NULL )
+{
+gfn_t b_gfn = gaddr_to_gfn(
+  shm_list[shm_id].borrower_gbase[j]);
+ret = destroy_shm(bd, b_gfn, nr_gfns);
+if ( ret )
+dprintk(XENLOG_ERR,
+"Domain %pd: failed to destroy static 
shared memory.\n",
+bd);
+}
+}
+
+continue;
 }
-
-ret = guest_physmap_remove_page(d, gfn_add(gfn, j), mfn, 0);
-if ( ret )
-return ret;
-
-/* Drop the reference. */
-put_page(mfn_to_page(mfn));
 }
+/*
+ * As borrower domain, remove foreign memory mapping and drop the
+ * reference count.
+ */
+ret = destroy_shm(d, gfn, nr_gfns);
+if ( ret )
+dprintk(XENLOG_ERR,
+"Domain %pd: failed to destroy static shared 
memory.\n",
+d);
 }
 }
 
-- 
2.25.1




[PATCH v1 11/13] xen/arm: store shm-info for deferred foreign memory map

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

In a few scenarios where owner domain, is defined after borrower domain in
device tree configuration, then statically shared pages haven't been properly
allocated if borrower domain tries to do foreign memory map during
domain construction.

In order to cover such scenario, we defer all borrower domains' foreign
memory map after all domain construction finished, then only need to store
shm-info during domain construction.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain.c |  3 +++
 xen/arch/arm/domain_build.c   | 34 ++-
 xen/arch/arm/include/asm/domain.h | 25 +++
 3 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index f0bfd67fe5..73ffbfb918 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -47,6 +47,9 @@ DEFINE_PER_CPU(struct vcpu *, curr_vcpu);
 
 #ifdef CONFIG_STATIC_SHM
 struct domain *__read_mostly dom_shared;
+
+shm_info_t shm_list[NR_MEM_BANKS];
+DECLARE_BITMAP(shm_list_mask, NR_MEM_BANKS);
 #endif
 
 static void do_idle(void)
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 7ee4d33e0b..4b19160674 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -771,7 +771,7 @@ static mfn_t __init acquire_shared_memory_bank(struct 
domain *d,
 
 }
 
-static int __init allocate_shared_memory(struct domain *d,
+static int __init allocate_shared_memory(struct domain *d, u32 shm_id,
  u32 addr_cells, u32 size_cells,
  paddr_t pbase, paddr_t psize,
  paddr_t gbase)
@@ -795,6 +795,18 @@ static int __init allocate_shared_memory(struct domain *d,
 return ret;
 }
 
+/*
+ * If owner domain is not default dom_shared, shm-info of owner domain
+ * shall also be recorded for later deferred foreign memory map.
+ */
+if ( d != dom_shared )
+{
+shm_list[shm_id].owner_dom = d->domain_id;
+shm_list[shm_id].owner_gbase = gbase;
+shm_list[shm_id].size = psize;
+set_bit(shm_id, shm_list_mask);
+}
+
 return ret;
 }
 
@@ -962,6 +974,26 @@ static int __init process_shm(struct domain *d,
 if ( ret )
 return ret;
 }
+else
+{
+if ( strcmp(role_str, "borrower") == 0 )
+{
+/*
+ * In a few scenarios where owner domain, is defined after
+ * borrower domain in device tree configuration, statically
+ * shared pages haven't been properly allocated if borrower
+ * domain here tries to do foreign memory map.
+ * In order to cover such scenario, we defer all borrower
+ * domains'foreign memory map after all domain construction
+ * finished, and only store shm-info here for later use.
+ */
+shm_list[shm_id].borrower_dom[shm_list[shm_id].nr_borrower] =
+d->domain_id;
+shm_list[shm_id].borrower_gbase[shm_list[shm_id].nr_borrower] =
+gbase;
+shm_list[shm_id].nr_borrower++;
+}
+}
 
 /*
  * Record static shared memory region info for later setting
diff --git a/xen/arch/arm/include/asm/domain.h 
b/xen/arch/arm/include/asm/domain.h
index 6df37d2c46..1c0f2e22ca 100644
--- a/xen/arch/arm/include/asm/domain.h
+++ b/xen/arch/arm/include/asm/domain.h
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 struct hvm_domain
@@ -33,6 +34,30 @@ enum domain_type {
 
 #ifdef CONFIG_STATIC_SHM
 extern struct domain *dom_shared;
+
+/* Maximum number of borrower domains. */
+#define NR_SHM_DOMAIN 32
+/*
+ * shm_list is indexed by unique identifier "xen,shm-id", but it only stores
+ * a subset of static shared memory regions, of which owner domain is not the
+ * default dom_shared.
+ * shm_list_mask bitmask is to record the position of these static shared
+ * memory regions.
+ * Per bit represents a entry in shm_list, and setting it 1 means the
+ * static shared memory region here is owned by a specific domain, then bit 0
+ * means the static shared memory region here is either owned by the default
+ * dom_shared or no static shared memory region here at all.
+ */
+typedef struct {
+domid_t owner_dom;
+paddr_t owner_gbase;
+paddr_t size;
+domid_t borrower_dom[NR_SHM_DOMAIN];
+paddr_t borrower_gbase[NR_SHM_DOMAIN];
+unsigned long nr_borrower;
+} shm_info_t;
+extern shm_info_t shm_list[NR_MEM_BANKS];
+extern unsigned long shm_list_mask[BITS_TO_LONGS(NR_MEM_BANKS)];
 #else
 #define dom_shared NULL
 #endif
-- 
2.25.1




[PATCH v1 12/13] xen/arm: defer foreign memory map in shm_init_late

2022-03-10 Thread Penny Zheng
From: Penny Zheng 

This commit introduces a new helper shm_init_late to implement
deferred foreign memory mapping of static shared memory.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain_build.c   | 51 +++
 xen/arch/arm/include/asm/domain.h |  1 +
 xen/arch/arm/setup.c  |  6 
 3 files changed, 58 insertions(+)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 4b19160674..f6ef5a702f 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1006,6 +1006,57 @@ static int __init process_shm(struct domain *d,
 
 return 0;
 }
+
+int __init shm_init_late(void)
+{
+unsigned long i = 0UL, shm_id;
+int ret = 0;
+struct domain *od, **bd = NULL;
+unsigned long o_gfn, b_gfn, nr_gfns;
+
+for ( shm_id = find_first_bit(shm_list_mask, NR_MEM_BANKS);
+  shm_id < NR_MEM_BANKS;
+  shm_id = find_next_bit(shm_list_mask, NR_MEM_BANKS, shm_id + 1) )
+
+{
+/* Acquire the only owner domain. */
+od = get_domain_by_id(shm_list[shm_id].owner_dom);
+if ( od == NULL )
+return -ESRCH;
+o_gfn = PFN_DOWN(shm_list[shm_id].owner_gbase);
+nr_gfns = PFN_DOWN(shm_list[shm_id].size);
+
+bd = xmalloc_array(struct domain *, shm_list[shm_id].nr_borrower);
+if ( !bd )
+return -ENOMEM;
+/* Set up foreign memory map for all borrower domains. */
+for ( i = 0; i < shm_list[shm_id].nr_borrower; i++ )
+{
+bd[i] = get_domain_by_id(shm_list[shm_id].borrower_dom[i]);
+if ( bd[i] == NULL )
+{
+return -ESRCH;
+goto fail;
+}
+
+b_gfn = PFN_DOWN(shm_list[shm_id].borrower_gbase[i]);
+ret = guest_physmap_add_shm(od, bd[i], o_gfn, b_gfn, nr_gfns);
+if ( ret )
+{
+ret = -EINVAL;
+goto fail;
+}
+}
+
+xfree(bd);
+}
+return ret;
+
+ fail:
+xfree(bd);
+
+return ret;
+}
 #endif /* CONFIG_STATIC_SHM */
 #else
 static void __init allocate_static_memory(struct domain *d,
diff --git a/xen/arch/arm/include/asm/domain.h 
b/xen/arch/arm/include/asm/domain.h
index 1c0f2e22ca..c3f2155f5c 100644
--- a/xen/arch/arm/include/asm/domain.h
+++ b/xen/arch/arm/include/asm/domain.h
@@ -58,6 +58,7 @@ typedef struct {
 } shm_info_t;
 extern shm_info_t shm_list[NR_MEM_BANKS];
 extern unsigned long shm_list_mask[BITS_TO_LONGS(NR_MEM_BANKS)];
+extern int shm_init_late(void);
 #else
 #define dom_shared NULL
 #endif
diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
index f6a3b04958..4987b7 100644
--- a/xen/arch/arm/setup.c
+++ b/xen/arch/arm/setup.c
@@ -1051,7 +1051,13 @@ void __init start_xen(unsigned long boot_phys_offset,
 printk(XENLOG_INFO "Xen dom0less mode detected\n");
 
 if ( acpi_disabled )
+{
 create_domUs();
+#ifdef CONFIG_STATIC_SHM
+if ( shm_init_late() )
+panic("Failed to set up deferred foreign memory mapping of static 
shared memory.\n");
+#endif
+}
 
 /*
  * This needs to be called **before** heap_init_late() so modules
-- 
2.25.1




RE: [PATCH v1 02/13] xen/arm: introduce a special domain DOMID_SHARED

2022-03-17 Thread Penny Zheng
Hi Stefano

> -Original Message-
> From: Stefano Stabellini 
> Sent: Friday, March 18, 2022 9:59 AM
> To: Penny Zheng 
> Cc: xen-devel@lists.xenproject.org; nd ; Penny Zheng
> ; Stefano Stabellini
> ; Julien Grall ; Bertrand Marquis
> ; Volodymyr Babchuk
> ; Andrew Cooper
> ; George Dunlap ;
> Jan Beulich ; Wei Liu 
> Subject: Re: [PATCH v1 02/13] xen/arm: introduce a special domain
> DOMID_SHARED
> 
> On Fri, 11 Mar 2022, Penny Zheng wrote:
> > From: Penny Zheng 
> >
> > In case to own statically shared pages when owner domain is not
> > explicitly defined, this commits propose a special domain
> > DOMID_SHARED, and we assign it 0x7FF5, as one of the system domains.
> >
> > Statically shared memory reuses the same way of initialization with
> > static memory, hence this commits proposes a new Kconfig
> > CONFIG_STATIC_SHM to wrap related codes, and this option depends on
> static memory(CONFIG_STATIC_MEMORY).
> 
> Why does it depend on CONFIG_STATIC_MEMORY? This is a genuine question,
> I am not trying to scope-creep the series. Is there an actual technical
> dependency on CONFIG_STATIC_MEMORY? If not, it would be super useful to
> be able to share memory statically even between normal dom0less guests (of
> course it would be responsibility of the user to provide the right addresses 
> and
> avoid mapping clashes.) I know that some of our users have requested this
> feature in the past.
> 

I may find a proper way to rephrase here. My poor English writing skill...
When I implemented domain on static allocation, statically configured guest RAM 
is
treated as static memory in Xen and I introduced a few helpers to 
initialize/allocate/free
static memory, like acquire_staticmem_pages, etc, and all these helpers are 
guarded with
CONFIG_STATIC_MEMORY. 
I want to reuse these helpers on static shared memory, so CONFIG_STATIC_SHM 
depends
on CONFIG_STATIC_MEMORY.

So I'm not restricting sharing static memory between domain on static 
allocation, current
Implementation is also useful to normal dom0less guests.
 
> 
> > We intends to do shared domain creation after setup_virt_paging so
> > shared domain could successfully do p2m initialization.
> >
> > Signed-off-by: Penny Zheng 
> > ---
> >  xen/arch/arm/Kconfig  |  7 +++
> >  xen/arch/arm/domain.c | 12 ++--
> >  xen/arch/arm/include/asm/domain.h |  6 ++
> >  xen/arch/arm/setup.c  | 22 ++
> >  xen/common/domain.c   | 11 +++
> >  xen/common/page_alloc.c   |  5 +
> >  xen/common/vsprintf.c |  9 +
> >  xen/include/public/xen.h  |  6 ++
> >  xen/include/xen/sched.h   |  2 ++
> >  9 files changed, 70 insertions(+), 10 deletions(-)
> >
> > diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index
> > ecfa6822e4..c54accefb1 100644
> > --- a/xen/arch/arm/Kconfig
> > +++ b/xen/arch/arm/Kconfig
> > @@ -106,6 +106,13 @@ config TEE
> >
> >  source "arch/arm/tee/Kconfig"
> >
> > +config STATIC_SHM
> > +   bool "Statically shared memory on a dom0less system" if UNSUPPORTED
> > +   depends on STATIC_MEMORY
> > +   default n
> > +   help
> > + This option enables statically shared memory on a dom0less system.
> > +
> >  endmenu
> >
> >  menu "ARM errata workaround via the alternative framework"
> > diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index
> > 8110c1df86..1ff1df5d3f 100644
> > --- a/xen/arch/arm/domain.c
> > +++ b/xen/arch/arm/domain.c
> > @@ -44,6 +44,10 @@
> >
> >  DEFINE_PER_CPU(struct vcpu *, curr_vcpu);
> >
> > +#ifdef CONFIG_STATIC_SHM
> > +struct domain *__read_mostly dom_shared; #endif
> 
> This one should probably go to xen/common/domain.c to stay close to the
> other special domains.
> 

Ack. Thx

> 
> >  static void do_idle(void)
> >  {
> >  unsigned int cpu = smp_processor_id(); @@ -703,7 +707,7 @@ int
> > arch_domain_create(struct domain *d,
> >  if ( is_idle_domain(d) )
> >  return 0;
> >
> > -ASSERT(config != NULL);
> > +ASSERT(is_shared_domain(d) ? config == NULL : config != NULL);
> >
> >  #ifdef CONFIG_IOREQ_SERVER
> >  ioreq_domain_init(d);
> > @@ -712,12 +716,16 @@ int arch_domain_create(struct domain *d,
> >  d->arch.directmap = flags & CDF_directmap;
> >
> >  /* p2m_init relies on some value initialized by the IOMMU subsystem */
> > -if ( (rc = iommu_domain_init(d, conf

RE: [PATCH v1 03/13] xen/arm: allocate static shared memory to dom_shared

2022-03-18 Thread Penny Zheng
Hi Stefano

> -Original Message-
> From: Stefano Stabellini 
> Sent: Friday, March 18, 2022 10:00 AM
> To: Penny Zheng 
> Cc: xen-devel@lists.xenproject.org; nd ; Stefano Stabellini
> ; Julien Grall ; Bertrand Marquis
> ; Volodymyr Babchuk
> 
> Subject: Re: [PATCH v1 03/13] xen/arm: allocate static shared memory to
> dom_shared
> 
> On Fri, 11 Mar 2022, Penny Zheng wrote:
> > From: Penny Zheng 
> >
> > This commit introduces process_shm to cope with static shared memory
> > in domain construction.
> >
> > This commit only considers allocating static shared memory to
> > dom_shared when owner domain is not explicitly defined in device tree,
> > the other scenario will be covered in the following patches.
> >
> > Static shared memory could reuse acquire_static_memory_bank() to
> > acquire and allocate static memory.
> >
> > Signed-off-by: Penny Zheng 
> > ---
> >  xen/arch/arm/domain_build.c | 116
> > +++-
> >  1 file changed, 115 insertions(+), 1 deletion(-)
> >
> > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> > index 8be01678de..6e6349caac 100644
> > --- a/xen/arch/arm/domain_build.c
> > +++ b/xen/arch/arm/domain_build.c
> > @@ -527,7 +527,8 @@ static mfn_t __init
> acquire_static_memory_bank(struct domain *d,
> >  mfn_t smfn;
> >  int res;
> >
> > -device_tree_get_reg(cell, addr_cells, size_cells, pbase, psize);
> > +if ( cell )
> > +device_tree_get_reg(cell, addr_cells, size_cells, pbase,
> > + psize);
> 
> Why this change?
> 

This helper is also used for acquiring static memory as guest RAM for 
statically configured
domain.

And since we are reusing it for static shared memory, but try to avoid parsing 
the property
here, the "xen,static-shm" property getting parsed in different ways in 
process_shm.
So this change is needed here.

And I think I need to add in-code comment to explain. ;)

> 
> >  ASSERT(IS_ALIGNED(*pbase, PAGE_SIZE) && IS_ALIGNED(*psize,
> PAGE_SIZE));
> >  if ( PFN_DOWN(*psize) > UINT_MAX )
> >  {
> > @@ -751,6 +752,113 @@ static void __init assign_static_memory_11(struct
> domain *d,
> >  panic("Failed to assign requested static memory for direct-map
> domain %pd.",
> >d);
> >  }
> > +
> > +#ifdef CONFIG_STATIC_SHM
> > +static __initdata DECLARE_BITMAP(shm_mask, NR_MEM_BANKS);
> > +
> > +static mfn_t __init acquire_shared_memory_bank(struct domain *d,
> > +   u32 addr_cells, u32 
> > size_cells,
> > +   paddr_t *pbase,
> > +paddr_t *psize) {
> > +/*
> > + * Pages of statically shared memory shall be included
> > + * in domain_tot_pages().
> > + */
> > +d->max_pages += PFN_DOWN(*psize);
> > +
> > +return acquire_static_memory_bank(d, NULL, addr_cells, size_cells,
> > +  pbase, psize);
> > +
> > +}
> > +
> > +static int __init allocate_shared_memory(struct domain *d,
> > + u32 addr_cells, u32 size_cells,
> > + paddr_t pbase, paddr_t psize,
> > + paddr_t gbase) {
> > +mfn_t smfn;
> > +int ret = 0;
> > +
> > +printk(XENLOG_INFO "Allocate static shared memory
> BANK %#"PRIpaddr"-%#"PRIpaddr"\n",
> > +   pbase, pbase + psize);
> > +
> > +smfn = acquire_shared_memory_bank(d, addr_cells, size_cells, &pbase,
> > +  &psize);
> > +if ( mfn_eq(smfn, INVALID_MFN) )
> > +return -EINVAL;
> > +
> > +ret = guest_physmap_add_pages(d, gaddr_to_gfn(gbase), smfn,
> PFN_DOWN(psize));
> > +if ( ret )
> > +{
> > +dprintk(XENLOG_ERR, "Failed to map shared memory to %pd.\n", d);
> > +return ret;
> > +}
> > +
> > +return ret;
> > +}
> > +
> > +static int __init process_shm(struct domain *d,
> > +  const struct dt_device_node *node) {
> > +struct dt_device_node *shm_node;
> > +int ret = 0;
> > +const struct dt_property *prop;
> > +const __be32 *cells;
> > +u32 shm_id;
> > +u32 addr_cells, size_cells;
> > +paddr_t gbase, pbase, psize;
> > +
> > +dt_for_each_chi

RE: [PATCH v1 06/13] xen/arm: set up shared memory foreign mapping for borrower domain

2022-03-28 Thread Penny Zheng
Hi Stefano

Sorry for the late response, got sidetracked an emergency issue. ;/

> -Original Message-
> From: Stefano Stabellini 
> Sent: Friday, March 18, 2022 10:00 AM
> To: Penny Zheng 
> Cc: xen-devel@lists.xenproject.org; nd ; Stefano Stabellini
> ; Julien Grall ; Bertrand Marquis
> ; Volodymyr Babchuk
> 
> Subject: Re: [PATCH v1 06/13] xen/arm: set up shared memory foreign
> mapping for borrower domain
> 
> On Fri, 11 Mar 2022, Penny Zheng wrote:
> > From: Penny Zheng 
> >
> > This commits introduces a new helper guest_physmap_add_shm to set up
> > shared memory foreign mapping for borrower domain.
> >
> > Firstly it should get and take reference of statically shared pages
> > from owner dom_shared. Then it will setup P2M foreign memory map of
> > these statically shared pages for borrower domain.
> >
> > This commits only considers owner domain is the default dom_shared,
> > the other scenario will be covered in the following patches.
> >
> > Signed-off-by: Penny Zheng 
> > ---
> >  xen/arch/arm/domain_build.c | 52
> > +
> >  1 file changed, 52 insertions(+)
> >
> > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> > index 984e70e5fc..8cee5ffbd1 100644
> > --- a/xen/arch/arm/domain_build.c
> > +++ b/xen/arch/arm/domain_build.c
> > @@ -798,6 +798,48 @@ static int __init allocate_shared_memory(struct
> domain *d,
> >  return ret;
> >  }
> >
> > +static int __init guest_physmap_add_shm(struct domain *od, struct domain
> *bd,
> > +unsigned long o_gfn,
> > +unsigned long b_gfn,
> > +unsigned long nr_gfns)
> 
> They should probably be gfn_t type
> 
>
 
Sure, will do.

> > +{
> > +struct page_info **pages = NULL;
> > +p2m_type_t p2mt, t;
> > +int ret = 0;
> > +
> > +pages = xmalloc_array(struct page_info *, nr_gfns);
> > +if ( !pages )
> > +return -ENOMEM;
> > +
> > +/*
> > + * Take reference of statically shared pages from owner domain.
> > + * Reference will be released when destroying shared memory region.
> > + */
> > +ret = get_pages_from_gfn(od, o_gfn, nr_gfns, pages, &p2mt, P2M_ALLOC);
> > +if ( ret )
> > +{
> > +ret = -EINVAL;
> > +goto fail_pages;
> > +}
> > +
> > +if ( p2m_is_ram(p2mt) )
> > +t = (p2mt == p2m_ram_rw) ? p2m_map_foreign_rw :
> p2m_map_foreign_ro;
> > +else
> > +{
> > +ret = -EINVAL;
> > +goto fail_pages;
> > +}
> 
> One idea is to initialize p2mt = p2m_ram_rw and pass it to
> get_pages_from_gfn. Then get_pages_from_gfn can return error immediately
> if any of the pages are of different type.
> 
> This way there is no need for checking again here.
>

Right now, the memory attribute of static shared memory is RW as default,
What if we add memory attribute setting in device tree configuration, sometimes,
Users want to specify that borrower domain only has RO right, hmm, then the
Initialization for p2mt could be either p2m_ram_rw or p2m_ram_ro?
In such case, we could add another parameter in guest_physmap_add_shm to
show the p2m type...
Hope I understand what you suggested here.
 
> 
> > +/* Set up guest foreign map. */
> > +ret = guest_physmap_add_pages(bd, _gfn(b_gfn), page_to_mfn(pages[0]),
> > +  nr_gfns, t);
> > +
> > + fail_pages:
> > +xfree(pages);
> > +
> > +return ret;
> > +}
> > +
> >  static int __init process_shm(struct domain *d,
> >const struct dt_device_node *node)  {
> > @@ -855,6 +897,16 @@ static int __init process_shm(struct domain *d,
> >
> >  set_bit(shm_id, shm_mask);
> >      }
> > +
> > +/*
> > + * All domains are borrower domains when owner domain is the
> > + * default dom_shared, so here we could just set up P2M foreign
> > + * mapping for borrower domain immediately.
> > + */
> > +ret = guest_physmap_add_shm(dom_shared, d, PFN_DOWN(pbase),
> > +PFN_DOWN(gbase), PFN_DOWN(psize));
> > +if ( ret )
> > +return ret;
> >  }
> >
> >  return 0;
> > --
> > 2.25.1
> >

---
Cheers,
Penny Zheng



RE: [PATCH v1 11/13] xen/arm: store shm-info for deferred foreign memory map

2022-03-29 Thread Penny Zheng
Hi Stefano

> -Original Message-
> From: Stefano Stabellini 
> Sent: Friday, March 18, 2022 10:01 AM
> To: Penny Zheng 
> Cc: xen-devel@lists.xenproject.org; nd ; Stefano Stabellini
> ; Julien Grall ; Bertrand Marquis
> ; Volodymyr Babchuk
> 
> Subject: Re: [PATCH v1 11/13] xen/arm: store shm-info for deferred foreign
> memory map
> 
> On Fri, 11 Mar 2022, Penny Zheng wrote:
> > From: Penny Zheng 
> >
> > In a few scenarios where owner domain, is defined after borrower
> > domain in device tree configuration, then statically shared pages
> > haven't been properly allocated if borrower domain tries to do foreign
> > memory map during domain construction.
> >
> > In order to cover such scenario, we defer all borrower domains'
> > foreign memory map after all domain construction finished, then only
> > need to store shm-info during domain construction.
> >
> > Signed-off-by: Penny Zheng 
> > ---
> >  xen/arch/arm/domain.c |  3 +++
> >  xen/arch/arm/domain_build.c   | 34 ++-
> >  xen/arch/arm/include/asm/domain.h | 25 +++
> >  3 files changed, 61 insertions(+), 1 deletion(-)
> >
> > diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index
> > f0bfd67fe5..73ffbfb918 100644
> > --- a/xen/arch/arm/domain.c
> > +++ b/xen/arch/arm/domain.c
> > @@ -47,6 +47,9 @@ DEFINE_PER_CPU(struct vcpu *, curr_vcpu);
> >
> >  #ifdef CONFIG_STATIC_SHM
> >  struct domain *__read_mostly dom_shared;
> > +
> > +shm_info_t shm_list[NR_MEM_BANKS];
> 
> Instead of adding shm_list, maybe we can we re-use mem->bank
> (bootinfo.reserved_mem)?
> 
> It is already storing the physical address and size (added in patch #1 with
> process_shm_node). We should be able to find the other info from the mfn:
> mfn_to_page, page_get_owner, mfn_to_gfn. At most, we need to mark the
> memory bank as shared and we could do that with another field in struct
> membank.
> 
> 
> > +DECLARE_BITMAP(shm_list_mask, NR_MEM_BANKS);
> 
> This is the third bitmask we introduce :-)
> 
> Can we narrow it down to a single bitmask? Maybe we don't need it at all if we
> switch to using bootinfo.mem.bank.
> 
> 
> >  #endif
> >
> >  static void do_idle(void)
> > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> > index 7ee4d33e0b..4b19160674 100644
> > --- a/xen/arch/arm/domain_build.c
> > +++ b/xen/arch/arm/domain_build.c
> > @@ -771,7 +771,7 @@ static mfn_t __init
> > acquire_shared_memory_bank(struct domain *d,
> >
> >  }
> >
> > -static int __init allocate_shared_memory(struct domain *d,
> > +static int __init allocate_shared_memory(struct domain *d, u32
> > +shm_id,
> 
> No need for it to be u32?
> 
> 
> >   u32 addr_cells, u32 size_cells,
> >   paddr_t pbase, paddr_t psize,
> >   paddr_t gbase) @@ -795,6
> > +795,18 @@ static int __init allocate_shared_memory(struct domain *d,
> >  return ret;
> >  }
> >
> > +/*
> > + * If owner domain is not default dom_shared, shm-info of owner domain
> > + * shall also be recorded for later deferred foreign memory map.
> > + */
> > +if ( d != dom_shared )
> > +{
> > +shm_list[shm_id].owner_dom = d->domain_id;
> > +shm_list[shm_id].owner_gbase = gbase;
> > +shm_list[shm_id].size = psize;
> > +set_bit(shm_id, shm_list_mask);
> > +}
> >  return ret;
> >  }
> >
> > @@ -962,6 +974,26 @@ static int __init process_shm(struct domain *d,
> >  if ( ret )
> >  return ret;
> >  }
> > +else
> > +{
> > +if ( strcmp(role_str, "borrower") == 0 )
> > +{
> > +/*
> > + * In a few scenarios where owner domain, is defined after
> > + * borrower domain in device tree configuration, statically
> > + * shared pages haven't been properly allocated if borrower
> > + * domain here tries to do foreign memory map.
> > + * In order to cover such scenario, we defer all borrower
> > + * domains'foreign memory map after all domain construction
> > + * finished, and only store shm-info here for later use.
> > + */
> > +   

[PATCH 0/5] populate/unpopulate memory when domain on static

2022-03-30 Thread Penny Zheng
Today when a domain unpopulates the memory on runtime, they will always
hand the memory over to the heap allocator. And it will be a problem if domain
on static allocation.Since guest RAM for domain on static allocation is
static memory, which is pre-reserved through domain congifuration, it shall
never go back to heap.

This patch serie intends to fix this issue, by keeping page allocated and
storing it in page list when unpopulating memory, and retrieving page from page
list when populating memory.

Penny Zheng (5):
  xen/arm: field "flags" to cover all internal CDF_XXX
  xen/arm: introduce CDF_staticmem
  xen/arm: unpopulate memory when domain on static allocation
  xen/arm: retrieve reserved pages on populate_physmap
  xen/arm: no need to store pages in resv_page_list when domain is
directly mapped

 xen/arch/arm/domain.c |  3 ++-
 xen/arch/arm/domain_build.c   |  5 +++-
 xen/arch/arm/include/asm/domain.h |  7 +++--
 xen/common/domain.c   |  4 +++
 xen/common/memory.c   | 45 ++-
 xen/include/xen/domain.h  |  2 ++
 xen/include/xen/sched.h   |  6 +
 7 files changed, 67 insertions(+), 5 deletions(-)

-- 
2.25.1




[PATCH v1 2/5] xen/arm: introduce CDF_staticmem

2022-03-30 Thread Penny Zheng
In order to have an easy and quick way to find out whether this domain is
on static allocation, this commit introduces a new flag CDF_staticmem and a
new helper is_domain_on_static_allocation.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain_build.c   | 5 -
 xen/arch/arm/include/asm/domain.h | 2 ++
 xen/include/xen/domain.h  | 2 ++
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 8be01678de..4e62fd0bf1 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -3191,9 +3191,12 @@ void __init create_domUs(void)
 if ( !dt_device_is_compatible(node, "xen,domain") )
 continue;
 
+if ( dt_find_property(node, "xen,static-mem", NULL) )
+flags |= CDF_staticmem;
+
 if ( dt_property_read_bool(node, "direct-map") )
 {
-if ( !IS_ENABLED(CONFIG_STATIC_MEMORY) || !dt_find_property(node, 
"xen,static-mem", NULL) )
+if ( !IS_ENABLED(CONFIG_STATIC_MEMORY) || !(flags & CDF_staticmem) 
)
 panic("direct-map is not valid for domain %s without static 
allocation.\n",
   dt_node_name(node));
 
diff --git a/xen/arch/arm/include/asm/domain.h 
b/xen/arch/arm/include/asm/domain.h
index 95fef29111..4379f20a12 100644
--- a/xen/arch/arm/include/asm/domain.h
+++ b/xen/arch/arm/include/asm/domain.h
@@ -31,6 +31,8 @@ enum domain_type {
 
 #define is_domain_direct_mapped(d) (((d)->arch.flags) & CDF_directmap)
 
+#define is_domain_on_static_allocation(d) (((d)->arch.flags) & CDF_staticmem)
+
 /*
  * Is the domain using the host memory layout?
  *
diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h
index 1c3c88a14d..35dc7143a4 100644
--- a/xen/include/xen/domain.h
+++ b/xen/include/xen/domain.h
@@ -34,6 +34,8 @@ void arch_get_domain_info(const struct domain *d,
 #ifdef CONFIG_ARM
 /* Should domain memory be directly mapped? */
 #define CDF_directmap(1U << 1)
+/* Is domain memory on static allocation? */
+#define CDF_staticmem(1U << 2)
 #endif
 
 /*
-- 
2.25.1




[PATCH v1 1/5] xen/arm: field "flags" to cover all internal CDF_XXX

2022-03-30 Thread Penny Zheng
With more and more CDF_xxx internal flags in and to save the space, this
commit introduces a new field "flags" to store CDF_* internal flags
directly.

Another new CDF_xxx will be introduced in the next patch.

Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain.c | 3 ++-
 xen/arch/arm/include/asm/domain.h | 5 +++--
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 8110c1df86..35c157d499 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -709,7 +709,8 @@ int arch_domain_create(struct domain *d,
 ioreq_domain_init(d);
 #endif
 
-d->arch.directmap = flags & CDF_directmap;
+/* Holding CDF_* internal flags. */
+d->arch.flags = flags;
 
 /* p2m_init relies on some value initialized by the IOMMU subsystem */
 if ( (rc = iommu_domain_init(d, config->iommu_opts)) != 0 )
diff --git a/xen/arch/arm/include/asm/domain.h 
b/xen/arch/arm/include/asm/domain.h
index ed63c2b6f9..95fef29111 100644
--- a/xen/arch/arm/include/asm/domain.h
+++ b/xen/arch/arm/include/asm/domain.h
@@ -29,7 +29,7 @@ enum domain_type {
 #define is_64bit_domain(d) (0)
 #endif
 
-#define is_domain_direct_mapped(d) (d)->arch.directmap
+#define is_domain_direct_mapped(d) (((d)->arch.flags) & CDF_directmap)
 
 /*
  * Is the domain using the host memory layout?
@@ -103,7 +103,8 @@ struct arch_domain
 void *tee;
 #endif
 
-bool directmap;
+/* Holding CDF_* constant. Internal flags for domain creation. */
+uint32_t flags;
 }  __cacheline_aligned;
 
 struct arch_vcpu
-- 
2.25.1




[PATCH v1 3/5] xen/arm: unpopulate memory when domain on static allocation

2022-03-30 Thread Penny Zheng
Today when a domain unpopulates the memory on runtime, they will always
hand the memory over to the heap allocator. And it will be a problem if domain
on static allocation.

Guest RAM for domain on static allocation is static memory, which is reserved
to only this domain, so it shall never go back to heap.

For above purpose, this commit tries to keep page allocated and store it
in page list d->resv_page_list on guest_remove_page, when domain on
static allocation.

Signed-off-by: Penny Zheng 
---
 xen/common/domain.c |  4 
 xen/common/memory.c | 22 +-
 xen/include/xen/sched.h |  6 ++
 3 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/xen/common/domain.c b/xen/common/domain.c
index 351029f8b2..e572f27fce 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -602,6 +602,10 @@ struct domain *domain_create(domid_t domid,
 INIT_PAGE_LIST_HEAD(&d->page_list);
 INIT_PAGE_LIST_HEAD(&d->extra_page_list);
 INIT_PAGE_LIST_HEAD(&d->xenpage_list);
+#ifdef CONFIG_STATIC_MEMORY
+INIT_PAGE_LIST_HEAD(&d->resv_page_list);
+#endif
+
 
 spin_lock_init(&d->node_affinity_lock);
 d->node_affinity = NODE_MASK_ALL;
diff --git a/xen/common/memory.c b/xen/common/memory.c
index 69b0cd1e50..2afc3c6f10 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -35,6 +35,10 @@
 #include 
 #endif
 
+#ifndef is_domain_on_static_allocation
+#define is_domain_on_static_allocation(d) 0
+#endif
+
 struct memop_args {
 /* INPUT */
 struct domain *domain; /* Domain to be affected. */
@@ -405,13 +409,29 @@ int guest_remove_page(struct domain *d, unsigned long 
gmfn)
  * device must retrieve the same pfn when the hypercall populate_physmap
  * is called.
  *
+ * When domain on static allocation, they should always get pages from the
+ * reserved static region when the hypercall populate_physmap is called.
+ *
  * For this purpose (and to match populate_physmap() behavior), the page
  * is kept allocated.
  */
-if ( !rc && !is_domain_direct_mapped(d) )
+if ( !rc && !(is_domain_direct_mapped(d) ||
+  is_domain_on_static_allocation(d)) )
 put_page_alloc_ref(page);
 
 put_page(page);
+#ifdef CONFIG_STATIC_MEMORY
+/*
+ * When domain on static allocation, we shall store pages to 
resv_page_list,
+ * so the hypercall populate_physmap could retrieve pages from it,
+ * rather than allocating from heap.
+ */
+if ( is_domain_on_static_allocation(d) )
+{
+page_list_add_tail(page, &d->resv_page_list);
+d->resv_pages++;
+}
+#endif
 
 #ifdef CONFIG_X86
  out_put_gfn:
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 406d9bc610..d7e047bf36 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -376,6 +376,9 @@ struct domain
 struct page_list_head page_list;  /* linked list */
 struct page_list_head extra_page_list; /* linked list (size extra_pages) */
 struct page_list_head xenpage_list; /* linked list (size xenheap_pages) */
+#ifdef CONFIG_STATIC_MEMORY
+struct page_list_head resv_page_list; /* linked list (size resv_pages) */
+#endif
 
 /*
  * This field should only be directly accessed by domain_adjust_tot_pages()
@@ -389,6 +392,9 @@ struct domain
 unsigned int extra_pages;   /* pages not included in 
domain_tot_pages() */
 atomic_t shr_pages; /* shared pages */
 atomic_t paged_pages;   /* paged-out pages */
+#ifdef CONFIG_STATIC_MEMORY
+unsigned int resv_pages;/* reserved pages from static region. 
*/
+#endif
 
 /* Scheduling. */
 void*sched_priv;/* scheduler-specific data */
-- 
2.25.1




[PATCH v1 5/5] xen/arm: no need to store pages in resv_page_list when domain is directly mapped

2022-03-30 Thread Penny Zheng
When domain on static allocation and is directly mapped, in terms of
GPA == HPA(guest physical address == host physical address), we could use
mfn_to_page() to easily find the page, so there is no need to store pages
in resv_page_list.

Signed-off-by: Penny Zheng 
---
 xen/common/memory.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/xen/common/memory.c b/xen/common/memory.c
index 2122ceeba7..2865e09a33 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -445,8 +445,11 @@ int guest_remove_page(struct domain *d, unsigned long gmfn)
  * When domain on static allocation, we shall store pages to 
resv_page_list,
  * so the hypercall populate_physmap could retrieve pages from it,
  * rather than allocating from heap.
+ * No need to store pages in resv_page_list when domain on static
+ * allocation and directly mapped, since we could use mfn_to_page() to
+ * easily find the page.
  */
-if ( is_domain_on_static_allocation(d) )
+if ( is_domain_on_static_allocation(d) && !is_domain_direct_mapped(d) )
 {
 page_list_add_tail(page, &d->resv_page_list);
 d->resv_pages++;
-- 
2.25.1




[PATCH v1 4/5] xen/arm: retrieve reserved pages on populate_physmap

2022-03-30 Thread Penny Zheng
When domain on static allocation populates memory through populate_physmap,
other than allocating from heap, it shall allocate from resv_page_list to
make sure that all guest RAM are still restricted in statically configured
regions.

Signed-off-by: Penny Zheng 
---
 xen/common/memory.c | 20 
 1 file changed, 20 insertions(+)

diff --git a/xen/common/memory.c b/xen/common/memory.c
index 2afc3c6f10..2122ceeba7 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -249,6 +249,26 @@ static void populate_physmap(struct memop_args *a)
 
 mfn = _mfn(gpfn);
 }
+#ifdef CONFIG_STATIC_MEMORY
+else if ( is_domain_on_static_allocation(d) )
+{
+for ( j = 0; j < (1U << a->extent_order); j++ )
+{
+page = page_list_remove_head(&d->resv_page_list);
+if ( unlikely(!page) )
+{
+gdprintk(XENLOG_INFO,
+ "Could not allocate guest page number %lx\n",
+ gfn_x(_gfn(gpfn)));
+goto out;
+}
+d->resv_pages--;
+
+if ( j == 0 )
+mfn = page_to_mfn(page);
+}
+}
+#endif
 else
 {
 page = alloc_domheap_pages(d, a->extent_order, a->memflags);
-- 
2.25.1




RE: [PATCH v1 3/5] xen/arm: unpopulate memory when domain on static allocation

2022-03-30 Thread Penny Zheng
Hi Jan

> -Original Message-
> From: Jan Beulich 
> Sent: Wednesday, March 30, 2022 5:53 PM
> To: Penny Zheng 
> Cc: Wei Chen ; Henry Wang ;
> Andrew Cooper ; George Dunlap
> ; Julien Grall ; Stefano Stabellini
> ; Wei Liu ; xen-
> de...@lists.xenproject.org
> Subject: Re: [PATCH v1 3/5] xen/arm: unpopulate memory when domain on
> static allocation
> 
> On 30.03.2022 11:36, Penny Zheng wrote:
> > --- a/xen/common/memory.c
> > +++ b/xen/common/memory.c
> > @@ -35,6 +35,10 @@
> >  #include 
> >  #endif
> >
> > +#ifndef is_domain_on_static_allocation #define
> > +is_domain_on_static_allocation(d) 0
> 
> Nit: "false", not "0".
> 
> > @@ -405,13 +409,29 @@ int guest_remove_page(struct domain *d,
> unsigned long gmfn)
> >   * device must retrieve the same pfn when the hypercall
> populate_physmap
> >   * is called.
> >   *
> > + * When domain on static allocation, they should always get pages from
> the
> > + * reserved static region when the hypercall populate_physmap is 
> > called.
> > + *
> >   * For this purpose (and to match populate_physmap() behavior), the 
> > page
> >   * is kept allocated.
> >   */
> > -if ( !rc && !is_domain_direct_mapped(d) )
> > +if ( !rc && !(is_domain_direct_mapped(d) ||
> > +  is_domain_on_static_allocation(d)) )
> >  put_page_alloc_ref(page);
> >
> >  put_page(page);
> > +#ifdef CONFIG_STATIC_MEMORY
> > +/*
> > + * When domain on static allocation, we shall store pages to
> resv_page_list,
> > + * so the hypercall populate_physmap could retrieve pages from it,
> > + * rather than allocating from heap.
> > + */
> > +if ( is_domain_on_static_allocation(d) )
> > +{
> > +page_list_add_tail(page, &d->resv_page_list);
> > +d->resv_pages++;
> > +}
> > +#endif
> 
> I think this is wrong, as a result of not integrating with put_page().
> The page should only go on that list once its last ref was dropped. I don't 
> recall
> for sure, but iirc staticmem pages are put on the domain's page list just like
> other pages would be. But then you also corrupt the list when this isn't the 
> last
> ref which is put.

Yes, staticmem pages are put on the domain's page list.
Here, I tried to only destroy the P2M mapping, and keep the page still allocated
to this domain.
resv_page_list is just providing an easy way to track down the unpopulated 
memory. 
'''
But then you also corrupt the list when this isn't the last
ref which is put.
'''
I'm sorry, would you like to be more specific on this comment?
I want these pages to linked in the domain's page list, then it could be
freed properly when domain get destroyed through relinquish_memory.

> 
> As a result I also think that you shouldn't need to touch the earlier if().
> 
> Jan



RE: [PATCH v1 4/5] xen/arm: retrieve reserved pages on populate_physmap

2022-03-30 Thread Penny Zheng
Hi Jan

> -Original Message-
> From: Jan Beulich 
> Sent: Wednesday, March 30, 2022 5:59 PM
> To: Penny Zheng 
> Cc: Wei Chen ; Henry Wang ;
> Andrew Cooper ; George Dunlap
> ; Julien Grall ; Stefano Stabellini
> ; Wei Liu ; xen-
> de...@lists.xenproject.org
> Subject: Re: [PATCH v1 4/5] xen/arm: retrieve reserved pages on
> populate_physmap
> 
> On 30.03.2022 11:36, Penny Zheng wrote:
> > --- a/xen/common/memory.c
> > +++ b/xen/common/memory.c
> > @@ -249,6 +249,26 @@ static void populate_physmap(struct memop_args
> *a)
> >
> >  mfn = _mfn(gpfn);
> >  }
> > +#ifdef CONFIG_STATIC_MEMORY
> > +else if ( is_domain_on_static_allocation(d) )
> > +{
> > +for ( j = 0; j < (1U << a->extent_order); j++ )
> > +{
> > +page = page_list_remove_head(&d->resv_page_list);
> 
> How do you guarantee the pages are contiguous, as required by a non-zero
> a->extent_order? Did you perhaps mean to forbid non-zero-order requests
> in this configuration?,

True, true, thanks for pointing that out.
I would not intend to add complex algorithm here to find contiguous pages of 
requested
order, forbidding non-zero-order with error message shall be added here.

> 
> > +if ( unlikely(!page) )
> > +{
> > +gdprintk(XENLOG_INFO,
> > + "Could not allocate guest page number 
> > %lx\n",
> > + gfn_x(_gfn(gpfn)));
> > +goto out;
> 
> And earlier allocated pages are simply lost / leaked?
> 

That was unconsidered, thanks for pointing that out.
Since now we are forbidding non-zero-order requests, earlier allocated pages 
shall
not need to be considered.
 
> Jan



RE: [PATCH v1 3/5] xen/arm: unpopulate memory when domain on static allocation

2022-03-31 Thread Penny Zheng
Hi Jan 

> -Original Message-
> From: Jan Beulich 
> Sent: Thursday, March 31, 2022 3:06 PM
> To: Penny Zheng 
> Cc: Wei Chen ; Henry Wang ;
> Andrew Cooper ; George Dunlap
> ; Julien Grall ; Stefano Stabellini
> ; Wei Liu ; xen-
> de...@lists.xenproject.org
> Subject: Re: [PATCH v1 3/5] xen/arm: unpopulate memory when domain on
> static allocation
> 
> On 31.03.2022 08:13, Penny Zheng wrote:
> > Hi Jan
> >
> >> -Original Message-
> >> From: Jan Beulich 
> >> Sent: Wednesday, March 30, 2022 5:53 PM
> >> To: Penny Zheng 
> >> Cc: Wei Chen ; Henry Wang
> ;
> >> Andrew Cooper ; George Dunlap
> >> ; Julien Grall ; Stefano
> >> Stabellini ; Wei Liu ; xen-
> >> de...@lists.xenproject.org
> >> Subject: Re: [PATCH v1 3/5] xen/arm: unpopulate memory when domain on
> >> static allocation
> >>
> >> On 30.03.2022 11:36, Penny Zheng wrote:
> >>> --- a/xen/common/memory.c
> >>> +++ b/xen/common/memory.c
> >>> @@ -35,6 +35,10 @@
> >>>  #include 
> >>>  #endif
> >>>
> >>> +#ifndef is_domain_on_static_allocation #define
> >>> +is_domain_on_static_allocation(d) 0
> >>
> >> Nit: "false", not "0".
> >>
> >>> @@ -405,13 +409,29 @@ int guest_remove_page(struct domain *d,
> >> unsigned long gmfn)
> >>>   * device must retrieve the same pfn when the hypercall
> >> populate_physmap
> >>>   * is called.
> >>>   *
> >>> + * When domain on static allocation, they should always get
> >>> + pages from
> >> the
> >>> + * reserved static region when the hypercall populate_physmap is
> called.
> >>> + *
> >>>   * For this purpose (and to match populate_physmap() behavior), the
> page
> >>>   * is kept allocated.
> >>>   */
> >>> -if ( !rc && !is_domain_direct_mapped(d) )
> >>> +if ( !rc && !(is_domain_direct_mapped(d) ||
> >>> +  is_domain_on_static_allocation(d)) )
> >>>  put_page_alloc_ref(page);
> >>>
> >>>  put_page(page);
> >>> +#ifdef CONFIG_STATIC_MEMORY
> >>> +/*
> >>> + * When domain on static allocation, we shall store pages to
> >> resv_page_list,
> >>> + * so the hypercall populate_physmap could retrieve pages from it,
> >>> + * rather than allocating from heap.
> >>> + */
> >>> +if ( is_domain_on_static_allocation(d) )
> >>> +{
> >>> +page_list_add_tail(page, &d->resv_page_list);
> >>> +d->resv_pages++;
> >>> +}
> >>> +#endif
> >>
> >> I think this is wrong, as a result of not integrating with put_page().
> >> The page should only go on that list once its last ref was dropped. I
> >> don't recall for sure, but iirc staticmem pages are put on the
> >> domain's page list just like other pages would be. But then you also
> >> corrupt the list when this isn't the last ref which is put.
> >
> > Yes, staticmem pages are put on the domain's page list.
> > Here, I tried to only destroy the P2M mapping, and keep the page still
> > allocated to this domain.
> 
> Well, much depends on what you call "allocated". For populate_physmap you
> then take pages from resv_page_list. So I'd like to distinguish "allocated" 
> from
> "reserved": The pages are allocated to the domain when they're on the normal
> page list; they're reserved when they're on the new list you introduce. And
> what you want to initiate here is an "allocated" -> "reserved" transition.
> 
> > resv_page_list is just providing an easy way to track down the unpopulated
> memory.
> > '''
> > But then you also corrupt the list when this isn't the last ref which
> > is put.
> > '''
> > I'm sorry, would you like to be more specific on this comment?
> > I want these pages to linked in the domain's page list, then it could
> > be freed properly when domain get destroyed through relinquish_memory.
> 
> Clearly they can't be on both lists. Hence you can put them on the new list
> only _after_ having taken them off the "normal" list. That "taking off the
> normal list" should happen when the last ref is droppe

RE: [PATCH v1 3/5] xen/arm: unpopulate memory when domain on static allocation

2022-04-02 Thread Penny Zheng
Hi Julien and Jan

> -Original Message-
> From: Julien Grall 
> Sent: Saturday, April 2, 2022 2:54 AM
> To: Penny Zheng ; Jan Beulich 
> Cc: Wei Chen ; Henry Wang ;
> Andrew Cooper ; George Dunlap
> ; Stefano Stabellini ; Wei
> Liu ; xen-devel@lists.xenproject.org
> Subject: Re: [PATCH v1 3/5] xen/arm: unpopulate memory when domain on
> static allocation
> 
> Hi Penny,
> 
> On 31/03/2022 11:30, Penny Zheng wrote:
> > Another reason I want to keep page allocated is that if putting pages
> > in resv_page_list upon dropping the last ref, we need to do a lot
> > things on pages to totally let it free, like set its owner to NULL,
> > changing page state from in_use to free, etc.
> This is not only about optimization here. Bad things can happen if you let a
> page in state free that is not meant to be used by the buddy allocator (e.g. 
> it
> was reserved for static memory).
> 
> I discovered it earlier this year when trying to optimize
> init_heap_pages() for Live-Update. It was quite hard to debug because the
> corruption very rarely happened. So let me explain it before you face the same
> issue :).
> 
> free_heap_pages() will try to merge the about-to-be-freed chunk with the
> predecessor and/or successor. To know if the page can be merged, the
> algorithm is looking at whether the chunk is suitably aligned (e.g. same
> order) and if the page is in state free.
> 
> AFAICT, the pages belonging to the buddy allocator could be right next to
> region reserved memory. So there is a very slim chance that
> free_heap_pages() may decide to merge a chunk from the static region with
> the about-to-be-free chunk. Nothing very good will ensue.
> 

Oh,,, that's a thousand true.
If the free static region is the buddy of the about-to-be-free chunk, current
code will merge the static region to the heap, which is unacceptable.

I'll fix it in this patch serie too and I'm also preferring option 1~

And for unpopulating memory on runtime, I'll do what Jan suggests,
adding a new logic of moving the page from d->page_list to
d->resv_page_list in arch_free_heap_page() for reserved pages. 

> Technically, this is already a bug in the already merged implementation of the
> static memory allocator.
> 
> I can see two ways to fix it:
>1) Update free_heap_pages() to check whether the page has PGC_reserved
> set.
>2) Use a different state for pages used by the static allocator.
> 
> So far my preference is leaning towards 1. But I would like to hear other
> opinions.
> 
> Cheers,
> 
> --
> Julien Grall


RE: [PATCH v1 02/13] xen/arm: introduce a special domain DOMID_SHARED

2022-04-15 Thread Penny Zheng
Hi Julien and Stefano

> -Original Message-
> From: Julien Grall 
> Sent: Saturday, April 9, 2022 5:12 PM
> To: Stefano Stabellini ; Jan Beulich
> 
> Cc: Penny Zheng ; nd ; Penny Zheng
> ; Bertrand Marquis
> ; Volodymyr Babchuk
> ; Andrew Cooper
> ; George Dunlap ;
> Wei Liu ; xen-devel@lists.xenproject.org
> Subject: Re: [PATCH v1 02/13] xen/arm: introduce a special domain
> DOMID_SHARED
> 
> Hi Stefano,
> 
> On 21/03/2022 20:03, Stefano Stabellini wrote:
> > On Mon, 21 Mar 2022, Jan Beulich wrote:
> >> On 18.03.2022 22:50, Stefano Stabellini wrote:
> >>> On Fri, 18 Mar 2022, Jan Beulich wrote:
> >>>> On 11.03.2022 07:11, Penny Zheng wrote:
> >>>>> In case to own statically shared pages when owner domain is not
> >>>>> explicitly defined, this commits propose a special domain
> >>>>> DOMID_SHARED, and we assign it 0x7FF5, as one of the system domains.
> >>>>>
> >>>>> Statically shared memory reuses the same way of initialization
> >>>>> with static memory, hence this commits proposes a new Kconfig
> >>>>> CONFIG_STATIC_SHM to wrap related codes, and this option depends
> on static memory(CONFIG_STATIC_MEMORY).
> >>>>>
> >>>>> We intends to do shared domain creation after setup_virt_paging so
> >>>>> shared domain could successfully do p2m initialization.
> >>>>
> >>>> There's nothing said here, in the earlier patch, or in the cover
> >>>> letter about the security aspects of this. There is a reason we
> >>>> haven't been allowing arbitrary, un-supervised sharing of memory
> >>>> between domains. It wants clarifying why e.g. grants aren't an
> >>>> option to achieve what you need, and how you mean to establish
> >>>> which domains are / aren't permitted to access any individual page
> owned by this domain.
> >>>
> >>>
> >>> I'll let Penny write a full reply but I'll chime in to try to help
> >>> with the explanation.
> >>>
> >>> This is not arbitrary un-supervised sharing of memory between
> >>> domains, which indeed is concerning.
> >>>
> >>> This is statically-configured, supervised by the system
> >>> configurator, sharing of memory between domains.
> >>>
> >>> And in fact safety (which is just a different aspect of security) is
> >>> one of the primary goals for this work.
> >>>
> >>> In safety-critical environments, it is not considered safe to
> >>> dynamically change important configurations at runtime. Everything
> >>> should be statically defined and statically verified.
> >>>
> >>> In this case, if the system configuration knows a priori that there
> >>> are only 2 VM and they need to communication over shared memory, it
> >>> is safer to pre-configure the shared memory at build time rather
> >>> than let the VMs attempt to share memory at runtime. It is faster too.
> >>>
> >>> The only way to trigger this static shared memory configuration
> >>> should be via device tree, which is at the same level as the XSM
> >>> rules themselves.
> >>>
> >>> Hopefully I made things clearer and not murkier :-)
> >>
> >> It adds some helpful background, yes, but at the same time it doesn't
> >> address the security concern at all: How are access permissions
> >> managed when the owning domain is a special one? I haven't spotted
> >> any recording of the domains which are actually permitted to map /
> >> access the pages in questions. (But of course I also only looked at
> >> non-Arm-specific code. I'd expect such code not to live in arch-
> >> specific files.)
> >
> > All this static memory sharing is statically done at __init time only.
> > It should not be possible to trigger any further memory sharing at
> > runtime (if there is, that would be a bug).
> 
> Looking at the code, get_pg_owner() will be able to handle DOMID_SHARED.
> So anyone that is permitted to access DOMID_SHARED will be able to map any
> memory region at runtime.
> 
> > There are no new interfaces for the guest to map this memory because
> > it is already "pre-mapped".
> 
> It can via XENMAPSPACE_gmfn_foreign (assuming proper permission).
> 

Correct me if I'm wrong:
The existing XENMAPSPACE_gmfn_foreign only allows privileged Dom0 to map
memory pages from one foreign DomU to itself. So It can happen that Dom0 is
using XENMAPSPACE_gmfn_foreign to (maliciously?) access shared memory owned
by DOMID_SHARED, and for now only Dom0 could.

So, maybe we should enhance the check of xsm_map_gmfn_foreign() to forbid the
access to DOMID_SHARED, hmm, but static shared memory region could actually be 
owned
by any arbitrary domain.

So, how about we add restriction on the page itself?
Pages of static shared memory region are static memory(with PGC_reserved flag 
on),
so maybe we could restrict XENMAPSPACE_gmfn_foreign to access any PGC_reserved 
pages?

> Cheers,
> 
> --

Cheers,

--
Penny Zheng
> Julien Grall


RE: [PATCH v1 02/13] xen/arm: introduce a special domain DOMID_SHARED

2022-04-15 Thread Penny Zheng
Hi jan 

> -Original Message-
> From: Jan Beulich 
> Sent: Friday, March 18, 2022 4:53 PM
> To: Penny Zheng 
> Cc: nd ; Penny Zheng
> ; Stefano Stabellini
> ; Julien Grall ; Bertrand Marquis
> ; Volodymyr Babchuk
> ; Andrew Cooper
> ; George Dunlap ;
> Wei Liu ; xen-devel@lists.xenproject.org
> Subject: Re: [PATCH v1 02/13] xen/arm: introduce a special domain
> DOMID_SHARED
> 
> On 11.03.2022 07:11, Penny Zheng wrote:
> > In case to own statically shared pages when owner domain is not
> > explicitly defined, this commits propose a special domain
> > DOMID_SHARED, and we assign it 0x7FF5, as one of the system domains.
> >
> > Statically shared memory reuses the same way of initialization with
> > static memory, hence this commits proposes a new Kconfig
> > CONFIG_STATIC_SHM to wrap related codes, and this option depends on
> static memory(CONFIG_STATIC_MEMORY).
> >
> > We intends to do shared domain creation after setup_virt_paging so
> > shared domain could successfully do p2m initialization.
> 
> There's nothing said here, in the earlier patch, or in the cover letter about 
> the
> security aspects of this. There is a reason we haven't been allowing 
> arbitrary,
> un-supervised sharing of memory between domains. It wants clarifying why e.g.
> grants aren't an option to achieve what you need, and how you mean to
> establish which domains are / aren't permitted to access any individual page
> owned by this domain.
> 

I'll add the security aspects what Stefano explains in the cover letter next 
serie
for better understanding.

> > --- a/xen/arch/arm/Kconfig
> > +++ b/xen/arch/arm/Kconfig
> > @@ -106,6 +106,13 @@ config TEE
> >
> >  source "arch/arm/tee/Kconfig"
> >
> > +config STATIC_SHM
> > +   bool "Statically shared memory on a dom0less system" if UNSUPPORTED
> > +   depends on STATIC_MEMORY
> > +   default n
> 
> Nit: "default n" is redundant and hence would imo better be omitted.
> 
> > @@ -712,12 +716,16 @@ int arch_domain_create(struct domain *d,
> >  d->arch.directmap = flags & CDF_directmap;
> >
> >  /* p2m_init relies on some value initialized by the IOMMU subsystem */
> > -if ( (rc = iommu_domain_init(d, config->iommu_opts)) != 0 )
> > +if ( (rc = iommu_domain_init(d, is_shared_domain(d) ? 0 :
> > + config->iommu_opts)) != 0 )
> 
> Nit: Overlong line.
> 
> > --- a/xen/arch/arm/setup.c
> > +++ b/xen/arch/arm/setup.c
> > @@ -855,6 +855,20 @@ static bool __init is_dom0less_mode(void)
> >  return ( !dom0found && domUfound );  }
> >
> > +#ifdef CONFIG_STATIC_SHM
> > +static void __init setup_shared_domain(void) {
> > +/*
> > + * Initialise our DOMID_SHARED domain.
> > + * This domain owns statically shared pages when owner domain is not
> > + * explicitly defined.
> > + */
> > +dom_shared = domain_create(DOMID_SHARED, NULL, CDF_directmap);
> > +if ( IS_ERR(dom_shared) )
> > +panic("Failed to create d[SHARED]: %ld\n",
> > +PTR_ERR(dom_shared));
> 
> I don't think this should be a panic - the system ought to be able to come up
> fine, just without actually using this domain. After all this is an optional
> feature which may not actually be used.
> 
> Also, along the lines of what Stefano has said, this setting up of the domain
> would also better live next to where the other special domains are set up. And
> even if it was to remain here, ...
> 

The reason why I place the setting up here is that DOMID_SHARED needs to map
pre-configured static shared memory in its p2m table, so it must be set up
after system P2M initialization(setup_virt_paging()). setup_system_domains()
is called before system P2M initialization on xen/arch/arm/setup.c, which
can't meet the requirement.

> > @@ -1022,6 +1036,14 @@ void __init start_xen(unsigned long
> boot_phys_offset,
> >  apply_alternatives_all();
> >  enable_errata_workarounds();
> >
> > +#ifdef CONFIG_STATIC_SHM
> > +/*
> > + * This needs to be called **after** setup_virt_paging so shared
> > + * domains could successfully do p2m initialization.
> > + */
> > +setup_shared_domain();
> > +#endif
> 
> ... the #ifdef-ary here should be avoided by moving the other #ifdef inside 
> the
> function body.
> 
> > --- a/xen/common/domain.c
> > +++ b/xen/common/domain.c
> > @@ -643,11 +643,14 @@ struct domain *domain_create(domid_t domid,
> >
> >  rangeset_domain_initialise(d);

[PATCH v2 1/6] xen/arm: do not free reserved memory into heap

2022-04-18 Thread Penny Zheng
Pages as guest RAM for static domain, shall be reserved to this domain only.
So in case reserved pages being used for other purpose, users
shall not free them back to heap, even when last ref gets dropped.

free_staticmem_pages will be called by free_domheap_pages in runtime
for static domain freeing memory resource, so let's drop the __init
flag.

Signed-off-by: Penny Zheng 
---
v2 changes:
- new commit
---
 xen/common/page_alloc.c | 10 --
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 319029140f..9a3e9c1328 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -2488,7 +2488,13 @@ void free_domheap_pages(struct page_info *pg, unsigned 
int order)
 scrub = 1;
 }
 
-free_heap_pages(pg, order, scrub);
+#ifdef CONFIG_STATIC_MEMORY
+if ( pg->count_info & PGC_reserved )
+/* Reserved page shall not go back to the heap. */
+free_staticmem_pages(pg, 1 << order, scrub);
+else
+#endif
+free_heap_pages(pg, order, scrub);
 }
 
 if ( drop_dom_ref )
@@ -2636,7 +2642,7 @@ struct domain *get_pg_owner(domid_t domid)
 
 #ifdef CONFIG_STATIC_MEMORY
 /* Equivalent of free_heap_pages to free nr_mfns pages of static memory. */
-void __init free_staticmem_pages(struct page_info *pg, unsigned long nr_mfns,
+void free_staticmem_pages(struct page_info *pg, unsigned long nr_mfns,
  bool need_scrub)
 {
 mfn_t mfn = page_to_mfn(pg);
-- 
2.25.1




[PATCH V2 0/6] populate/unpopulate memory when domain on static

2022-04-18 Thread Penny Zheng
Today when a domain unpopulates the memory on runtime, they will always
hand the memory over to the heap allocator. And it will be a problem if it
is a static domain. Pages as guest RAM for static domain shall always be
reserved to only this domain and not be used for any other purposes, so
they shall never go back to heap allocator.

This patch serie intends to fix this issue, by adding pages on the new list
resv_page_list after having taken them off the "normal" list, when unpopulating
memory, and retrieving pages from resv page list(resv_page_list) when
populating memory.

---
v2 changes:
- let "flags" live in the struct domain. So other arch can take
advantage of it in the future
- change name from "is_domain_on_static_allocation" to "is_domain_static()"
- put reserved pages on resv_page_list after having taken them off
the "normal" list
- introduce acquire_reserved_page to retrieve reserved pages from
resv_page_list
- forbid non-zero-order requests in populate_physmap
- let is_domain_static return ((void)(d), false) on x86
- fix coding style

Penny Zheng (6):
  xen/arm: do not free reserved memory into heap
  xen/arm: do not merge reserved pages in free_heap_pages()
  xen: add field "flags" to cover all internal CDF_XXX
  xen/arm: introduce CDF_staticmem
  xen/arm: unpopulate memory when domain is static
  xen/arm: retrieve reserved pages on populate_physmap

 xen/arch/arm/domain.c |  2 --
 xen/arch/arm/domain_build.c   |  5 +++-
 xen/arch/arm/include/asm/domain.h |  5 ++--
 xen/arch/arm/include/asm/mm.h | 17 +
 xen/common/domain.c   |  7 ++
 xen/common/memory.c   | 29 ++
 xen/common/page_alloc.c   | 40 +--
 xen/include/xen/domain.h  |  2 ++
 xen/include/xen/mm.h  |  1 +
 xen/include/xen/sched.h   |  9 +++
 10 files changed, 110 insertions(+), 7 deletions(-)

-- 
2.25.1




[PATCH v2 2/6] xen/arm: do not merge reserved pages in free_heap_pages()

2022-04-18 Thread Penny Zheng
There is a slim chance that free_heap_pages() may decide to merge a chunk
from the static region(PGC_reserved) with the about-to-be-free chunk.

So in order to avoid the above scenario, this commit updates free_heap_pages()
to check whether the predecessor and/or successor has PGC_reserved set,
when trying to merge the about-to-be-freed chunk with the predecessor
and/or successor.

Signed-off-by: Penny Zheng 
---
v2 changes:
- new commit
---
 xen/common/page_alloc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 9a3e9c1328..8ba38bca9a 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -1479,6 +1479,7 @@ static void free_heap_pages(
 /* Merge with predecessor block? */
 if ( !mfn_valid(page_to_mfn(predecessor)) ||
  !page_state_is(predecessor, free) ||
+ (predecessor->count_info & PGC_reserved) ||
  (PFN_ORDER(predecessor) != order) ||
  (phys_to_nid(page_to_maddr(predecessor)) != node) )
 break;
@@ -1502,6 +1503,7 @@ static void free_heap_pages(
 /* Merge with successor block? */
 if ( !mfn_valid(page_to_mfn(successor)) ||
  !page_state_is(successor, free) ||
+ (successor->count_info & PGC_reserved) ||
  (PFN_ORDER(successor) != order) ||
  (phys_to_nid(page_to_maddr(successor)) != node) )
 break;
-- 
2.25.1




[PATCH v2 5/6] xen/arm: unpopulate memory when domain is static

2022-04-18 Thread Penny Zheng
Today when a domain unpopulates the memory on runtime, they will always
hand the memory back to the heap allocator. And it will be a problem if domain
is static.

Pages as guest RAM for static domain shall be reserved to only this domain
and not be used for any other purposes, so they shall never go back to heap
allocator.

This commit puts reserved pages on the new list resv_page_list only after
having taken them off the "normal" list, when the last ref dropped.

Signed-off-by: Penny Zheng 
---
v2 changes:
- put reserved pages on resv_page_list after having taken them off
the "normal" list
---
 xen/arch/arm/include/asm/mm.h | 17 +
 xen/common/domain.c   |  4 
 xen/include/xen/sched.h   |  6 ++
 3 files changed, 27 insertions(+)

diff --git a/xen/arch/arm/include/asm/mm.h b/xen/arch/arm/include/asm/mm.h
index 424aaf2823..a2dde01cfa 100644
--- a/xen/arch/arm/include/asm/mm.h
+++ b/xen/arch/arm/include/asm/mm.h
@@ -358,6 +358,23 @@ void clear_and_clean_page(struct page_info *page);
 
 unsigned int arch_get_dma_bitsize(void);
 
+/*
+ * Put free pages on the resv page list after having taken them
+ * off the "normal" page list, when pages from static memory
+ */
+#ifdef CONFIG_STATIC_MEMORY
+#define arch_free_heap_page(d, pg) {\
+if ( (pg)->count_info & PGC_reserved )  \
+{   \
+page_list_del(pg, page_to_list(d, pg)); \
+page_list_add_tail(pg, &(d)->resv_page_list);   \
+(d)->resv_pages++;  \
+}   \
+else\
+page_list_del(pg, page_to_list(d, pg)); \
+}
+#endif
+
 #endif /*  __ARCH_ARM_MM__ */
 /*
  * Local variables:
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 859cc13d3b..b499cf8d2c 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -605,6 +605,10 @@ struct domain *domain_create(domid_t domid,
 INIT_PAGE_LIST_HEAD(&d->page_list);
 INIT_PAGE_LIST_HEAD(&d->extra_page_list);
 INIT_PAGE_LIST_HEAD(&d->xenpage_list);
+#ifdef CONFIG_STATIC_MEMORY
+INIT_PAGE_LIST_HEAD(&d->resv_page_list);
+#endif
+
 
 spin_lock_init(&d->node_affinity_lock);
 d->node_affinity = NODE_MASK_ALL;
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 68eb08058e..85ef378752 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -376,6 +376,9 @@ struct domain
 struct page_list_head page_list;  /* linked list */
 struct page_list_head extra_page_list; /* linked list (size extra_pages) */
 struct page_list_head xenpage_list; /* linked list (size xenheap_pages) */
+#ifdef CONFIG_STATIC_MEMORY
+struct page_list_head resv_page_list; /* linked list (size resv_pages) */
+#endif
 
 /*
  * This field should only be directly accessed by domain_adjust_tot_pages()
@@ -395,6 +398,9 @@ struct domain
 #ifdef CONFIG_MEM_PAGING
 atomic_t paged_pages;   /* paged-out pages */
 #endif
+#ifdef CONFIG_STATIC_MEMORY
+unsigned int resv_pages;/* reserved pages from static region. 
*/
+#endif
 
 /* Scheduling. */
 void*sched_priv;/* scheduler-specific data */
-- 
2.25.1




[PATCH v2 3/6] xen: add field "flags" to cover all internal CDF_XXX

2022-04-18 Thread Penny Zheng
With more and more CDF_xxx internal flags in and to save the space, this
commit introduces a new field "flags" in struct domain to store CDF_*
internal flags directly.

Another new CDF_xxx will be introduced in the next patch.

Signed-off-by: Penny Zheng 
---
v2 changes:
- let "flags" live in the struct domain. So other arch can take
advantage of it in the future
- fix coding style
---
 xen/arch/arm/domain.c | 2 --
 xen/arch/arm/include/asm/domain.h | 3 +--
 xen/common/domain.c   | 3 +++
 xen/include/xen/sched.h   | 3 +++
 4 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 8110c1df86..74189d9878 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -709,8 +709,6 @@ int arch_domain_create(struct domain *d,
 ioreq_domain_init(d);
 #endif
 
-d->arch.directmap = flags & CDF_directmap;
-
 /* p2m_init relies on some value initialized by the IOMMU subsystem */
 if ( (rc = iommu_domain_init(d, config->iommu_opts)) != 0 )
 goto fail;
diff --git a/xen/arch/arm/include/asm/domain.h 
b/xen/arch/arm/include/asm/domain.h
index ed63c2b6f9..36ec00e62d 100644
--- a/xen/arch/arm/include/asm/domain.h
+++ b/xen/arch/arm/include/asm/domain.h
@@ -29,7 +29,7 @@ enum domain_type {
 #define is_64bit_domain(d) (0)
 #endif
 
-#define is_domain_direct_mapped(d) (d)->arch.directmap
+#define is_domain_direct_mapped(d) ((d)->flags & CDF_directmap)
 
 /*
  * Is the domain using the host memory layout?
@@ -103,7 +103,6 @@ struct arch_domain
 void *tee;
 #endif
 
-bool directmap;
 }  __cacheline_aligned;
 
 struct arch_vcpu
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 351029f8b2..859cc13d3b 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -568,6 +568,9 @@ struct domain *domain_create(domid_t domid,
 /* Sort out our idea of is_system_domain(). */
 d->domain_id = domid;
 
+/* Holding CDF_* internal flags. */
+d->flags = flags;
+
 /* Debug sanity. */
 ASSERT(is_system_domain(d) ? config == NULL : config != NULL);
 
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index ed8539f6d2..68eb08058e 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -591,6 +591,9 @@ struct domain
 struct ioreq_server *server[MAX_NR_IOREQ_SERVERS];
 } ioreq_server;
 #endif
+
+/* Holding CDF_* constant. Internal flags for domain creation. */
+uint32_t flags;
 };
 
 static inline struct page_list_head *page_to_list(
-- 
2.25.1




[PATCH v2 4/6] xen/arm: introduce CDF_staticmem

2022-04-18 Thread Penny Zheng
In order to have an easy and quick way to find out whether this domain memory
is statically configured, this commit introduces a new flag CDF_staticmem and a
new helper is_domain_static to tell.

Signed-off-by: Penny Zheng 
---
v2 changes:
- change name from "is_domain_on_static_allocation" to "is_domain_static()"
---
 xen/arch/arm/domain_build.c   | 5 -
 xen/arch/arm/include/asm/domain.h | 2 ++
 xen/include/xen/domain.h  | 2 ++
 3 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 8be01678de..4e62fd0bf1 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -3191,9 +3191,12 @@ void __init create_domUs(void)
 if ( !dt_device_is_compatible(node, "xen,domain") )
 continue;
 
+if ( dt_find_property(node, "xen,static-mem", NULL) )
+flags |= CDF_staticmem;
+
 if ( dt_property_read_bool(node, "direct-map") )
 {
-if ( !IS_ENABLED(CONFIG_STATIC_MEMORY) || !dt_find_property(node, 
"xen,static-mem", NULL) )
+if ( !IS_ENABLED(CONFIG_STATIC_MEMORY) || !(flags & CDF_staticmem) 
)
 panic("direct-map is not valid for domain %s without static 
allocation.\n",
   dt_node_name(node));
 
diff --git a/xen/arch/arm/include/asm/domain.h 
b/xen/arch/arm/include/asm/domain.h
index 36ec00e62d..b097433f9f 100644
--- a/xen/arch/arm/include/asm/domain.h
+++ b/xen/arch/arm/include/asm/domain.h
@@ -31,6 +31,8 @@ enum domain_type {
 
 #define is_domain_direct_mapped(d) ((d)->flags & CDF_directmap)
 
+#define is_domain_static(d) ((d)->flags & CDF_staticmem)
+
 /*
  * Is the domain using the host memory layout?
  *
diff --git a/xen/include/xen/domain.h b/xen/include/xen/domain.h
index 1c3c88a14d..35dc7143a4 100644
--- a/xen/include/xen/domain.h
+++ b/xen/include/xen/domain.h
@@ -34,6 +34,8 @@ void arch_get_domain_info(const struct domain *d,
 #ifdef CONFIG_ARM
 /* Should domain memory be directly mapped? */
 #define CDF_directmap(1U << 1)
+/* Is domain memory on static allocation? */
+#define CDF_staticmem(1U << 2)
 #endif
 
 /*
-- 
2.25.1




[PATCH v2 6/6] xen/arm: retrieve reserved pages on populate_physmap

2022-04-18 Thread Penny Zheng
When static domain populates memory through populate_physmap on runtime,
other than allocating from heap, it shall retrieve reserved pages from
resv_page_list to make sure that guest RAM is still restricted in statically
configured memory regions. And this commit introduces a new helper
acquire_reserved_page to make it work.

Signed-off-by: Penny Zheng 
---
v2 changes:
- introduce acquire_reserved_page to retrieve reserved pages from
resv_page_list
- forbid non-zero-order requests in populate_physmap
- let is_domain_static return ((void)(d), false) on x86
---
 xen/common/memory.c | 29 +
 xen/common/page_alloc.c | 28 
 xen/include/xen/mm.h|  1 +
 3 files changed, 58 insertions(+)

diff --git a/xen/common/memory.c b/xen/common/memory.c
index 69b0cd1e50..f7729dfa5c 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -35,6 +35,10 @@
 #include 
 #endif
 
+#ifndef is_domain_static
+#define is_domain_static(d) ((void)(d), false)
+#endif
+
 struct memop_args {
 /* INPUT */
 struct domain *domain; /* Domain to be affected. */
@@ -245,6 +249,31 @@ static void populate_physmap(struct memop_args *a)
 
 mfn = _mfn(gpfn);
 }
+#ifdef CONFIG_STATIC_MEMORY
+else if ( is_domain_static(d) )
+{
+/*
+ * No easy way to guarantee the retreived pages are contiguous,
+ * so forbid non-zero-order requests here.
+ */
+if ( a->extent_order != 0 )
+{
+gdprintk(XENLOG_INFO,
+ "Could not allocate non-zero-order pages for 
static %pd.\n.",
+ d);
+goto out;
+}
+
+mfn = acquire_reserved_page(d, a->memflags);
+if ( mfn_eq(mfn, INVALID_MFN) )
+{
+gdprintk(XENLOG_INFO,
+ "%pd: failed to retrieve a reserved page.\n.",
+ d);
+goto out;
+}
+}
+#endif
 else
 {
 page = alloc_domheap_pages(d, a->extent_order, a->memflags);
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 8ba38bca9a..759d612eb8 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -2770,6 +2770,34 @@ int __init acquire_domstatic_pages(struct domain *d, 
mfn_t smfn,
 
 return 0;
 }
+
+/*
+ * Acquire a page from reserved page list(resv_page_list), when populating
+ * memory for static domain on runtime.
+ */
+mfn_t acquire_reserved_page(struct domain *d, unsigned int memflags)
+{
+struct page_info *page;
+mfn_t smfn;
+
+/* Acquire a page from reserved page list(resv_page_list). */
+page = page_list_remove_head(&d->resv_page_list);
+if ( unlikely(!page) )
+{
+printk(XENLOG_ERR
+   "%pd: failed to acquire a reserved page %"PRI_mfn".\n",
+   d, mfn_x(page_to_mfn(page)));
+return INVALID_MFN;
+}
+d->resv_pages--;
+
+smfn = page_to_mfn(page);
+
+if ( acquire_domstatic_pages(d, smfn, 1, memflags) )
+return INVALID_MFN;
+
+return smfn;
+}
 #endif
 
 /*
diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
index 3be754da92..6ef5a6adcd 100644
--- a/xen/include/xen/mm.h
+++ b/xen/include/xen/mm.h
@@ -91,6 +91,7 @@ void free_staticmem_pages(struct page_info *pg, unsigned long 
nr_mfns,
   bool need_scrub);
 int acquire_domstatic_pages(struct domain *d, mfn_t smfn, unsigned int nr_mfns,
 unsigned int memflags);
+mfn_t acquire_reserved_page(struct domain *d, unsigned int memflags);
 #endif
 
 /* Map machine page range in Xen virtual address space. */
-- 
2.25.1




RE: [PATCH V2 0/6] populate/unpopulate memory when domain on static

2022-04-19 Thread Penny Zheng
Hi jan

> -Original Message-
> From: Jan Beulich 
> Sent: Tuesday, April 19, 2022 4:47 PM
> To: Penny Zheng 
> Cc: Wei Chen ; Andrew Cooper
> ; George Dunlap ;
> Julien Grall ; Stefano Stabellini ; 
> Wei
> Liu ; Bertrand Marquis ;
> Volodymyr Babchuk ; xen-
> de...@lists.xenproject.org
> Subject: Re: [PATCH V2 0/6] populate/unpopulate memory when domain on
> static
> 
> On 18.04.2022 14:22, Penny Zheng wrote:
> > Today when a domain unpopulates the memory on runtime, they will
> > always hand the memory over to the heap allocator. And it will be a
> > problem if it is a static domain. Pages as guest RAM for static domain
> > shall always be reserved to only this domain and not be used for any
> > other purposes, so they shall never go back to heap allocator.
> >
> > This patch serie intends to fix this issue, by adding pages on the new
> > list resv_page_list after having taken them off the "normal" list,
> > when unpopulating memory, and retrieving pages from resv page
> > list(resv_page_list) when populating memory.
> >
> > ---
> > v2 changes:
> > - let "flags" live in the struct domain. So other arch can take
> > advantage of it in the future
> > - change name from "is_domain_on_static_allocation" to
> "is_domain_static()"
> 
> I have reservations against this new name: This could mean far more aspects of
> the domain are static than just its memory assignment. Was this intended (or
> at least considered)?
> 

Ok. Julien gave me two suggestions back the day, maybe the other 
"is_domain_using_staticmem()"
is better and to the point. I'll change it in the next serie.

> Jan



RE: [PATCH v2 1/6] xen/arm: do not free reserved memory into heap

2022-04-19 Thread Penny Zheng
Hi jan

> -Original Message-
> From: Jan Beulich 
> Sent: Tuesday, April 19, 2022 4:59 PM
> To: Penny Zheng 
> Cc: Wei Chen ; Andrew Cooper
> ; George Dunlap ;
> Julien Grall ; Stefano Stabellini ; 
> Wei
> Liu ; xen-devel@lists.xenproject.org
> Subject: Re: [PATCH v2 1/6] xen/arm: do not free reserved memory into heap
> 
> On 18.04.2022 14:22, Penny Zheng wrote:
> > Pages as guest RAM for static domain, shall be reserved to this domain only.
> 
> Is there "used" missing as the 2nd word of the sentence?
> 
> > So in case reserved pages being used for other purpose, users shall
> > not free them back to heap, even when last ref gets dropped.
> >
> > free_staticmem_pages will be called by free_domheap_pages in runtime
> > for static domain freeing memory resource, so let's drop the __init
> > flag.
> >
> > Signed-off-by: Penny Zheng 
> > ---
> > v2 changes:
> > - new commit
> > ---
> >  xen/common/page_alloc.c | 10 --
> >  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> With this diffstat the patch subject prefix is somewhat misleading; I first
> thought I could skip this patch.
> 

Oh, sorry. Will change the 'xen/arm' to 'xen'

> > --- a/xen/common/page_alloc.c
> > +++ b/xen/common/page_alloc.c
> > @@ -2488,7 +2488,13 @@ void free_domheap_pages(struct page_info *pg,
> unsigned int order)
> >  scrub = 1;
> >  }
> >
> > -free_heap_pages(pg, order, scrub);
> > +#ifdef CONFIG_STATIC_MEMORY
> > +if ( pg->count_info & PGC_reserved )
> > +/* Reserved page shall not go back to the heap. */
> > +free_staticmem_pages(pg, 1 << order, scrub);
> 
> 1UL with, in particular, the function parameter by "unsigned long".
> 
> By calling free_staticmem_pages() at runtime, you make the previous race free
> (because of init-time only) update of .count_info there racy. Making a clone 
> of
> that function just for this difference would likely be excessive, so I'd 
> suggest to
> change the code there to
> 
> /* In case initializing page of static memory, mark it PGC_reserved. 
> */
> if ( !(pg[i].count_info & PGC_reserved) )
> pg[i].count_info |= PGC_reserved;
> 

Learned!

> > +else
> > +#endif
> > +free_heap_pages(pg, order, scrub);
> 
> Of course it would be nice to avoid the #ifdef-ary here. May I ask that you
> introduce a stub free_staticmem_pages() for the !CONFIG_STATIC_MEMORY
> case, such that the construct can become
> 

Sure, will do.

> if ( !(pg->count_info & PGC_reserved) )
> free_heap_pages(pg, order, scrub);
> else
> /* Reserved page shall not go back to the heap. */
> free_staticmem_pages(pg, 1 << order, scrub);
> 
> Another question is whether the distinction should be made here in the first
> place. Would it perhaps better belong in free_heap_pages() itself, thus also
> covering other potential call sites? Of course this depends on where, long 
> term,
> reserved pages can / will be used.
> For domains to be truly static, Xen's own allocations to manage the domain
> may also want to come from the reserved set ...
> 

Yes, you're right. I'll defer the distinction to free_heap_pages. And refine the
in-code comment above free_staticmem_pages, in the first place, I was intending
to make it equivalent of free_heap_pages to free static memory.

However as you said, if letting free_heap_pages call free_staticmem_pages, it 
will 
cover other potential call site. We've already been trying to enable p2m pool 
on arm,
and in the future, maybe the pages constituting the pool shall not come from 
heap, but
from reserved set, if the domain is fully static

> > @@ -2636,7 +2642,7 @@ struct domain *get_pg_owner(domid_t domid)
> >
> >  #ifdef CONFIG_STATIC_MEMORY
> >  /* Equivalent of free_heap_pages to free nr_mfns pages of static
> > memory. */ -void __init free_staticmem_pages(struct page_info *pg,
> > unsigned long nr_mfns,
> > +void free_staticmem_pages(struct page_info *pg, unsigned long
> > +nr_mfns,
> >   bool need_scrub)
> 
> This line now wants its indentation adjusted.
> 
> Jan



RE: [PATCH v1 06/13] xen/arm: set up shared memory foreign mapping for borrower domain

2022-04-20 Thread Penny Zheng
Hi julien

> -Original Message-
> From: Julien Grall 
> Sent: Saturday, April 9, 2022 6:59 AM
> To: Penny Zheng ; xen-devel@lists.xenproject.org
> Cc: nd ; Stefano Stabellini ; Bertrand
> Marquis ; Volodymyr Babchuk
> 
> Subject: Re: [PATCH v1 06/13] xen/arm: set up shared memory foreign
> mapping for borrower domain
> 
> Hi Penny,
> 
> On 11/03/2022 06:11, Penny Zheng wrote:
> > From: Penny Zheng 
> >
> > This commits introduces a new helper guest_physmap_add_shm to set up
> > shared memory foreign mapping for borrower domain.
> >
> > Firstly it should get and take reference of statically shared pages
> > from owner dom_shared. Then it will setup P2M foreign memory map of
> > these statically shared pages for borrower domain.
> >
> > This commits only considers owner domain is the default dom_shared,
> > the other scenario will be covered in the following patches.
> >
> > Signed-off-by: Penny Zheng 
> > ---
> >   xen/arch/arm/domain_build.c | 52
> +
> >   1 file changed, 52 insertions(+)
> >
> > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> > index 984e70e5fc..8cee5ffbd1 100644
> > --- a/xen/arch/arm/domain_build.c
> > +++ b/xen/arch/arm/domain_build.c
> > @@ -798,6 +798,48 @@ static int __init allocate_shared_memory(struct
> domain *d,
> >   return ret;
> >   }
> >
> > +static int __init guest_physmap_add_shm(struct domain *od, struct domain
> *bd,
> > +unsigned long o_gfn,
> > +unsigned long b_gfn,
> > +unsigned long nr_gfns) {
> > +struct page_info **pages = NULL;
> > +p2m_type_t p2mt, t;
> > +int ret = 0;
> 
> You don't need to initialize ret.
> 
> > +
> > +pages = xmalloc_array(struct page_info *, nr_gfns);
> > +if ( !pages )
> > +return -ENOMEM;
> > +
> > +/*
> > + * Take reference of statically shared pages from owner domain.
> > + * Reference will be released when destroying shared memory region.
> > + */
> > +ret = get_pages_from_gfn(od, o_gfn, nr_gfns, pages, &p2mt, P2M_ALLOC);
> > +if ( ret )
> > +{
> > +ret = -EINVAL;
> > +goto fail_pages;
> > +}
> > +
> > +if ( p2m_is_ram(p2mt) )
> > +t = (p2mt == p2m_ram_rw) ? p2m_map_foreign_rw :
> p2m_map_foreign_ro;
> > +else
> > +{
> > +ret = -EINVAL;
> > +goto fail_pages;
> 
> Where would we release the references?
> 
> > +}
> > +
> > +/* Set up guest foreign map. */
> > +ret = guest_physmap_add_pages(bd, _gfn(b_gfn), page_to_mfn(pages[0]),
> > +  nr_gfns, t);
> 
> A few things:
>- The beginning of the code assumes that the MFN may be discontiguous in
> the physical memory. But here, you are assuming they are contiguous.
> If you want the latter, then you should check the MFNs are contiguous.
> That said, I am not sure if this restriction is really necessary.
> 

Oh,, caught me, it never occurred to me that the pages in array `pages` could
be discontinuous.
I definitely want the latter. This function is always dealing with a memory 
region
(contiguous MFNS) each time. So maybe a loop to check
page_to_mfn(pages[i]) == mfn_add(smfn, i) is needed.

>- IIRC, guest_physmap_add_pages() doesn't revert the mappings. So you
> need to revert it in case of failure.
> 

Yes, both failure points you are referring to are requiring reverting the 
mappings.

> Cheers,
> 
> --
> Julien Grall


RE: [PATCH v1 06/13] xen/arm: set up shared memory foreign mapping for borrower domain

2022-04-20 Thread Penny Zheng
Hi

> -Original Message-
> From: Julien Grall 
> Sent: Saturday, April 9, 2022 5:31 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org
> Cc: nd ; Stefano Stabellini ; Bertrand
> Marquis ; Volodymyr Babchuk
> 
> Subject: Re: [PATCH v1 06/13] xen/arm: set up shared memory foreign
> mapping for borrower domain
> 
> Hi,
> 
> On 08/04/2022 23:59, Julien Grall wrote:
> > On 11/03/2022 06:11, Penny Zheng wrote:
> >> From: Penny Zheng 
> >>
> >> This commits introduces a new helper guest_physmap_add_shm to set up
> >> shared memory foreign mapping for borrower domain.
> >>
> >> Firstly it should get and take reference of statically shared pages
> >> from owner dom_shared. Then it will setup P2M foreign memory map of
> >> these statically shared pages for borrower domain.
> >>
> >> This commits only considers owner domain is the default dom_shared,
> >> the other scenario will be covered in the following patches.
> >>
> >> Signed-off-by: Penny Zheng 
> >> ---
> >>   xen/arch/arm/domain_build.c | 52
> >> +
> >>   1 file changed, 52 insertions(+)
> >>
> >> diff --git a/xen/arch/arm/domain_build.c
> >> b/xen/arch/arm/domain_build.c index 984e70e5fc..8cee5ffbd1 100644
> >> --- a/xen/arch/arm/domain_build.c
> >> +++ b/xen/arch/arm/domain_build.c
> >> @@ -798,6 +798,48 @@ static int __init allocate_shared_memory(struct
> >> domain *d,
> >>   return ret;
> >>   }
> >> +static int __init guest_physmap_add_shm(struct domain *od, struct
> >> domain *bd,
> >> +    unsigned long o_gfn,
> >> +    unsigned long b_gfn,
> >> +    unsigned long nr_gfns) {
> >> +    struct page_info **pages = NULL;
> >> +    p2m_type_t p2mt, t;
> >> +    int ret = 0;
> >
> > You don't need to initialize ret.
> >
> >> +
> >> +    pages = xmalloc_array(struct page_info *, nr_gfns);
> >> +    if ( !pages )
> >> +    return -ENOMEM;
> >> +
> >> +    /*
> >> + * Take reference of statically shared pages from owner domain.
> >> + * Reference will be released when destroying shared memory region.
> >> + */
> >> +    ret = get_pages_from_gfn(od, o_gfn, nr_gfns, pages, &p2mt,
> >> P2M_ALLOC);
> >> +    if ( ret )
> >> +    {
> >> +    ret = -EINVAL;
> >> +    goto fail_pages;
> >> +    }
> >> +
> >> +    if ( p2m_is_ram(p2mt) )
> >> +    t = (p2mt == p2m_ram_rw) ? p2m_map_foreign_rw :
> >> p2m_map_foreign_ro;
> >> +    else
> >> +    {
> >> +    ret = -EINVAL;
> >> +    goto fail_pages;
> >
> > Where would we release the references?
> >
> >> +    }
> >> +
> >> +    /* Set up guest foreign map. */
> >> +    ret = guest_physmap_add_pages(bd, _gfn(b_gfn),
> >> page_to_mfn(pages[0]),
> >> +  nr_gfns, t);
> >
> > A few things:
> >    - The beginning of the code assumes that the MFN may be
> > discontiguous in the physical memory. But here, you are assuming they are
> contiguous.
> > If you want the latter, then you should check the MFNs are contiguous.
> > That said, I am not sure if this restriction is really necessary.
> >
> >    - IIRC, guest_physmap_add_pages() doesn't revert the mappings. So
> > you need to revert it in case of failure.
> 
> 
> There is another issue here. guest_physmap_add_pages() may use superpage
> mapping. The P2M code is currently assuming the foreing mapping will be
> using L3 mapping (4KB).
> 
> Do you need to use superpage mapping here?
> 

Right now, there is no user case on my side needing superpage mapping.

> Cheers,
> 
> --
> Julien Grall


RE: [PATCH v1 08/13] xen/arm: destroy static shared memory when de-construct domain

2022-04-21 Thread Penny Zheng
Hi, julien

> -Original Message-
> From: Julien Grall 
> Sent: Saturday, April 9, 2022 5:26 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org
> Cc: nd ; Stefano Stabellini ; Bertrand
> Marquis ; Volodymyr Babchuk
> 
> Subject: Re: [PATCH v1 08/13] xen/arm: destroy static shared memory when
> de-construct domain
> 
> Hi Penny,
> 
> On 11/03/2022 06:11, Penny Zheng wrote:
> > From: Penny Zheng 
> >
> > This commit introduces a new helper destroy_domain_shm to destroy
> > static shared memory at domain de-construction.
> >
> > This patch only considers the scenario where the owner domain is the
> > default dom_shared, for user-defined owner domain, it will be covered
> > in the following patches.
> >
> > Since all domains are borrower domains, we could simply remove guest
> > P2M foreign mapping of statically shared memory region and drop the
> > reference added at guest_physmap_add_shm.
> >
> > Signed-off-by: Penny Zheng 
> > ---
> >   xen/arch/arm/domain.c | 48
> +++
> >   1 file changed, 48 insertions(+)
> >
> > diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c index
> > 1ff1df5d3f..f0bfd67fe5 100644
> > --- a/xen/arch/arm/domain.c
> > +++ b/xen/arch/arm/domain.c
> > @@ -34,6 +34,7 @@
> >   #include 
> >   #include 
> >   #include 
> > +#include 
> >   #include 
> >   #include 
> >   #include 
> > @@ -993,6 +994,48 @@ static int relinquish_memory(struct domain *d,
> struct page_list_head *list)
> >   return ret;
> >   }
> >
> > +#ifdef CONFIG_STATIC_SHM
> > +static int domain_destroy_shm(struct domain *d) {
> > +int ret = 0;
> > +unsigned long i = 0UL, j;
> > +
> > +if ( d->arch.shm_mem == NULL )
> > +return ret;
> 
> You already return the value here. So...
> 
> > +else
> 
> ... the else is pointless.
> 
> > +{
> > +for ( ; i < d->arch.shm_mem->nr_banks; i++ )
> > +{
> > +unsigned long nr_gfns = PFN_DOWN(d->arch.shm_mem-
> >bank[i].size);
> > +gfn_t gfn = gaddr_to_gfn(d->arch.shm_mem->bank[i].start);
> > +
> > +for ( j = 0; j < nr_gfns; j++ )
> > +{
> > +mfn_t mfn;
> > +
> > +mfn = gfn_to_mfn(d, gfn_add(gfn, j));
> 
> A domain is allowed to modify its P2M. So there are no guarantee that the
> GFN will still point to the shared memory. This will allow the guest...
> 
> > +if ( !mfn_valid(mfn) )
> > +{
> > +dprintk(XENLOG_ERR,
> > +"Domain %pd page number %lx invalid.\n",
> > +d, gfn_x(gfn) + i);
> > +return -EINVAL;
> 
> ... to actively prevent destruction.
> 
> > +}
> 
> 
> > +
> > +ret = guest_physmap_remove_page(d, gfn_add(gfn, j), mfn, 
> > 0);
> > +if ( ret )
> > +return ret;
> > +
> > +/* Drop the reference. */
> > +put_page(mfn_to_page(mfn));
> 
> guest_physmap_remove_page() will already drop the reference taken for the
> foreign mapping. I couldn't find any other reference taken, what is the
> put_page() for?
> 
> Also, as per above we don't know whether this is a page from the shared page.
> So we can't blindly call put_page().
> 
> However, I don't think we need any specific code here. We can rely on
> relinquish_p2m_mappings() to drop any reference. If there is an extra one for
> shared mappings, then we should update p2m_put_l3_page().
> 

True, true. Thanks for pointing this out!
In p2m_put_l3_page, it has already called put_page() for foreign mapping,
definitely no extra one here!

> Cheers,
> 
> --
> Julien Grall


RE: [PATCH v2 5/6] xen/arm: unpopulate memory when domain is static

2022-04-24 Thread Penny Zheng
Hi jan

> -Original Message-
> From: Jan Beulich 
> Sent: Tuesday, April 19, 2022 5:11 PM
> To: Penny Zheng 
> Cc: Wei Chen ; Stefano Stabellini
> ; Julien Grall ; Bertrand Marquis
> ; Volodymyr Babchuk
> ; Andrew Cooper
> ; George Dunlap ;
> Wei Liu ; xen-devel@lists.xenproject.org
> Subject: Re: [PATCH v2 5/6] xen/arm: unpopulate memory when domain is
> static
> 
> On 18.04.2022 14:22, Penny Zheng wrote:
> > --- a/xen/arch/arm/include/asm/mm.h
> > +++ b/xen/arch/arm/include/asm/mm.h
> > @@ -358,6 +358,23 @@ void clear_and_clean_page(struct page_info
> > *page);
> >
> >  unsigned int arch_get_dma_bitsize(void);
> >
> > +/*
> > + * Put free pages on the resv page list after having taken them
> > + * off the "normal" page list, when pages from static memory  */
> > +#ifdef CONFIG_STATIC_MEMORY
> > +#define arch_free_heap_page(d, pg) {\
> > +if ( (pg)->count_info & PGC_reserved )  \
> > +{   \
> > +page_list_del(pg, page_to_list(d, pg)); \
> > +page_list_add_tail(pg, &(d)->resv_page_list);   \
> > +(d)->resv_pages++;  \
> 
> There's no consumer of this counter, so I'd like to ask that it be introduced
> once a consumer appears.
> 
> > +}   \
> > +else\
> > +page_list_del(pg, page_to_list(d, pg)); \
> 
> Is there a particular reason to have this page_list_del() twice, instead of 
> just
> once ahead of the if()?
> 
> > +}
> 
> Also this entire construct want to be an expression, not a
> (compound) statement. And it probably would better evaluate its parameters
> just once.
> 

#define arch_free_heap_page(d, pg) {\
page_list_del(pg, page_to_list(d, pg)); \
if ( (pg)->count_info & PGC_reserved )  \
 page_list_add_tail(pg, &(d)->resv_page_list);   \
}

I'm trying to refine the arch_free_heap_page() here, but I'm a bit confused
about to let it be an expression, not a compound statement.  Do you mean that
you prefer to let the if-clause out of the arch_free_heap_page()?

> Jan



RE: [PATCH v2 5/6] xen/arm: unpopulate memory when domain is static

2022-04-25 Thread Penny Zheng
Hi, jan

> -Original Message-
> From: Jan Beulich 
> Sent: Monday, April 25, 2022 4:01 PM
> To: Penny Zheng 
> Cc: Wei Chen ; Stefano Stabellini
> ; Julien Grall ; Bertrand Marquis
> ; Volodymyr Babchuk
> ; Andrew Cooper
> ; George Dunlap ;
> Wei Liu ; xen-devel@lists.xenproject.org
> Subject: Re: [PATCH v2 5/6] xen/arm: unpopulate memory when domain is
> static
> 
> On 25.04.2022 08:34, Penny Zheng wrote:
> >> -Original Message-
> >> From: Jan Beulich 
> >> Sent: Tuesday, April 19, 2022 5:11 PM
> >>
> >> On 18.04.2022 14:22, Penny Zheng wrote:
> >>> --- a/xen/arch/arm/include/asm/mm.h
> >>> +++ b/xen/arch/arm/include/asm/mm.h
> >>> @@ -358,6 +358,23 @@ void clear_and_clean_page(struct page_info
> >>> *page);
> >>>
> >>>  unsigned int arch_get_dma_bitsize(void);
> >>>
> >>> +/*
> >>> + * Put free pages on the resv page list after having taken them
> >>> + * off the "normal" page list, when pages from static memory  */
> >>> +#ifdef CONFIG_STATIC_MEMORY
> >>> +#define arch_free_heap_page(d, pg) {\
> >>> +if ( (pg)->count_info & PGC_reserved )  \
> >>> +{   \
> >>> +page_list_del(pg, page_to_list(d, pg)); \
> >>> +page_list_add_tail(pg, &(d)->resv_page_list);   \
> >>> +(d)->resv_pages++;  \
> >>
> >> There's no consumer of this counter, so I'd like to ask that it be
> >> introduced once a consumer appears.
> >>
> >>> +}   \
> >>> +else\
> >>> +page_list_del(pg, page_to_list(d, pg)); \
> >>
> >> Is there a particular reason to have this page_list_del() twice,
> >> instead of just once ahead of the if()?
> >>
> >>> +}
> >>
> >> Also this entire construct want to be an expression, not a
> >> (compound) statement. And it probably would better evaluate its
> >> parameters just once.
> >>
> >
> > #define arch_free_heap_page(d, pg) {\
> > page_list_del(pg, page_to_list(d, pg)); \
> > if ( (pg)->count_info & PGC_reserved )  \
> >  page_list_add_tail(pg, &(d)->resv_page_list);   \
> > }
> >
> > I'm trying to refine the arch_free_heap_page() here, but I'm a bit
> > confused about to let it be an expression, not a compound statement.
> > Do you mean that you prefer to let the if-clause out of the
> arch_free_heap_page()?
> 
> No. You want to put parentheses around the braces, using a gcc extension we
> make extensive use of throughout the code base.
> 

Oh, oh, thanks!
put parentheses around the braces, then that's what you said about make it 
be an expression

> Jan



RE: [PATCH 03/11] xen/arm: introduce 1:1 direct-map for domUs

2021-10-07 Thread Penny Zheng
Hi Julien

So sorry for taking so long to respond. Just being back from the long National 
Day holidays. 😉

> -Original Message-
> From: Julien Grall 
> Sent: Thursday, September 23, 2021 6:36 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Bertrand Marquis ; Wei Chen
> 
> Subject: Re: [PATCH 03/11] xen/arm: introduce 1:1 direct-map for domUs
> 
> 
> 
> On 23/09/2021 08:11, Penny Zheng wrote:
> > From: Stefano Stabellini 
> >
> > Cases where domU needs 1:1 direct-map memory map:
> 
> "1:1" and "direct-map" means pretty much the same. Given that the property
> is name "direct-map", then I would drop "1:1".
> 
> >* IOMMU not present in the system.
> >* IOMMU disabled if it doesn't cover a specific device and all the
> > guests are trusted. Thinking a mixed scenario, where a few devices
> > with IOMMU and a few without, then guest DMA security still could not be
> totally guaranteed.
> > So users may want to disable the IOMMU, to at least gain some
> > performance improvement from IOMMU disabled.
> >* IOMMU disabled as a workaround when it doesn't have enough
> bandwidth.
> > To be specific, in a few extreme situation, when multiple devices do
> > DMA concurrently, these requests may exceed IOMMU's transmission
> capacity.
> >* IOMMU disabled when it adds too much latency on DMA. For example,
> > TLB may be missing in some IOMMU hardware, which may bring latency in
> > DMA progress, so users may want to disable it in some realtime scenario.
> >
> > *WARNING:
> > Users should be aware that it is not always secure to assign a device
> > without IOMMU protection.
> > When the device is not protected by the IOMMU, the administrator
> > should make sure that:
> >   1. The device is assigned to a trusted guest.
> >   2. Users have additional security mechanism on the platform.
> 
> The two requirements are only necessary for device that are DMA-capable.
> For device that can't do DMA, it will likely be fine to assign to non-trusted
> guest.
> 
> >
> > Given that with direct-map, the IOMMU could be used but it is not required.
> 
> I can't parse it.
> 

Now when doing device assignments, IOMMU is forced to be enabled. And since
we are introducing direct-map here, I think that maybe even if IOMMU is 
missing/disabled,
direct-map on trust guests could also make it work.

Maybe I should rephrase it to
"
When doing device assignments and IOMMU is missing or disabled, direct-map
shall be used on trust guests.
"

> > This commit avoids setting XEN_DOMCTL_CDF_iommu when the IOMMU is
> > disabled and direct_map is requested.
> >
> > Since, for now, 1:1 direct-map is only supported when domain on Static
> 
> I think "Since" seems unnecessary.
> 
> > Allocation, that is, "xen.static-mem" is defined in the domain 
> > configuration.
> >
> > This commit also re-implements allocate_static_memory to allocate
> > static memory as guest RAM for 1:1 direct-map domain.
> >
> > Signed-off-by: Stefano Stabellini 
> > Signed-off-by: Penny Zheng 
> > ---
> >   docs/misc/arm/device-tree/booting.txt |   9 ++
> >   xen/arch/arm/domain_build.c   | 117 +-
> >   2 files changed, 85 insertions(+), 41 deletions(-)
> >
> > diff --git a/docs/misc/arm/device-tree/booting.txt
> > b/docs/misc/arm/device-tree/booting.txt
> > index 44cd9e1a9a..3d637c747e 100644
> > --- a/docs/misc/arm/device-tree/booting.txt
> > +++ b/docs/misc/arm/device-tree/booting.txt
> > @@ -164,6 +164,15 @@ with the following properties:
> >   Both #address-cells and #size-cells need to be specified because
> >   both sub-nodes (described shortly) have reg properties.
> >
> > +- direct-map
> > +
> > +Optional for Domain on Static Allocation.
> > +An empty property to request the memory of the domain to be 1:1
> > +direct-map(guest physical address == physical address).
> > +WARNING: Users must be aware of this risk, that guests having access
> > +to hardware with DMA capacity must be trusted, or it could use the
> > +DMA engine to access any other memory area.
> 
> The WARNING is only applicable if the device is not protected by an IOMMU.
> So this should be clarified because one may want still want to use the direct-
> map (e.g. because the OS relies on the host layout) and have IOMMU enabled.
> 
> > +
> >   Under the "xen,domain" compatible node, one or more sub-nodes ar

RE: [PATCH 09/11] xen/arm: if 1:1 direct-map domain use native UART address and IRQ number for vPL011

2021-10-09 Thread Penny Zheng
Hi Julien

> -Original Message-
> From: Julien Grall 
> Sent: Thursday, September 23, 2021 7:14 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Bertrand Marquis ; Wei Chen
> 
> Subject: Re: [PATCH 09/11] xen/arm: if 1:1 direct-map domain use native
> UART address and IRQ number for vPL011
> 
> 
> 
> On 23/09/2021 08:11, Penny Zheng wrote:
> > From: Stefano Stabellini 
> >
> > We always use a fix address to map the vPL011 to domains. The address
> > could be a problem for domains that are directly mapped.
> >
> > So, for domains that are directly mapped, reuse the address of the
> > physical UART on the platform to avoid potential clashes.
> >
> > Do the same for the virtual IRQ number: instead of always using
> > GUEST_VPL011_SPI, try to reuse the physical SPI number if possible.
> >
> > Signed-off-by: Stefano Stabellini 
> > Signed-off-by: Penny Zheng 
> > ---
> >   xen/arch/arm/domain_build.c  | 34 +++---
> >   xen/arch/arm/vpl011.c| 34 +++---
> >   xen/include/asm-arm/vpl011.h |  2 ++
> >   3 files changed, 56 insertions(+), 14 deletions(-)
> >
> > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> > index 120f1ae575..c92e510ae7 100644
> > --- a/xen/arch/arm/domain_build.c
> > +++ b/xen/arch/arm/domain_build.c
> > @@ -30,6 +30,7 @@
> >
> >   #include 
> >   #include 
> > +#include 
> >
> >   static unsigned int __initdata opt_dom0_max_vcpus;
> >   integer_param("dom0_max_vcpus", opt_dom0_max_vcpus); @@ -1942,8
> > +1943,11 @@ static int __init make_vpl011_uart_node(struct kernel_info
> *kinfo)
> >   gic_interrupt_t intr;
> >   __be32 reg[GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS];
> >   __be32 *cells;
> > +struct domain *d = kinfo->d;
> > +char buf[27];
> >
> > -res = fdt_begin_node(fdt, "sbsa-uart@"__stringify(GUEST_PL011_BASE));
> > +snprintf(buf, sizeof(buf), "sbsa-uart@%"PRIx64, d-
> >arch.vpl011.base_addr);
> > +res = fdt_begin_node(fdt, buf);
> >   if ( res )
> >   return res;
> >
> > @@ -1953,14 +1957,14 @@ static int __init make_vpl011_uart_node(struct
> > kernel_info *kinfo)
> >
> >   cells = ®[0];
> >   dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS,
> > -   GUEST_ROOT_SIZE_CELLS, GUEST_PL011_BASE,
> > +   GUEST_ROOT_SIZE_CELLS,
> > + d->arch.vpl011.base_addr,
> >  GUEST_PL011_SIZE);
> >
> >   res = fdt_property(fdt, "reg", reg, sizeof(reg));
> >   if ( res )
> >   return res;
> >
> > -set_interrupt(intr, GUEST_VPL011_SPI, 0xf, DT_IRQ_TYPE_LEVEL_HIGH);
> > +set_interrupt(intr, d->arch.vpl011.virq, 0xf,
> > + DT_IRQ_TYPE_LEVEL_HIGH);
> >
> >   res = fdt_property(fdt, "interrupts", intr, sizeof (intr));
> >   if ( res )
> > @@ -2670,6 +2674,13 @@ static int __init construct_domU(struct domain
> *d,
> >   else
> >   allocate_static_memory(d, &kinfo, node);
> >
> > +/*
> > + * Initialization before creating its device
> > + * tree node in prepare_dtb_domU.
> > + */
> 
> I think it would be better to explain *why* this needs to be done before.
> 
> > +if ( kinfo.vpl011 )
> > +rc = domain_vpl011_init(d, NULL);
> > +
> >   rc = prepare_dtb_domU(d, &kinfo);
> >   if ( rc < 0 )
> >   return rc;
> > @@ -2678,9 +2689,6 @@ static int __init construct_domU(struct domain
> *d,
> >   if ( rc < 0 )
> >   return rc;
> >
> > -if ( kinfo.vpl011 )
> > -rc = domain_vpl011_init(d, NULL);
> > -
> >   return rc;
> >   }
> >
> > @@ -2723,15 +2731,27 @@ void __init create_domUs(void)
> >
> >   if ( !dt_property_read_u32(node, "nr_spis", &d_cfg.arch.nr_spis) )
> >   {
> > +unsigned int vpl011_virq = GUEST_VPL011_SPI;
> 
> Coding style: Add a newline here.
> 
> >   d_cfg.arch.nr_spis = gic_number_lines() - 32;
> >
> > +/*
> > + * The VPL011 virq is GUEST_VPL011_SPI, unless direct-map in
> > + * set, in which case we'll try to match the hardware.
> > + *
> > + * Typically, d-&

RE: [PATCH 10/11] xen/arm: device assignment on 1:1 direct-map domain

2021-10-09 Thread Penny Zheng
Hi Julien

> -Original Message-
> From: Julien Grall 
> Sent: Thursday, September 23, 2021 7:27 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Bertrand Marquis ; Wei Chen
> 
> Subject: Re: [PATCH 10/11] xen/arm: device assignment on 1:1 direct-map
> domain
> 
> Hi,
> 
> On 23/09/2021 08:11, Penny Zheng wrote:
> > User could do device passthrough, with
> > "xen,force-assign-without-iommu" in the device tree snippet, on
> > trusted guest through 1:1 direct-map, if IOMMU absent or disabled on
> hardware.
> 
> At the moment, it would be possible to passthrough a non-DMA capable
> device with direct-mapping. After this patch, this is going to be forbidden.
> 
> >
> > In order to achieve that, this patch adds 1:1 direct-map check and
> > disables iommu-related action.
> >
> > Signed-off-by: Penny Zheng 
> > ---
> >   xen/arch/arm/domain_build.c | 12 
> >   1 file changed, 8 insertions(+), 4 deletions(-)
> >
> > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> > index c92e510ae7..9a9d2522b7 100644
> > --- a/xen/arch/arm/domain_build.c
> > +++ b/xen/arch/arm/domain_build.c
> > @@ -2070,14 +2070,18 @@ static int __init
> handle_passthrough_prop(struct kernel_info *kinfo,
> >   if ( res < 0 )
> >   return res;
> >
> > +/*
> > + * If xen_force, we allow assignment of devices without IOMMU
> protection.
> > + * And if IOMMU is disabled or absent, 1:1 direct-map is necessary > +
> */
> > +if ( xen_force && is_domain_direct_mapped(kinfo->d) &&
> > + !dt_device_is_protected(node) )
> 
> dt_device_is_protected() will be always false unless the device is protected
> behing an SMMU using the legacy binding. So I don't think this is correct to
> move this check ahead. In fact..
> 
> > +return 0;
> > +
> >   res = iommu_add_dt_device(node);
> 
> ... the call should already be a NOP when the IOMMU is disabled or the
> device is not behind an IOMMU. So can you explain what you are trying to
> prevent here?
> 

If the IOMMU is disabled, iommu_add_dt_device will return 1 as errno. 
So we could not make it to the xen_force check...

So I tried to move all IOMMU action behind xen_force check.

Now, device assignment without IOMMU protection is only
applicable on direct-map domains, so this commit also adds
is_domain_direct_mapped check together with xen_force check.

> >   if ( res < 0 )
> >   return res;
> >
> > -/* If xen_force, we allow assignment of devices without IOMMU
> protection. */
> > -if ( xen_force && !dt_device_is_protected(node) )
> > -return 0;
> > -
> >   return iommu_assign_dt_device(kinfo->d, node);
> >   }
> >
> >
> 
> Cheers,
> 
> --
> Julien Grall


RE: [PATCH 10/11] xen/arm: device assignment on 1:1 direct-map domain

2021-10-11 Thread Penny Zheng
Hi julien

> -Original Message-
> From: Julien Grall 
> Sent: Monday, October 11, 2021 7:14 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Bertrand Marquis ; Wei Chen
> 
> Subject: Re: [PATCH 10/11] xen/arm: device assignment on 1:1 direct-map
> domain
> 
> 
> 
> On 09/10/2021 10:40, Penny Zheng wrote:
> > Hi Julien
> 
> Hi Penny,
> 
> >
> >> -Original Message-
> >> From: Julien Grall 
> >> Sent: Thursday, September 23, 2021 7:27 PM
> >> To: Penny Zheng ;
> >> xen-devel@lists.xenproject.org; sstabell...@kernel.org
> >> Cc: Bertrand Marquis ; Wei Chen
> >> 
> >> Subject: Re: [PATCH 10/11] xen/arm: device assignment on 1:1
> >> direct-map domain
> >>
> >> Hi,
> >>
> >> On 23/09/2021 08:11, Penny Zheng wrote:
> >>> User could do device passthrough, with
> >>> "xen,force-assign-without-iommu" in the device tree snippet, on
> >>> trusted guest through 1:1 direct-map, if IOMMU absent or disabled on
> >> hardware.
> >>
> >> At the moment, it would be possible to passthrough a non-DMA capable
> >> device with direct-mapping. After this patch, this is going to be 
> >> forbidden.
> >>
> >>>
> >>> In order to achieve that, this patch adds 1:1 direct-map check and
> >>> disables iommu-related action.
> >>>
> >>> Signed-off-by: Penny Zheng 
> >>> ---
> >>>xen/arch/arm/domain_build.c | 12 
> >>>1 file changed, 8 insertions(+), 4 deletions(-)
> >>>
> >>> diff --git a/xen/arch/arm/domain_build.c
> >>> b/xen/arch/arm/domain_build.c index c92e510ae7..9a9d2522b7 100644
> >>> --- a/xen/arch/arm/domain_build.c
> >>> +++ b/xen/arch/arm/domain_build.c
> >>> @@ -2070,14 +2070,18 @@ static int __init
> >> handle_passthrough_prop(struct kernel_info *kinfo,
> >>>if ( res < 0 )
> >>>return res;
> >>>
> >>> +/*
> >>> + * If xen_force, we allow assignment of devices without IOMMU
> >> protection.
> >>> + * And if IOMMU is disabled or absent, 1:1 direct-map is
> >>> + necessary > +
> >> */
> >>> +if ( xen_force && is_domain_direct_mapped(kinfo->d) &&
> >>> + !dt_device_is_protected(node) )
> >>
> >> dt_device_is_protected() will be always false unless the device is
> >> protected behing an SMMU using the legacy binding. So I don't think
> >> this is correct to move this check ahead. In fact..
> >>
> >>> +return 0;
> >>> +
> >>>res = iommu_add_dt_device(node);
> >>
> >> ... the call should already be a NOP when the IOMMU is disabled or
> >> the device is not behind an IOMMU. So can you explain what you are
> >> trying to prevent here?
> >>
> >
> > If the IOMMU is disabled, iommu_add_dt_device will return 1 as errno.
> > So we could not make it to the xen_force check...
> 
> I disagree. The check is:
> 
> if ( res < 0 )
>return res;
> 
> Given that res is 1, we wouldn't return and move to check whether the
> assignment can be done.
> 
> >
> > So I tried to move all IOMMU action behind xen_force check.
> >
> > Now, device assignment without IOMMU protection is only applicable on
> > direct-map domains,
> 
> It is fine to assign a non-DMA capable device without direct-mapping. So why
> do you want to add this restriction?

I understand.
If it is fine to assign a non-DMA capable device without direct-mapping, the 
former
commit containing the following changes needs fix.

 if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") )
{
if ( iommu_enabled )
d_cfg.flags |= XEN_DOMCTL_CDF_iommu;
else if ( d_cfg.flags & XEN_DOMCTL_INTERNAL_directmap )
warning_add("Please be sure of having trusted guests, when 
doing device assignment without IOMMU protection\n");
else
panic("Assign a device but IOMMU and direct-map are all 
disabled\n");
}

Definitely no panic when IOMMU and direct-map are all disabled.

> 
> Cheers,
> 
> --
> Julien Grall


RE: [PATCH 09/11] xen/arm: if 1:1 direct-map domain use native UART address and IRQ number for vPL011

2021-10-11 Thread Penny Zheng
Hi Julien

> -Original Message-
> From: Julien Grall 
> Sent: Monday, October 11, 2021 6:49 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Bertrand Marquis ; Wei Chen
> 
> Subject: Re: [PATCH 09/11] xen/arm: if 1:1 direct-map domain use native UART
> address and IRQ number for vPL011
> 
> On 09/10/2021 09:47, Penny Zheng wrote:
> > Hi Julien
> 
> Hi Penny,
> 
> >> -Original Message-
> >> From: Julien Grall 
> >> Sent: Thursday, September 23, 2021 7:14 PM
> >> To: Penny Zheng ;
> >> xen-devel@lists.xenproject.org; sstabell...@kernel.org
> >> Cc: Bertrand Marquis ; Wei Chen
> >> 
> >> Subject: Re: [PATCH 09/11] xen/arm: if 1:1 direct-map domain use
> >> native UART address and IRQ number for vPL011
> >>
> >>
> >>
> >> On 23/09/2021 08:11, Penny Zheng wrote:
> >>> From: Stefano Stabellini 
> >>>
> >>> We always use a fix address to map the vPL011 to domains. The
> >>> address could be a problem for domains that are directly mapped.
> >>>
> >>> So, for domains that are directly mapped, reuse the address of the
> >>> physical UART on the platform to avoid potential clashes.
> >>>
> >>> Do the same for the virtual IRQ number: instead of always using
> >>> GUEST_VPL011_SPI, try to reuse the physical SPI number if possible.
> >>>
> >>> Signed-off-by: Stefano Stabellini 
> >>> Signed-off-by: Penny Zheng 
> >>> ---
> >>>xen/arch/arm/domain_build.c  | 34 +++-
> --
> >>>xen/arch/arm/vpl011.c| 34 +++---
> >>>xen/include/asm-arm/vpl011.h |  2 ++
> >>>3 files changed, 56 insertions(+), 14 deletions(-)
> >>>
> >>> diff --git a/xen/arch/arm/domain_build.c
> >>> b/xen/arch/arm/domain_build.c index 120f1ae575..c92e510ae7 100644
> >>> --- a/xen/arch/arm/domain_build.c
> >>> +++ b/xen/arch/arm/domain_build.c
> >>> @@ -30,6 +30,7 @@
> >>>
> >>>#include 
> >>>#include 
> >>> +#include 
> >>>
> >>>static unsigned int __initdata opt_dom0_max_vcpus;
> >>>integer_param("dom0_max_vcpus", opt_dom0_max_vcpus); @@ -
> 1942,8
> >>> +1943,11 @@ static int __init make_vpl011_uart_node(struct
> >>> +kernel_info
> >> *kinfo)
> >>>gic_interrupt_t intr;
> >>>__be32 reg[GUEST_ROOT_ADDRESS_CELLS +
> GUEST_ROOT_SIZE_CELLS];
> >>>__be32 *cells;
> >>> +struct domain *d = kinfo->d;
> >>> +char buf[27];
> >>>
> >>> -res = fdt_begin_node(fdt, "sbsa-
> uart@"__stringify(GUEST_PL011_BASE));
> >>> +snprintf(buf, sizeof(buf), "sbsa-uart@%"PRIx64, d-
> >>> arch.vpl011.base_addr);
> >>> +res = fdt_begin_node(fdt, buf);
> >>>if ( res )
> >>>return res;
> >>>
> >>> @@ -1953,14 +1957,14 @@ static int __init
> >>> make_vpl011_uart_node(struct kernel_info *kinfo)
> >>>
> >>>cells = ®[0];
> >>>dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS,
> >>> -   GUEST_ROOT_SIZE_CELLS, GUEST_PL011_BASE,
> >>> +   GUEST_ROOT_SIZE_CELLS,
> >>> + d->arch.vpl011.base_addr,
> >>>   GUEST_PL011_SIZE);
> >>>
> >>>res = fdt_property(fdt, "reg", reg, sizeof(reg));
> >>>if ( res )
> >>>return res;
> >>>
> >>> -set_interrupt(intr, GUEST_VPL011_SPI, 0xf, DT_IRQ_TYPE_LEVEL_HIGH);
> >>> +set_interrupt(intr, d->arch.vpl011.virq, 0xf,
> >>> + DT_IRQ_TYPE_LEVEL_HIGH);
> >>>
> >>>res = fdt_property(fdt, "interrupts", intr, sizeof (intr));
> >>>if ( res )
> >>> @@ -2670,6 +2674,13 @@ static int __init construct_domU(struct
> >>> domain
> >> *d,
> >>>else
> >>>allocate_static_memory(d, &kinfo, node);
> >>>
> >>> +/*
> >>> + * Initialization before creating its device
> >>> + * tree node in prepare_dtb_domU.
> >>> + */
> >>
> >> I think it would be better t

RE: [PATCH 10/11] xen/arm: device assignment on 1:1 direct-map domain

2021-10-13 Thread Penny Zheng
Hi Julien

> -Original Message-
> From: Julien Grall 
> Sent: Monday, October 11, 2021 7:14 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Bertrand Marquis ; Wei Chen
> 
> Subject: Re: [PATCH 10/11] xen/arm: device assignment on 1:1 direct-map
> domain
> 
> 
> 
> On 09/10/2021 10:40, Penny Zheng wrote:
> > Hi Julien
> 
> Hi Penny,
> 
> >
> >> -Original Message-
> >> From: Julien Grall 
> >> Sent: Thursday, September 23, 2021 7:27 PM
> >> To: Penny Zheng ;
> >> xen-devel@lists.xenproject.org; sstabell...@kernel.org
> >> Cc: Bertrand Marquis ; Wei Chen
> >> 
> >> Subject: Re: [PATCH 10/11] xen/arm: device assignment on 1:1
> >> direct-map domain
> >>
> >> Hi,
> >>
> >> On 23/09/2021 08:11, Penny Zheng wrote:
> >>> User could do device passthrough, with
> >>> "xen,force-assign-without-iommu" in the device tree snippet, on
> >>> trusted guest through 1:1 direct-map, if IOMMU absent or disabled on
> >> hardware.
> >>
> >> At the moment, it would be possible to passthrough a non-DMA capable
> >> device with direct-mapping. After this patch, this is going to be 
> >> forbidden.
> >>
> >>>
> >>> In order to achieve that, this patch adds 1:1 direct-map check and
> >>> disables iommu-related action.
> >>>
> >>> Signed-off-by: Penny Zheng 
> >>> ---
> >>>xen/arch/arm/domain_build.c | 12 
> >>>1 file changed, 8 insertions(+), 4 deletions(-)
> >>>
> >>> diff --git a/xen/arch/arm/domain_build.c
> >>> b/xen/arch/arm/domain_build.c index c92e510ae7..9a9d2522b7 100644
> >>> --- a/xen/arch/arm/domain_build.c
> >>> +++ b/xen/arch/arm/domain_build.c
> >>> @@ -2070,14 +2070,18 @@ static int __init
> >> handle_passthrough_prop(struct kernel_info *kinfo,
> >>>if ( res < 0 )
> >>>return res;
> >>>
> >>> +/*
> >>> + * If xen_force, we allow assignment of devices without IOMMU
> >> protection.
> >>> + * And if IOMMU is disabled or absent, 1:1 direct-map is
> >>> + necessary > +
> >> */
> >>> +if ( xen_force && is_domain_direct_mapped(kinfo->d) &&
> >>> + !dt_device_is_protected(node) )
> >>
> >> dt_device_is_protected() will be always false unless the device is
> >> protected behing an SMMU using the legacy binding. So I don't think
> >> this is correct to move this check ahead. In fact..
> >>
> >>> +return 0;
> >>> +
> >>>res = iommu_add_dt_device(node);
> >>
> >> ... the call should already be a NOP when the IOMMU is disabled or
> >> the device is not behind an IOMMU. So can you explain what you are
> >> trying to prevent here?
> >>
> >
> > If the IOMMU is disabled, iommu_add_dt_device will return 1 as errno.
> > So we could not make it to the xen_force check...
> 
> I disagree. The check is:
> 
> if ( res < 0 )
>return res;
> 
> Given that res is 1, we wouldn't return and move to check whether the
> assignment can be done.
> 
> >
> > So I tried to move all IOMMU action behind xen_force check.
> >
> > Now, device assignment without IOMMU protection is only applicable on
> > direct-map domains,
> 
> It is fine to assign a non-DMA capable device without direct-mapping. So why
> do you want to add this restriction?
> 

When constructing direct-map-v2, found that, in xen/arch/arm/domain_build.c

if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") )
d_cfg.flags |= XEN_DOMCTL_CDF_iommu;

And this flag XEN_DOMCTL_CDF_iommu determines whether iommu is enabled.

In ./xen/include/xen/sched.h

static always_inline bool is_iommu_enabled(const struct domain *d)
{
return evaluate_nospec(d->options & XEN_DOMCTL_CDF_iommu);
}

That is, even if we assign a non-DMA capable device, we request the platform to 
be
iommu enabled.

> Cheers,
> 
> --
> Julien Grall


RE: [PATCH 10/11] xen/arm: device assignment on 1:1 direct-map domain

2021-10-13 Thread Penny Zheng

> -Original Message-
> From: Penny Zheng
> Sent: Wednesday, October 13, 2021 3:44 PM
> To: Julien Grall ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Bertrand Marquis ; Wei Chen
> 
> Subject: RE: [PATCH 10/11] xen/arm: device assignment on 1:1 direct-map
> domain
> 
> Hi Julien
> 
> > -Original Message-
> > From: Julien Grall 
> > Sent: Monday, October 11, 2021 7:14 PM
> > To: Penny Zheng ; xen-devel@lists.xenproject.org;
> > sstabell...@kernel.org
> > Cc: Bertrand Marquis ; Wei Chen
> > 
> > Subject: Re: [PATCH 10/11] xen/arm: device assignment on 1:1
> > direct-map domain
> >
> >
> >
> > On 09/10/2021 10:40, Penny Zheng wrote:
> > > Hi Julien
> >
> > Hi Penny,
> >
> > >
> > >> -Original Message-
> > >> From: Julien Grall 
> > >> Sent: Thursday, September 23, 2021 7:27 PM
> > >> To: Penny Zheng ;
> > >> xen-devel@lists.xenproject.org; sstabell...@kernel.org
> > >> Cc: Bertrand Marquis ; Wei Chen
> > >> 
> > >> Subject: Re: [PATCH 10/11] xen/arm: device assignment on 1:1
> > >> direct-map domain
> > >>
> > >> Hi,
> > >>
> > >> On 23/09/2021 08:11, Penny Zheng wrote:
> > >>> User could do device passthrough, with
> > >>> "xen,force-assign-without-iommu" in the device tree snippet, on
> > >>> trusted guest through 1:1 direct-map, if IOMMU absent or disabled
> > >>> on
> > >> hardware.
> > >>
> > >> At the moment, it would be possible to passthrough a non-DMA
> > >> capable device with direct-mapping. After this patch, this is going to be
> forbidden.
> > >>
> > >>>
> > >>> In order to achieve that, this patch adds 1:1 direct-map check and
> > >>> disables iommu-related action.
> > >>>
> > >>> Signed-off-by: Penny Zheng 
> > >>> ---
> > >>>xen/arch/arm/domain_build.c | 12 
> > >>>1 file changed, 8 insertions(+), 4 deletions(-)
> > >>>
> > >>> diff --git a/xen/arch/arm/domain_build.c
> > >>> b/xen/arch/arm/domain_build.c index c92e510ae7..9a9d2522b7 100644
> > >>> --- a/xen/arch/arm/domain_build.c
> > >>> +++ b/xen/arch/arm/domain_build.c
> > >>> @@ -2070,14 +2070,18 @@ static int __init
> > >> handle_passthrough_prop(struct kernel_info *kinfo,
> > >>>if ( res < 0 )
> > >>>return res;
> > >>>
> > >>> +/*
> > >>> + * If xen_force, we allow assignment of devices without IOMMU
> > >> protection.
> > >>> + * And if IOMMU is disabled or absent, 1:1 direct-map is
> > >>> + necessary > +
> > >> */
> > >>> +if ( xen_force && is_domain_direct_mapped(kinfo->d) &&
> > >>> + !dt_device_is_protected(node) )
> > >>
> > >> dt_device_is_protected() will be always false unless the device is
> > >> protected behing an SMMU using the legacy binding. So I don't think
> > >> this is correct to move this check ahead. In fact..
> > >>
> > >>> +return 0;
> > >>> +
> > >>>res = iommu_add_dt_device(node);
> > >>
> > >> ... the call should already be a NOP when the IOMMU is disabled or
> > >> the device is not behind an IOMMU. So can you explain what you are
> > >> trying to prevent here?
> > >>
> > >
> > > If the IOMMU is disabled, iommu_add_dt_device will return 1 as errno.
> > > So we could not make it to the xen_force check...
> >
> > I disagree. The check is:
> >
> > if ( res < 0 )
> >return res;
> >
> > Given that res is 1, we wouldn't return and move to check whether the
> > assignment can be done.
> >
> > >
> > > So I tried to move all IOMMU action behind xen_force check.
> > >
> > > Now, device assignment without IOMMU protection is only applicable
> > > on direct-map domains,
> >
> > It is fine to assign a non-DMA capable device without direct-mapping.
> > So why do you want to add this restriction?
> >
> 
> When constructing direct-map-v2, found that, in
> xen/arch/arm/domain_build.c
> 
> if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") )
> d_cfg.flags |= XEN_DOMCTL_CDF_iommu;
> 
> And this flag XEN_DOMCTL_CDF_iommu determines whether iommu is
> enabled.
> 
> In ./xen/include/xen/sched.h
> 
> static always_inline bool is_iommu_enabled(const struct domain *d) {
> return evaluate_nospec(d->options & XEN_DOMCTL_CDF_iommu); }
> 
> That is, even if we assign a non-DMA capable device, we request the platform
> to be iommu enabled.
>

I intend to change it to

if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") )
{
if ( iommu_enabled )
d_cfg.flags |= XEN_DOMCTL_CDF_iommu;
else if ( d_cfg.flags & XEN_DOMCTL_CDF_directmap )
warning_add("Please be sure of having trusted guests, when 
doing device assignment without IOMMU protection\n");
}

> > Cheers,
> >
> > --
> > Julien Grall


RE: [PATCH 09/11] xen/arm: if 1:1 direct-map domain use native UART address and IRQ number for vPL011

2021-10-13 Thread Penny Zheng
Hi Julien

> -Original Message-
> From: Julien Grall 
> Sent: Thursday, October 14, 2021 2:01 AM
> To: Penny Zheng ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Bertrand Marquis ; Wei Chen
> 
> Subject: Re: [PATCH 09/11] xen/arm: if 1:1 direct-map domain use native UART
> address and IRQ number for vPL011
> 
> On 12/10/2021 03:42, Penny Zheng wrote:
> > Hi Julien
> 
> Hi Penny,
> 
> >> -Original Message-
> >> From: Julien Grall 
> >> Sent: Monday, October 11, 2021 6:49 PM
> >> To: Penny Zheng ;
> >> xen-devel@lists.xenproject.org; sstabell...@kernel.org
> >> Cc: Bertrand Marquis ; Wei Chen
> >> 
> >> Subject: Re: [PATCH 09/11] xen/arm: if 1:1 direct-map domain use
> >> native UART address and IRQ number for vPL011
> >>
> >> On 09/10/2021 09:47, Penny Zheng wrote:
> >>> Hi Julien
> >>
> >> Hi Penny,
> >>
> >>>> -Original Message-
> >>>> From: Julien Grall 
> >>>> Sent: Thursday, September 23, 2021 7:14 PM
> >>>> To: Penny Zheng ;
> >>>> xen-devel@lists.xenproject.org; sstabell...@kernel.org
> >>>> Cc: Bertrand Marquis ; Wei Chen
> >>>> 
> >>>> Subject: Re: [PATCH 09/11] xen/arm: if 1:1 direct-map domain use
> >>>> native UART address and IRQ number for vPL011
> >>>>
> >>>>
> >>>>
> >>>> On 23/09/2021 08:11, Penny Zheng wrote:
> >>>>> From: Stefano Stabellini 
> >>>>>
> >>>>> We always use a fix address to map the vPL011 to domains. The
> >>>>> address could be a problem for domains that are directly mapped.
> >>>>>
> >>>>> So, for domains that are directly mapped, reuse the address of the
> >>>>> physical UART on the platform to avoid potential clashes.
> >>>>>
> >>>>> Do the same for the virtual IRQ number: instead of always using
> >>>>> GUEST_VPL011_SPI, try to reuse the physical SPI number if possible.
> >>>>>
> >>>>> Signed-off-by: Stefano Stabellini 
> >>>>> Signed-off-by: Penny Zheng 
> >>>>> ---
> >>>>> xen/arch/arm/domain_build.c  | 34
> >>>>> +++-
> >> --
> >>>>> xen/arch/arm/vpl011.c| 34 +++---
> >>>>> xen/include/asm-arm/vpl011.h |  2 ++
> >>>>> 3 files changed, 56 insertions(+), 14 deletions(-)
> >>>>>
> >>>>> diff --git a/xen/arch/arm/domain_build.c
> >>>>> b/xen/arch/arm/domain_build.c index 120f1ae575..c92e510ae7 100644
> >>>>> --- a/xen/arch/arm/domain_build.c
> >>>>> +++ b/xen/arch/arm/domain_build.c
> >>>>> @@ -30,6 +30,7 @@
> >>>>>
> >>>>> #include 
> >>>>> #include 
> >>>>> +#include 
> >>>>>
> >>>>> static unsigned int __initdata opt_dom0_max_vcpus;
> >>>>> integer_param("dom0_max_vcpus", opt_dom0_max_vcpus); @@ -
> >> 1942,8
> >>>>> +1943,11 @@ static int __init make_vpl011_uart_node(struct
> >>>>> +kernel_info
> >>>> *kinfo)
> >>>>> gic_interrupt_t intr;
> >>>>> __be32 reg[GUEST_ROOT_ADDRESS_CELLS +
> >> GUEST_ROOT_SIZE_CELLS];
> >>>>> __be32 *cells;
> >>>>> +struct domain *d = kinfo->d;
> >>>>> +char buf[27];
> >>>>>
> >>>>> -res = fdt_begin_node(fdt, "sbsa-
> >> uart@"__stringify(GUEST_PL011_BASE));
> >>>>> +snprintf(buf, sizeof(buf), "sbsa-uart@%"PRIx64, d-
> >>>>> arch.vpl011.base_addr);
> >>>>> +res = fdt_begin_node(fdt, buf);
> >>>>> if ( res )
> >>>>> return res;
> >>>>>
> >>>>> @@ -1953,14 +1957,14 @@ static int __init
> >>>>> make_vpl011_uart_node(struct kernel_info *kinfo)
> >>>>>
> >>>>> cells = ®[0];
> >>>>> dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS,
> >>>>> -   GUEST_ROOT_SIZE_CELLS, GUEST_PL011_BASE,
> >>>>&

[PATCH v2 1/6] xen: introduce XEN_DOMCTL_CDF_directmap

2021-10-14 Thread Penny Zheng
From: Stefano Stabellini 

This commit introduces a new arm-specific flag XEN_DOMCTL_CDF_directmap to
specify that this domain should have its memory directly mapped
(guest physical address == physical address) at domain creation.

Refine is_domain_direct_mapped to check whether the flag
XEN_DOMCTL_CDF_directmap is set.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
---
CC: andrew.coop...@citrix.com
CC: jbeul...@suse.com
CC: George Dunlap 
CC: Ian Jackson 
CC: Wei Liu 
CC: "Roger Pau Monné" 
---
 xen/arch/arm/domain.c| 3 ++-
 xen/arch/arm/domain_build.c  | 4 +++-
 xen/common/domain.c  | 3 ++-
 xen/include/asm-arm/domain.h | 4 ++--
 xen/include/public/domctl.h  | 4 +++-
 5 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index eef0661beb..8cee1c6349 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -628,7 +628,8 @@ int arch_sanitise_domain_config(struct 
xen_domctl_createdomain *config)
 {
 unsigned int max_vcpus;
 unsigned int flags_required = (XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap);
-unsigned int flags_optional = (XEN_DOMCTL_CDF_iommu | XEN_DOMCTL_CDF_vpmu);
+unsigned int flags_optional = (XEN_DOMCTL_CDF_iommu | XEN_DOMCTL_CDF_vpmu |
+   XEN_DOMCTL_CDF_directmap);
 
 if ( (config->flags & ~flags_optional) != flags_required )
 {
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 0167731ab0..37e2d62d47 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -3069,8 +3069,10 @@ static int __init construct_dom0(struct domain *d)
 void __init create_dom0(void)
 {
 struct domain *dom0;
+/* DOM0 has always its memory directly mapped. */
 struct xen_domctl_createdomain dom0_cfg = {
-.flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
+.flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap |
+ XEN_DOMCTL_CDF_directmap,
 .max_evtchn_port = -1,
 .max_grant_frames = gnttab_dom0_frames(),
 .max_maptrack_frames = -1,
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 8b53c49d1e..7a6131db74 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -486,7 +486,8 @@ static int sanitise_domain_config(struct 
xen_domctl_createdomain *config)
  ~(XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap |
XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off |
XEN_DOMCTL_CDF_xs_domain | XEN_DOMCTL_CDF_iommu |
-   XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu) )
+   XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu |
+   XEN_DOMCTL_CDF_directmap) )
 {
 dprintk(XENLOG_INFO, "Unknown CDF flags %#x\n", config->flags);
 return -EINVAL;
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 14e575288f..fc42c6a310 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -29,8 +29,8 @@ enum domain_type {
 #define is_64bit_domain(d) (0)
 #endif
 
-/* The hardware domain has always its memory direct mapped. */
-#define is_domain_direct_mapped(d) is_hardware_domain(d)
+/* Check if domain is direct-map memory map. */
+#define is_domain_direct_mapped(d) (d->options & XEN_DOMCTL_CDF_directmap)
 
 struct vtimer {
 struct vcpu *v;
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 238384b5ae..b505a0db51 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -72,9 +72,11 @@ struct xen_domctl_createdomain {
 #define XEN_DOMCTL_CDF_nested_virt(1U << _XEN_DOMCTL_CDF_nested_virt)
 /* Should we expose the vPMU to the guest? */
 #define XEN_DOMCTL_CDF_vpmu   (1U << 7)
+/* If this domain has its memory directly mapped? (ARM only) */
+#define XEN_DOMCTL_CDF_directmap  (1U << 8)
 
 /* Max XEN_DOMCTL_CDF_* constant.  Used for ABI checking. */
-#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_vpmu
+#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_directmap
 
 uint32_t flags;
 
-- 
2.25.1




[PATCH v2 0/6] direct-map memory map

2021-10-14 Thread Penny Zheng
Cases where domU needs direct-map memory map:
  * IOMMU not present in the system.
  * IOMMU disabled if it doesn't cover a specific device and all the guests
are trusted. Thinking a mixed scenario, where a few devices with IOMMU and
a few without, then guest DMA security still could not be totally guaranteed.
So users may want to disable the IOMMU, to at least gain some performance
improvement from IOMMU disabled.
  * IOMMU disabled as a workaround when it doesn't have enough bandwidth.
To be specific, in a few extreme situation, when multiple devices do DMA
concurrently, these requests may exceed IOMMU's transmission capacity.
  * IOMMU disabled when it adds too much latency on DMA. For example,
TLB may be missing in some IOMMU hardware, which may bring latency in DMA
progress, so users may want to disable it in some realtime scenario.

*WARNING:
Users should be aware that it is not always secure to assign a DMA-capable
device without IOMMU protection.
When the device is not protected by the IOMMU, the administrator should make
sure that:
 1. The device is assigned to a trusted guest.
 2. Users have additional security mechanism on the platform.

Requesting direct-map memory mapping for the domain, when IOMMU is absent from
the system or it is disabled (status = "disabled" in device tree), In which
case, "direct-map" property is added under the appropriate domain node.

Right now, direct-map is only supported when domain on Static Allocation,
that is, "xen,static-mem" is also necessary in the domain configuration.

Looking into related [design link](
https://lists.xenproject.org/archives/html/xen-devel/2021-05/msg00882.html)
for more details.

The whole design is about Static Allocation and direct-map, and this
Patch Serie only covers parts of it, which are direct-map memory map.
Other features will be delievered through different patch series.

See https://lists.xenproject.org/archives/html/xen-devel/2021-09/msg00855.html
for Domain on Static Allocation.

This patch serie is based on
https://lists.xenproject.org/archives/html/xen-devel/2021-10/msg00822.html

---
v2 changes:
- remove the introduce of internal flag
- Refine is_domain_direct_mapped to check whether the flag
XEN_DOMCTL_CDF_directmap is set
- reword "1:1 direct-map" to just "direct-map"
- split the common codes into two helpers: parse_static_mem_prop and
acquire_static_memory_bank to deduce complexity.
- introduce a new helper allocate_static_memory_11 for allocating static
memory for direct-map guests
- remove panic action since it is fine to assign a non-DMA capable device when
IOMMU and direct-map both off
- remove redistributor accessor
- introduce new helper "is_domain_use_host_layout()"
- explain why vpl011 initialization before creating its device tree node
- error out if the domain is direct-mapped and the IRQ is not found
- harden the code and add a check/comment when the hardware UART region
is smaller than CUEST_VPL011_SIZE.

Stefano Stabellini (6):
  xen: introduce XEN_DOMCTL_CDF_directmap
  xen/arm: introduce direct-map for domUs
  xen/arm: if direct-map domain use native addresses for GICv2
  xen/arm: if direct-map domain use native addresses for GICv3
  xen/arm: if direct-map domain use native UART address and IRQ number
for vPL011
  xen/docs: add a document to explain how to do passthrough without
IOMMU

 docs/misc/arm/device-tree/booting.txt |  10 +
 docs/misc/arm/passthrough-noiommu.txt |  54 +
 xen/arch/arm/domain.c |   3 +-
 xen/arch/arm/domain_build.c   | 316 --
 xen/arch/arm/vgic-v2.c|  26 ++-
 xen/arch/arm/vgic-v3.c|  20 +-
 xen/arch/arm/vgic/vgic-v2.c   |  27 ++-
 xen/arch/arm/vpl011.c |  54 -
 xen/common/domain.c   |   3 +-
 xen/include/asm-arm/domain.h  |   7 +-
 xen/include/asm-arm/new_vgic.h|  10 +
 xen/include/asm-arm/vgic.h|  12 +-
 xen/include/asm-arm/vpl011.h  |   2 +
 xen/include/public/domctl.h   |   4 +-
 14 files changed, 449 insertions(+), 99 deletions(-)
 create mode 100644 docs/misc/arm/passthrough-noiommu.txt

-- 
2.25.1




[PATCH v2 2/6] xen/arm: introduce direct-map for domUs

2021-10-14 Thread Penny Zheng
From: Stefano Stabellini 

Cases where domU needs direct-map memory map:
  * IOMMU not present in the system.
  * IOMMU disabled if it doesn't cover a specific device and all the guests
are trusted. Thinking a mixed scenario, where a few devices with IOMMU and
a few without, then guest DMA security still could not be totally guaranteed.
So users may want to disable the IOMMU, to at least gain some performance
improvement from IOMMU disabled.
  * IOMMU disabled as a workaround when it doesn't have enough bandwidth.
To be specific, in a few extreme situation, when multiple devices do DMA
concurrently, these requests may exceed IOMMU's transmission capacity.
  * IOMMU disabled when it adds too much latency on DMA. For example,
TLB may be missing in some IOMMU hardware, which may bring latency in DMA
progress, so users may want to disable it in some realtime scenario.
  * Guest OS relies on the host memory layout-capablei

*WARNING:
Users should be aware that it is not always secure to assign a DMA-capable
device without IOMMU protection.
The administrator should make sure that:
 1. The device is assigned to a trusted guest.
 2. Users have additional security mechanism on the platform.

This commit also avoids setting XEN_DOMCTL_CDF_iommu when the IOMMU is
absent/disabled.

For now, direct-map is only supported when domain on Static Allocation, that is,
"xen.static-mem" must be also defined in the domain configuration.

This commit also introduces a new helper allocate_static_memory_11 to allocate
static memory as guest RAM for direct-map domain.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
---
 docs/misc/arm/device-tree/booting.txt |  10 ++
 xen/arch/arm/domain_build.c   | 215 --
 2 files changed, 179 insertions(+), 46 deletions(-)

diff --git a/docs/misc/arm/device-tree/booting.txt 
b/docs/misc/arm/device-tree/booting.txt
index 71895663a4..297f8fa0c8 100644
--- a/docs/misc/arm/device-tree/booting.txt
+++ b/docs/misc/arm/device-tree/booting.txt
@@ -182,6 +182,16 @@ with the following properties:
 Both #address-cells and #size-cells need to be specified because
 both sub-nodes (described shortly) have reg properties.
 
+- direct-map
+
+Optional for Domain on Static Allocation.
+An empty property to request the memory of the domain to be
+direct-map (guest physical address == physical address).
+WARNING:
+Users must be aware of this risk, when doing DMA-capable device assignment,
+direct-map guest must be trusted or have additional security mechanism,
+otherwise it could use the DMA engine to access any other memory area.
+
 Under the "xen,domain" compatible node, one or more sub-nodes are present
 for the DomU kernel and ramdisk.
 
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 37e2d62d47..d9118e5bc1 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -492,8 +492,14 @@ static bool __init append_static_memory_to_bank(struct 
domain *d,
 {
 int res;
 unsigned int nr_pages = PFN_DOWN(size);
-/* Infer next GFN. */
-gfn_t sgfn = gaddr_to_gfn(bank->start + bank->size);
+gfn_t sgfn;
+
+if ( !is_domain_direct_mapped(d) )
+/* Infer next GFN when GFN != MFN. */
+sgfn = gaddr_to_gfn(bank->start + bank->size);
+else
+sgfn = gaddr_to_gfn(mfn_to_maddr(smfn));
+
 
 res = guest_physmap_add_pages(d, sgfn, smfn, nr_pages);
 if ( res )
@@ -507,12 +513,69 @@ static bool __init append_static_memory_to_bank(struct 
domain *d,
 return true;
 }
 
-/* Allocate memory from static memory as RAM for one specific domain d. */
+static int __init acquire_static_memory_bank(struct domain *d,
+ const __be32 **cell,
+ u32 addr_cells, u32 size_cells,
+ paddr_t *pbase, paddr_t *psize)
+{
+int res = 0;
+
+device_tree_get_reg(cell, addr_cells, size_cells, pbase, psize);
+ASSERT(IS_ALIGNED(*pbase, PAGE_SIZE) && IS_ALIGNED(*psize, PAGE_SIZE));
+if ( PFN_DOWN(*psize) > UINT_MAX )
+{
+printk(XENLOG_ERR "%pd: static memory size too large: %#"PRIpaddr,
+   d, *psize);
+return -EINVAL;
+}
+
+res = acquire_domstatic_pages(d, maddr_to_mfn(*pbase), PFN_DOWN(*psize), 
0);
+if ( res )
+printk(XENLOG_ERR
+   "%pd: failed to acquire static memory: %d.\n", d, res);
+
+return res;
+}
+
+static int __init parse_static_mem_prop(const struct dt_device_node *node,
+u32 *addr_cells, u32 *size_cells,
+int *length, const __be32 **cell)
+{
+const struct dt_property *prop;
+
+prop = dt_find_property(node, "xen,static-mem", NULL);
+if ( !dt_property_read_u32(node, "#xen,st

[PATCH v2 3/6] xen/arm: if direct-map domain use native addresses for GICv2

2021-10-14 Thread Penny Zheng
From: Stefano Stabellini 

Today we use native addresses to map the GICv2 for Dom0 and fixed
addresses for DomUs.

This patch changes the behavior so that native addresses are used for
all domains that are direct-map memory map.

NEW VGIC has different naming schemes, like referring distributor base
address as vgic_dist_base, other than the dbase. So this patch also introduces
vgic_dist_base/vgic_cpu_base accessor to access correct distributor base
address/cpu interface base address on varied scenarios,

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain_build.c| 10 +++---
 xen/arch/arm/vgic-v2.c | 26 +-
 xen/arch/arm/vgic/vgic-v2.c| 27 ++-
 xen/include/asm-arm/new_vgic.h | 10 ++
 xen/include/asm-arm/vgic.h | 12 +++-
 5 files changed, 71 insertions(+), 14 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index d9118e5bc1..6cd03e4d0f 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2207,8 +2207,12 @@ static int __init make_gicv2_domU_node(struct 
kernel_info *kinfo)
 int res = 0;
 __be32 reg[(GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) * 2];
 __be32 *cells;
+struct domain *d = kinfo->d;
+char buf[38];
 
-res = fdt_begin_node(fdt, 
"interrupt-controller@"__stringify(GUEST_GICD_BASE));
+snprintf(buf, sizeof(buf), "interrupt-controller@%"PRIx64,
+ vgic_dist_base(&d->arch.vgic));
+res = fdt_begin_node(fdt, buf);
 if ( res )
 return res;
 
@@ -2230,9 +2234,9 @@ static int __init make_gicv2_domU_node(struct kernel_info 
*kinfo)
 
 cells = ®[0];
 dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-   GUEST_GICD_BASE, GUEST_GICD_SIZE);
+   vgic_dist_base(&d->arch.vgic), GUEST_GICD_SIZE);
 dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-   GUEST_GICC_BASE, GUEST_GICC_SIZE);
+   vgic_cpu_base(&d->arch.vgic), GUEST_GICC_SIZE);
 
 res = fdt_property(fdt, "reg", reg, sizeof(reg));
 if (res)
diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index b2da886adc..a8cf8173d0 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -652,7 +652,7 @@ static int vgic_v2_vcpu_init(struct vcpu *v)
 static int vgic_v2_domain_init(struct domain *d)
 {
 int ret;
-paddr_t cbase, csize;
+paddr_t csize;
 paddr_t vbase;
 
 /*
@@ -669,10 +669,26 @@ static int vgic_v2_domain_init(struct domain *d)
  * Note that we assume the size of the CPU interface is always
  * aligned to PAGE_SIZE.
  */
-cbase = vgic_v2_hw.cbase;
+d->arch.vgic.cbase = vgic_v2_hw.cbase;
 csize = vgic_v2_hw.csize;
 vbase = vgic_v2_hw.vbase;
 }
+else if ( is_domain_direct_mapped(d) )
+{
+/*
+ * For non-dom0 direct_mapped guests we only map a 8kB CPU
+ * interface but we make sure it is at a location occupied by
+ * the physical GIC in the host device tree.
+ *
+ * We need to add an offset to the virtual CPU interface base
+ * address when the GIC is aliased to get a 8kB contiguous
+ * region.
+ */
+d->arch.vgic.dbase = vgic_v2_hw.dbase;
+d->arch.vgic.cbase = vgic_v2_hw.cbase + vgic_v2_hw.aliased_offset;
+csize = GUEST_GICC_SIZE;
+vbase = vgic_v2_hw.vbase + vgic_v2_hw.aliased_offset;
+}
 else
 {
 d->arch.vgic.dbase = GUEST_GICD_BASE;
@@ -683,7 +699,7 @@ static int vgic_v2_domain_init(struct domain *d)
  * region.
  */
 BUILD_BUG_ON(GUEST_GICC_SIZE != SZ_8K);
-cbase = GUEST_GICC_BASE;
+d->arch.vgic.cbase = GUEST_GICC_BASE;
 csize = GUEST_GICC_SIZE;
 vbase = vgic_v2_hw.vbase + vgic_v2_hw.aliased_offset;
 }
@@ -692,8 +708,8 @@ static int vgic_v2_domain_init(struct domain *d)
  * Map the gic virtual cpu interface in the gic cpu interface
  * region of the guest.
  */
-ret = map_mmio_regions(d, gaddr_to_gfn(cbase), csize / PAGE_SIZE,
-   maddr_to_mfn(vbase));
+ret = map_mmio_regions(d, gaddr_to_gfn(d->arch.vgic.cbase),
+   csize / PAGE_SIZE, maddr_to_mfn(vbase));
 if ( ret )
 return ret;
 
diff --git a/xen/arch/arm/vgic/vgic-v2.c b/xen/arch/arm/vgic/vgic-v2.c
index b5ba4ace87..ce1f6e4373 100644
--- a/xen/arch/arm/vgic/vgic-v2.c
+++ b/xen/arch/arm/vgic/vgic-v2.c
@@ -258,7 +258,7 @@ void vgic_v2_enable(struct vcpu *vcpu)
 int vgic_v2_map_resources(struct domain *d)
 {
 struct vgic_dist *dist = &d->arch.vgic;
-paddr_t cbase, csize;
+paddr_t csize;
 paddr_t vbase;
 int ret;
 
@@ -276,10 +276,27 @@ int vgic

[PATCH v2 5/6] xen/arm: if direct-map domain use native UART address and IRQ number for vPL011

2021-10-14 Thread Penny Zheng
From: Stefano Stabellini 

We always use a fix address to map the vPL011 to domains. The address
could be a problem for direct-map domains.

So, for domains that are directly mapped, reuse the address of the
physical UART on the platform to avoid potential clashes.

Do the same for the virtual IRQ number: instead of always using
GUEST_VPL011_SPI, try to reuse the physical SPI number if possible.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain_build.c  | 41 ++-
 xen/arch/arm/vpl011.c| 54 +++-
 xen/include/asm-arm/vpl011.h |  2 ++
 3 files changed, 83 insertions(+), 14 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 7e0ee07e06..f3e87709f6 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -30,6 +30,7 @@
 
 #include 
 #include 
+#include 
 
 static unsigned int __initdata opt_dom0_max_vcpus;
 integer_param("dom0_max_vcpus", opt_dom0_max_vcpus);
@@ -2350,8 +2351,11 @@ static int __init make_vpl011_uart_node(struct 
kernel_info *kinfo)
 gic_interrupt_t intr;
 __be32 reg[GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS];
 __be32 *cells;
+struct domain *d = kinfo->d;
+char buf[27];
 
-res = fdt_begin_node(fdt, "sbsa-uart@"__stringify(GUEST_PL011_BASE));
+snprintf(buf, sizeof(buf), "sbsa-uart@%"PRIx64, d->arch.vpl011.base_addr);
+res = fdt_begin_node(fdt, buf);
 if ( res )
 return res;
 
@@ -2361,14 +2365,14 @@ static int __init make_vpl011_uart_node(struct 
kernel_info *kinfo)
 
 cells = ®[0];
 dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS,
-   GUEST_ROOT_SIZE_CELLS, GUEST_PL011_BASE,
+   GUEST_ROOT_SIZE_CELLS, d->arch.vpl011.base_addr,
GUEST_PL011_SIZE);
 
 res = fdt_property(fdt, "reg", reg, sizeof(reg));
 if ( res )
 return res;
 
-set_interrupt(intr, GUEST_VPL011_SPI, 0xf, DT_IRQ_TYPE_LEVEL_HIGH);
+set_interrupt(intr, d->arch.vpl011.virq, 0xf, DT_IRQ_TYPE_LEVEL_HIGH);
 
 res = fdt_property(fdt, "interrupts", intr, sizeof (intr));
 if ( res )
@@ -3083,6 +3087,14 @@ static int __init construct_domU(struct domain *d,
 allocate_static_memory(d, &kinfo, node);
 }
 
+/*
+ * Base address and irq number are needed when creating vpl011 device
+ * tree node in prepare_dtb_domU, so initialization on related variables
+ * shall be dealt firstly.
+ */
+if ( kinfo.vpl011 )
+rc = domain_vpl011_init(d, NULL);
+
 rc = prepare_dtb_domU(d, &kinfo);
 if ( rc < 0 )
 return rc;
@@ -3091,9 +3103,6 @@ static int __init construct_domU(struct domain *d,
 if ( rc < 0 )
 return rc;
 
-if ( kinfo.vpl011 )
-rc = domain_vpl011_init(d, NULL);
-
 return rc;
 }
 
@@ -3132,15 +3141,33 @@ void __init create_domUs(void)
 
 if ( !dt_property_read_u32(node, "nr_spis", &d_cfg.arch.nr_spis) )
 {
+unsigned int vpl011_virq = GUEST_VPL011_SPI;
+
 d_cfg.arch.nr_spis = gic_number_lines() - 32;
 
+/*
+ * The VPL011 virq is GUEST_VPL011_SPI, unless direct-map in
+ * set, in which case we'll try to match the hardware.
+ *
+ * Typically, d->arch.vpl011.virq has the vpl011 irq number
+ * but at this point of the boot sequence it is not
+ * initialized yet.
+ */
+if ( d_cfg.flags & XEN_DOMCTL_CDF_directmap )
+{
+vpl011_virq = serial_irq(SERHND_DTUART);
+if ( vpl011_virq < 0 )
+panic("Error getting IRQ number for this serial port %d\n",
+  SERHND_DTUART);
+}
+
 /*
  * vpl011 uses one emulated SPI. If vpl011 is requested, make
  * sure that we allocate enough SPIs for it.
  */
 if ( dt_property_read_bool(node, "vpl011") )
 d_cfg.arch.nr_spis = MAX(d_cfg.arch.nr_spis,
- GUEST_VPL011_SPI - 32 + 1);
+ vpl011_virq - 32 + 1);
 }
 
 /*
diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c
index 895f436cc4..2de59e584d 100644
--- a/xen/arch/arm/vpl011.c
+++ b/xen/arch/arm/vpl011.c
@@ -29,6 +29,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -71,11 +72,11 @@ static void vpl011_update_interrupt_status(struct domain *d)
  * status bit has been set since the last time.
  */
 if ( uartmis & ~vpl011->shadow_uartmis )
-vgic_inject_irq(d, NULL, GUEST_VPL011_SPI, true);
+vgic_inject_irq(d, NULL, vpl011->virq, true);
 
 vpl011->shadow_uar

[PATCH v2 6/6] xen/docs: add a document to explain how to do passthrough without IOMMU

2021-10-14 Thread Penny Zheng
From: Stefano Stabellini 

Make sure to start with a WARNING about security.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
---
 docs/misc/arm/passthrough-noiommu.txt | 54 +++
 1 file changed, 54 insertions(+)
 create mode 100644 docs/misc/arm/passthrough-noiommu.txt

diff --git a/docs/misc/arm/passthrough-noiommu.txt 
b/docs/misc/arm/passthrough-noiommu.txt
new file mode 100644
index 00..61aeb8a5cd
--- /dev/null
+++ b/docs/misc/arm/passthrough-noiommu.txt
@@ -0,0 +1,54 @@
+Request Device Assignment without IOMMU support
+===
+
+*WARNING:
+Users should be aware that it is not always secure to assign a device without
+IOMMU protection.
+When the device is not protected by the IOMMU, the administrator should make
+sure that:
+ 1. The device is assigned to a trusted guest.
+ 2. Users have additional security mechanism on the platform.
+
+
+This document assumes that the IOMMU is absent from the system or it is
+disabled (status = "disabled" in device tree).
+
+
+Add xen,force-assign-without-iommu; to the device tree snippet:
+
+ethernet: ethernet@ff0e {
+   compatible = "cdns,zynqmp-gem";
+   xen,path = "/amba/ethernet@ff0e";
+   xen,reg = <0x0 0xff0e 0x1000 0x0 0xff0e>;
+   xen,force-assign-without-iommu;
+};
+
+Request 1:1 memory mapping for the domain on static allocation
+==
+
+Add a direct-map property under the appropriate /chosen/domU node which
+is also statically allocated with physical memory ranges through
+xen,static-mem property as its guest RAM.
+
+Below is an example on how to specify the 1:1 memory mapping for the domain
+on static allocation in the device-tree:
+
+/ {
+   chosen {
+   domU1 {
+   compatible = "xen,domain";
+   #address-cells = <0x2>;
+   #size-cells = <0x2>;
+   cpus = <2>;
+   memory = <0x0 0x8>;
+   #xen,static-mem-address-cells = <0x1>;
+   #xen,static-mem-size-cells = <0x1>;
+   xen,static-mem = <0x3000 0x2000>;
+   direct-map;
+   ...
+   };
+   };
+};
+
+Besides reserving a 512MB region starting at the host physical address
+0x3000 to DomU1, it also requests 1:1 memory mapping.
-- 
2.25.1




[PATCH v2 4/6] xen/arm: if direct-map domain use native addresses for GICv3

2021-10-14 Thread Penny Zheng
From: Stefano Stabellini 

Today we use native addresses to map the GICv3 for Dom0 and fixed
addresses for DomUs.

This patch changes the behavior so that native addresses are used for
all direct-map domains(including Dom0).

Considering that dom0 may not always be directly mapped in the future,
this patch introduces a new helper "is_domain_use_host_layout()" that
wraps both two check "is_domain_direct_mapped(d) || is_hardware_domain(d)"
for more flexible useage.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
---
 xen/arch/arm/domain_build.c  | 46 +++-
 xen/arch/arm/vgic-v3.c   | 20 +---
 xen/include/asm-arm/domain.h |  3 +++
 3 files changed, 50 insertions(+), 19 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 6cd03e4d0f..7e0ee07e06 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2255,16 +2255,20 @@ static int __init make_gicv2_domU_node(struct 
kernel_info *kinfo)
 return res;
 }
 
+#ifdef CONFIG_ARM_64
 static int __init make_gicv3_domU_node(struct kernel_info *kinfo)
 {
 void *fdt = kinfo->fdt;
 int res = 0;
-__be32 reg[(GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) * 2];
+__be32 *reg;
 __be32 *cells;
+struct domain *d = kinfo->d;
+char buf[38];
+unsigned int i, len = 0;
 
-res = fdt_begin_node(fdt, 
"interrupt-controller@"__stringify(GUEST_GICV3_GICD_BASE));
-if ( res )
-return res;
+snprintf(buf, sizeof(buf), "interrupt-controller@%"PRIx64,
+ vgic_dist_base(&d->arch.vgic));
+res = fdt_begin_node(fdt, buf);
 
 res = fdt_property_cell(fdt, "#address-cells", 0);
 if ( res )
@@ -2282,35 +2286,55 @@ static int __init make_gicv3_domU_node(struct 
kernel_info *kinfo)
 if ( res )
 return res;
 
+/* reg specifies all re-distributors and Distributor. */
+len = (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) *
+  (d->arch.vgic.nr_regions + 1) * sizeof(__be32);
+reg = xmalloc_bytes(len);
+if ( reg == NULL )
+return -ENOMEM;
+
 cells = ®[0];
 dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-   GUEST_GICV3_GICD_BASE, GUEST_GICV3_GICD_SIZE);
-dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-   GUEST_GICV3_GICR0_BASE, GUEST_GICV3_GICR0_SIZE);
+   vgic_dist_base(&d->arch.vgic), GUEST_GICV3_GICD_SIZE);
 
-res = fdt_property(fdt, "reg", reg, sizeof(reg));
+for ( i = 0;
+  i < d->arch.vgic.nr_regions;
+  i++, cells += (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) )
+{
+dt_child_set_range(&cells,
+   GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
+   d->arch.vgic.rdist_regions[i].base,
+   d->arch.vgic.rdist_regions[i].size);
+}
+
+res = fdt_property(fdt, "reg", reg, len);
 if (res)
-return res;
+goto out;
 
 res = fdt_property_cell(fdt, "linux,phandle", kinfo->phandle_gic);
 if (res)
-return res;
+goto out;
 
 res = fdt_property_cell(fdt, "phandle", kinfo->phandle_gic);
 if (res)
-return res;
+goto out;
 
 res = fdt_end_node(fdt);
 
+ out:
+xfree(reg);
 return res;
 }
+#endif
 
 static int __init make_gic_domU_node(struct kernel_info *kinfo)
 {
 switch ( kinfo->d->arch.vgic.version )
 {
+#ifdef CONFIG_ARM_64
 case GIC_V3:
 return make_gicv3_domU_node(kinfo);
+#endif
 case GIC_V2:
 return make_gicv2_domU_node(kinfo);
 default:
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index cb5a70c42e..70168ca1ac 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1641,14 +1641,15 @@ static inline unsigned int 
vgic_v3_max_rdist_count(struct domain *d)
  * Normally there is only one GICv3 redistributor region.
  * The GICv3 DT binding provisions for multiple regions, since there are
  * platforms out there which need those (multi-socket systems).
- * For Dom0 we have to live with the MMIO layout the hardware provides,
- * so we have to copy the multiple regions - as the first region may not
- * provide enough space to hold all redistributors we need.
+ * For direct-map domain(including dom0), we have to live with the MMIO
+ * layout the hardware provides, so we have to copy the multiple regions
+ * - as the first region may not provide enough space to hold all
+ * redistributors we need.
  * However DomU get a constructed memory map, so we can go with
  * the architected single redistributor region.
  */
-return is_hardware_domain

RE: [PATCH v2 1/6] xen: introduce XEN_DOMCTL_CDF_directmap

2021-10-15 Thread Penny Zheng
Hi Jan

> -Original Message-
> From: Jan Beulich 
> Sent: Friday, October 15, 2021 4:47 PM
> To: Penny Zheng 
> Cc: Wei Chen ; Bertrand Marquis
> ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org; jul...@xen.org
> Subject: Re: [PATCH v2 1/6] xen: introduce XEN_DOMCTL_CDF_directmap
> 
> On 15.10.2021 05:09, Penny Zheng wrote:
> > From: Stefano Stabellini 
> >
> > This commit introduces a new arm-specific flag
> > XEN_DOMCTL_CDF_directmap to specify that this domain should have its
> > memory directly mapped (guest physical address == physical address) at
> domain creation.
> >
> > Refine is_domain_direct_mapped to check whether the flag
> > XEN_DOMCTL_CDF_directmap is set.
> >
> > Signed-off-by: Stefano Stabellini 
> > Signed-off-by: Penny Zheng 
> > ---
> > CC: andrew.coop...@citrix.com
> > CC: jbeul...@suse.com
> > CC: George Dunlap 
> > CC: Ian Jackson 
> > CC: Wei Liu 
> > CC: "Roger Pau Monné" 
> > ---
> 
> Please have here a brief log of changes in the new version, to aid reviewers.
> 

Sure.

> >  xen/arch/arm/domain.c| 3 ++-
> >  xen/arch/arm/domain_build.c  | 4 +++-
> >  xen/common/domain.c  | 3 ++-
> >  xen/include/asm-arm/domain.h | 4 ++--  xen/include/public/domctl.h  |
> > 4 +++-
> >  5 files changed, 12 insertions(+), 6 deletions(-)
> 
> You clearly had to re-base over the XEN_DOMCTL_CDF_vpmu addition. I think
> just like that change (which I'd expect you to have looked at while doing the
> re-base) you also need to at least fiddle with OCaml's domain_create_flag, to
> keep the ABI check there happy.
> 

The patch serie is based on the staging branch with an extra commit "
Revert "xen/domctl: Introduce XEN_DOMCTL_CDF_vpci flag", which
Is already been pushed to community for review.(
https://lists.xenproject.org/archives/html/xen-devel/2021-10/msg00822.html)

> > --- a/xen/include/public/domctl.h
> > +++ b/xen/include/public/domctl.h
> > @@ -72,9 +72,11 @@ struct xen_domctl_createdomain {
> >  #define XEN_DOMCTL_CDF_nested_virt(1U <<
> _XEN_DOMCTL_CDF_nested_virt)
> >  /* Should we expose the vPMU to the guest? */
> >  #define XEN_DOMCTL_CDF_vpmu   (1U << 7)
> > +/* If this domain has its memory directly mapped? (ARM only) */
> > +#define XEN_DOMCTL_CDF_directmap  (1U << 8)
> 
> The comment doesn't read well; how about "Should domain memory be
> directly mapped?" That's if a comment here is really needed in the first 
> place. I
> also don't think "Arm only" should be here - this may go stale. What I'm
> missing in this regard is rejecting of the flag in x86'es
> arch_sanitise_domain_config() (or by whichever other means).
> 
> Jan



RE: [PATCH v2 1/6] xen: introduce XEN_DOMCTL_CDF_directmap

2021-10-15 Thread Penny Zheng
Hi julien 

> -Original Message-
> From: Julien Grall 
> Sent: Friday, October 15, 2021 4:57 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Wei Chen ; Bertrand Marquis
> 
> Subject: Re: [PATCH v2 1/6] xen: introduce XEN_DOMCTL_CDF_directmap
> 
> Hi Penny,
> 
> On 15/10/2021 04:09, Penny Zheng wrote:
> > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> > index 0167731ab0..37e2d62d47 100644
> > --- a/xen/arch/arm/domain_build.c
> > +++ b/xen/arch/arm/domain_build.c
> > @@ -3069,8 +3069,10 @@ static int __init construct_dom0(struct domain *d)
> >   void __init create_dom0(void)
> >   {
> >   struct domain *dom0;
> > +/* DOM0 has always its memory directly mapped. */
> >   struct xen_domctl_createdomain dom0_cfg = {
> > -.flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
> > +.flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap |
> > + XEN_DOMCTL_CDF_directmap,
> >   .max_evtchn_port = -1,
> >   .max_grant_frames = gnttab_dom0_frames(),
> >   .max_maptrack_frames = -1,
> > diff --git a/xen/common/domain.c b/xen/common/domain.c index
> > 8b53c49d1e..7a6131db74 100644
> > --- a/xen/common/domain.c
> > +++ b/xen/common/domain.c
> > @@ -486,7 +486,8 @@ static int sanitise_domain_config(struct
> xen_domctl_createdomain *config)
> >~(XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap |
> >  XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off |
> >  XEN_DOMCTL_CDF_xs_domain | XEN_DOMCTL_CDF_iommu |
> > -   XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu) )
> > +   XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu |
> > +   XEN_DOMCTL_CDF_directmap) )
> >   {
> >   dprintk(XENLOG_INFO, "Unknown CDF flags %#x\n", config->flags);
> >   return -EINVAL;
> > diff --git a/xen/include/asm-arm/domain.h
> > b/xen/include/asm-arm/domain.h index 14e575288f..fc42c6a310 100644
> > --- a/xen/include/asm-arm/domain.h
> > +++ b/xen/include/asm-arm/domain.h
> > @@ -29,8 +29,8 @@ enum domain_type {
> >   #define is_64bit_domain(d) (0)
> >   #endif
> >
> > -/* The hardware domain has always its memory direct mapped. */
> > -#define is_domain_direct_mapped(d) is_hardware_domain(d)
> > +/* Check if domain is direct-map memory map. */ #define
> > +is_domain_direct_mapped(d) (d->options & XEN_DOMCTL_CDF_directmap)
> >
> >   struct vtimer {
> >   struct vcpu *v;
> > diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> > index 238384b5ae..b505a0db51 100644
> > --- a/xen/include/public/domctl.h
> > +++ b/xen/include/public/domctl.h
> > @@ -72,9 +72,11 @@ struct xen_domctl_createdomain {
> >   #define XEN_DOMCTL_CDF_nested_virt(1U <<
> _XEN_DOMCTL_CDF_nested_virt)
> >   /* Should we expose the vPMU to the guest? */
> >   #define XEN_DOMCTL_CDF_vpmu   (1U << 7)
> > +/* If this domain has its memory directly mapped? (ARM only) */
> > +#define XEN_DOMCTL_CDF_directmap  (1U << 8)
> >
> >   /* Max XEN_DOMCTL_CDF_* constant.  Used for ABI checking. */
> > -#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_vpmu
> > +#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_directmap
> 
> In the previous version, this flag was only settable for domain created by 
> Xen.
> Now this is also settable by the toolstack. I don't think the toolstack can
> sensibly use this flag (at least in the current state).
> 
> So can you explain why this flag is exposed to the toolstack?

Oh,  I misunderstood the previous discussion on internal usage a bit, sorry.

And I will make it back to xen/include/xen/domain.h 

> 
> Cheers,
> 
> --
> Julien Grall


RE: [PATCH v2 4/6] xen/arm: if direct-map domain use native addresses for GICv3

2021-10-20 Thread Penny Zheng
Hi Julien

> -Original Message-
> From: Julien Grall 
> Sent: Wednesday, October 20, 2021 7:11 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Wei Chen ; Bertrand Marquis
> 
> Subject: Re: [PATCH v2 4/6] xen/arm: if direct-map domain use native
> addresses for GICv3
> 
> Hi Penny,
> 
> On 15/10/2021 04:09, Penny Zheng wrote:
> > From: Stefano Stabellini 
> >
> > Today we use native addresses to map the GICv3 for Dom0 and fixed
> > addresses for DomUs.
> >
> > This patch changes the behavior so that native addresses are used for
> > all direct-map domains(including Dom0).
> >
> > Considering that dom0 may not always be directly mapped in the future,
> > this patch introduces a new helper "is_domain_use_host_layout()" that
> > wraps both two check "is_domain_direct_mapped(d) ||
> is_hardware_domain(d)"
> > for more flexible useage.
> 
> Typo: s/useage/usage/
> 
> >
> > Signed-off-by: Stefano Stabellini 
> > Signed-off-by: Penny Zheng 
> > ---
> >   xen/arch/arm/domain_build.c  | 46 +++-
> >   xen/arch/arm/vgic-v3.c   | 20 +---
> >   xen/include/asm-arm/domain.h |  3 +++
> >   3 files changed, 50 insertions(+), 19 deletions(-)
> >
> > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> > index 6cd03e4d0f..7e0ee07e06 100644
> > --- a/xen/arch/arm/domain_build.c
> > +++ b/xen/arch/arm/domain_build.c
> > @@ -2255,16 +2255,20 @@ static int __init make_gicv2_domU_node(struct
> kernel_info *kinfo)
> >   return res;
> >   }
> >
> > +#ifdef CONFIG_ARM_64
> 
> The code below is specific to the GICv3 (and not 64-bit). So this should be
> gated with CONFIG_GICV3.
> 
> Personally, I would have gated the code in a separate patch. But I am fine if
> this is added in this patch so long this is mentionned in the commit message.
> 
> >   static int __init make_gicv3_domU_node(struct kernel_info *kinfo)
> >   {
> >   void *fdt = kinfo->fdt;
> >   int res = 0;
> > -__be32 reg[(GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) *
> 2];
> > +__be32 *reg;
> >   __be32 *cells;
> > +struct domain *d = kinfo->d;
> 
> AFAICT, 'd' is not going to be modified. So please add const.
> 
> > +char buf[38];
> 
> Please explain how 38 was found. For an example, see the comment on top of
> 'buf' in make_memory_node().
> 
> > +unsigned int i, len = 0;
> >
> > -res = fdt_begin_node(fdt, "interrupt-
> controller@"__stringify(GUEST_GICV3_GICD_BASE));
> > -if ( res )
> > -return res;
> > +snprintf(buf, sizeof(buf), "interrupt-controller@%"PRIx64,
> > + vgic_dist_base(&d->arch.vgic));
> > +res = fdt_begin_node(fdt, buf);
> 
> You set res but it gets overwritten just below. Were you meant to check the
> return value?
> 
> >
> >   res = fdt_property_cell(fdt, "#address-cells", 0);
> >   if ( res )
> > @@ -2282,35 +2286,55 @@ static int __init make_gicv3_domU_node(struct
> kernel_info *kinfo)
> >   if ( res )
> >   return res;
> >
> > +/* reg specifies all re-distributors and Distributor. */
> > +len = (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) *
> > +  (d->arch.vgic.nr_regions + 1) * sizeof(__be32);
> > +reg = xmalloc_bytes(len);
> > +if ( reg == NULL )
> > +return -ENOMEM;
> > +
> >   cells = ®[0];
> >   dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS,
> GUEST_ROOT_SIZE_CELLS,
> > -   GUEST_GICV3_GICD_BASE, GUEST_GICV3_GICD_SIZE);
> > -dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS,
> GUEST_ROOT_SIZE_CELLS,
> > -   GUEST_GICV3_GICR0_BASE, GUEST_GICV3_GICR0_SIZE);
> > +   vgic_dist_base(&d->arch.vgic),
> > + GUEST_GICV3_GICD_SIZE);
> >
> > -res = fdt_property(fdt, "reg", reg, sizeof(reg));
> > +for ( i = 0;
> > +  i < d->arch.vgic.nr_regions;
> > +  i++, cells += (GUEST_ROOT_ADDRESS_CELLS +
> > + GUEST_ROOT_SIZE_CELLS) )
> 
> dt_child_set_range() will already update cells to the next ones. So this needs
> to be dropped.
> 

You're so right!!! I checked the code and it will already points to the next 
ones

> I was expecting this to be caugt during test. So did you test this series with
> GICv3?

RE: static-mem preventing dom0 from booting

2021-11-04 Thread Penny Zheng
Hi Stefano

> -Original Message-
> From: Stefano Stabellini 
> Sent: Friday, November 5, 2021 9:36 AM
> To: Penny Zheng 
> Cc: sstabell...@kernel.org; xen-devel@lists.xenproject.org
> Subject: static-mem preventing dom0 from booting
> 
> Hi Penny,
> 
> I am trying to test the static-mem feature in Xen 4.16 but I am having some
> issues. I can boot a dom0less domU with static-mem configured correctly, but
> when I do so, dom0 doesn't boot any longer.
> 

Hmm, In our first intention, dom0less is a mandatory option for static 
allocation.
domU on static allocation shall boot when dom0 doesn't boot there.

We think that, nevertheless, dom0 memory range is allocated by Xen 
automatically,
and it leads to the unpredictability. Static allocation through device tree 
configuration
prefers the total static environment to avoid unpredictability.

> In the same configuration, if I remove the static-mem related lines from the
> domU node on device tree, both dom0 and domU boot successfully.
> 
> I am sure the dom0 memory range, allocated by Xen automatically, and the
> domU memory range, hand-picked by me, do not clash as you can see from the
> boot logs (appended).
> 
> Am I missing anything in the configuration? I am using a ZCU102 board, the
> memory node on the host device tree is:
> 

Are you suggesting one scenario where dom0 with static-mem domU?

Hmmm, one quick thought, it may not be working with vpl011 emulation.
When dom0 exists, vpl011 will take dom0 as backend, which requests event
channel, xen store, etc, involved to communicate. but static-mem domU
without CONFIG_XEN shall not handle it.

>   memory {
>   device_type = "memory";
>   reg = <0x00 0x00 0x00 0x7ff0 0x08 0x00 0x00 0x8000>;
>   };
> 
> I am attaching my u-boot boot.scr script with the device tree modification to
> add static memory.
> 
> Many thanks for your help!
> 
> Cheers,
> 
> Stefano
> 
> 
> (XEN) Xen version 4.16-rc (sstabellini@) (gcc (Ubuntu 9.3.0-17ubuntu1~20.04)
> 9.3.0) debug=y Thu Nov  4 18:28:30 PDT 2021
> (XEN) Latest ChangeSet: Mon Nov 1 12:36:26 2021 + git:9f8434d778-dirty
> (XEN) Processor: 410fd034: "ARM Limited", variant: 0x0, part
> 0xd03,rev 0x4
> (XEN) 64-bit Execution:
> (XEN)   Processor Features: 1100 
> (XEN) Exception Levels: EL3:64+32 EL2:64+32 EL1:64+32 EL0:64+32
> (XEN) Extensions: FloatingPoint AdvancedSIMD
> (XEN)   Debug Features: 10305106 
> (XEN)   Auxiliary Features:  
> (XEN)   Memory Model Features: 1122 
> (XEN)   ISA Features:  00011120 
> (XEN) 32-bit Execution:
> (XEN)   Processor Features: 1231:00011011
> (XEN) Instruction Sets: AArch32 A32 Thumb Thumb-2 ThumbEE Jazelle
> (XEN) Extensions: GenericTimer Security
> (XEN)   Debug Features: 03010066
> (XEN)   Auxiliary Features: 
> (XEN)   Memory Model Features: 10101105 4000
> (XEN)  0126 02102211
> (XEN)   ISA Features: 02101110 13112111
> 21232042
> (XEN) 01112131 00011142 00011121
> (XEN) Generic Timer IRQ: phys=30 hyp=26 virt=27 Freq: 65000 KHz
> (XEN) GICv2 initialization:
> (XEN) gic_dist_addr=f901
> (XEN) gic_cpu_addr=f902
> (XEN) gic_hyp_addr=f904
> (XEN) gic_vcpu_addr=f906
> (XEN) gic_maintenance_irq=25
> (XEN) GICv2: Adjusting CPU interface base to 0xf902f000
> (XEN) GICv2: 192 lines, 4 cpus, secure (IID ).
> (XEN) XSM Framework v1.0.1 initialized
> (XEN) Initialising XSM SILO mode
> (XEN) Using scheduler: null Scheduler (null)
> (XEN) Initializing null scheduler
> (XEN) WARNING: This is experimental software in development.
> (XEN) Use at your own risk.
> (XEN) Allocated console ring of 16 KiB.
> (XEN) Bringing up CPU1
> (XEN) Bringing up CPU2
> (XEN) Bringing up CPU3
> (XEN) Brought up 4 CPUs
> (XEN) I/O virtualisation enabled
> (XEN)  - Dom0 mode: Relaxed
> (XEN) P2M: 40-bit IPA with 40-bit PA and 8-bit VMID
> (XEN) P2M: 3 levels with order-1 root, VTCR 0x80023558
> (XEN) Scheduling granularity: cpu, 1 CPU per sched-resource
> (XEN) *** LOADING DOMAIN 0 ***
> (XEN) Loading d0 kernel from boot module @ 00e0
> (XEN) Loading ramdisk from boot module @ 0220
> (XEN) Allocating 1:1 mappings totalling 1024MB for dom0:
> (XEN) BANK[0] 0x002000-0x006000 (1024MB)
> (XEN) Grant table range: 0x000560-0x000

RE: static-mem preventing dom0 from booting

2021-11-04 Thread Penny Zheng
Hi stefano

> -Original Message-
> From: Penny Zheng
> Sent: Friday, November 5, 2021 11:23 AM
> To: Stefano Stabellini 
> Cc: xen-devel@lists.xenproject.org; Wei Chen 
> Subject: RE: static-mem preventing dom0 from booting
> 
> Hi Stefano
> 
> > -Original Message-
> > From: Stefano Stabellini 
> > Sent: Friday, November 5, 2021 9:36 AM
> > To: Penny Zheng 
> > Cc: sstabell...@kernel.org; xen-devel@lists.xenproject.org
> > Subject: static-mem preventing dom0 from booting
> >
> > Hi Penny,
> >
> > I am trying to test the static-mem feature in Xen 4.16 but I am having
> > some issues. I can boot a dom0less domU with static-mem configured
> > correctly, but when I do so, dom0 doesn't boot any longer.
> >
> 
> Hmm, In our first intention, dom0less is a mandatory option for static
> allocation.
> domU on static allocation shall boot when dom0 doesn't boot there.
> 
> We think that, nevertheless, dom0 memory range is allocated by Xen
> automatically, and it leads to the unpredictability. Static allocation through
> device tree configuration prefers the total static environment to avoid
> unpredictability.
> 
> > In the same configuration, if I remove the static-mem related lines
> > from the domU node on device tree, both dom0 and domU boot successfully.
> >
> > I am sure the dom0 memory range, allocated by Xen automatically, and
> > the domU memory range, hand-picked by me, do not clash as you can see
> > from the boot logs (appended).
> >
> > Am I missing anything in the configuration? I am using a ZCU102 board,
> > the memory node on the host device tree is:
> >
> 
> Are you suggesting one scenario where dom0 with static-mem domU?
> 
> Hmmm, one quick thought, it may not be working with vpl011 emulation.
> When dom0 exists, vpl011 will take dom0 as backend, which requests event
> channel, xen store, etc, involved to communicate. but static-mem domU
> without CONFIG_XEN shall not handle it.
> 

Digging on this, and my misunderstanding. Domain created through device tree
shall use xen as backend, not dom0. I guess that only the one created by xl is 
using
dom0 as backend.

Nevertheless, if this is your scenario, where dom0 and static-mem domU(NO 
CONFIG_XEN) co-exists,
I'll test for you.

> > memory {
> > device_type = "memory";
> > reg = <0x00 0x00 0x00 0x7ff0 0x08 0x00 0x00 0x8000>;
> > };
> >
> > I am attaching my u-boot boot.scr script with the device tree
> > modification to add static memory.
> >
> > Many thanks for your help!
> >
> > Cheers,
> >
> > Stefano
> >
> >
> > (XEN) Xen version 4.16-rc (sstabellini@) (gcc (Ubuntu
> > 9.3.0-17ubuntu1~20.04)
> > 9.3.0) debug=y Thu Nov  4 18:28:30 PDT 2021
> > (XEN) Latest ChangeSet: Mon Nov 1 12:36:26 2021 +
> > git:9f8434d778-dirty
> > (XEN) Processor: 410fd034: "ARM Limited", variant: 0x0, part
> > 0xd03,rev 0x4
> > (XEN) 64-bit Execution:
> > (XEN)   Processor Features: 1100 
> > (XEN) Exception Levels: EL3:64+32 EL2:64+32 EL1:64+32 EL0:64+32
> > (XEN) Extensions: FloatingPoint AdvancedSIMD
> > (XEN)   Debug Features: 10305106 
> > (XEN)   Auxiliary Features:  
> > (XEN)   Memory Model Features: 1122 
> > (XEN)   ISA Features:  00011120 
> > (XEN) 32-bit Execution:
> > (XEN)   Processor Features: 1231:00011011
> > (XEN) Instruction Sets: AArch32 A32 Thumb Thumb-2 ThumbEE Jazelle
> > (XEN) Extensions: GenericTimer Security
> > (XEN)   Debug Features: 03010066
> > (XEN)   Auxiliary Features: 
> > (XEN)   Memory Model Features: 10101105 4000
> > (XEN)  0126 02102211
> > (XEN)   ISA Features: 02101110 13112111
> > 21232042
> > (XEN) 01112131 00011142 00011121
> > (XEN) Generic Timer IRQ: phys=30 hyp=26 virt=27 Freq: 65000 KHz
> > (XEN) GICv2 initialization:
> > (XEN) gic_dist_addr=f901
> > (XEN) gic_cpu_addr=f902
> > (XEN) gic_hyp_addr=f904
> > (XEN) gic_vcpu_addr=f906
> > (XEN) gic_maintenance_irq=25
> > (XEN) GICv2: Adjusting CPU interface base to 0xf902f000
> > (XEN) GICv2: 192 lines, 4 cpus, secure (IID ).
> > (XEN) XSM Fra

RE: static-mem preventing dom0 from booting

2021-11-07 Thread Penny Zheng
Hi Stefano

> -Original Message-
> From: Stefano Stabellini 
> Sent: Saturday, November 6, 2021 7:03 AM
> To: Stefano Stabellini 
> Cc: Penny Zheng ; xen-devel@lists.xenproject.org;
> Wei Chen ; Bertrand Marquis
> 
> Subject: RE: static-mem preventing dom0 from booting
> 
> On Fri, 5 Nov 2021, Stefano Stabellini wrote:
> > The scenario is extremely simple; you can see the full device tree
> > configuration in the attachment to my previous email.
> >
> > - dom0
> > - dom0less domU with static-mem
> >
> > That's it! So basically it is just a normal dom0 + dom0less domU
> > configuration, which already works fine, where I added static-mem to
> > the domU and suddenly dom0 (not the domU!) stopped working.
> 

Got it. Sorry, I missed the scenario you are talking about... I simply think 
what dom0less
means that dom0 is absent... ;/
  
> I did some more debugging today and I found the problem. The issue is that
> static-mem regions are added to the list of reserved_mem. However,
> reserved_mem is automatically assigned to Dom0 by default at the bottom of
> xen/arch/arm/domain_build.c:handle_node, see the second call to
> make_memory_node. Really, we shouldn't give to dom0 static-mem ranges
> meant for other domUs. E.g. the following change is sufficient to solve the
> problem:
> 
> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> index 88a79247cb..dc609c4f0e 100644
> --- a/xen/arch/arm/domain_build.c
> +++ b/xen/arch/arm/domain_build.c
> @@ -891,6 +891,9 @@ static int __init make_memory_node(const struct
> domain *d,
>  u64 start = mem->bank[i].start;
>  u64 size = mem->bank[i].size;
> 
> +if ( mem->bank[i].xen_domain )
> +continue;
> +
>  dt_dprintk("  Bank %d: %#"PRIx64"->%#"PRIx64"\n",
> i, start, start + size);
> 
> However, maybe a better fix would be to purge reserved_mem of any
> xen_domain items before calling make_memory_node.
> 
> 
> I found one additional issue regarding is_domain_direct_mapped which
> doesn't return true for static-mem domains. I think we need to add a
> direct_map bool to arch_domain and set it for both dom0 and static-mem
> dom0less domUs, so that we can change the implementation of
> is_domain_direct_mapped to:
> 
> #define is_domain_direct_mapped(d) (d->arch.direct_map)

Yeah, I already pushed a patch serie regarding direct-map to community for 
review, 
and it is also based on your old direct-map serie. 

Today, I may push direct-map version 3 to community for review~~~ If you're 
free, plz take a look.

Cheers,
Penny Zheng



RE: [PATCH v2 1/6] xen: introduce XEN_DOMCTL_CDF_directmap

2021-11-09 Thread Penny Zheng
Hi Julien

> -Original Message-
> From: Julien Grall 
> Sent: Friday, October 15, 2021 4:57 PM
> To: Penny Zheng ; xen-devel@lists.xenproject.org;
> sstabell...@kernel.org
> Cc: Wei Chen ; Bertrand Marquis
> 
> Subject: Re: [PATCH v2 1/6] xen: introduce XEN_DOMCTL_CDF_directmap
> 
> Hi Penny,
> 
> On 15/10/2021 04:09, Penny Zheng wrote:
> > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> > index 0167731ab0..37e2d62d47 100644
> > --- a/xen/arch/arm/domain_build.c
> > +++ b/xen/arch/arm/domain_build.c
> > @@ -3069,8 +3069,10 @@ static int __init construct_dom0(struct domain *d)
> >   void __init create_dom0(void)
> >   {
> >   struct domain *dom0;
> > +/* DOM0 has always its memory directly mapped. */
> >   struct xen_domctl_createdomain dom0_cfg = {
> > -.flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
> > +.flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap |
> > + XEN_DOMCTL_CDF_directmap,
> >   .max_evtchn_port = -1,
> >   .max_grant_frames = gnttab_dom0_frames(),
> >   .max_maptrack_frames = -1,
> > diff --git a/xen/common/domain.c b/xen/common/domain.c index
> > 8b53c49d1e..7a6131db74 100644
> > --- a/xen/common/domain.c
> > +++ b/xen/common/domain.c
> > @@ -486,7 +486,8 @@ static int sanitise_domain_config(struct
> xen_domctl_createdomain *config)
> >~(XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap |
> >  XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off |
> >  XEN_DOMCTL_CDF_xs_domain | XEN_DOMCTL_CDF_iommu |
> > -   XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu) )
> > +   XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu |
> > +   XEN_DOMCTL_CDF_directmap) )
> >   {
> >   dprintk(XENLOG_INFO, "Unknown CDF flags %#x\n", config->flags);
> >   return -EINVAL;
> > diff --git a/xen/include/asm-arm/domain.h
> > b/xen/include/asm-arm/domain.h index 14e575288f..fc42c6a310 100644
> > --- a/xen/include/asm-arm/domain.h
> > +++ b/xen/include/asm-arm/domain.h
> > @@ -29,8 +29,8 @@ enum domain_type {
> >   #define is_64bit_domain(d) (0)
> >   #endif
> >
> > -/* The hardware domain has always its memory direct mapped. */
> > -#define is_domain_direct_mapped(d) is_hardware_domain(d)
> > +/* Check if domain is direct-map memory map. */ #define
> > +is_domain_direct_mapped(d) (d->options & XEN_DOMCTL_CDF_directmap)
> >
> >   struct vtimer {
> >   struct vcpu *v;
> > diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> > index 238384b5ae..b505a0db51 100644
> > --- a/xen/include/public/domctl.h
> > +++ b/xen/include/public/domctl.h
> > @@ -72,9 +72,11 @@ struct xen_domctl_createdomain {
> >   #define XEN_DOMCTL_CDF_nested_virt(1U <<
> _XEN_DOMCTL_CDF_nested_virt)
> >   /* Should we expose the vPMU to the guest? */
> >   #define XEN_DOMCTL_CDF_vpmu   (1U << 7)
> > +/* If this domain has its memory directly mapped? (ARM only) */
> > +#define XEN_DOMCTL_CDF_directmap  (1U << 8)
> >
> >   /* Max XEN_DOMCTL_CDF_* constant.  Used for ABI checking. */
> > -#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_vpmu
> > +#define XEN_DOMCTL_CDF_MAX XEN_DOMCTL_CDF_directmap
> 
> In the previous version, this flag was only settable for domain created by 
> Xen.
> Now this is also settable by the toolstack. I don't think the toolstack can
> sensibly use this flag (at least in the current state).
> 
> So can you explain why this flag is exposed to the toolstack?
> 

if I moved XEN_DOMCTL_CDF_directmap to the domain.h, and let it hold the
bit 8, in case later another developer wants to introduce a new flag to 
accidently
hold 8 bit too, I would like to add some explanatory comments here and maybe 
rename
the XEN_DOMCTL_CDF_directmap to XEN_DOMCTL_CDF_Internal_directmap, wdyt?

> Cheers,
> 
> --

Cheers

Penny Zheng
> Julien Grall


RE: [PATCH v3] xen/arm: don't assign domU static-mem to dom0 as reserved-memory

2021-11-11 Thread Penny Zheng
Hi Stefano

> -Original Message-
> From: Stefano Stabellini 
> Sent: Thursday, November 11, 2021 4:18 AM
> To: jul...@xen.org
> Cc: sstabell...@kernel.org; Penny Zheng ; Bertrand
> Marquis ; Wei Chen ;
> i...@xenproject.org; volodymyr_babc...@epam.com; xen-
> de...@lists.xenproject.org; Stefano Stabellini 
> Subject: [PATCH v3] xen/arm: don't assign domU static-mem to dom0 as
> reserved-memory
> 
> From: Stefano Stabellini 
> 
> DomUs static-mem ranges are added to the reserved_mem array for
> accounting, but they shouldn't be assigned to dom0 as the other regular
> reserved-memory ranges in device tree.
> 
> In make_memory_nodes, fix the error by skipping banks with xen_domain set
> to true in the reserved-memory array. Also make sure to use the first valid
> (!xen_domain) start address for the memory node name.
> 
> Fixes: 41c031ff437b ("xen/arm: introduce domain on Static Allocation")
> Signed-off-by: Stefano Stabellini 
> Release-Acked-by: Ian Jackson 

Thx again for the fixing up.

Reviewed-by: Penny Zheng 
> ---
> Changes in v3:
> - move BUG_ON inside the loop
> 
> Changes in v2:
> - improve commit message
> - improve in-code comment
> - update nr_cells appropriately
> ---
>  xen/arch/arm/domain_build.c | 23 +--
>  1 file changed, 17 insertions(+), 6 deletions(-)
> 
> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> index 9e92b640cd..dafbc13962 100644
> --- a/xen/arch/arm/domain_build.c
> +++ b/xen/arch/arm/domain_build.c
> @@ -862,21 +862,25 @@ static int __init make_memory_node(const struct
> domain *d,  {
>  int res, i;
>  int reg_size = addrcells + sizecells;
> -int nr_cells = reg_size * mem->nr_banks;
> +int nr_cells = 0;
>  /* Placeholder for memory@ + a 64-bit number + \0 */
>  char buf[24];
>  __be32 reg[NR_MEM_BANKS * 4 /* Worst case addrcells + sizecells */];
>  __be32 *cells;
> 
> -BUG_ON(nr_cells >= ARRAY_SIZE(reg));
>  if ( mem->nr_banks == 0 )
>  return -ENOENT;
> 
> -dt_dprintk("Create memory node (reg size %d, nr cells %d)\n",
> -   reg_size, nr_cells);
> +/* find first memory range not bound to a Xen domain */
> +for ( i = 0; i < mem->nr_banks && mem->bank[i].xen_domain; i++ )
> +;
> +if ( i == mem->nr_banks )
> +return 0;
> +
> +dt_dprintk("Create memory node\n");
> 
>  /* ePAPR 3.4 */
> -snprintf(buf, sizeof(buf), "memory@%"PRIx64, mem->bank[0].start);
> +snprintf(buf, sizeof(buf), "memory@%"PRIx64, mem->bank[i].start);
>  res = fdt_begin_node(fdt, buf);
>  if ( res )
>  return res;
> @@ -886,17 +890,24 @@ static int __init make_memory_node(const struct
> domain *d,
>  return res;
> 
>  cells = ®[0];
> -for ( i = 0 ; i < mem->nr_banks; i++ )
> +for ( ; i < mem->nr_banks; i++ )
>  {
>  u64 start = mem->bank[i].start;
>  u64 size = mem->bank[i].size;
> 
> +if ( mem->bank[i].xen_domain )
> +continue;
> +
>  dt_dprintk("  Bank %d: %#"PRIx64"->%#"PRIx64"\n",
> i, start, start + size);
> 
> +nr_cells += reg_size;
> +BUG_ON(nr_cells >= ARRAY_SIZE(reg));
>  dt_child_set_range(&cells, addrcells, sizecells, start, size);
>  }
> 
> +dt_dprintk("(reg size %d, nr cells %d)\n", reg_size, nr_cells);
> +
>  res = fdt_property(fdt, "reg", reg, nr_cells * sizeof(*reg));
>  if ( res )
>  return res;
> --
> 2.25.1

--
Cheers,
Penny Zheng





[PATCH v3 02/10] xen/arm: avoid setting XEN_DOMCTL_CDF_iommu when IOMMU off

2021-11-15 Thread Penny Zheng
From: Stefano Stabellini 

This commit avoids setting XEN_DOMCTL_CDF_iommu when the IOMMU is
absent/disabled, otherwise xen will fail later when handling
device assignment.

Signed-off-by: Penny Zheng 
Signed-off-by: Stefano Stabellini 
---
v3 changes:
- new commit, split from the original "[PATCH v2 2/6] xen/arm: introduce
direct-map for domUs"
---
 xen/arch/arm/domain_build.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 664c88ebe4..7a063f62fe 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2996,7 +2996,8 @@ void __init create_domUs(void)
 panic("Missing property 'cpus' for domain %s\n",
   dt_node_name(node));
 
-if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") )
+if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") &&
+ iommu_enabled )
 d_cfg.flags |= XEN_DOMCTL_CDF_iommu;
 
 if ( !dt_property_read_u32(node, "nr_spis", &d_cfg.arch.nr_spis) )
-- 
2.25.1




[PATCH v3 00/10] direct-map memory map

2021-11-15 Thread Penny Zheng
Cases where domU needs direct-map memory map:
  * IOMMU not present in the system.
  * IOMMU disabled if it doesn't cover a specific device and all the guests
are trusted. Thinking a mixed scenario, where a few devices with IOMMU and
a few without, then guest DMA security still could not be totally guaranteed.
So users may want to disable the IOMMU, to at least gain some performance
improvement from IOMMU disabled.
  * IOMMU disabled as a workaround when it doesn't have enough bandwidth.
To be specific, in a few extreme situation, when multiple devices do DMA
concurrently, these requests may exceed IOMMU's transmission capacity.
  * IOMMU disabled when it adds too much latency on DMA. For example,
TLB may be missing in some IOMMU hardware, which may bring latency in DMA
progress, so users may want to disable it in some realtime scenario.
  * Guest OS relies on the host memory layout

"direct-map" property shall be added under the appropriate domain node,
when users requesting direct-map memory mapping for the domain.

Right now, direct-map is only supported when domain on Static Allocation,
that is, "xen,static-mem" is also necessary in the domain configuration.

Looking into related [design link](
https://lists.xenproject.org/archives/html/xen-devel/2021-05/msg00882.html)
for more details.

The whole design is about Static Allocation and direct-map, and this
Patch Serie only covers parts of it, which are direct-map memory map.
Other features will be delievered through different patch series.

See https://lists.xenproject.org/archives/html/xen-devel/2021-09/msg00855.html
for Domain on Static Allocation.

This patch serie is based on
https://lists.xenproject.org/archives/html/xen-devel/2021-10/msg00822.html
---
v3 changes:
- move flag XEN_DOMCTL_CDF_INTERNAL_directmap back to xen/include/xen/domain.h,
to let it be only available for domain created by XEN.
- name it with extra "INTERNAL" and add comments to warn developers not
to accidently use its bitfield when introducing new XEN_DOMCTL_CDF_xxx flag.
- reject this flag in x86'es arch_sanitise_domain_config()
- add ASSERT_UNREACHABLE to catch any misuse in allocate_static_memory()
and allocate_static_memory_11()
- add another check of validating flag XEN_DOMCTL_CDF_INTERNAL_directmap only
when CONFIG_STATIC_MEMORY is set.
- simply map the CPU interface at the GPA vgic_v2_hw.cbase
- drop 'cells += (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS)'
- rename 'is_domain_use_host_layout()' to 'domain_use_host_layout()'
---
v2 changes:
- remove the introduce of internal flag
- Refine is_domain_direct_mapped to check whether the flag
XEN_DOMCTL_CDF_directmap is set
- reword "1:1 direct-map" to just "direct-map"
- split the common codes into two helpers: parse_static_mem_prop and
acquire_static_memory_bank to deduce complexity.
- introduce a new helper allocate_static_memory_11 for allocating static
memory for direct-map guests
- remove panic action since it is fine to assign a non-DMA capable device when
IOMMU and direct-map both off
- remove redistributor accessor
- introduce new helper "is_domain_use_host_layout()"
- explain why vpl011 initialization before creating its device tree node
- error out if the domain is direct-mapped and the IRQ is not found
- harden the code and add a check/comment when the hardware UART region
is smaller than CUEST_VPL011_SIZE.

Penny Zheng (4):
  xen/arm: introduce new helper parse_static_mem_prop and ...
  xen/arm: introduce direct-map for domUs
  xen/arm: add ASSERT_UNREACHABLE in allocate_static_memory
  xen/arm: gate make_gicv3_domU_node with CONFIG_GICV3

Stefano Stabellini (6):
  xen: introduce XEN_DOMCTL_CDF_INTERNAL_directmap
  xen/arm: avoid setting XEN_DOMCTL_CDF_iommu when IOMMU off
  xen/arm: if direct-map domain use native addresses for GICv2
  xen/arm: if direct-map domain use native addresses for GICv3
  xen/arm: if direct-map domain use native UART address and IRQ ...
  xen/docs: Document how to do passthrough without IOMMU

 docs/misc/arm/device-tree/booting.txt |   6 +
 docs/misc/arm/passthrough-noiommu.txt |  52 +
 xen/arch/arm/domain.c |   3 +-
 xen/arch/arm/domain_build.c   | 310 +-
 xen/arch/arm/vgic-v2.c|  31 ++-
 xen/arch/arm/vgic-v3.c|  29 ++-
 xen/arch/arm/vgic/vgic-v2.c   |  31 ++-
 xen/arch/arm/vpl011.c |  60 -
 xen/arch/x86/domain.c |   6 +
 xen/common/domain.c   |   3 +-
 xen/include/asm-arm/domain.h  |  11 +-
 xen/include/asm-arm/new_vgic.h|  10 +
 xen/include/asm-arm/vgic.h|  11 +
 xen/include/asm-arm/vpl011.h  |   2 +
 xen/include/public/domctl.h   |   4 +
 xen/include/xen/domain.h  |   3 +
 16 files changed, 471 insertions(+), 101 deletions(-)
 create mode 100644 docs/misc/arm/passthrough-noiommu.txt

-- 
2.25.1




[PATCH v3 05/10] xen/arm: add ASSERT_UNREACHABLE in allocate_static_memory

2021-11-15 Thread Penny Zheng
Helper allocate_static_memory is not meant to be reachable when built with
!CONFIG_STATIC_MEMORY, so this commit adds ASSERT_UNREACHABLE in it to catch
potential misuse.

Signed-off-by: Penny Zheng 
---
v3 changes:
- new commit
---
 xen/arch/arm/domain_build.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 97a5b5dedd..b6fde74d74 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -759,6 +759,7 @@ static void __init allocate_static_memory(struct domain *d,
   struct kernel_info *kinfo,
   const struct dt_device_node *node)
 {
+ASSERT_UNREACHABLE();
 }
 
 static void __init allocate_static_memory_11(struct domain *d,
-- 
2.25.1




[PATCH v3 01/10] xen: introduce XEN_DOMCTL_CDF_INTERNAL_directmap

2021-11-15 Thread Penny Zheng
From: Stefano Stabellini 

This commit introduces a new arm-specific flag
XEN_DOMCTL_CDF_INTERNAL_directmap to specify that a domain should
have its memory direct-map(guest physical address == physical address)
at domain creation.

Since this flag is only available for domain created by XEN, not exposed
to the toolstack, we name it with extra "INTERNAL" to distinguish from
other public XEN_DOMCTL_CDF_xxx flags, and add comments to warn developers
not to accidently use its bitfield when introducing new
XEN_DOMCTL_CDF_xxx flag.

Refine is_domain_direct_mapped to check whether the flag
XEN_DOMCTL_CDF_INTERNAL_directmap is set.

Signed-off-by: Penny Zheng 
Signed-off-by: Stefano Stabellini 
---
CC: andrew.coop...@citrix.com
CC: jbeul...@suse.com
CC: George Dunlap 
CC: Ian Jackson 
CC: Wei Liu 
CC: "Roger Pau Monné" 
---
v2 changes
- remove the introduce of internal flag
- remove flag direct_map since we already store this flag in d->options
- Refine is_domain_direct_mapped to check whether the flag
XEN_DOMCTL_CDF_directmap is set
- reword "1:1 direct-map" to just "direct-map"
---
v3 changes
- move flag back to xen/include/xen/domain.h, to let it be only available for
domain created by XEN.
- name it with extra "INTERNAL" and add comments to warn developers not
to accidently use its bitfield when introducing new XEN_DOMCTL_CDF_xxx flag.
- reject this flag in x86'es arch_sanitise_domain_config()
---
 xen/arch/arm/domain.c| 3 ++-
 xen/arch/arm/domain_build.c  | 4 +++-
 xen/arch/x86/domain.c| 6 ++
 xen/common/domain.c  | 3 ++-
 xen/include/asm-arm/domain.h | 4 ++--
 xen/include/public/domctl.h  | 4 
 xen/include/xen/domain.h | 3 +++
 7 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 96e1b23550..d77265c03f 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -629,7 +629,8 @@ int arch_sanitise_domain_config(struct 
xen_domctl_createdomain *config)
 {
 unsigned int max_vcpus;
 unsigned int flags_required = (XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap);
-unsigned int flags_optional = (XEN_DOMCTL_CDF_iommu | XEN_DOMCTL_CDF_vpmu);
+unsigned int flags_optional = (XEN_DOMCTL_CDF_iommu | XEN_DOMCTL_CDF_vpmu |
+   XEN_DOMCTL_CDF_INTERNAL_directmap);
 
 if ( (config->flags & ~flags_optional) != flags_required )
 {
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 19487c79da..664c88ebe4 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -3089,8 +3089,10 @@ static int __init construct_dom0(struct domain *d)
 void __init create_dom0(void)
 {
 struct domain *dom0;
+/* DOM0 has always its memory direct-map. */
 struct xen_domctl_createdomain dom0_cfg = {
-.flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
+.flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap |
+ XEN_DOMCTL_CDF_INTERNAL_directmap,
 .max_evtchn_port = -1,
 .max_grant_frames = gnttab_dom0_frames(),
 .max_maptrack_frames = -1,
diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index ef1812dc14..eba6502218 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -692,6 +692,12 @@ int arch_sanitise_domain_config(struct 
xen_domctl_createdomain *config)
 return -EINVAL;
 }
 
+if ( config->flags & XEN_DOMCTL_CDF_INTERNAL_directmap )
+{
+dprintk(XENLOG_INFO, "direct-map cannot be enabled yet\n");
+return -EINVAL;
+}
+
 return 0;
 }
 
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 56d47dd664..13ac5950bc 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -486,7 +486,8 @@ static int sanitise_domain_config(struct 
xen_domctl_createdomain *config)
  ~(XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap |
XEN_DOMCTL_CDF_s3_integrity | XEN_DOMCTL_CDF_oos_off |
XEN_DOMCTL_CDF_xs_domain | XEN_DOMCTL_CDF_iommu |
-   XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu) )
+   XEN_DOMCTL_CDF_nested_virt | XEN_DOMCTL_CDF_vpmu |
+   XEN_DOMCTL_CDF_INTERNAL_directmap) )
 {
 dprintk(XENLOG_INFO, "Unknown CDF flags %#x\n", config->flags);
 return -EINVAL;
diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
index 9b3647587a..4f2c3f09d4 100644
--- a/xen/include/asm-arm/domain.h
+++ b/xen/include/asm-arm/domain.h
@@ -29,8 +29,8 @@ enum domain_type {
 #define is_64bit_domain(d) (0)
 #endif
 
-/* The hardware domain has always its memory direct mapped. */
-#define is_domain_direct_mapped(d) is_hardware_domain(d)
+#define is_domain_direct_mapped(d) \
+(d->options & XEN_DOMCTL_CDF_INTERNAL_directmap)
 
 struct vtimer {
 struct vcpu *v;
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 1c21d4dc75..054e545c9

[PATCH v3 04/10] xen/arm: introduce direct-map for domUs

2021-11-15 Thread Penny Zheng
Cases where domU needs direct-map memory map:
  * IOMMU not present in the system.
  * IOMMU disabled if it doesn't cover a specific device and all the guests
are trusted. Thinking a mixed scenario, where a few devices with IOMMU and
a few without, then guest DMA security still could not be totally guaranteed.
So users may want to disable the IOMMU, to at least gain some performance
improvement from IOMMU disabled.
  * IOMMU disabled as a workaround when it doesn't have enough bandwidth.
To be specific, in a few extreme situation, when multiple devices do DMA
concurrently, these requests may exceed IOMMU's transmission capacity.
  * IOMMU disabled when it adds too much latency on DMA. For example,
TLB may be missing in some IOMMU hardware, which may bring latency in DMA
progress, so users may want to disable it in some realtime scenario.
  * Guest OS relies on the host memory layout

This commit introduces a new helper allocate_static_memory_11 to allocate
static memory as guest RAM for direct-map domain.

For now, direct-map is only available when statically allocated memory is
used for the domain, that is, "xen,static-mem" must be also defined in the
domain configuration.

Signed-off-by: Penny Zheng 
Signed-off-by: Stefano Stabellini 
---
v2 changes:
- split the common codes into two helpers: parse_static_mem_prop and
acquire_static_memory_bank to deduce complexity.
- introduce a new helper allocate_static_memory_11 for allocating static
memory for direct-map guests
- remove redundant use "bool direct_map", to be replaced by
d_cfg.flags & XEN_DOMCTL_CDF_directmap
- remove panic action since it is fine to assign a non-DMA capable device when
IOMMU and direct-map both off
---
v3 changes:
- doc refinement
- drop the pointless gbank
- add check of the size of nr_banks shall not exceed NR_MEM_BANKS
- add ASSERT_UNREACHABLE to catch any misuse
- add another check of validating flag XEN_DOMCTL_CDF_INTERNAL_directmap only
when CONFIG_STATIC_MEMORY is set.
---
 docs/misc/arm/device-tree/booting.txt |   6 ++
 xen/arch/arm/domain_build.c   | 105 +-
 2 files changed, 108 insertions(+), 3 deletions(-)

diff --git a/docs/misc/arm/device-tree/booting.txt 
b/docs/misc/arm/device-tree/booting.txt
index 71895663a4..a94125394e 100644
--- a/docs/misc/arm/device-tree/booting.txt
+++ b/docs/misc/arm/device-tree/booting.txt
@@ -182,6 +182,12 @@ with the following properties:
 Both #address-cells and #size-cells need to be specified because
 both sub-nodes (described shortly) have reg properties.
 
+- direct-map
+
+Only available when statically allocated memory is used for the domain.
+An empty property to request the memory of the domain to be
+direct-map (guest physical address == physical address).
+
 Under the "xen,domain" compatible node, one or more sub-nodes are present
 for the DomU kernel and ramdisk.
 
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 1dc728e848..97a5b5dedd 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -500,8 +500,13 @@ static bool __init append_static_memory_to_bank(struct 
domain *d,
 {
 int res;
 unsigned int nr_pages = PFN_DOWN(size);
-/* Infer next GFN. */
-gfn_t sgfn = gaddr_to_gfn(bank->start + bank->size);
+gfn_t sgfn;
+
+if ( !is_domain_direct_mapped(d) )
+/* Infer next GFN when GFN != MFN. */
+sgfn = gaddr_to_gfn(bank->start + bank->size);
+else
+sgfn = gaddr_to_gfn(mfn_to_maddr(smfn));
 
 res = guest_physmap_add_pages(d, sgfn, smfn, nr_pages);
 if ( res )
@@ -674,12 +679,94 @@ static void __init allocate_static_memory(struct domain 
*d,
  fail:
 panic("Failed to allocate requested static memory for domain %pd.", d);
 }
+
+/*
+ * Allocate static memory as RAM for one specific domain d.
+ * The static memory will be directly mapped in the guest(Guest Physical
+ * Address == Physical Address).
+ */
+static void __init allocate_static_memory_11(struct domain *d,
+ struct kernel_info *kinfo,
+ const struct dt_device_node *node)
+{
+u32 addr_cells, size_cells, reg_cells;
+unsigned int nr_banks, bank = 0;
+const __be32 *cell;
+u64 tot_size = 0;
+paddr_t pbase, psize;
+mfn_t smfn;
+int length;
+
+if ( parse_static_mem_prop(node, &addr_cells, &size_cells, &length, &cell) 
)
+{
+printk(XENLOG_ERR
+   "%pd: failed to parse \"xen,static-mem\" property.\n", d);
+goto fail;
+}
+reg_cells = addr_cells + size_cells;
+nr_banks = length / (reg_cells * sizeof (u32));
+
+if ( nr_banks > NR_MEM_BANKS )
+{
+printk(XENLOG_ERR
+   "%pd: exceed max number of supported guest memory banks.\n", d);
+goto fail;
+}
+
+

[PATCH v3 10/10] xen/docs: Document how to do passthrough without IOMMU

2021-11-15 Thread Penny Zheng
From: Stefano Stabellini 

This commit creates a new doc to document how to do passthrough without IOMMU.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
---
 docs/misc/arm/passthrough-noiommu.txt | 52 +++
 1 file changed, 52 insertions(+)
 create mode 100644 docs/misc/arm/passthrough-noiommu.txt

diff --git a/docs/misc/arm/passthrough-noiommu.txt 
b/docs/misc/arm/passthrough-noiommu.txt
new file mode 100644
index 00..3e2ef21ad7
--- /dev/null
+++ b/docs/misc/arm/passthrough-noiommu.txt
@@ -0,0 +1,52 @@
+Request Device Assignment without IOMMU support
+===
+
+*WARNING:
+Users should be aware that it is not always secure to assign a device without
+IOMMU protection.
+When the device is not protected by the IOMMU, the administrator should make
+sure that:
+ 1. The device is assigned to a trusted guest.
+ 2. Users have additional security mechanism on the platform.
+
+This document assumes that the IOMMU is absent from the system or it is
+disabled (status = "disabled" in device tree).
+
+Add xen,force-assign-without-iommu; to the device tree snippet:
+
+ethernet: ethernet@ff0e {
+   compatible = "cdns,zynqmp-gem";
+   xen,path = "/amba/ethernet@ff0e";
+   xen,reg = <0x0 0xff0e 0x1000 0x0 0xff0e>;
+   xen,force-assign-without-iommu;
+};
+
+Request 1:1 memory mapping for the domain on static allocation
+==
+
+Add a direct-map property under the appropriate /chosen/domU node which
+is also statically allocated with physical memory ranges through
+xen,static-mem property as its guest RAM.
+
+Below is an example on how to specify the 1:1 memory mapping for the domain
+on static allocation in the device-tree:
+
+/ {
+   chosen {
+   domU1 {
+   compatible = "xen,domain";
+   #address-cells = <0x2>;
+   #size-cells = <0x2>;
+   cpus = <2>;
+   memory = <0x0 0x8>;
+   #xen,static-mem-address-cells = <0x1>;
+   #xen,static-mem-size-cells = <0x1>;
+   xen,static-mem = <0x3000 0x2000>;
+   direct-map;
+   ...
+   };
+   };
+};
+
+Besides reserving a 512MB region starting at the host physical address
+0x3000 to DomU1, it also requests 1:1 memory mapping.
-- 
2.25.1




[PATCH v3 06/10] xen/arm: if direct-map domain use native addresses for GICv2

2021-11-15 Thread Penny Zheng
From: Stefano Stabellini 

Today we use native addresses to map the GICv2 for Dom0 and fixed
addresses for DomUs.

This patch changes the behavior so that native addresses are used for
all domains that are direct-mapped.

NEW VGIC has different naming schemes, like referring distributor base
address as vgic_dist_base, other than the dbase. So this patch also introduces
vgic_dist_base/vgic_cpu_base accessor to access correct distributor base
address/cpu interface base address on varied scenarios,

Signed-off-by: Penny Zheng 
Signed-off-by: Stefano Stabellini 
---
v2 changes
- combine all changes in patch 4-6 here
---
v3 changes
- refine comment message
- add a comment explaining how the 38 was found of "char buf[38]"
- simply map the CPU interface at the GPA vgic_v2_hw.cbase
- remove a spurious change
---
 xen/arch/arm/domain_build.c| 11 ---
 xen/arch/arm/vgic-v2.c | 31 ++-
 xen/arch/arm/vgic/vgic-v2.c| 31 ++-
 xen/include/asm-arm/new_vgic.h | 10 ++
 xen/include/asm-arm/vgic.h | 11 +++
 5 files changed, 73 insertions(+), 21 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index b6fde74d74..c419a4b2cc 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2230,8 +2230,13 @@ static int __init make_gicv2_domU_node(struct 
kernel_info *kinfo)
 int res = 0;
 __be32 reg[(GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) * 2];
 __be32 *cells;
+const struct domain *d = kinfo->d;
+/* Placeholder for interrupt-controller@ + a 64-bit number + \0 */
+char buf[38];
 
-res = fdt_begin_node(fdt, 
"interrupt-controller@"__stringify(GUEST_GICD_BASE));
+snprintf(buf, sizeof(buf), "interrupt-controller@%"PRIx64,
+ vgic_dist_base(&d->arch.vgic));
+res = fdt_begin_node(fdt, buf);
 if ( res )
 return res;
 
@@ -2253,9 +2258,9 @@ static int __init make_gicv2_domU_node(struct kernel_info 
*kinfo)
 
 cells = ®[0];
 dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-   GUEST_GICD_BASE, GUEST_GICD_SIZE);
+   vgic_dist_base(&d->arch.vgic), GUEST_GICD_SIZE);
 dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-   GUEST_GICC_BASE, GUEST_GICC_SIZE);
+   vgic_cpu_base(&d->arch.vgic), GUEST_GICC_SIZE);
 
 res = fdt_property(fdt, "reg", reg, sizeof(reg));
 if (res)
diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index 589c033eda..6f5492e30e 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -654,13 +654,10 @@ static int vgic_v2_vcpu_init(struct vcpu *v)
 static int vgic_v2_domain_init(struct domain *d)
 {
 int ret;
-paddr_t cbase, csize;
+paddr_t csize;
 paddr_t vbase;
 
-/*
- * The hardware domain gets the hardware address.
- * Guests get the virtual platform layout.
- */
+/* The hardware domain gets the hardware address. */
 if ( is_hardware_domain(d) )
 {
 d->arch.vgic.dbase = vgic_v2_hw.dbase;
@@ -671,10 +668,26 @@ static int vgic_v2_domain_init(struct domain *d)
  * Note that we assume the size of the CPU interface is always
  * aligned to PAGE_SIZE.
  */
-cbase = vgic_v2_hw.cbase;
+d->arch.vgic.cbase = vgic_v2_hw.cbase;
 csize = vgic_v2_hw.csize;
 vbase = vgic_v2_hw.vbase;
 }
+else if ( is_domain_direct_mapped(d) )
+{
+/*
+ * For all the direct-mapped domain other than the hardware domain,
+ * we only map a 8kB CPU interface but we make sure it is at a
+ * location occupied by the physical GIC in the host device tree.
+ *
+ * We need to add an offset to the virtual CPU interface base
+ * address when the GIC is aliased to get a 8kB contiguous
+ * region.
+ */
+d->arch.vgic.dbase = vgic_v2_hw.dbase;
+d->arch.vgic.cbase = vgic_v2_hw.cbase;
+csize = GUEST_GICC_SIZE;
+vbase = vgic_v2_hw.vbase + vgic_v2_hw.aliased_offset;
+}
 else
 {
 d->arch.vgic.dbase = GUEST_GICD_BASE;
@@ -685,7 +698,7 @@ static int vgic_v2_domain_init(struct domain *d)
  * region.
  */
 BUILD_BUG_ON(GUEST_GICC_SIZE != SZ_8K);
-cbase = GUEST_GICC_BASE;
+d->arch.vgic.cbase = GUEST_GICC_BASE;
 csize = GUEST_GICC_SIZE;
 vbase = vgic_v2_hw.vbase + vgic_v2_hw.aliased_offset;
 }
@@ -694,8 +707,8 @@ static int vgic_v2_domain_init(struct domain *d)
  * Map the gic virtual cpu interface in the gic cpu interface
  * region of the guest.
  */
-ret = map_mmio_regions(d, gaddr_to_gfn(cbase), csize / PAGE_SIZE,
-   maddr_to_mfn(vbase));
+ret = map_mmio_

[PATCH v3 07/10] xen/arm: gate make_gicv3_domU_node with CONFIG_GICV3

2021-11-15 Thread Penny Zheng
This commit gates function make_gicv3_domU_node with CONFIG_GICV3, and
also adds ASSERT_UNREACHABLE to catch any misuse.

Signed-off-by: Penny Zheng 
---
v3 changes:
- new commit
---
 xen/arch/arm/domain_build.c | 7 +++
 1 file changed, 7 insertions(+)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index c419a4b2cc..24f3edf069 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2279,6 +2279,7 @@ static int __init make_gicv2_domU_node(struct kernel_info 
*kinfo)
 return res;
 }
 
+#ifdef CONFIG_GICV3
 static int __init make_gicv3_domU_node(struct kernel_info *kinfo)
 {
 void *fdt = kinfo->fdt;
@@ -2328,6 +2329,12 @@ static int __init make_gicv3_domU_node(struct 
kernel_info *kinfo)
 
 return res;
 }
+#else
+static int __init make_gicv3_domU_node(struct kernel_info *kinfo)
+{
+ASSERT_UNREACHABLE();
+}
+#endif
 
 static int __init make_gic_domU_node(struct kernel_info *kinfo)
 {
-- 
2.25.1




[PATCH v3 08/10] xen/arm: if direct-map domain use native addresses for GICv3

2021-11-15 Thread Penny Zheng
From: Stefano Stabellini 

Today we use native addresses to map the GICv3 for Dom0 and fixed
addresses for DomUs.

This patch changes the behavior so that native addresses are used for
all domain which is using the host memory layout

Considering that DOM0 may not always be directly mapped in the future,
this patch introduces a new helper "domain_use_host_layout()" that
wraps both two check "is_domain_direct_mapped(d) || is_hardware_domain(d)"
for more flexible usage.

Signed-off-by: Penny Zheng 
Signed-off-by: Stefano Stabellini 
---
v2 changes:
- remove redistributor accessor
- introduce new helper "is_domain_use_host_layout()"
- comment fix
---
v3 changes:
- the comment on top of 'buf' to explain how 38 was found
- fix res getting overwritten
- drop 'cells += (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS)'
- free 'reg' right way
- fix comment
- rename 'is_domain_use_host_layout()' to 'domain_use_host_layout()'
---
 xen/arch/arm/domain_build.c  | 37 +++-
 xen/arch/arm/vgic-v3.c   | 29 
 xen/include/asm-arm/domain.h |  7 +++
 3 files changed, 52 insertions(+), 21 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 24f3edf069..61fd374c5d 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2284,10 +2284,16 @@ static int __init make_gicv3_domU_node(struct 
kernel_info *kinfo)
 {
 void *fdt = kinfo->fdt;
 int res = 0;
-__be32 reg[(GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) * 2];
-__be32 *cells;
+__be32 *reg;
+const struct domain *d = kinfo->d;
+/* Placeholder for interrupt-controller@ + a 64-bit number + \0 */
+char buf[38];
+unsigned int i, len = 0;
 
-res = fdt_begin_node(fdt, 
"interrupt-controller@"__stringify(GUEST_GICV3_GICD_BASE));
+snprintf(buf, sizeof(buf), "interrupt-controller@%"PRIx64,
+ vgic_dist_base(&d->arch.vgic));
+
+res = fdt_begin_node(fdt, buf);
 if ( res )
 return res;
 
@@ -2307,13 +2313,26 @@ static int __init make_gicv3_domU_node(struct 
kernel_info *kinfo)
 if ( res )
 return res;
 
-cells = ®[0];
-dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-   GUEST_GICV3_GICD_BASE, GUEST_GICV3_GICD_SIZE);
-dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-   GUEST_GICV3_GICR0_BASE, GUEST_GICV3_GICR0_SIZE);
+/* reg specifies all re-distributors and Distributor. */
+len = (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) *
+  (d->arch.vgic.nr_regions + 1) * sizeof(__be32);
+reg = xmalloc_bytes(len);
+if ( reg == NULL )
+return -ENOMEM;
 
-res = fdt_property(fdt, "reg", reg, sizeof(reg));
+dt_child_set_range(®, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
+   vgic_dist_base(&d->arch.vgic), GUEST_GICV3_GICD_SIZE);
+
+for ( i = 0; i < d->arch.vgic.nr_regions; i++)
+{
+dt_child_set_range(®,
+   GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
+   d->arch.vgic.rdist_regions[i].base,
+   d->arch.vgic.rdist_regions[i].size);
+}
+
+res = fdt_property(fdt, "reg", reg, len);
+xfree(reg);
 if (res)
 return res;
 
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 65bb7991a6..181b66513d 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1640,14 +1640,15 @@ static inline unsigned int 
vgic_v3_max_rdist_count(struct domain *d)
  * Normally there is only one GICv3 redistributor region.
  * The GICv3 DT binding provisions for multiple regions, since there are
  * platforms out there which need those (multi-socket systems).
- * For Dom0 we have to live with the MMIO layout the hardware provides,
- * so we have to copy the multiple regions - as the first region may not
- * provide enough space to hold all redistributors we need.
+ * For domain using the host memory layout, we have to live with the MMIO
+ * layout the hardware provides, so we have to copy the multiple regions
+ * - as the first region may not provide enough space to hold all
+ * redistributors we need.
  * However DomU get a constructed memory map, so we can go with
  * the architected single redistributor region.
  */
-return is_hardware_domain(d) ? vgic_v3_hw.nr_rdist_regions :
-   GUEST_GICV3_RDIST_REGIONS;
+return domain_use_host_layout(d) ? vgic_v3_hw.nr_rdist_regions :
+   GUEST_GICV3_RDIST_REGIONS;
 }
 
 static int vgic_v3_domain_init(struct domain *d)
@@ -1669,10 +1670,14 @@ static int vgic_v3_domain_init(struct domain *d)
 radix_tre

[PATCH v3 03/10] xen/arm: introduce new helper parse_static_mem_prop and acquire_static_memory_bank

2021-11-15 Thread Penny Zheng
Later, we will introduce allocate_static_memory_11 for allocating static
memory for direct-map domains, and it will share a lot common codes with
the existing allocate_static_memory.

In order not to bring a lot of duplicate codes, and also to make the whole
code more readable, this commit extracts common codes into two new helpers
parse_static_mem_prop and acquire_static_memory_bank.

Signed-off-by: Penny Zheng 
---
v3 changes:
- new commit to move the split off of the code outside in a separate patch
---
 xen/arch/arm/domain_build.c | 100 +++-
 1 file changed, 64 insertions(+), 36 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 7a063f62fe..1dc728e848 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -515,12 +515,69 @@ static bool __init append_static_memory_to_bank(struct 
domain *d,
 return true;
 }
 
+static mfn_t __init acquire_static_memory_bank(struct domain *d,
+ const __be32 **cell,
+ u32 addr_cells, u32 size_cells,
+ paddr_t *pbase, paddr_t *psize)
+{
+mfn_t smfn;
+int res;
+
+device_tree_get_reg(cell, addr_cells, size_cells, pbase, psize);
+ASSERT(IS_ALIGNED(*pbase, PAGE_SIZE) && IS_ALIGNED(*psize, PAGE_SIZE));
+if ( PFN_DOWN(*psize) > UINT_MAX )
+{
+printk(XENLOG_ERR "%pd: static memory size too large: %#"PRIpaddr,
+   d, *psize);
+return INVALID_MFN;
+}
+
+smfn = maddr_to_mfn(*pbase);
+res = acquire_domstatic_pages(d, smfn, PFN_DOWN(*psize), 0);
+if ( res )
+{
+printk(XENLOG_ERR
+   "%pd: failed to acquire static memory: %d.\n", d, res);
+return INVALID_MFN;
+}
+
+return smfn;
+}
+
+static int __init parse_static_mem_prop(const struct dt_device_node *node,
+u32 *addr_cells, u32 *size_cells,
+int *length, const __be32 **cell)
+{
+const struct dt_property *prop;
+
+prop = dt_find_property(node, "xen,static-mem", NULL);
+if ( !dt_property_read_u32(node, "#xen,static-mem-address-cells",
+   addr_cells) )
+{
+printk(XENLOG_ERR
+   "failed to read \"#xen,static-mem-address-cells\".\n");
+return -EINVAL;
+}
+
+if ( !dt_property_read_u32(node, "#xen,static-mem-size-cells",
+   size_cells) )
+{
+printk(XENLOG_ERR
+   "failed to read \"#xen,static-mem-size-cells\".\n");
+return -EINVAL;
+}
+
+*cell = (const __be32 *)prop->value;
+*length = prop->length;
+
+return 0;
+}
+
 /* Allocate memory from static memory as RAM for one specific domain d. */
 static void __init allocate_static_memory(struct domain *d,
   struct kernel_info *kinfo,
   const struct dt_device_node *node)
 {
-const struct dt_property *prop;
 u32 addr_cells, size_cells, reg_cells;
 unsigned int nr_banks, gbank, bank = 0;
 const uint64_t rambase[] = GUEST_RAM_BANK_BASES;
@@ -529,24 +586,10 @@ static void __init allocate_static_memory(struct domain 
*d,
 u64 tot_size = 0;
 paddr_t pbase, psize, gsize;
 mfn_t smfn;
-int res;
-
-prop = dt_find_property(node, "xen,static-mem", NULL);
-if ( !dt_property_read_u32(node, "#xen,static-mem-address-cells",
-   &addr_cells) )
-{
-printk(XENLOG_ERR
-   "%pd: failed to read \"#xen,static-mem-address-cells\".\n", d);
-goto fail;
-}
+int length;
 
-if ( !dt_property_read_u32(node, "#xen,static-mem-size-cells",
-   &size_cells) )
-{
-printk(XENLOG_ERR
-   "%pd: failed to read \"#xen,static-mem-size-cells\".\n", d);
+if ( parse_static_mem_prop(node, &addr_cells, &size_cells, &length, &cell) 
)
 goto fail;
-}
 reg_cells = addr_cells + size_cells;
 
 /*
@@ -557,29 +600,14 @@ static void __init allocate_static_memory(struct domain 
*d,
 gbank = 0;
 gsize = ramsize[gbank];
 kinfo->mem.bank[gbank].start = rambase[gbank];
-
-cell = (const __be32 *)prop->value;
-nr_banks = (prop->length) / (reg_cells * sizeof (u32));
+nr_banks = length / (reg_cells * sizeof (u32));
 
 for ( ; bank < nr_banks; bank++ )
 {
-device_tree_get_reg(&cell, addr_cells, size_cells, &pbase, &psize);
-ASSERT(IS_ALIGNED(pbase, PAGE_SIZE) && IS_ALIGNED(psize, PAGE_SIZE));
-
-if ( PFN_DOWN(psize) > UINT_MAX )
-{
-

[PATCH v3 09/10] xen/arm: if direct-map domain use native UART address and IRQ number for vPL011

2021-11-15 Thread Penny Zheng
From: Stefano Stabellini 

We always use a fix address to map the vPL011 to domains. The address
could be a problem for direct-map domains.

So, for domains that are directly mapped, reuse the address of the
physical UART on the platform to avoid potential clashes.

Do the same for the virtual IRQ number: instead of always using
GUEST_VPL011_SPI, try to reuse the physical SPI number if possible.

Signed-off-by: Penny Zheng 
Signed-off-by: Stefano Stabellini 
---
v2 changes:
- explain why vpl011 initialization before creating its device tree node
- error out if the domain is direct-mapped and the IRQ is not found
- harden the code and add a check/comment when the hardware UART region
is smaller than GUEST_VPL011_SIZE.
---
v3 changes:
- explain how the '27' was found for 'buf'
- fix checking before dereferencing
- refine comment message
---
 xen/arch/arm/domain_build.c  | 42 -
 xen/arch/arm/vpl011.c| 60 +++-
 xen/include/asm-arm/vpl011.h |  2 ++
 3 files changed, 90 insertions(+), 14 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 61fd374c5d..871c7114ae 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -30,6 +30,7 @@
 
 #include 
 #include 
+#include 
 
 static unsigned int __initdata opt_dom0_max_vcpus;
 integer_param("dom0_max_vcpus", opt_dom0_max_vcpus);
@@ -2376,8 +2377,12 @@ static int __init make_vpl011_uart_node(struct 
kernel_info *kinfo)
 gic_interrupt_t intr;
 __be32 reg[GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS];
 __be32 *cells;
+struct domain *d = kinfo->d;
+/* Placeholder for sbsa-uart@ + a 64-bit number + \0 */
+char buf[27];
 
-res = fdt_begin_node(fdt, "sbsa-uart@"__stringify(GUEST_PL011_BASE));
+snprintf(buf, sizeof(buf), "sbsa-uart@%"PRIx64, d->arch.vpl011.base_addr);
+res = fdt_begin_node(fdt, buf);
 if ( res )
 return res;
 
@@ -2387,14 +2392,14 @@ static int __init make_vpl011_uart_node(struct 
kernel_info *kinfo)
 
 cells = ®[0];
 dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS,
-   GUEST_ROOT_SIZE_CELLS, GUEST_PL011_BASE,
+   GUEST_ROOT_SIZE_CELLS, d->arch.vpl011.base_addr,
GUEST_PL011_SIZE);
 
 res = fdt_property(fdt, "reg", reg, sizeof(reg));
 if ( res )
 return res;
 
-set_interrupt(intr, GUEST_VPL011_SPI, 0xf, DT_IRQ_TYPE_LEVEL_HIGH);
+set_interrupt(intr, d->arch.vpl011.virq, 0xf, DT_IRQ_TYPE_LEVEL_HIGH);
 
 res = fdt_property(fdt, "interrupts", intr, sizeof (intr));
 if ( res )
@@ -3109,6 +3114,14 @@ static int __init construct_domU(struct domain *d,
 allocate_static_memory(d, &kinfo, node);
 }
 
+/*
+ * Base address and irq number are needed when creating vpl011 device
+ * tree node in prepare_dtb_domU, so initialization on related variables
+ * shall be done first.
+ */
+if ( kinfo.vpl011 )
+rc = domain_vpl011_init(d, NULL);
+
 rc = prepare_dtb_domU(d, &kinfo);
 if ( rc < 0 )
 return rc;
@@ -3117,9 +3130,6 @@ static int __init construct_domU(struct domain *d,
 if ( rc < 0 )
 return rc;
 
-if ( kinfo.vpl011 )
-rc = domain_vpl011_init(d, NULL);
-
 return rc;
 }
 
@@ -3161,15 +3171,33 @@ void __init create_domUs(void)
 
 if ( !dt_property_read_u32(node, "nr_spis", &d_cfg.arch.nr_spis) )
 {
+unsigned int vpl011_virq = GUEST_VPL011_SPI;
+
 d_cfg.arch.nr_spis = gic_number_lines() - 32;
 
+/*
+ * The VPL011 virq is GUEST_VPL011_SPI, unless direct-map is
+ * set, in which case it'll match the hardware.
+ *
+ * Since here the domain is not totally built, we need to
+ * open-code the logic to find the vIRQ. and the logic here
+ * is consistent with the ones in domain_vpl011_init().
+ */
+if ( d_cfg.flags & XEN_DOMCTL_CDF_INTERNAL_directmap )
+{
+vpl011_virq = serial_irq(SERHND_DTUART);
+if ( vpl011_virq < 0 )
+panic("Error getting IRQ number for this serial port %d\n",
+  SERHND_DTUART);
+}
+
 /*
  * vpl011 uses one emulated SPI. If vpl011 is requested, make
  * sure that we allocate enough SPIs for it.
  */
 if ( dt_property_read_bool(node, "vpl011") )
 d_cfg.arch.nr_spis = MAX(d_cfg.arch.nr_spis,
- GUEST_VPL011_SPI - 32 + 1);
+ vpl011_virq - 32 + 1);
 }
 
 /*
diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c
index 895f436cc4..65610bccaf

[PATCH] design: design doc for shared memory on a dom0less system

2022-01-26 Thread Penny Zheng
This commit provides a design doc for static shared memory
on a dom0less system.

Signed-off-by: Penny Zheng 
---
 design/shm-dom0less.md | 182 +
 1 file changed, 182 insertions(+)
 create mode 100644 design/shm-dom0less.md

diff --git a/design/shm-dom0less.md b/design/shm-dom0less.md
new file mode 100644
index 000..b46199d
--- /dev/null
+++ b/design/shm-dom0less.md
@@ -0,0 +1,182 @@
+# Static Shared Memory between domains on a dom0less system
+
+This design aims to provide an overview of the new feature: setting up static
+shared memory between domains on a dom0less system, through device tree
+configuration.
+
+The new feature is driven by the need of finding a way to build up
+communication channels on dom0less system, since the legacy ways including
+grant table, etc are all absent there.
+
+It was inspired by the patch serie of "xl/libxl-based shared memory", see
+[1] for more details.
+
+# Static Shared Memory Device Tree Configuration
+
+The static shared memory device tree nodes allow users to statically set up
+shared memory among a group of dom0less DomUs and Dom0, enabling domains
+to do shm-based communication.
+
+- compatible
+
+"xen,domain-shared-memory-v1"
+
+- xen,shm-id
+
+An u32 value represents the unique identifier of the shared memory region.
+User valuing per shared memory region shall follow the ascending order,
+starting from xen,shm-id = <0x0>, to the maximum identifier
+xen,shm-id = <0x126>. The special xen,shm-id = <0x127> is reserved for
+INVALID_SHMID.
+
+- xen,shared-mem
+
+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.
+
+- role(Optional)
+
+A string property specifying the ownership of a shared memory region,
+the value must be one of the following: "owner", or "borrower"
+A shared memory region could be explicitly backed by one domain, which is
+called "owner domain", and all the other domains who are also sharing
+this region are called "borrower domain".
+If not specified, the default value is "borrower" and owner is
+"dom_shared", a system domain.
+
+## Example
+
+chosen {
+#address-cells = <0x1>;
+#size-cells = <0x1>;
+xen,xen-bootargs = "console=dtuart dtuart=serial0 bootscrub=0";
+
+..
+
+/* this is for Dom0 */
+dom0-shared-mem@1000 {
+compatible = "xen,domain-shared-memory-v1";
+xen,shm-id = <0x0>;
+role = "owner";
+xen,shared-mem = <0x1000 0x1000 0x1000>;
+}
+
+domU1 {
+compatible = "xen,domain";
+#address-cells = <0x1>;
+#size-cells = <0x1>;
+memory = <0 131072>;
+cpus = <2>;
+vpl011;
+
+/*
+ * shared memory region identified as 0x0(xen,shm-id = <0x0>)
+ * shared between dom0.
+ */
+domU1-shared-mem@1000 {
+compatible = "xen,domain-shared-memory-v1";
+xen,shm-id = <0x0>;
+role = "borrower";
+xen,shared-mem = <0x1000 0x1000 0x5000>;
+}
+
+domU1-shared-mem@5000 {
+compatible = "xen,domain-shared-memory-v1";
+xen,shm-id = <0x1>;
+xen,shared-mem = <0x5000 0x2000 0x6000>;
+}
+
+..
+
+};
+
+domU2 {
+compatible = "xen,domain";
+#address-cells = <0x1>;
+#size-cells = <0x1>;
+memory = <0 65536>;
+cpus = <1>;
+
+/*
+ * shared memory region identified as 0x1(xen,shm-id = <0x1>)
+ * shared between domU1.
+ */
+domU2-shared-mem@5000 {
+compatible = "xen,domain-shared-memory-v1";
+xen,shm-id = <0x1>;
+xen,shared-mem = <0x5000 0x2000 0x7000>;
+}
+
+..
+};
+};
+
+It is the example of two static shared memory regions.
+
+In terms of shared memory region identified as 0x0, host physical address
+starting at 0x1000 of 256MB will be reserved to be shared between Dom0
+and DomU1. It will get mapped at 0x1000 in Dom0 guest physical address
+space, and at 0x5000 in DomU1 guest physical address space. Dom0 is the
+owner domain, and domU1 is the borrower domain.
+
+And in terms of shared memory region identified as 0x1, host physical address
+starting at 0x5000 of 512MB will be reserved to be shared between DomU1
+and DomU2. It will get mapped at 0x6000 in DomU1 guest physical address
+space, and at 0x7000 in DomU2 guest physical

[PATCH v5 00/11] direct-map memory map

2022-01-26 Thread Penny Zheng
Cases where domU needs direct-map memory map:
  * IOMMU not present in the system.
  * IOMMU disabled if it doesn't cover a specific device and all the guests
are trusted. Thinking a mixed scenario, where a few devices with IOMMU and
a few without, then guest DMA security still could not be totally guaranteed.
So users may want to disable the IOMMU, to at least gain some performance
improvement from IOMMU disabled.
  * IOMMU disabled as a workaround when it doesn't have enough bandwidth.
To be specific, in a few extreme situation, when multiple devices do DMA
concurrently, these requests may exceed IOMMU's transmission capacity.
  * IOMMU disabled when it adds too much latency on DMA. For example,
TLB may be missing in some IOMMU hardware, which may bring latency in DMA
progress, so users may want to disable it in some realtime scenario.
  * Guest OS relies on the host memory layout

"direct-map" property shall be added under the appropriate domain node,
when users requesting direct-map memory mapping for the domain.

Right now, direct-map is only supported when domain on Static Allocation,
that is, "xen,static-mem" is also necessary in the domain configuration.

Looking into related [design link](
https://lists.xenproject.org/archives/html/xen-devel/2021-05/msg00882.html)
for more details.

The whole design is about Static Allocation and direct-map, and this
Patch Serie only covers parts of it, which are direct-map memory map.
Other features will be delievered through different patch series.

See https://lists.xenproject.org/archives/html/xen-devel/2021-09/msg00855.html
for Domain on Static Allocation.

This patch serie is based on
https://lists.xenproject.org/archives/html/xen-devel/2021-10/msg00822.html\
---
v5 changes:
- remove const constraint and strict "static allocation" check
- fix coding style
---
v4 changes:
- introduce internal const CDF_xxx flags for domain creation
- introduce internal flag CDF_privileged
- introduce new internal flag CDF_directmap
- add a directmap flag under struct arch_domain and use it to
reimplement is_domain_direct_mapped.
- expand arch_domain_create/domain_create to include internal-only parameter
"const unsigned int flags"
- use mfn_eq() instead, because it is the only value used to indicate
there is an error and this is more lightweight than mfn_valid()
- rename function allocate_static_memory_11() to assign_static_memory_11()
to make clear there is actually no allocation done. Instead we are only
mapping pre-defined host regions to pre-defined guest regions.
- remove tot_size to directly substract psize from kinfo->unassigned_mem
- check kinfo->unassigned_mem doesn't underflow or overflow
- remove nested if/else
- remove ASSERT_UNREACHABLE() to avoid breaking compilation on prod build with
CONFIG_GICV3=n
- comment and commit message refinement
---
v3 changes:
- move flag XEN_DOMCTL_CDF_INTERNAL_directmap back to xen/include/xen/domain.h,
to let it be only available for domain created by XEN.
- name it with extra "INTERNAL" and add comments to warn developers not
to accidently use its bitfield when introducing new XEN_DOMCTL_CDF_xxx flag.
- reject this flag in x86'es arch_sanitise_domain_config()
- add ASSERT_UNREACHABLE to catch any misuse in allocate_static_memory()
and allocate_static_memory_11()
- add another check of validating flag XEN_DOMCTL_CDF_INTERNAL_directmap only
when CONFIG_STATIC_MEMORY is set.
- simply map the CPU interface at the GPA vgic_v2_hw.cbase
- drop 'cells += (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS)'
- rename 'is_domain_use_host_layout()' to 'domain_use_host_layout()'
---
v2 changes:
- remove the introduce of internal flag
- Refine is_domain_direct_mapped to check whether the flag
XEN_DOMCTL_CDF_directmap is set
- reword "1:1 direct-map" to just "direct-map"
- split the common codes into two helpers: parse_static_mem_prop and
acquire_static_memory_bank to deduce complexity.
- introduce a new helper allocate_static_memory_11 for allocating static
memory for direct-map guests
- remove panic action since it is fine to assign a non-DMA capable device when
IOMMU and direct-map both off
- remove redistributor accessor
- introduce new helper "is_domain_use_host_layout()"
- explain why vpl011 initialization before creating its device tree node
- error out if the domain is direct-mapped and the IRQ is not found
- harden the code and add a check/comment when the hardware UART region
is smaller than CUEST_VPL011_SIZE.

Penny Zheng (4):
  xen/arm: introduce new helper parse_static_mem_prop and
acquire_static_memory_bank
  xen/arm: introduce direct-map for domUs
  xen/arm: add ASSERT_UNREACHABLE in allocate_static_memory
  xen/arm: gate make_gicv3_domU_node with CONFIG_GICV3

Stefano Stabellini (7):
  xen: introduce internal CDF_xxx flags for domain creation
  xen: introduce CDF_directmap
  xen/a

[PATCH v5 01/11] xen: introduce internal CDF_xxx flags for domain creation

2022-01-26 Thread Penny Zheng
From: Stefano Stabellini 

We are passing an internal-only boolean flag at domain creation to
specify whether we want the domain to be privileged (i.e. dom0) or
not. Another flag will be introduced later in this series.

This commit extends original "boolean" to an "unsigned int" covering both
the existing "is_priv" and our new "directmap", which will be introduced later.

To make visible the relationship, we name the respective constants CDF_xxx
(with no XEN_DOMCTL_ prefix) to represent the difference with the public
constants XEN_DOMCTL_CDF_xxx.

Allocate bit 0 as CDF_privileged: whether a domain is privileged or not.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
Reviewed-by: Jan Beulich 
Tested-by: Stefano Stabellini 
---
v4 changes:
- new commit
---
v5 changes
- remove const constraint
---
 xen/arch/arm/domain_build.c |  4 ++--
 xen/arch/x86/setup.c|  2 +-
 xen/common/domain.c | 10 +-
 xen/common/sched/core.c |  2 +-
 xen/include/xen/domain.h|  4 
 xen/include/xen/sched.h |  2 +-
 6 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 6931c022a2..0fab8604de 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -3058,7 +3058,7 @@ void __init create_domUs(void)
  * very important to use the pre-increment operator to call
  * domain_create() with a domid > 0. (domid == 0 is reserved for Dom0)
  */
-d = domain_create(++max_init_domid, &d_cfg, false);
+d = domain_create(++max_init_domid, &d_cfg, 0);
 if ( IS_ERR(d) )
 panic("Error creating domain %s\n", dt_node_name(node));
 
@@ -3160,7 +3160,7 @@ void __init create_dom0(void)
 if ( iommu_enabled )
 dom0_cfg.flags |= XEN_DOMCTL_CDF_iommu;
 
-dom0 = domain_create(0, &dom0_cfg, true);
+dom0 = domain_create(0, &dom0_cfg, CDF_privileged);
 if ( IS_ERR(dom0) || (alloc_dom0_vcpu0(dom0) == NULL) )
 panic("Error creating domain 0\n");
 
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index e716005145..a14271488c 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -789,7 +789,7 @@ static struct domain *__init create_dom0(const module_t 
*image,
 
 /* Create initial domain.  Not d0 for pvshim. */
 domid = get_initial_domain_id();
-d = domain_create(domid, &dom0_cfg, !pv_shim);
+d = domain_create(domid, &dom0_cfg, pv_shim ? 0 : CDF_privileged);
 if ( IS_ERR(d) )
 panic("Error creating d%u: %ld\n", domid, PTR_ERR(d));
 
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 2048ebad86..a79103e04a 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -552,7 +552,7 @@ static int sanitise_domain_config(struct 
xen_domctl_createdomain *config)
 
 struct domain *domain_create(domid_t domid,
  struct xen_domctl_createdomain *config,
- bool is_priv)
+ unsigned int flags)
 {
 struct domain *d, **pd, *old_hwdom = NULL;
 enum { INIT_watchdog = 1u<<1,
@@ -578,7 +578,7 @@ struct domain *domain_create(domid_t domid,
 }
 
 /* Sort out our idea of is_control_domain(). */
-d->is_privileged = is_priv;
+d->is_privileged = flags & CDF_privileged;
 
 /* Sort out our idea of is_hardware_domain(). */
 if ( domid == 0 || domid == hardware_domid )
@@ -772,7 +772,7 @@ void __init setup_system_domains(void)
  * Hidden PCI devices will also be associated with this domain
  * (but be [partly] controlled by Dom0 nevertheless).
  */
-dom_xen = domain_create(DOMID_XEN, NULL, false);
+dom_xen = domain_create(DOMID_XEN, NULL, 0);
 if ( IS_ERR(dom_xen) )
 panic("Failed to create d[XEN]: %ld\n", PTR_ERR(dom_xen));
 
@@ -782,7 +782,7 @@ void __init setup_system_domains(void)
  * array. Mappings occur at the priv of the caller.
  * Quarantined PCI devices will be associated with this domain.
  */
-dom_io = domain_create(DOMID_IO, NULL, false);
+dom_io = domain_create(DOMID_IO, NULL, 0);
 if ( IS_ERR(dom_io) )
 panic("Failed to create d[IO]: %ld\n", PTR_ERR(dom_io));
 
@@ -791,7 +791,7 @@ void __init setup_system_domains(void)
  * Initialise our COW domain.
  * This domain owns sharable pages.
  */
-dom_cow = domain_create(DOMID_COW, NULL, false);
+dom_cow = domain_create(DOMID_COW, NULL, 0);
 if ( IS_ERR(dom_cow) )
 panic("Failed to create d[COW]: %ld\n", PTR_ERR(dom_cow));
 #endif
diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c
index 8f4b1ca10d..f5c819349b 100644
--- a/xen/common/sched/core.c
+++ b/xen/common/sched/core.c
@@ -3021,7 +3021,7 @@ void __init scheduler_init(void)
 sched_ratelimit_us = SCHED_DEFAULT_RATELIMIT_US

[PATCH v5 04/11] xen/arm: introduce new helper parse_static_mem_prop and acquire_static_memory_bank

2022-01-26 Thread Penny Zheng
Later, we will introduce assign_static_memory_11 for allocating static
memory for direct-map domains, and it will share a lot common codes with
the existing allocate_static_memory.

In order not to bring a lot of duplicate codes, and also to make the whole
code more readable, this commit extracts common codes into two new helpers
parse_static_mem_prop and acquire_static_memory_bank.

Signed-off-by: Penny Zheng 
Reviewed-by: Stefano Stabellini 
Tested-by: Stefano Stabellini 
---
v3 changes:
- new commit, split from the original "[PATCH v2 2/6] xen/arm: introduce
direct-map for domUs"
---
v4 changes
- explain briefly in the commit message why we want to do device assignment
without IOMMU.
---
v5 changes
- fix coding style
---
 xen/arch/arm/domain_build.c | 100 +++-
 1 file changed, 64 insertions(+), 36 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index c1e8c99f64..e61d2d53ba 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -509,12 +509,69 @@ static bool __init append_static_memory_to_bank(struct 
domain *d,
 return true;
 }
 
+static mfn_t __init acquire_static_memory_bank(struct domain *d,
+   const __be32 **cell,
+   u32 addr_cells, u32 size_cells,
+   paddr_t *pbase, paddr_t *psize)
+{
+mfn_t smfn;
+int res;
+
+device_tree_get_reg(cell, addr_cells, size_cells, pbase, psize);
+ASSERT(IS_ALIGNED(*pbase, PAGE_SIZE) && IS_ALIGNED(*psize, PAGE_SIZE));
+if ( PFN_DOWN(*psize) > UINT_MAX )
+{
+printk(XENLOG_ERR "%pd: static memory size too large: %#"PRIpaddr,
+   d, *psize);
+return INVALID_MFN;
+}
+
+smfn = maddr_to_mfn(*pbase);
+res = acquire_domstatic_pages(d, smfn, PFN_DOWN(*psize), 0);
+if ( res )
+{
+printk(XENLOG_ERR
+   "%pd: failed to acquire static memory: %d.\n", d, res);
+return INVALID_MFN;
+}
+
+return smfn;
+}
+
+static int __init parse_static_mem_prop(const struct dt_device_node *node,
+u32 *addr_cells, u32 *size_cells,
+int *length, const __be32 **cell)
+{
+const struct dt_property *prop;
+
+prop = dt_find_property(node, "xen,static-mem", NULL);
+if ( !dt_property_read_u32(node, "#xen,static-mem-address-cells",
+   addr_cells) )
+{
+printk(XENLOG_ERR
+   "failed to read \"#xen,static-mem-address-cells\".\n");
+return -EINVAL;
+}
+
+if ( !dt_property_read_u32(node, "#xen,static-mem-size-cells",
+   size_cells) )
+{
+printk(XENLOG_ERR
+   "failed to read \"#xen,static-mem-size-cells\".\n");
+return -EINVAL;
+}
+
+*cell = (const __be32 *)prop->value;
+*length = prop->length;
+
+return 0;
+}
+
 /* Allocate memory from static memory as RAM for one specific domain d. */
 static void __init allocate_static_memory(struct domain *d,
   struct kernel_info *kinfo,
   const struct dt_device_node *node)
 {
-const struct dt_property *prop;
 u32 addr_cells, size_cells, reg_cells;
 unsigned int nr_banks, gbank, bank = 0;
 const uint64_t rambase[] = GUEST_RAM_BANK_BASES;
@@ -523,24 +580,10 @@ static void __init allocate_static_memory(struct domain 
*d,
 u64 tot_size = 0;
 paddr_t pbase, psize, gsize;
 mfn_t smfn;
-int res;
-
-prop = dt_find_property(node, "xen,static-mem", NULL);
-if ( !dt_property_read_u32(node, "#xen,static-mem-address-cells",
-   &addr_cells) )
-{
-printk(XENLOG_ERR
-   "%pd: failed to read \"#xen,static-mem-address-cells\".\n", d);
-goto fail;
-}
+int length;
 
-if ( !dt_property_read_u32(node, "#xen,static-mem-size-cells",
-   &size_cells) )
-{
-printk(XENLOG_ERR
-   "%pd: failed to read \"#xen,static-mem-size-cells\".\n", d);
+if ( parse_static_mem_prop(node, &addr_cells, &size_cells, &length, &cell) 
)
 goto fail;
-}
 reg_cells = addr_cells + size_cells;
 
 /*
@@ -551,29 +594,14 @@ static void __init allocate_static_memory(struct domain 
*d,
 gbank = 0;
 gsize = ramsize[gbank];
 kinfo->mem.bank[gbank].start = rambase[gbank];
-
-cell = (const __be32 *)prop->value;
-nr_banks = (prop->length) / (reg_cells * sizeof (u32));
+nr_banks = length / (reg_cells * sizeof (u32));
 
 for ( ; bank < n

[PATCH v5 02/11] xen: introduce CDF_directmap

2022-01-26 Thread Penny Zheng
From: Stefano Stabellini 

This commit introduces a new arm-specific flag CDF_directmap to specify
that a domain should have its memory direct-map(guest physical address
== physical address) at domain creation.

Also, add a directmap flag under struct arch_domain and use it to
reimplement is_domain_direct_mapped.

For now, direct-map is only available when statically allocated memory is
used for the domain, that is, "xen,static-mem" must be also defined in the
domain configuration.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
Acked-by: Jan Beulich 
Tested-by: Stefano Stabellini 
---
CC: andrew.coop...@citrix.com
CC: jbeul...@suse.com
CC: George Dunlap 
CC: Ian Jackson 
CC: Wei Liu 
CC: "Roger Pau Monné" 
---
v2 changes
- remove the introduce of internal flag
- remove flag direct_map since we already store this flag in d->options
- Refine is_domain_direct_mapped to check whether the flag
XEN_DOMCTL_CDF_directmap is set
- reword "1:1 direct-map" to just "direct-map"
---
v3 changes
- move flag back to xen/include/xen/domain.h, to let it be only available for
domain created by XEN.
- name it with extra "INTERNAL" and add comments to warn developers not
to accidently use its bitfield when introducing new XEN_DOMCTL_CDF_xxx flag.
- reject this flag in x86'es arch_sanitise_domain_config()
---
v4 changes
- introduce new internal flag CDF_directmap
- add a directmap flag under struct arch_domain and use it to
reimplement is_domain_direct_mapped.
- expand arch_domain_create to include internal-only parameter "const unsigned
int flags"
---
v5 changes
- remove const constraint
- strict "static allocation" check
---
 docs/misc/arm/device-tree/booting.txt |  6 ++
 xen/arch/arm/domain.c |  5 -
 xen/arch/arm/domain_build.c   | 14 --
 xen/arch/arm/include/asm/domain.h |  5 +++--
 xen/arch/x86/domain.c |  3 ++-
 xen/common/domain.c   |  2 +-
 xen/include/xen/domain.h  |  5 -
 7 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/docs/misc/arm/device-tree/booting.txt 
b/docs/misc/arm/device-tree/booting.txt
index 71895663a4..a94125394e 100644
--- a/docs/misc/arm/device-tree/booting.txt
+++ b/docs/misc/arm/device-tree/booting.txt
@@ -182,6 +182,12 @@ with the following properties:
 Both #address-cells and #size-cells need to be specified because
 both sub-nodes (described shortly) have reg properties.
 
+- direct-map
+
+Only available when statically allocated memory is used for the domain.
+An empty property to request the memory of the domain to be
+direct-map (guest physical address == physical address).
+
 Under the "xen,domain" compatible node, one or more sub-nodes are present
 for the DomU kernel and ramdisk.
 
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 92a6c509e5..8110c1df86 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -692,7 +692,8 @@ int arch_sanitise_domain_config(struct 
xen_domctl_createdomain *config)
 }
 
 int arch_domain_create(struct domain *d,
-   struct xen_domctl_createdomain *config)
+   struct xen_domctl_createdomain *config,
+   unsigned int flags)
 {
 int rc, count = 0;
 
@@ -708,6 +709,8 @@ int arch_domain_create(struct domain *d,
 ioreq_domain_init(d);
 #endif
 
+d->arch.directmap = flags & CDF_directmap;
+
 /* p2m_init relies on some value initialized by the IOMMU subsystem */
 if ( (rc = iommu_domain_init(d, config->iommu_opts)) != 0 )
 goto fail;
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 0fab8604de..6467e8ee32 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -3029,10 +3029,20 @@ void __init create_domUs(void)
 .max_maptrack_frames = -1,
 .grant_opts = XEN_DOMCTL_GRANT_version(opt_gnttab_max_version),
 };
+unsigned int flags = 0U;
 
 if ( !dt_device_is_compatible(node, "xen,domain") )
 continue;
 
+if ( dt_property_read_bool(node, "direct-map") )
+{
+if ( !IS_ENABLED(CONFIG_STATIC_MEMORY) || !dt_find_property(node, 
"xen,static-mem", NULL) )
+panic("direct-map is not valid for domain %s without static 
allocation.\n",
+  dt_node_name(node));
+
+flags |= CDF_directmap;
+}
+
 if ( !dt_property_read_u32(node, "cpus", &d_cfg.max_vcpus) )
 panic("Missing property 'cpus' for domain %s\n",
   dt_node_name(node));
@@ -3058,7 +3068,7 @@ void __init create_domUs(void)
  * very important to use the pre-increment operator to call
  * domain_create() with a domid > 0. (domid == 0 is reserved for Dom0)
   

[PATCH v5 06/11] xen/arm: add ASSERT_UNREACHABLE in allocate_static_memory

2022-01-26 Thread Penny Zheng
Helper allocate_static_memory is not meant to be reachable when built with
!CONFIG_STATIC_MEMORY, so this commit adds ASSERT_UNREACHABLE in it to catch
potential misuse.

Signed-off-by: Penny Zheng 
Acked-by: Julien Grall 
Tested-by: Stefano Stabellini 
---
v3 changes:
- new commit
---
v4 changes:
- nothing changed
---
v5 changes:
- nothing changed
---
 xen/arch/arm/domain_build.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index ec29bd302c..52f256de9c 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -755,6 +755,7 @@ static void __init allocate_static_memory(struct domain *d,
   struct kernel_info *kinfo,
   const struct dt_device_node *node)
 {
+ASSERT_UNREACHABLE();
 }
 
 static void __init assign_static_memory_11(struct domain *d,
-- 
2.25.1




[PATCH v5 08/11] xen/arm: gate make_gicv3_domU_node with CONFIG_GICV3

2022-01-26 Thread Penny Zheng
This commit gates function make_gicv3_domU_node with CONFIG_GICV3.

Signed-off-by: Penny Zheng 
Acked-by: Stefano Stabellini 
Tested-by: Stefano Stabellini 
---
v4 changes:
- remove ASSERT_UNREACHABLE() to avoid breaking compilation on prod build with
CONFIG_GICV3=n
---
v5 changes:
- nothing changed
---
 xen/arch/arm/domain_build.c | 4 
 1 file changed, 4 insertions(+)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 87391adde6..a01dc60b55 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2322,6 +2322,7 @@ static int __init make_gicv2_domU_node(struct kernel_info 
*kinfo)
 return res;
 }
 
+#ifdef CONFIG_GICV3
 static int __init make_gicv3_domU_node(struct kernel_info *kinfo)
 {
 void *fdt = kinfo->fdt;
@@ -2371,13 +2372,16 @@ static int __init make_gicv3_domU_node(struct 
kernel_info *kinfo)
 
 return res;
 }
+#endif
 
 static int __init make_gic_domU_node(struct kernel_info *kinfo)
 {
 switch ( kinfo->d->arch.vgic.version )
 {
+#ifdef CONFIG_GICV3
 case GIC_V3:
 return make_gicv3_domU_node(kinfo);
+#endif
 case GIC_V2:
 return make_gicv2_domU_node(kinfo);
 default:
-- 
2.25.1




[PATCH v5 07/11] xen/arm: if direct-map domain use native addresses for GICv2

2022-01-26 Thread Penny Zheng
From: Stefano Stabellini 

Today we use native addresses to map the GICv2 for Dom0 and fixed
addresses for DomUs.

This patch changes the behavior so that native addresses are used for
all domains that are direct-mapped.

NEW VGIC has different naming schemes, like referring distributor base
address as vgic_dist_base, other than the dbase. So this patch also introduces
vgic_dist_base/vgic_cpu_base accessor to access correct distributor base
address/cpu interface base address on varied scenarios,

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
Tested-by: Stefano Stabellini 
---
v2 changes
- combine all changes in patch 4-6 here
---
v3 changes
- refine comment message
- add a comment explaining how the 38 was found of "char buf[38]"
- simply map the CPU interface at the GPA vgic_v2_hw.cbase
- remove a spurious change
---
v4 changes:
- refine comment to let it be a summary of the if/else if/else.
---
v5 changes:
- nothing changed
---
 xen/arch/arm/domain_build.c | 11 +++---
 xen/arch/arm/include/asm/new_vgic.h | 10 +
 xen/arch/arm/include/asm/vgic.h | 11 ++
 xen/arch/arm/vgic-v2.c  | 34 +++--
 xen/arch/arm/vgic/vgic-v2.c | 34 +++--
 5 files changed, 83 insertions(+), 17 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 52f256de9c..87391adde6 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2273,8 +2273,13 @@ static int __init make_gicv2_domU_node(struct 
kernel_info *kinfo)
 int res = 0;
 __be32 reg[(GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) * 2];
 __be32 *cells;
+const struct domain *d = kinfo->d;
+/* Placeholder for interrupt-controller@ + a 64-bit number + \0 */
+char buf[38];
 
-res = fdt_begin_node(fdt, 
"interrupt-controller@"__stringify(GUEST_GICD_BASE));
+snprintf(buf, sizeof(buf), "interrupt-controller@%"PRIx64,
+ vgic_dist_base(&d->arch.vgic));
+res = fdt_begin_node(fdt, buf);
 if ( res )
 return res;
 
@@ -2296,9 +2301,9 @@ static int __init make_gicv2_domU_node(struct kernel_info 
*kinfo)
 
 cells = ®[0];
 dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-   GUEST_GICD_BASE, GUEST_GICD_SIZE);
+   vgic_dist_base(&d->arch.vgic), GUEST_GICD_SIZE);
 dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-   GUEST_GICC_BASE, GUEST_GICC_SIZE);
+   vgic_cpu_base(&d->arch.vgic), GUEST_GICC_SIZE);
 
 res = fdt_property(fdt, "reg", reg, sizeof(reg));
 if (res)
diff --git a/xen/arch/arm/include/asm/new_vgic.h 
b/xen/arch/arm/include/asm/new_vgic.h
index 97d622bff6..ab57fcd91d 100644
--- a/xen/arch/arm/include/asm/new_vgic.h
+++ b/xen/arch/arm/include/asm/new_vgic.h
@@ -186,6 +186,16 @@ struct vgic_cpu {
 uint32_t num_id_bits;
 };
 
+static inline paddr_t vgic_cpu_base(const struct vgic_dist *vgic)
+{
+return vgic->vgic_cpu_base;
+}
+
+static inline paddr_t vgic_dist_base(const struct vgic_dist *vgic)
+{
+return vgic->vgic_dist_base;
+}
+
 #endif /* __ASM_ARM_NEW_VGIC_H */
 
 /*
diff --git a/xen/arch/arm/include/asm/vgic.h b/xen/arch/arm/include/asm/vgic.h
index ade427a808..d2a9fc7d83 100644
--- a/xen/arch/arm/include/asm/vgic.h
+++ b/xen/arch/arm/include/asm/vgic.h
@@ -152,6 +152,7 @@ struct vgic_dist {
 struct pending_irq *pending_irqs;
 /* Base address for guest GIC */
 paddr_t dbase; /* Distributor base address */
+paddr_t cbase; /* CPU interface base address */
 #ifdef CONFIG_GICV3
 /* GIC V3 addressing */
 /* List of contiguous occupied by the redistributors */
@@ -271,6 +272,16 @@ static inline int REG_RANK_NR(int b, uint32_t n)
 
 enum gic_sgi_mode;
 
+static inline paddr_t vgic_cpu_base(const struct vgic_dist *vgic)
+{
+return vgic->cbase;
+}
+
+static inline paddr_t vgic_dist_base(const struct vgic_dist *vgic)
+{
+return vgic->dbase;
+}
+
 /*
  * Offset of GICD_ with its rank, for GICD_ size  with
  * -bits-per-interrupt.
diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index 589c033eda..b1bd7a46ad 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -654,12 +654,16 @@ static int vgic_v2_vcpu_init(struct vcpu *v)
 static int vgic_v2_domain_init(struct domain *d)
 {
 int ret;
-paddr_t cbase, csize;
+paddr_t csize;
 paddr_t vbase;
 
 /*
- * The hardware domain gets the hardware address.
- * Guests get the virtual platform layout.
+ * The hardware domain and direct-mapped domain both get the hardware
+ * address.
+ * We have to handle them separately because the hwdom is re-using the
+ * same Device-Tree as the host (see more details below).
+ *
+ * Other domains get the virtual platform layout

[PATCH v5 10/11] xen/arm: if direct-map domain use native UART address and IRQ number for vPL011

2022-01-26 Thread Penny Zheng
From: Stefano Stabellini 

We always use a fix address to map the vPL011 to domains. The address
could be a problem for direct-map domains.

So, for domains that are directly mapped, reuse the address of the
physical UART on the platform to avoid potential clashes.

Do the same for the virtual IRQ number: instead of always using
GUEST_VPL011_SPI, try to reuse the physical SPI number if possible.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
Tested-by: Stefano Stabellini 
---
v2 changes:
- explain why vpl011 initialization before creating its device tree node
- error out if the domain is direct-mapped and the IRQ is not found
- harden the code and add a check/comment when the hardware UART region
is smaller than GUEST_VPL011_SIZE.
---
v3 changes:
- explain how the '27' was found for 'buf'
- fix checking before dereferencing
- refine comment message
---
v4 changes:
- refine comment message
---
v5 changes:
- nothing changed
---
 xen/arch/arm/domain_build.c   | 44 +++
 xen/arch/arm/include/asm/vpl011.h |  2 ++
 xen/arch/arm/vpl011.c | 60 +++
 3 files changed, 92 insertions(+), 14 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index cff2cb93cc..8be01678de 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -30,6 +30,7 @@
 
 #include 
 #include 
+#include 
 
 static unsigned int __initdata opt_dom0_max_vcpus;
 integer_param("dom0_max_vcpus", opt_dom0_max_vcpus);
@@ -2415,8 +2416,12 @@ static int __init make_vpl011_uart_node(struct 
kernel_info *kinfo)
 gic_interrupt_t intr;
 __be32 reg[GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS];
 __be32 *cells;
+struct domain *d = kinfo->d;
+/* Placeholder for sbsa-uart@ + a 64-bit number + \0 */
+char buf[27];
 
-res = fdt_begin_node(fdt, "sbsa-uart@"__stringify(GUEST_PL011_BASE));
+snprintf(buf, sizeof(buf), "sbsa-uart@%"PRIx64, d->arch.vpl011.base_addr);
+res = fdt_begin_node(fdt, buf);
 if ( res )
 return res;
 
@@ -2426,14 +2431,14 @@ static int __init make_vpl011_uart_node(struct 
kernel_info *kinfo)
 
 cells = ®[0];
 dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS,
-   GUEST_ROOT_SIZE_CELLS, GUEST_PL011_BASE,
+   GUEST_ROOT_SIZE_CELLS, d->arch.vpl011.base_addr,
GUEST_PL011_SIZE);
 
 res = fdt_property(fdt, "reg", reg, sizeof(reg));
 if ( res )
 return res;
 
-set_interrupt(intr, GUEST_VPL011_SPI, 0xf, DT_IRQ_TYPE_LEVEL_HIGH);
+set_interrupt(intr, d->arch.vpl011.virq, 0xf, DT_IRQ_TYPE_LEVEL_HIGH);
 
 res = fdt_property(fdt, "interrupts", intr, sizeof (intr));
 if ( res )
@@ -3145,6 +3150,14 @@ static int __init construct_domU(struct domain *d,
 else
 assign_static_memory_11(d, &kinfo, node);
 
+/*
+ * Base address and irq number are needed when creating vpl011 device
+ * tree node in prepare_dtb_domU, so initialization on related variables
+ * shall be done first.
+ */
+if ( kinfo.vpl011 )
+rc = domain_vpl011_init(d, NULL);
+
 rc = prepare_dtb_domU(d, &kinfo);
 if ( rc < 0 )
 return rc;
@@ -3153,9 +3166,6 @@ static int __init construct_domU(struct domain *d,
 if ( rc < 0 )
 return rc;
 
-if ( kinfo.vpl011 )
-rc = domain_vpl011_init(d, NULL);
-
 return rc;
 }
 
@@ -3200,15 +3210,35 @@ void __init create_domUs(void)
 
 if ( !dt_property_read_u32(node, "nr_spis", &d_cfg.arch.nr_spis) )
 {
+unsigned int vpl011_virq = GUEST_VPL011_SPI;
+
 d_cfg.arch.nr_spis = gic_number_lines() - 32;
 
+/*
+ * The VPL011 virq is GUEST_VPL011_SPI, unless direct-map is
+ * set, in which case it'll match the hardware.
+ *
+ * Since the domain is not yet created, we can't use
+ * d->arch.vpl011.irq. So the logic to find the vIRQ has to
+ * be hardcoded.
+ * The logic here shall be consistent with the one in
+ * domain_vpl011_init().
+ */
+if ( flags & CDF_directmap )
+{
+vpl011_virq = serial_irq(SERHND_DTUART);
+if ( vpl011_virq < 0 )
+panic("Error getting IRQ number for this serial port %d\n",
+  SERHND_DTUART);
+}
+
 /*
  * vpl011 uses one emulated SPI. If vpl011 is requested, make
  * sure that we allocate enough SPIs for it.
  */
 if ( dt_property_read_bool(node, "vpl011") )
 d_cfg.arch.nr_spis = MAX(d_cfg.arch.nr_spis,
- GUEST_VPL011_SPI - 32 + 1);
+  

[PATCH v5 03/11] xen/arm: avoid setting XEN_DOMCTL_CDF_iommu when IOMMU off

2022-01-26 Thread Penny Zheng
From: Stefano Stabellini 

When IOMMU is absent or shall not be used (trusted domain, performance,
hardware limitation, ..., etc), in which cases this commit avoids setting
XEN_DOMCTL_CDF_iommu to make those user cases possible and prevent failure
later during device assignment.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
Tested-by: Stefano Stabellini 
---
v3 changes:
- new commit, split from the original "[PATCH v2 2/6] xen/arm: introduce
direct-map for domUs"
---
v4 changes:
- explain briefly in the commit message why we want to do device assignment
without IOMMU.
---
v5 changes:
- nothing changed
---
 xen/arch/arm/domain_build.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 6467e8ee32..c1e8c99f64 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -3047,7 +3047,8 @@ void __init create_domUs(void)
 panic("Missing property 'cpus' for domain %s\n",
   dt_node_name(node));
 
-if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") )
+if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") &&
+ iommu_enabled )
 d_cfg.flags |= XEN_DOMCTL_CDF_iommu;
 
 if ( !dt_property_read_u32(node, "nr_spis", &d_cfg.arch.nr_spis) )
-- 
2.25.1




[PATCH v5 05/11] xen/arm: introduce direct-map for domUs

2022-01-26 Thread Penny Zheng
Cases where domU needs direct-map memory map:
  * IOMMU not present in the system.
  * IOMMU disabled if it doesn't cover a specific device and all the guests
are trusted. Thinking a mixed scenario, where a few devices with IOMMU and
a few without, then guest DMA security still could not be totally guaranteed.
So users may want to disable the IOMMU, to at least gain some performance
improvement from IOMMU disabled.
  * IOMMU disabled as a workaround when it doesn't have enough bandwidth.
To be specific, in a few extreme situation, when multiple devices do DMA
concurrently, these requests may exceed IOMMU's transmission capacity.
  * IOMMU disabled when it adds too much latency on DMA. For example,
TLB may be missing in some IOMMU hardware, which may bring latency in DMA
progress, so users may want to disable it in some realtime scenario.
  * Guest OS relies on the host memory layout

This commit introduces a new helper assign_static_memory_11 to allocate
static memory as guest RAM for direct-map domain.

Signed-off-by: Penny Zheng 
Reviewed-by: Stefano Stabellini 
Tested-by: Stefano Stabellini 
---
v2 changes:
- split the common codes into two helpers: parse_static_mem_prop and
acquire_static_memory_bank to deduce complexity.
- introduce a new helper allocate_static_memory_11 for allocating static
memory for direct-map guests
- remove redundant use "bool direct_map", to be replaced by
d_cfg.flags & XEN_DOMCTL_CDF_directmap
- remove panic action since it is fine to assign a non-DMA capable device when
IOMMU and direct-map both off
---
v3 changes:
- doc refinement
- drop the pointless gbank
- add check of the size of nr_banks shall not exceed NR_MEM_BANKS
- add ASSERT_UNREACHABLE to catch any misuse
- add another check of validating flag XEN_DOMCTL_CDF_INTERNAL_directmap only
when CONFIG_STATIC_MEMORY is set.
---
v4 changes:
- comment refinement
- rename function allocate_static_memory_11() to assign_static_memory_11()
to make clear there is actually no allocation done. Instead we are only
mapping pre-defined host regions to pre-defined guest regions.
- remove tot_size to directly substract psize from kinfo->unassigned_mem
- check kinfo->unassigned_mem doesn't underflow or overflow
- remove nested if/else
- refine "panic" info
---
v5 changes:
- fix coding style
---
 xen/arch/arm/domain_build.c | 97 +++--
 1 file changed, 94 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index e61d2d53ba..ec29bd302c 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -494,8 +494,17 @@ static bool __init append_static_memory_to_bank(struct 
domain *d,
 {
 int res;
 unsigned int nr_pages = PFN_DOWN(size);
-/* Infer next GFN. */
-gfn_t sgfn = gaddr_to_gfn(bank->start + bank->size);
+gfn_t sgfn;
+
+/*
+ * For direct-mapped domain, the GFN match the MFN.
+ * Otherwise, this is inferred on what has already been allocated
+ * in the bank.
+ */
+if ( !is_domain_direct_mapped(d) )
+sgfn = gaddr_to_gfn(bank->start + bank->size);
+else
+sgfn = gaddr_to_gfn(mfn_to_maddr(smfn));
 
 res = guest_physmap_add_pages(d, sgfn, smfn, nr_pages);
 if ( res )
@@ -668,12 +677,92 @@ static void __init allocate_static_memory(struct domain 
*d,
  fail:
 panic("Failed to allocate requested static memory for domain %pd.", d);
 }
+
+/*
+ * Allocate static memory as RAM for one specific domain d.
+ * The static memory will be directly mapped in the guest(Guest Physical
+ * Address == Physical Address).
+ */
+static void __init assign_static_memory_11(struct domain *d,
+   struct kernel_info *kinfo,
+   const struct dt_device_node *node)
+{
+u32 addr_cells, size_cells, reg_cells;
+unsigned int nr_banks, bank = 0;
+const __be32 *cell;
+paddr_t pbase, psize;
+mfn_t smfn;
+int length;
+
+if ( parse_static_mem_prop(node, &addr_cells, &size_cells, &length, &cell) 
)
+{
+printk(XENLOG_ERR
+   "%pd: failed to parse \"xen,static-mem\" property.\n", d);
+goto fail;
+}
+reg_cells = addr_cells + size_cells;
+nr_banks = length / (reg_cells * sizeof(u32));
+
+if ( nr_banks > NR_MEM_BANKS )
+{
+printk(XENLOG_ERR
+   "%pd: exceed max number of supported guest memory banks.\n", d);
+goto fail;
+}
+
+for ( ; bank < nr_banks; bank++ )
+{
+smfn = acquire_static_memory_bank(d, &cell, addr_cells, size_cells,
+  &pbase, &psize);
+if ( mfn_eq(smfn, INVALID_MFN) )
+goto fail;
+
+printk(XENLOG_INFO "%pd: STATIC BANK[%u] %#"PRIpaddr"-%#"PRIpaddr"\n",
+  

[PATCH v5 11/11] xen/docs: Document how to do passthrough without IOMMU

2022-01-26 Thread Penny Zheng
From: Stefano Stabellini 

This commit creates a new doc to document how to do passthrough without IOMMU.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
Tested-by: Stefano Stabellini 
---
v2 changes:
- nothing changed
---
v3 changes:
- nothing changed
---
v4 changes:
- nothing changed
---
v5 changes:
- nothing changed
---
 docs/misc/arm/passthrough-noiommu.txt | 52 +++
 1 file changed, 52 insertions(+)
 create mode 100644 docs/misc/arm/passthrough-noiommu.txt

diff --git a/docs/misc/arm/passthrough-noiommu.txt 
b/docs/misc/arm/passthrough-noiommu.txt
new file mode 100644
index 00..3e2ef21ad7
--- /dev/null
+++ b/docs/misc/arm/passthrough-noiommu.txt
@@ -0,0 +1,52 @@
+Request Device Assignment without IOMMU support
+===
+
+*WARNING:
+Users should be aware that it is not always secure to assign a device without
+IOMMU protection.
+When the device is not protected by the IOMMU, the administrator should make
+sure that:
+ 1. The device is assigned to a trusted guest.
+ 2. Users have additional security mechanism on the platform.
+
+This document assumes that the IOMMU is absent from the system or it is
+disabled (status = "disabled" in device tree).
+
+Add xen,force-assign-without-iommu; to the device tree snippet:
+
+ethernet: ethernet@ff0e {
+   compatible = "cdns,zynqmp-gem";
+   xen,path = "/amba/ethernet@ff0e";
+   xen,reg = <0x0 0xff0e 0x1000 0x0 0xff0e>;
+   xen,force-assign-without-iommu;
+};
+
+Request 1:1 memory mapping for the domain on static allocation
+==
+
+Add a direct-map property under the appropriate /chosen/domU node which
+is also statically allocated with physical memory ranges through
+xen,static-mem property as its guest RAM.
+
+Below is an example on how to specify the 1:1 memory mapping for the domain
+on static allocation in the device-tree:
+
+/ {
+   chosen {
+   domU1 {
+   compatible = "xen,domain";
+   #address-cells = <0x2>;
+   #size-cells = <0x2>;
+   cpus = <2>;
+   memory = <0x0 0x8>;
+   #xen,static-mem-address-cells = <0x1>;
+   #xen,static-mem-size-cells = <0x1>;
+   xen,static-mem = <0x3000 0x2000>;
+   direct-map;
+   ...
+   };
+   };
+};
+
+Besides reserving a 512MB region starting at the host physical address
+0x3000 to DomU1, it also requests 1:1 memory mapping.
-- 
2.25.1




[PATCH v5 09/11] xen/arm: if direct-map domain use native addresses for GICv3

2022-01-26 Thread Penny Zheng
From: Stefano Stabellini 

Today we use native addresses to map the GICv3 for Dom0 and fixed
addresses for DomUs.

This patch changes the behavior so that native addresses are used for
all domain which is using the host memory layout

Considering that DOM0 may not always be directly mapped in the future,
this patch introduces a new helper "domain_use_host_layout()" that
wraps both two check "is_domain_direct_mapped(d) || is_hardware_domain(d)"
for more flexible usage.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
Tested-by: Stefano Stabellini 
---
v2 changes:
- remove redistributor accessor
- introduce new helper "is_domain_use_host_layout()"
- comment fix
---
v3 changes:
- the comment on top of 'buf' to explain how 38 was found
- fix res getting overwritten
- drop 'cells += (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS)'
- free 'reg' right way
- fix comment
- rename 'is_domain_use_host_layout()' to 'domain_use_host_layout()'
---
v4 changes:
- refine comment
---
v5 changes:
- nothing changed
---
 xen/arch/arm/domain_build.c   | 34 +++
 xen/arch/arm/include/asm/domain.h | 14 +
 xen/arch/arm/vgic-v3.c| 26 ---
 3 files changed, 54 insertions(+), 20 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index a01dc60b55..cff2cb93cc 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -2327,10 +2327,16 @@ static int __init make_gicv3_domU_node(struct 
kernel_info *kinfo)
 {
 void *fdt = kinfo->fdt;
 int res = 0;
-__be32 reg[(GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) * 2];
-__be32 *cells;
+__be32 *reg, *cells;
+const struct domain *d = kinfo->d;
+/* Placeholder for interrupt-controller@ + a 64-bit number + \0 */
+char buf[38];
+unsigned int i, len = 0;
+
+snprintf(buf, sizeof(buf), "interrupt-controller@%"PRIx64,
+ vgic_dist_base(&d->arch.vgic));
 
-res = fdt_begin_node(fdt, 
"interrupt-controller@"__stringify(GUEST_GICV3_GICD_BASE));
+res = fdt_begin_node(fdt, buf);
 if ( res )
 return res;
 
@@ -2350,13 +2356,25 @@ static int __init make_gicv3_domU_node(struct 
kernel_info *kinfo)
 if ( res )
 return res;
 
-cells = ®[0];
-dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-   GUEST_GICV3_GICD_BASE, GUEST_GICV3_GICD_SIZE);
+/* reg specifies all re-distributors and Distributor. */
+len = (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS) *
+  (d->arch.vgic.nr_regions + 1) * sizeof(__be32);
+reg = xmalloc_bytes(len);
+if ( reg == NULL )
+return -ENOMEM;
+cells = reg;
+
 dt_child_set_range(&cells, GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
-   GUEST_GICV3_GICR0_BASE, GUEST_GICV3_GICR0_SIZE);
+   vgic_dist_base(&d->arch.vgic), GUEST_GICV3_GICD_SIZE);
 
-res = fdt_property(fdt, "reg", reg, sizeof(reg));
+for ( i = 0; i < d->arch.vgic.nr_regions; i++ )
+dt_child_set_range(&cells,
+   GUEST_ROOT_ADDRESS_CELLS, GUEST_ROOT_SIZE_CELLS,
+   d->arch.vgic.rdist_regions[i].base,
+   d->arch.vgic.rdist_regions[i].size);
+
+res = fdt_property(fdt, "reg", reg, len);
+xfree(reg);
 if (res)
 return res;
 
diff --git a/xen/arch/arm/include/asm/domain.h 
b/xen/arch/arm/include/asm/domain.h
index cb37ce89ec..848fec8a0f 100644
--- a/xen/arch/arm/include/asm/domain.h
+++ b/xen/arch/arm/include/asm/domain.h
@@ -31,6 +31,20 @@ enum domain_type {
 
 #define is_domain_direct_mapped(d) (d->arch.directmap)
 
+/*
+ * Is the domain using the host memory layout?
+ *
+ * Direct-mapped domain will always have the RAM mapped with GFN == MFN.
+ * To avoid any trouble finding space, it is easier to force using the
+ * host memory layout.
+ *
+ * The hardware domain will use the host layout regardless of
+ * direct-mapped because some OS may rely on a specific address ranges
+ * for the devices.
+ */
+#define domain_use_host_layout(d) (is_domain_direct_mapped(d) || \
+   is_hardware_domain(d))
+
 struct vtimer {
 struct vcpu *v;
 int irq;
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index 65bb7991a6..144089a7b6 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -1640,14 +1640,15 @@ static inline unsigned int 
vgic_v3_max_rdist_count(struct domain *d)
  * Normally there is only one GICv3 redistributor region.
  * The GICv3 DT binding provisions for multiple regions, since there are
  * platforms out there which need those (multi-socket systems).
- * For Dom0 we have to live with the MMIO layout the hardware p

[PATCH v6 02/11] xen: introduce CDF_directmap

2022-02-13 Thread Penny Zheng
From: Stefano Stabellini 

This commit introduces a new arm-specific flag CDF_directmap to specify
that a domain should have its memory direct-map(guest physical address
== host physical address) at domain creation.

Also, add a directmap flag under struct arch_domain and use it to
reimplement is_domain_direct_mapped.

For now, direct-map is only available when statically allocated memory is
used for the domain, that is, "xen,static-mem" must be also defined in the
domain configuration.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
Acked-by: Jan Beulich 
Tested-by: Stefano Stabellini 
---
CC: andrew.coop...@citrix.com
CC: jbeul...@suse.com
CC: George Dunlap 
CC: Ian Jackson 
CC: Wei Liu 
CC: "Roger Pau Monné" 
---
v2 changes
- remove the introduce of internal flag
- remove flag direct_map since we already store this flag in d->options
- Refine is_domain_direct_mapped to check whether the flag
XEN_DOMCTL_CDF_directmap is set
- reword "1:1 direct-map" to just "direct-map"
---
v3 changes
- move flag back to xen/include/xen/domain.h, to let it be only available for
domain created by XEN.
- name it with extra "INTERNAL" and add comments to warn developers not
to accidently use its bitfield when introducing new XEN_DOMCTL_CDF_xxx flag.
- reject this flag in x86'es arch_sanitise_domain_config()
---
v4 changes
- introduce new internal flag CDF_directmap
- add a directmap flag under struct arch_domain and use it to
reimplement is_domain_direct_mapped.
- expand arch_domain_create to include internal-only parameter "const unsigned
int flags"
---
v5 changes
- remove const constraint
---
v6 changes
- comment and coding style fix
- protect CDF_directmap with #ifdef CONFIG_ARM
---
 docs/misc/arm/device-tree/booting.txt |  6 ++
 xen/arch/arm/domain.c |  5 -
 xen/arch/arm/domain_build.c   | 14 --
 xen/arch/arm/include/asm/domain.h |  5 +++--
 xen/arch/x86/domain.c |  3 ++-
 xen/common/domain.c   |  2 +-
 xen/include/xen/domain.h  |  7 ++-
 7 files changed, 34 insertions(+), 8 deletions(-)

diff --git a/docs/misc/arm/device-tree/booting.txt 
b/docs/misc/arm/device-tree/booting.txt
index 71895663a4..a94125394e 100644
--- a/docs/misc/arm/device-tree/booting.txt
+++ b/docs/misc/arm/device-tree/booting.txt
@@ -182,6 +182,12 @@ with the following properties:
 Both #address-cells and #size-cells need to be specified because
 both sub-nodes (described shortly) have reg properties.
 
+- direct-map
+
+Only available when statically allocated memory is used for the domain.
+An empty property to request the memory of the domain to be
+direct-map (guest physical address == physical address).
+
 Under the "xen,domain" compatible node, one or more sub-nodes are present
 for the DomU kernel and ramdisk.
 
diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index 92a6c509e5..8110c1df86 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -692,7 +692,8 @@ int arch_sanitise_domain_config(struct 
xen_domctl_createdomain *config)
 }
 
 int arch_domain_create(struct domain *d,
-   struct xen_domctl_createdomain *config)
+   struct xen_domctl_createdomain *config,
+   unsigned int flags)
 {
 int rc, count = 0;
 
@@ -708,6 +709,8 @@ int arch_domain_create(struct domain *d,
 ioreq_domain_init(d);
 #endif
 
+d->arch.directmap = flags & CDF_directmap;
+
 /* p2m_init relies on some value initialized by the IOMMU subsystem */
 if ( (rc = iommu_domain_init(d, config->iommu_opts)) != 0 )
 goto fail;
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 0fab8604de..6467e8ee32 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -3029,10 +3029,20 @@ void __init create_domUs(void)
 .max_maptrack_frames = -1,
 .grant_opts = XEN_DOMCTL_GRANT_version(opt_gnttab_max_version),
 };
+unsigned int flags = 0U;
 
 if ( !dt_device_is_compatible(node, "xen,domain") )
 continue;
 
+if ( dt_property_read_bool(node, "direct-map") )
+{
+if ( !IS_ENABLED(CONFIG_STATIC_MEMORY) || !dt_find_property(node, 
"xen,static-mem", NULL) )
+panic("direct-map is not valid for domain %s without static 
allocation.\n",
+  dt_node_name(node));
+
+flags |= CDF_directmap;
+}
+
 if ( !dt_property_read_u32(node, "cpus", &d_cfg.max_vcpus) )
 panic("Missing property 'cpus' for domain %s\n",
   dt_node_name(node));
@@ -3058,7 +3068,7 @@ void __init create_domUs(void)
  * very important to use the pre-increment operator to call
  * domain_create() with a domi

[PATCH v6 01/11] xen: introduce internal CDF_xxx flags for domain creation

2022-02-13 Thread Penny Zheng
From: Stefano Stabellini 

We are passing an internal-only boolean flag at domain creation to
specify whether we want the domain to be privileged (i.e. dom0) or
not. Another flag will be introduced later in this series.

This commit extends original "boolean" to an "unsigned int" covering both
the existing "is_priv" and our new "directmap", which will be introduced later.

To make visible the relationship, we name the respective constants CDF_xxx
(with no XEN_DOMCTL_ prefix) to represent the difference with the public
constants XEN_DOMCTL_CDF_xxx.

Allocate bit 0 as CDF_privileged: whether a domain is privileged or not.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
Reviewed-by: Jan Beulich 
Reviewed-by: Julien Grall 
Tested-by: Stefano Stabellini 
---
v4 changes:
- new commit
---
v5 changes
- remove const constraint
---
v6 changes
- no changes
---
 xen/arch/arm/domain_build.c |  4 ++--
 xen/arch/x86/setup.c|  2 +-
 xen/common/domain.c | 10 +-
 xen/common/sched/core.c |  2 +-
 xen/include/xen/domain.h|  4 
 xen/include/xen/sched.h |  2 +-
 6 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 6931c022a2..0fab8604de 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -3058,7 +3058,7 @@ void __init create_domUs(void)
  * very important to use the pre-increment operator to call
  * domain_create() with a domid > 0. (domid == 0 is reserved for Dom0)
  */
-d = domain_create(++max_init_domid, &d_cfg, false);
+d = domain_create(++max_init_domid, &d_cfg, 0);
 if ( IS_ERR(d) )
 panic("Error creating domain %s\n", dt_node_name(node));
 
@@ -3160,7 +3160,7 @@ void __init create_dom0(void)
 if ( iommu_enabled )
 dom0_cfg.flags |= XEN_DOMCTL_CDF_iommu;
 
-dom0 = domain_create(0, &dom0_cfg, true);
+dom0 = domain_create(0, &dom0_cfg, CDF_privileged);
 if ( IS_ERR(dom0) || (alloc_dom0_vcpu0(dom0) == NULL) )
 panic("Error creating domain 0\n");
 
diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c
index 115f8f6517..624b53ded4 100644
--- a/xen/arch/x86/setup.c
+++ b/xen/arch/x86/setup.c
@@ -789,7 +789,7 @@ static struct domain *__init create_dom0(const module_t 
*image,
 
 /* Create initial domain.  Not d0 for pvshim. */
 domid = get_initial_domain_id();
-d = domain_create(domid, &dom0_cfg, !pv_shim);
+d = domain_create(domid, &dom0_cfg, pv_shim ? 0 : CDF_privileged);
 if ( IS_ERR(d) )
 panic("Error creating d%u: %ld\n", domid, PTR_ERR(d));
 
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 2048ebad86..a79103e04a 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -552,7 +552,7 @@ static int sanitise_domain_config(struct 
xen_domctl_createdomain *config)
 
 struct domain *domain_create(domid_t domid,
  struct xen_domctl_createdomain *config,
- bool is_priv)
+ unsigned int flags)
 {
 struct domain *d, **pd, *old_hwdom = NULL;
 enum { INIT_watchdog = 1u<<1,
@@ -578,7 +578,7 @@ struct domain *domain_create(domid_t domid,
 }
 
 /* Sort out our idea of is_control_domain(). */
-d->is_privileged = is_priv;
+d->is_privileged = flags & CDF_privileged;
 
 /* Sort out our idea of is_hardware_domain(). */
 if ( domid == 0 || domid == hardware_domid )
@@ -772,7 +772,7 @@ void __init setup_system_domains(void)
  * Hidden PCI devices will also be associated with this domain
  * (but be [partly] controlled by Dom0 nevertheless).
  */
-dom_xen = domain_create(DOMID_XEN, NULL, false);
+dom_xen = domain_create(DOMID_XEN, NULL, 0);
 if ( IS_ERR(dom_xen) )
 panic("Failed to create d[XEN]: %ld\n", PTR_ERR(dom_xen));
 
@@ -782,7 +782,7 @@ void __init setup_system_domains(void)
  * array. Mappings occur at the priv of the caller.
  * Quarantined PCI devices will be associated with this domain.
  */
-dom_io = domain_create(DOMID_IO, NULL, false);
+dom_io = domain_create(DOMID_IO, NULL, 0);
 if ( IS_ERR(dom_io) )
 panic("Failed to create d[IO]: %ld\n", PTR_ERR(dom_io));
 
@@ -791,7 +791,7 @@ void __init setup_system_domains(void)
  * Initialise our COW domain.
  * This domain owns sharable pages.
  */
-dom_cow = domain_create(DOMID_COW, NULL, false);
+dom_cow = domain_create(DOMID_COW, NULL, 0);
 if ( IS_ERR(dom_cow) )
 panic("Failed to create d[COW]: %ld\n", PTR_ERR(dom_cow));
 #endif
diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c
index 8f4b1ca10d..f5c819349b 100644
--- a/xen/common/sched/core.c
+++ b/xen/common/sched/core.c
@@ -3021,7 +3021,7 @@ void __init scheduler_init(void)

[PATCH v6 00/11] direct-map memory map

2022-02-13 Thread Penny Zheng
"direct-map" property shall be added under the appropriate domain node,
when users requesting direct-map memory mapping for the domain.

Right now, direct-map is only supported when domain on Static Allocation,
that is, "xen,static-mem" is also necessary in the domain configuration.

Looking into related [design link](
https://lists.xenproject.org/archives/html/xen-devel/2021-05/msg00882.html)
for more details.

The whole design is about Static Allocation and direct-map, and this
Patch Serie only covers parts of it, which are direct-map memory map.
Other features will be delievered through different patch series.

See https://lists.xenproject.org/archives/html/xen-devel/2021-09/msg00855.html
for Domain on Static Allocation.

This patch serie is based on
https://lists.xenproject.org/archives/html/xen-devel/2021-10/msg00822.html\
---
v6 changes:
- comment, commit message and coding style fix
- protect CDF_directmap with #ifdef CONFIG_ARM
---
v5 changes:
- remove const constraint and strict "static allocation" check
- fix coding style
---
v4 changes:
- introduce internal const CDF_xxx flags for domain creation
- introduce internal flag CDF_privileged
- introduce new internal flag CDF_directmap
- add a directmap flag under struct arch_domain and use it to
reimplement is_domain_direct_mapped.
- expand arch_domain_create/domain_create to include internal-only parameter
"const unsigned int flags"
- use mfn_eq() instead, because it is the only value used to indicate
there is an error and this is more lightweight than mfn_valid()
- rename function allocate_static_memory_11() to assign_static_memory_11()
to make clear there is actually no allocation done. Instead we are only
mapping pre-defined host regions to pre-defined guest regions.
- remove tot_size to directly substract psize from kinfo->unassigned_mem
- check kinfo->unassigned_mem doesn't underflow or overflow
- remove nested if/else
- remove ASSERT_UNREACHABLE() to avoid breaking compilation on prod build with
CONFIG_GICV3=n
- comment and commit message refinement
---
v3 changes:
- move flag XEN_DOMCTL_CDF_INTERNAL_directmap back to xen/include/xen/domain.h,
to let it be only available for domain created by XEN.
- name it with extra "INTERNAL" and add comments to warn developers not
to accidently use its bitfield when introducing new XEN_DOMCTL_CDF_xxx flag.
- reject this flag in x86'es arch_sanitise_domain_config()
- add ASSERT_UNREACHABLE to catch any misuse in allocate_static_memory()
and allocate_static_memory_11()
- add another check of validating flag XEN_DOMCTL_CDF_INTERNAL_directmap only
when CONFIG_STATIC_MEMORY is set.
- simply map the CPU interface at the GPA vgic_v2_hw.cbase
- drop 'cells += (GUEST_ROOT_ADDRESS_CELLS + GUEST_ROOT_SIZE_CELLS)'
- rename 'is_domain_use_host_layout()' to 'domain_use_host_layout()'
---
v2 changes:
- remove the introduce of internal flag
- Refine is_domain_direct_mapped to check whether the flag
XEN_DOMCTL_CDF_directmap is set
- reword "1:1 direct-map" to just "direct-map"
- split the common codes into two helpers: parse_static_mem_prop and
acquire_static_memory_bank to deduce complexity.
- introduce a new helper allocate_static_memory_11 for allocating static
memory for direct-map guests
- remove panic action since it is fine to assign a non-DMA capable device when
IOMMU and direct-map both off
- remove redistributor accessor
- introduce new helper "is_domain_use_host_layout()"
- explain why vpl011 initialization before creating its device tree node
- error out if the domain is direct-mapped and the IRQ is not found
- harden the code and add a check/comment when the hardware UART region
is smaller than CUEST_VPL011_SIZE.
Penny Zheng (4):
  xen/arm: introduce new helper parse_static_mem_prop and
acquire_static_memory_bank
  xen/arm: introduce direct-map for domUs
  xen/arm: add ASSERT_UNREACHABLE in allocate_static_memory
  xen/arm: gate make_gicv3_domU_node with CONFIG_GICV3

Stefano Stabellini (7):
  xen: introduce internal CDF_xxx flags for domain creation
  xen: introduce CDF_directmap
  xen/arm: Allow device-passthrough even the IOMMU is off
  xen/arm: if direct-map domain use native addresses for GICv2
  xen/arm: if direct-map domain use native addresses for GICv3
  xen/arm: if direct-map domain use native UART address and IRQ number
for vPL011
  xen/docs: Document how to do passthrough without IOMMU

 docs/misc/arm/device-tree/booting.txt |   6 +
 docs/misc/arm/passthrough-noiommu.txt |  52 +
 xen/arch/arm/domain.c |   5 +-
 xen/arch/arm/domain_build.c   | 308 +-
 xen/arch/arm/include/asm/domain.h |  19 +-
 xen/arch/arm/include/asm/new_vgic.h   |  10 +
 xen/arch/arm/include/asm/vgic.h   |  11 +
 xen/arch/arm/include/asm/vpl011.h |   2 +
 xen/arch/arm/vgic-v2.c|  34 ++-
 xen/arch/arm/vgic-v3.c 

[PATCH v6 03/11] xen/arm: Allow device-passthrough even the IOMMU is off

2022-02-13 Thread Penny Zheng
From: Stefano Stabellini 

At the moment, we are only supporting device-passthrough when Xen has
enabled the IOMMU. There are some use cases where it is not possible to
use the IOMMU (e.g. doesn't exist, hardware limitation, performance) yet
it would be OK to assign a device to trusted domain so long they are
direct-mapped or the device doesn't do DMA.

Note that when the IOMMU is disabled, it will be necessary to add
xen,force-assign-without-iommu for every device that needs to be assigned.

Signed-off-by: Stefano Stabellini 
Signed-off-by: Penny Zheng 
Tested-by: Stefano Stabellini 
---
v3 changes:
- new commit, split from the original "[PATCH v2 2/6] xen/arm: introduce
direct-map for domUs"
---
v4 changes:
- explain briefly in the commit message why we want to do device assignment
without IOMMU.
---
v5 changes:
- nothing changed
---
v6 changes
- commit message refinement
---
 xen/arch/arm/domain_build.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 6467e8ee32..c1e8c99f64 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -3047,7 +3047,8 @@ void __init create_domUs(void)
 panic("Missing property 'cpus' for domain %s\n",
   dt_node_name(node));
 
-if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") )
+if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") &&
+ iommu_enabled )
 d_cfg.flags |= XEN_DOMCTL_CDF_iommu;
 
 if ( !dt_property_read_u32(node, "nr_spis", &d_cfg.arch.nr_spis) )
-- 
2.25.1




[PATCH v6 04/11] xen/arm: introduce new helper parse_static_mem_prop and acquire_static_memory_bank

2022-02-13 Thread Penny Zheng
Later, we will introduce assign_static_memory_11 for allocating static
memory for direct-map domains, and it will share a lot common codes with
the existing allocate_static_memory.

In order not to bring a lot of duplicate codes, and also to make the whole
code more readable, this commit extracts common codes into two new helpers
parse_static_mem_prop and acquire_static_memory_bank.

Signed-off-by: Penny Zheng 
Reviewed-by: Stefano Stabellini 
Tested-by: Stefano Stabellini 
---
v3 changes:
- new commit, split from the original "[PATCH v2 2/6] xen/arm: introduce
direct-map for domUs"
---
v4 changes
- explain briefly in the commit message why we want to do device assignment
without IOMMU.
---
v5 changes
- fix coding style
---
v6 changes
- no changes
---
 xen/arch/arm/domain_build.c | 100 +++-
 1 file changed, 64 insertions(+), 36 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index c1e8c99f64..e61d2d53ba 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -509,12 +509,69 @@ static bool __init append_static_memory_to_bank(struct 
domain *d,
 return true;
 }
 
+static mfn_t __init acquire_static_memory_bank(struct domain *d,
+   const __be32 **cell,
+   u32 addr_cells, u32 size_cells,
+   paddr_t *pbase, paddr_t *psize)
+{
+mfn_t smfn;
+int res;
+
+device_tree_get_reg(cell, addr_cells, size_cells, pbase, psize);
+ASSERT(IS_ALIGNED(*pbase, PAGE_SIZE) && IS_ALIGNED(*psize, PAGE_SIZE));
+if ( PFN_DOWN(*psize) > UINT_MAX )
+{
+printk(XENLOG_ERR "%pd: static memory size too large: %#"PRIpaddr,
+   d, *psize);
+return INVALID_MFN;
+}
+
+smfn = maddr_to_mfn(*pbase);
+res = acquire_domstatic_pages(d, smfn, PFN_DOWN(*psize), 0);
+if ( res )
+{
+printk(XENLOG_ERR
+   "%pd: failed to acquire static memory: %d.\n", d, res);
+return INVALID_MFN;
+}
+
+return smfn;
+}
+
+static int __init parse_static_mem_prop(const struct dt_device_node *node,
+u32 *addr_cells, u32 *size_cells,
+int *length, const __be32 **cell)
+{
+const struct dt_property *prop;
+
+prop = dt_find_property(node, "xen,static-mem", NULL);
+if ( !dt_property_read_u32(node, "#xen,static-mem-address-cells",
+   addr_cells) )
+{
+printk(XENLOG_ERR
+   "failed to read \"#xen,static-mem-address-cells\".\n");
+return -EINVAL;
+}
+
+if ( !dt_property_read_u32(node, "#xen,static-mem-size-cells",
+   size_cells) )
+{
+printk(XENLOG_ERR
+   "failed to read \"#xen,static-mem-size-cells\".\n");
+return -EINVAL;
+}
+
+*cell = (const __be32 *)prop->value;
+*length = prop->length;
+
+return 0;
+}
+
 /* Allocate memory from static memory as RAM for one specific domain d. */
 static void __init allocate_static_memory(struct domain *d,
   struct kernel_info *kinfo,
   const struct dt_device_node *node)
 {
-const struct dt_property *prop;
 u32 addr_cells, size_cells, reg_cells;
 unsigned int nr_banks, gbank, bank = 0;
 const uint64_t rambase[] = GUEST_RAM_BANK_BASES;
@@ -523,24 +580,10 @@ static void __init allocate_static_memory(struct domain 
*d,
 u64 tot_size = 0;
 paddr_t pbase, psize, gsize;
 mfn_t smfn;
-int res;
-
-prop = dt_find_property(node, "xen,static-mem", NULL);
-if ( !dt_property_read_u32(node, "#xen,static-mem-address-cells",
-   &addr_cells) )
-{
-printk(XENLOG_ERR
-   "%pd: failed to read \"#xen,static-mem-address-cells\".\n", d);
-goto fail;
-}
+int length;
 
-if ( !dt_property_read_u32(node, "#xen,static-mem-size-cells",
-   &size_cells) )
-{
-printk(XENLOG_ERR
-   "%pd: failed to read \"#xen,static-mem-size-cells\".\n", d);
+if ( parse_static_mem_prop(node, &addr_cells, &size_cells, &length, &cell) 
)
 goto fail;
-}
 reg_cells = addr_cells + size_cells;
 
 /*
@@ -551,29 +594,14 @@ static void __init allocate_static_memory(struct domain 
*d,
 gbank = 0;
 gsize = ramsize[gbank];
 kinfo->mem.bank[gbank].start = rambase[gbank];
-
-cell = (const __be32 *)prop->value;
-nr_banks = (prop->length) / (reg_cells * sizeof (u32));
+nr_banks = length / (reg_cells * sizeof (u32));
 
 for ( ;

[PATCH v6 05/11] xen/arm: introduce direct-map for domUs

2022-02-13 Thread Penny Zheng
Cases where domU needs direct-map memory map:
  * IOMMU not present in the system.
  * IOMMU disabled if it doesn't cover a specific device and all the guests
are trusted. Thinking a mixed scenario, where a few devices with IOMMU and
a few without, then guest DMA security still could not be totally guaranteed.
So users may want to disable the IOMMU, to at least gain some performance
improvement from IOMMU disabled.
  * IOMMU disabled as a workaround when it doesn't have enough bandwidth.
To be specific, in a few extreme situation, when multiple devices do DMA
concurrently, these requests may exceed IOMMU's transmission capacity.
  * IOMMU disabled when it adds too much latency on DMA. For example,
TLB may be missing in some IOMMU hardware, which may bring latency in DMA
progress, so users may want to disable it in some realtime scenario.
  * Guest OS relies on the host memory layout

This commit introduces a new helper assign_static_memory_11 to allocate
static memory as guest RAM for direct-map domain.

Signed-off-by: Penny Zheng 
Reviewed-by: Stefano Stabellini 
Tested-by: Stefano Stabellini 
---
v2 changes:
- split the common codes into two helpers: parse_static_mem_prop and
acquire_static_memory_bank to deduce complexity.
- introduce a new helper allocate_static_memory_11 for allocating static
memory for direct-map guests
- remove redundant use "bool direct_map", to be replaced by
d_cfg.flags & XEN_DOMCTL_CDF_directmap
- remove panic action since it is fine to assign a non-DMA capable device when
IOMMU and direct-map both off
---
v3 changes:
- doc refinement
- drop the pointless gbank
- add check of the size of nr_banks shall not exceed NR_MEM_BANKS
- add ASSERT_UNREACHABLE to catch any misuse
- add another check of validating flag XEN_DOMCTL_CDF_INTERNAL_directmap only
when CONFIG_STATIC_MEMORY is set.
---
v4 changes:
- comment refinement
- rename function allocate_static_memory_11() to assign_static_memory_11()
to make clear there is actually no allocation done. Instead we are only
mapping pre-defined host regions to pre-defined guest regions.
- remove tot_size to directly substract psize from kinfo->unassigned_mem
- check kinfo->unassigned_mem doesn't underflow or overflow
- remove nested if/else
- refine "panic" info
---
v5 changes:
- fix coding style
---
v6 changes:
- no changes
---
 xen/arch/arm/domain_build.c | 97 +++--
 1 file changed, 94 insertions(+), 3 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index e61d2d53ba..ec29bd302c 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -494,8 +494,17 @@ static bool __init append_static_memory_to_bank(struct 
domain *d,
 {
 int res;
 unsigned int nr_pages = PFN_DOWN(size);
-/* Infer next GFN. */
-gfn_t sgfn = gaddr_to_gfn(bank->start + bank->size);
+gfn_t sgfn;
+
+/*
+ * For direct-mapped domain, the GFN match the MFN.
+ * Otherwise, this is inferred on what has already been allocated
+ * in the bank.
+ */
+if ( !is_domain_direct_mapped(d) )
+sgfn = gaddr_to_gfn(bank->start + bank->size);
+else
+sgfn = gaddr_to_gfn(mfn_to_maddr(smfn));
 
 res = guest_physmap_add_pages(d, sgfn, smfn, nr_pages);
 if ( res )
@@ -668,12 +677,92 @@ static void __init allocate_static_memory(struct domain 
*d,
  fail:
 panic("Failed to allocate requested static memory for domain %pd.", d);
 }
+
+/*
+ * Allocate static memory as RAM for one specific domain d.
+ * The static memory will be directly mapped in the guest(Guest Physical
+ * Address == Physical Address).
+ */
+static void __init assign_static_memory_11(struct domain *d,
+   struct kernel_info *kinfo,
+   const struct dt_device_node *node)
+{
+u32 addr_cells, size_cells, reg_cells;
+unsigned int nr_banks, bank = 0;
+const __be32 *cell;
+paddr_t pbase, psize;
+mfn_t smfn;
+int length;
+
+if ( parse_static_mem_prop(node, &addr_cells, &size_cells, &length, &cell) 
)
+{
+printk(XENLOG_ERR
+   "%pd: failed to parse \"xen,static-mem\" property.\n", d);
+goto fail;
+}
+reg_cells = addr_cells + size_cells;
+nr_banks = length / (reg_cells * sizeof(u32));
+
+if ( nr_banks > NR_MEM_BANKS )
+{
+printk(XENLOG_ERR
+   "%pd: exceed max number of supported guest memory banks.\n", d);
+goto fail;
+}
+
+for ( ; bank < nr_banks; bank++ )
+{
+smfn = acquire_static_memory_bank(d, &cell, addr_cells, size_cells,
+  &pbase, &psize);
+if ( mfn_eq(smfn, INVALID_MFN) )
+goto fail;
+
+printk(XENLOG_INFO "%pd: STATIC BANK[%u] %#"PRIpaddr"-%#"P

[PATCH v6 06/11] xen/arm: add ASSERT_UNREACHABLE in allocate_static_memory

2022-02-13 Thread Penny Zheng
Helper allocate_static_memory is not meant to be reachable when built with
!CONFIG_STATIC_MEMORY, so this commit adds ASSERT_UNREACHABLE in it to catch
potential misuse.

Signed-off-by: Penny Zheng 
Acked-by: Julien Grall 
Tested-by: Stefano Stabellini 
---
v3 changes:
- new commit
---
v4 changes:
- nothing changed
---
v5 changes:
- nothing changed
---
v6 changes:
- nothing changed
---
 xen/arch/arm/domain_build.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index ec29bd302c..52f256de9c 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -755,6 +755,7 @@ static void __init allocate_static_memory(struct domain *d,
   struct kernel_info *kinfo,
   const struct dt_device_node *node)
 {
+ASSERT_UNREACHABLE();
 }
 
 static void __init assign_static_memory_11(struct domain *d,
-- 
2.25.1




  1   2   3   4   5   6   7   8   9   >