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

Re: [Xen-devel] [PATCH 1 of 2] x86/mm: When mem event automatically promotes access rights, let other subsystems know



Hi, 

At 16:58 -0500 on 29 Nov (1322585904), Andres Lagar-Cavilla wrote:
>  xen/arch/x86/hvm/hvm.c    |  45 ++++++++++++++++++++++++++++++++++++++-------
>  xen/arch/x86/mm/p2m.c     |   8 +++++---
>  xen/include/asm-x86/p2m.h |   9 +++++----
>  3 files changed, 48 insertions(+), 14 deletions(-)
> 
> 
> The mem event fault handler in the p2m can automatically promote the access
> rights of a p2m entry. In those scenarios, vcpu's are not paused and they will
> immediately retry the faulting instructions. This will generate a second fault
> if the underlying entry type requires so (paging, unsharing, pod, etc).
> Collapse the two faults into a single one.
> 
> Signed-off-by: Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx>
> 
> diff -r 29701f5bdd84 -r d6354df726a0 xen/arch/x86/hvm/hvm.c
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -1278,9 +1278,13 @@ int hvm_hap_nested_page_fault(unsigned l
>  
>          if ( violation )
>          {
> -            p2m_mem_access_check(gpa, gla_valid, gla, access_r, access_w, 
> access_x);
> -            rc = 1;
> -            goto out_put_gfn;
> +            if ( !p2m_mem_access_check(gpa, gla_valid, gla, access_r, 
> +                                        access_w, access_x) )
> +            {
> +                /* Rights not promoted, vcpu paused, work here is done */
> +                rc = 1;
> +                goto out_put_gfn;
> +            }
>          }
>      }
>  
> @@ -1288,7 +1292,8 @@ int hvm_hap_nested_page_fault(unsigned l
>       * If this GFN is emulated MMIO or marked as read-only, pass the fault
>       * to the mmio handler.
>       */
> -    if ( (p2mt == p2m_mmio_dm) || (p2mt == p2m_ram_ro) )
> +    if ( (p2mt == p2m_mmio_dm) || 
> +         (access_w && (p2mt == p2m_ram_ro)) )

I think this is a separate change from the main intent of the patch; it
would be better to have two patches, once that inserts all these
'access_w' checks and a second that does what the cset comment
decribes. 

>      {
>          if ( !handle_mmio() )
>              hvm_inject_exception(TRAP_gp_fault, 0, 0);
> @@ -1302,7 +1307,7 @@ int hvm_hap_nested_page_fault(unsigned l
>          p2m_mem_paging_populate(v->domain, gfn);
>  
>      /* Mem sharing: unshare the page and try again */
> -    if ( p2mt == p2m_ram_shared )
> +    if ( access_w && (p2mt == p2m_ram_shared) )
>      {
>          ASSERT(!p2m_is_nestedp2m(p2m));
>          mem_sharing_unshare_page(p2m->domain, gfn, 0);
> @@ -1319,14 +1324,15 @@ int hvm_hap_nested_page_fault(unsigned l
>           * a large page, we do not change other pages type within that large
>           * page.
>           */
> -        paging_mark_dirty(v->domain, mfn_x(mfn));
> +        if ( access_w )
> +            paging_mark_dirty(v->domain, mfn_x(mfn));
>          p2m_change_type(v->domain, gfn, p2m_ram_logdirty, p2m_ram_rw);

No!  If we call p2m_change_type(-->ram_rw) we _must_ call mark_dirty()
too.  It would be OK to put both lines under the test, though. 

>          rc = 1;
>          goto out_put_gfn;
>      }
>  
>      /* Shouldn't happen: Maybe the guest was writing to a r/o grant mapping? 
> */
> -    if ( p2mt == p2m_grant_map_ro )
> +    if ( access_w && (p2mt == p2m_grant_map_ro) )
>      {
>          gdprintk(XENLOG_WARNING,
>                   "trying to write to read-only grant mapping\n");
> @@ -1335,6 +1341,31 @@ int hvm_hap_nested_page_fault(unsigned l
>          goto out_put_gfn;
>      }
>  
> +    if ( access_x && (p2m_is_grant(p2mt)) )
> +    {
> +        gdprintk(XENLOG_WARNING,
> +                 "trying to execut a grant mapping\n");
> +        hvm_inject_exception(TRAP_gp_fault, 0, 0);
> +        rc = 1;
> +        goto out_put_gfn;
> +    }

Again, this is a separate bugfix and should go in its own patch.

> +    if ( p2m_is_grant(p2mt) )
> +    {
> +        /* If we haven't caught this by now, then it's a valid access */
> +        rc = 1;
> +        goto out_put_gfn;
> +    }
> +    if ( p2mt == p2m_mmio_direct )
> +    {
> +        if ( !(access_w && 
> +                rangeset_contains_singleton(mmio_ro_ranges, mfn_x(mfn))) ) {
> +            rc = 1;
> +            goto out_put_gfn;
> +        }
> +    }

I wonder whether, rather than trying to enumerate all the acceptable
cases here, you could just remember that p2m_mem_access_check() changed
something and always return 1 in that case. 

> +
>      rc = 0;
>  out_put_gfn:
>      put_gfn(p2m->domain, gfn);
> diff -r 29701f5bdd84 -r d6354df726a0 xen/arch/x86/mm/p2m.c
> --- a/xen/arch/x86/mm/p2m.c
> +++ b/xen/arch/x86/mm/p2m.c
> @@ -1126,7 +1126,7 @@ void p2m_mem_paging_resume(struct domain
>      mem_event_unpause_vcpus(d, &d->mem_paging);
>  }
>  
> -void p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsigned long 
> gla, 
> +int p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsigned long 
> gla, 
>                            bool_t access_r, bool_t access_w, bool_t access_x)
>  {
>      struct vcpu *v = current;
> @@ -1146,7 +1146,7 @@ void p2m_mem_access_check(unsigned long 
>      {
>          p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K, p2mt, p2m_access_rw);
>          p2m_unlock(p2m);
> -        return;
> +        return 1;
>      }
>      p2m_unlock(p2m);
>  
> @@ -1166,9 +1166,10 @@ void p2m_mem_access_check(unsigned long 
>              p2m_lock(p2m);
>              p2m->set_entry(p2m, gfn, mfn, PAGE_ORDER_4K, p2mt, 
> p2m_access_rwx);
>              p2m_unlock(p2m);
> +            return 1;
>          }
>  
> -        return;
> +        return 0;
>      }
>  
>      memset(&req, 0, sizeof(req));
> @@ -1192,6 +1193,7 @@ void p2m_mem_access_check(unsigned long 
>  
>      (void)mem_event_put_request(d, &d->mem_access, &req);
>      /* VCPU paused */
> +    return 0;
>  }
>  
>  void p2m_mem_access_resume(struct domain *d)
> diff -r 29701f5bdd84 -r d6354df726a0 xen/include/asm-x86/p2m.h
> --- a/xen/include/asm-x86/p2m.h
> +++ b/xen/include/asm-x86/p2m.h
> @@ -491,8 +491,9 @@ static inline void p2m_mem_paging_popula
>  
>  #ifdef __x86_64__
>  /* Send mem event based on the access (gla is -1ull if not available).  
> Handles
> - * the rw2rx conversion */
> -void p2m_mem_access_check(unsigned long gpa, bool_t gla_valid, unsigned long 
> gla, 
> + * the rw2rx conversion. Return value indicate if access rights have been
> + * promoted with no underlying vcpu pause. */

How does it indicate that -- i.e., what values can it return and what do
they mean?  (And if it only returns 0 or 1, maybe use bool_t.)

Cheers,

Tim.

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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