[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [RFC 02/22] xen/arm: p2m: Store in p2m_domain whether we need to clean the entry



On Thu, 28 Jul 2016, Julien Grall wrote:
> Each entry in the page table has to table clean when the IOMMU does not

What does it mean to "table clean" ?


> support coherent walk. Rather than querying every time the page table is
> updated, it is possible to do it only once when the p2m is initialized.
> 
> This is because this value can never change, Xen would be in big trouble
> otherwise.
> 
> With this change, the initialize of the IOMMU for a given domain has to

"the initialization"


> be done earlier in order to know whether the page table entries need to
> be clean. It is fine to move the call earlier because it has no

"be cleaned"


Aside from the small imperfections in the commit message:

Reviewed-by: Stefano Stabellini <sstabellini@xxxxxxxxxx>


> dependency.
> 
> Signed-off-by: Julien Grall <julien.grall@xxxxxxx>
> ---
>  xen/arch/arm/domain.c     |  8 +++++---
>  xen/arch/arm/p2m.c        | 47 
> ++++++++++++++++++++++-------------------------
>  xen/include/asm-arm/p2m.h |  3 +++
>  3 files changed, 30 insertions(+), 28 deletions(-)
> 
> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> index 20bb2ba..48f04c8 100644
> --- a/xen/arch/arm/domain.c
> +++ b/xen/arch/arm/domain.c
> @@ -555,6 +555,11 @@ int arch_domain_create(struct domain *d, unsigned int 
> domcr_flags,
>          return 0;
>  
>      ASSERT(config != NULL);
> +
> +    /* p2m_init relies on some value initialized by the IOMMU subsystem */
> +    if ( (rc = iommu_domain_init(d)) != 0 )
> +        goto fail;
> +
>      if ( (rc = p2m_init(d)) != 0 )
>          goto fail;
>  
> @@ -637,9 +642,6 @@ int arch_domain_create(struct domain *d, unsigned int 
> domcr_flags,
>      if ( is_hardware_domain(d) && (rc = domain_vuart_init(d)) )
>          goto fail;
>  
> -    if ( (rc = iommu_domain_init(d)) != 0 )
> -        goto fail;
> -
>      return 0;
>  
>  fail:
> diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
> index 40a0b80..d389f2b 100644
> --- a/xen/arch/arm/p2m.c
> +++ b/xen/arch/arm/p2m.c
> @@ -416,7 +416,7 @@ static inline void p2m_remove_pte(lpae_t *p, bool_t 
> flush_cache)
>   * level_shift is the number of bits at the level we want to create.
>   */
>  static int p2m_create_table(struct p2m_domain *p2m, lpae_t *entry,
> -                            int level_shift, bool_t flush_cache)
> +                            int level_shift)
>  {
>      struct page_info *page;
>      lpae_t *p;
> @@ -462,7 +462,7 @@ static int p2m_create_table(struct p2m_domain *p2m, 
> lpae_t *entry,
>      else
>          clear_page(p);
>  
> -    if ( flush_cache )
> +    if ( p2m->clean_pte )
>          clean_dcache_va_range(p, PAGE_SIZE);
>  
>      unmap_domain_page(p);
> @@ -470,7 +470,7 @@ static int p2m_create_table(struct p2m_domain *p2m, 
> lpae_t *entry,
>      pte = mfn_to_p2m_entry(_mfn(page_to_mfn(page)), p2m_invalid,
>                             p2m->default_access);
>  
> -    p2m_write_pte(entry, pte, flush_cache);
> +    p2m_write_pte(entry, pte, p2m->clean_pte);
>  
>      return 0;
>  }
> @@ -653,12 +653,10 @@ static const paddr_t level_shifts[] =
>  
>  static int p2m_shatter_page(struct p2m_domain *p2m,
>                              lpae_t *entry,
> -                            unsigned int level,
> -                            bool_t flush_cache)
> +                            unsigned int level)
>  {
>      const paddr_t level_shift = level_shifts[level];
> -    int rc = p2m_create_table(p2m, entry,
> -                              level_shift - PAGE_SHIFT, flush_cache);
> +    int rc = p2m_create_table(p2m, entry, level_shift - PAGE_SHIFT);
>  
>      if ( !rc )
>      {
> @@ -680,7 +678,6 @@ static int p2m_shatter_page(struct p2m_domain *p2m,
>  static int apply_one_level(struct domain *d,
>                             lpae_t *entry,
>                             unsigned int level,
> -                           bool_t flush_cache,
>                             enum p2m_operation op,
>                             paddr_t start_gpaddr,
>                             paddr_t end_gpaddr,
> @@ -719,7 +716,7 @@ static int apply_one_level(struct domain *d,
>              if ( level < 3 )
>                  pte.p2m.table = 0; /* Superpage entry */
>  
> -            p2m_write_pte(entry, pte, flush_cache);
> +            p2m_write_pte(entry, pte, p2m->clean_pte);
>  
>              *flush |= p2m_valid(orig_pte);
>  
> @@ -754,7 +751,7 @@ static int apply_one_level(struct domain *d,
>              /* Not present -> create table entry and descend */
>              if ( !p2m_valid(orig_pte) )
>              {
> -                rc = p2m_create_table(p2m, entry, 0, flush_cache);
> +                rc = p2m_create_table(p2m, entry, 0);
>                  if ( rc < 0 )
>                      return rc;
>                  return P2M_ONE_DESCEND;
> @@ -764,7 +761,7 @@ static int apply_one_level(struct domain *d,
>              if ( p2m_mapping(orig_pte) )
>              {
>                  *flush = true;
> -                rc = p2m_shatter_page(p2m, entry, level, flush_cache);
> +                rc = p2m_shatter_page(p2m, entry, level);
>                  if ( rc < 0 )
>                      return rc;
>              } /* else: an existing table mapping -> descend */
> @@ -801,7 +798,7 @@ static int apply_one_level(struct domain *d,
>                   * and descend.
>                   */
>                  *flush = true;
> -                rc = p2m_shatter_page(p2m, entry, level, flush_cache);
> +                rc = p2m_shatter_page(p2m, entry, level);
>                  if ( rc < 0 )
>                      return rc;
>  
> @@ -827,7 +824,7 @@ static int apply_one_level(struct domain *d,
>  
>          *flush = true;
>  
> -        p2m_remove_pte(entry, flush_cache);
> +        p2m_remove_pte(entry, p2m->clean_pte);
>          p2m_mem_access_radix_set(p2m, paddr_to_pfn(*addr), p2m_access_rwx);
>  
>          *addr += level_size;
> @@ -886,7 +883,7 @@ static int apply_one_level(struct domain *d,
>              /* Shatter large pages as we descend */
>              if ( p2m_mapping(orig_pte) )
>              {
> -                rc = p2m_shatter_page(p2m, entry, level, flush_cache);
> +                rc = p2m_shatter_page(p2m, entry, level);
>                  if ( rc < 0 )
>                      return rc;
>              } /* else: an existing table mapping -> descend */
> @@ -904,7 +901,7 @@ static int apply_one_level(struct domain *d,
>                      return rc;
>  
>                  p2m_set_permission(&pte, pte.p2m.type, a);
> -                p2m_write_pte(entry, pte, flush_cache);
> +                p2m_write_pte(entry, pte, p2m->clean_pte);
>              }
>  
>              *addr += level_size;
> @@ -954,17 +951,9 @@ static int apply_p2m_changes(struct domain *d,
>      const unsigned int preempt_count_limit = (op == MEMACCESS) ? 1 : 0x2000;
>      const bool_t preempt = !is_idle_vcpu(current);
>      bool_t flush = false;
> -    bool_t flush_pt;
>      PAGE_LIST_HEAD(free_pages);
>      struct page_info *pg;
>  
> -    /*
> -     * Some IOMMU don't support coherent PT walk. When the p2m is
> -     * shared with the CPU, Xen has to make sure that the PT changes have
> -     * reached the memory
> -     */
> -    flush_pt = iommu_enabled && !iommu_has_feature(d, 
> IOMMU_FEAT_COHERENT_WALK);
> -
>      p2m_write_lock(p2m);
>  
>      /* Static mapping. P2M_ROOT_PAGES > 1 are handled below */
> @@ -1070,7 +1059,7 @@ static int apply_p2m_changes(struct domain *d,
>              lpae_t old_entry = *entry;
>  
>              ret = apply_one_level(d, entry,
> -                                  level, flush_pt, op,
> +                                  level, op,
>                                    start_gpaddr, end_gpaddr,
>                                    &addr, &maddr, &flush,
>                                    t, a);
> @@ -1127,7 +1116,7 @@ static int apply_p2m_changes(struct domain *d,
>  
>                  page_list_del(pg, &p2m->pages);
>  
> -                p2m_remove_pte(entry, flush_pt);
> +                p2m_remove_pte(entry, p2m->clean_pte);
>  
>                  p2m->stats.mappings[level - 1]--;
>                  update_reference_mapping(pages[level - 1], old_entry, 
> *entry);
> @@ -1399,6 +1388,14 @@ int p2m_init(struct domain *d)
>      p2m->mem_access_enabled = false;
>      radix_tree_init(&p2m->mem_access_settings);
>  
> +    /*
> +     * Some IOMMUs don't support coherent PT walk. When the p2m is
> +     * shared with the CPU, Xen has to make sure that the PT changes have
> +     * reached the memory
> +     */
> +    p2m->clean_pte = iommu_enabled &&
> +        !iommu_has_feature(d, IOMMU_FEAT_COHERENT_WALK);
> +
>      rc = p2m_alloc_table(d);
>  
>      return rc;
> diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
> index 53c4d78..03bfd5e 100644
> --- a/xen/include/asm-arm/p2m.h
> +++ b/xen/include/asm-arm/p2m.h
> @@ -48,6 +48,9 @@ struct p2m_domain {
>       * decrease. */
>      gfn_t lowest_mapped_gfn;
>  
> +    /* Indicate if it is required to clean the cache when writing an entry */
> +    bool_t clean_pte;
> +
>      /* Gather some statistics for information purposes only */
>      struct {
>          /* Number of mappings at each p2m tree level */
> -- 
> 1.9.1
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.