* Adds an ACCESS memory event type, with RESUME as the action.
  * Refactors the bits in the memory event to store whether the memory event   was a read, write, or execute (for access memory events only).  I used  
  bits sparingly to keep the structure somewhat the same size.
  * Modified VMX to report the needed information in its nested page fault.   SVM is not implemented in this patch series.
  Signed-off-by: Joe Epstein <jepstein98@xxxxxxxxx>   
  diff -r cae1ccf5857b -r 253cc5185fb5 tools/xenpaging/xenpaging.c --- a/tools/xenpaging/xenpaging.c    Wed Jan 05 18:44:56 2011 -0800 +++ b/tools/xenpaging/xenpaging.c    Wed Jan 05 18:49:34 2011 -0800 @@ -658,7 +658,7 @@ int main(int argc, char *argv[]) 
             {                  DPRINTF("page already populated (domain = %d; vcpu = %d;"                          " p2mt = %x;" -                        " gfn = %"PRIx64"; paused = %"PRId64")\n", 
+                        " gfn = %"PRIx64"; paused = %d)\n",                          paging->mem_event.domain_id, req.vcpu_id,                          req.p2mt,                          req.gfn, req.flags & MEM_EVENT_FLAG_VCPU_PAUSED); 
diff -r cae1ccf5857b -r 253cc5185fb5 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c    Wed Jan 05 18:44:56 2011 -0800 +++ b/xen/arch/x86/hvm/hvm.c    Wed Jan 05 18:49:34 2011 -0800 @@ -61,6 +61,8 @@  #include <public/hvm/ioreq.h> 
 #include <public/version.h>  #include <public/memory.h> +#include <asm/mem_event.h> +#include <public/mem_event.h>    bool_t __read_mostly hvm_enabled;   @@ -1086,14 +1088,66 @@ void hvm_triple_fault(void) 
     domain_shutdown(v->domain, SHUTDOWN_reboot);  }   -bool_t hvm_hap_nested_page_fault(unsigned long gfn) +bool_t hvm_hap_nested_page_fault(unsigned long gpa, +                                 bool_t gla_valid, 
+                                 unsigned long gla, +                                 bool_t access_valid, +                                 bool_t access_r, +                                 bool_t access_w, 
+                                 bool_t access_x)  { +    unsigned long gfn = gpa >> PAGE_SHIFT;      p2m_type_t p2mt; +    p2m_access_t p2ma;      mfn_t mfn;      struct vcpu *v = current;      struct p2m_domain *p2m = p2m_get_hostp2m(v->domain); 
  -    mfn = gfn_to_mfn_guest(p2m, gfn, &p2mt); +    p2m_lock(p2m); +    mfn = p2m->get_entry(p2m, gfn, &p2mt, &p2ma, p2m_guest); +    p2m_unlock(p2m); + +    /* Check access permissions first, then handle faults */ 
+    if ( access_valid && (mfn_x(mfn) != INVALID_MFN) ) +    { +        int violation = 0; +        /* If the access is against the permissions, then send to mem_event */ +        switch (p2ma)  +        { 
+        case p2m_access_n: +        default: +            violation = access_r || access_w || access_x; +            break; +        case p2m_access_r: +            violation = access_w || access_x; +            break; 
+        case p2m_access_w: +            violation = access_r || access_x; +            break; +        case p2m_access_x: +            violation = access_r || access_w; +            break; +        case p2m_access_rx: 
+        case p2m_access_rx2rw: +            violation = access_w; +            break; +        case p2m_access_wx: +            violation = access_r; +            break; +        case p2m_access_rw: 
+            violation = access_x; +            break; +        case p2m_access_rwx: +            break; +        } + +        if ( violation ) +        { +            p2m_mem_access_check(gpa, gla_valid, gla, access_r, access_w, access_x); 
+ +            return 1; +        } +    }        /*       * If this GFN is emulated MMIO or marked as read-only, pass the fault diff -r cae1ccf5857b -r 253cc5185fb5 xen/arch/x86/hvm/svm/svm.c --- a/xen/arch/x86/hvm/svm/svm.c    Wed Jan 05 18:44:56 2011 -0800 
+++ b/xen/arch/x86/hvm/svm/svm.c    Wed Jan 05 18:49:34 2011 -0800 @@ -979,7 +979,7 @@ static void svm_do_nested_pgfault(paddr_          __trace_var(TRC_HVM_NPF, 0, sizeof(_d), &_d);      }   -    if ( hvm_hap_nested_page_fault(gfn) ) 
+    if ( hvm_hap_nested_page_fault(gpa, 0, ~0ull, 0, 0, 0, 0) )          return;        /* Everything else is an error. */ diff -r cae1ccf5857b -r 253cc5185fb5 xen/arch/x86/hvm/vmx/vmx.c --- a/xen/arch/x86/hvm/vmx/vmx.c    Wed Jan 05 18:44:56 2011 -0800 
+++ b/xen/arch/x86/hvm/vmx/vmx.c    Wed Jan 05 18:49:34 2011 -0800 @@ -2079,7 +2079,14 @@ static void ept_handle_violation(unsigne          __trace_var(TRC_HVM_NPF, 0, sizeof(_d), &_d);      }   -    if ( hvm_hap_nested_page_fault(gfn) ) 
+    if ( hvm_hap_nested_page_fault(gpa, +                                   qualification & EPT_GLA_VALID       ? 1 : 0, +                                   qualification & EPT_GLA_VALID +                                     ? __vmread(GUEST_LINEAR_ADDRESS) : ~0ull, 
+                                   1, /* access types are as follows */ +                                   qualification & EPT_READ_VIOLATION  ? 1 : 0, +                                   qualification & EPT_WRITE_VIOLATION ? 1 : 0, 
+                                   qualification & EPT_EXEC_VIOLATION  ? 1 : 0) )          return;        /* Everything else is an error. */ diff -r cae1ccf5857b -r 253cc5185fb5 xen/arch/x86/mm/Makefile 
--- a/xen/arch/x86/mm/Makefile    Wed Jan 05 18:44:56 2011 -0800 +++ b/xen/arch/x86/mm/Makefile    Wed Jan 05 18:49:34 2011 -0800 @@ -9,6 +9,7 @@ obj-$(x86_64) += guest_walk_4.o  obj-$(x86_64) += mem_event.o 
 obj-$(x86_64) += mem_paging.o 
 obj-$(x86_64) += mem_sharing.o +obj-$(x86_64) += mem_access.o    guest_walk_%.o: guest_walk.c Makefile      $(CC) $(CFLAGS) -DGUEST_PAGING_LEVELS=$* -c $< -o $@ diff -r cae1ccf5857b -r 253cc5185fb5 xen/arch/x86/mm/mem_access.c 
--- /dev/null    Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/x86/mm/mem_access.c    Wed Jan 05 18:49:34 2011 -0800 @@ -0,0 +1,59 @@ +/****************************************************************************** 
+ * arch/x86/mm/mem_access.c + * + * Memory access support. + * + * Copyright (c) 2011 Virtuata, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by 
+ * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of 
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + + +#include <asm/p2m.h> +#include <asm/mem_event.h> + + +int mem_access_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec, 
+                      XEN_GUEST_HANDLE(void) u_domctl) +{ +    int rc; +    struct p2m_domain *p2m = p2m_get_hostp2m(d); + +    switch( mec->op ) +    { +    case XEN_DOMCTL_MEM_EVENT_OP_ACCESS_RESUME: 
+    { +        p2m_mem_access_resume(p2m); +        rc = 0; +    } +    break; + +    default: +        rc = -ENOSYS; +        break; +    } + +    return rc; +} + + +/* + * Local variables: 
+ * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff -r cae1ccf5857b -r 253cc5185fb5 xen/arch/x86/mm/mem_event.c --- a/xen/arch/x86/mm/mem_event.c    Wed Jan 05 18:44:56 2011 -0800 
+++ b/xen/arch/x86/mm/mem_event.c    Wed Jan 05 18:49:34 2011 -0800 @@ -26,6 +26,7 @@  #include <asm/p2m.h>  #include <asm/mem_event.h>  #include <asm/mem_paging.h> +#include <asm/mem_access.h> 
   /* for public/io/ring.h macros */  #define xen_mb()   mb() @@ -67,6 +68,9 @@ static int mem_event_enable(struct domai        mem_event_ring_lock_init(d);   +    /* Wake any VCPUs paused for memory events */ 
+    mem_event_unpause_vcpus(d); +      return 0;     err_shared: @@ -143,12 +147,21 @@ void mem_event_unpause_vcpus(struct doma              vcpu_wake(v);  }   +void mem_event_mark_and_pause(struct vcpu *v) 
+{ +    set_bit(_VPF_mem_event, &v->pause_flags); +    vcpu_sleep_nosync(v); +} +  int mem_event_check_ring(struct domain *d)  {      struct vcpu *curr = current;      int free_requests; 
     int ring_full;   +    if ( !d->mem_event.ring_page ) +        return -1; +      mem_event_ring_lock(d);        free_requests = RING_FREE_REQUESTS(&d->mem_event.front_ring); @@ -157,7 +170,7 @@ int mem_event_check_ring(struct domain * 
         gdprintk(XENLOG_INFO, "free request slots: %d\n", free_requests);          WARN_ON(free_requests == 0);      } -    ring_full = free_requests < MEM_EVENT_RING_THRESHOLD; +    ring_full = free_requests < MEM_EVENT_RING_THRESHOLD ? 1 : 0; 
       if ( (curr->domain->domain_id == d->domain_id) && ring_full )      { @@ -203,7 +216,11 @@ int mem_event_domctl(struct domain *d, x          return rc;  #endif   -    if ( mec->mode == 0 ) 
+    rc = -ENOSYS; + +    switch ( mec-> mode )  +    { +    case 0:      {          switch( mec->op )          { @@ -268,13 +285,18 @@ int mem_event_domctl(struct domain *d, x              rc = -ENOSYS; 
             break;          } +        break;      } -    else +    case XEN_DOMCTL_MEM_EVENT_OP_PAGING:      { -        rc = -ENOSYS; - -        if ( mec->mode & XEN_DOMCTL_MEM_EVENT_OP_PAGING ) 
-            rc = mem_paging_domctl(d, mec, u_domctl); +        rc = mem_paging_domctl(d, mec, u_domctl); +        break; +    } +    case XEN_DOMCTL_MEM_EVENT_OP_ACCESS:  +    { +        rc = mem_access_domctl(d, mec, u_domctl); 
+        break; +    }      }        return rc; diff -r cae1ccf5857b -r 253cc5185fb5 xen/arch/x86/mm/p2m.c --- a/xen/arch/x86/mm/p2m.c    Wed Jan 05 18:44:56 2011 -0800 +++ b/xen/arch/x86/mm/p2m.c    Wed Jan 05 18:49:34 2011 -0800 
@@ -2858,6 +2858,97 @@ void p2m_mem_paging_resume(struct p2m_do  }  #endif /* __x86_64__ */   +void 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; +    mem_event_request_t req; +    unsigned long gfn = gpa >> PAGE_SHIFT; +    struct domain *d = v->domain;     +    struct p2m_domain* p2m = p2m_get_hostp2m(d); 
+    int res; +    mfn_t mfn; +    p2m_type_t p2mt; +    p2m_access_t p2ma; +     +    /* First, handle rx2rw conversion automatically */ +    p2m_lock(p2m); +    mfn = p2m->get_entry(p2m, gfn, &p2mt, &p2ma, p2m_query); 
+ +    if ( access_w && p2ma == p2m_access_rx2rw )  +    { +        p2m->set_entry(p2m, gfn, mfn, 0, p2mt, p2m_access_rw); +        p2m_unlock(p2m); +        return; +    } +    p2m_unlock(p2m); 
+ +    /* Otherwise, check if there is a memory event listener, and send the message along */ +    res = mem_event_check_ring(d); +    if ( res < 0 )  +    { +        /* No listener */ +        if ( p2m->access_required )  
+        { +            printk(XENLOG_INFO  +                   "Memory access permissions failure, no mem_event listener: pausing VCPU %d, dom %d\n", +                   v->vcpu_id, d->domain_id); 
+ +            mem_event_mark_and_pause(v); +        } +        else +        { +            /* A listener is not required, so clear the access restrictions */ +            p2m_lock(p2m); +            p2m->set_entry(p2m, gfn, mfn, 0, p2mt, p2m_access_rwx); 
+            p2m_unlock(p2m); +        } + +        return; +    } +    else if ( res > 0 ) +        return;  /* No space in buffer; VCPU paused */ + +    memset(&req, 0, sizeof(req)); +    req.type = MEM_EVENT_TYPE_ACCESS; 
+    req.reason = MEM_EVENT_REASON_VIOLATION; + +    /* Pause the current VCPU unconditionally */ +    vcpu_pause_nosync(v); +    req.flags |= MEM_EVENT_FLAG_VCPU_PAUSED;     + +    /* Send request to mem event */ 
+    req.gfn = gfn; +    req.offset = gpa & ((1 << PAGE_SHIFT) - 1); +    req.gla_valid = gla_valid; +    req.gla = gla; +    req.access_r = access_r; +    req.access_w = access_w; +    req.access_x = access_x; 
+     +    req.vcpu_id = v->vcpu_id; + +    mem_event_put_request(d, &req);    + +    /* VCPU paused, mem event request sent */ +} + +void p2m_mem_access_resume(struct p2m_domain *p2m) +{ 
+    struct domain *d = p2m->domain; +    mem_event_response_t rsp; + +    mem_event_get_response(d, &rsp); + +    /* Unpause domain */ +    if ( rsp.flags & MEM_EVENT_FLAG_VCPU_PAUSED ) +        vcpu_unpause(d->vcpu[rsp.vcpu_id]); 
+ +    /* Unpause any domains that were paused because the ring was full or no listener  +     * was available */ +    mem_event_unpause_vcpus(d); +} +  /*   * Local variables:   * mode: C diff -r cae1ccf5857b -r 253cc5185fb5 xen/include/asm-x86/hvm/hvm.h 
--- a/xen/include/asm-x86/hvm/hvm.h    Wed Jan 05 18:44:56 2011 -0800 +++ b/xen/include/asm-x86/hvm/hvm.h    Wed Jan 05 18:49:34 2011 -0800 @@ -356,7 +356,12 @@ static inline void hvm_set_info_guest(st    int hvm_debug_op(struct vcpu *v, int32_t op); 
  -bool_t hvm_hap_nested_page_fault(unsigned long gfn); +bool_t hvm_hap_nested_page_fault(unsigned long gpa, +                                 bool_t gla_valid, unsigned long gla, +                                 bool_t access_valid,  
+                                 bool_t access_r, +                                 bool_t access_w, +                                 bool_t access_x);    #define hvm_msr_tsc_aux(v) ({                                               \ 
     struct domain *__d = (v)->domain;                                       \ diff -r cae1ccf5857b -r 253cc5185fb5 xen/include/asm-x86/mem_access.h --- /dev/null    Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/include/asm-x86/mem_access.h    Wed Jan 05 18:49:34 2011 -0800 
@@ -0,0 +1,35 @@ +/****************************************************************************** + * include/asm-x86/mem_paging.h + * + * Memory access support. + * + * Copyright (c) 2011 Virtuata, Inc. 
+ * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+ */ + + +int mem_access_domctl(struct domain *d, xen_domctl_mem_event_op_t *mec, +                      XEN_GUEST_HANDLE(void) u_domctl); + + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" 
+ * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff -r cae1ccf5857b -r 253cc5185fb5 xen/include/asm-x86/mem_event.h --- a/xen/include/asm-x86/mem_event.h    Wed Jan 05 18:44:56 2011 -0800 
+++ b/xen/include/asm-x86/mem_event.h    Wed Jan 05 18:49:34 2011 -0800 @@ -24,6 +24,8 @@  #ifndef __MEM_EVENT_H__  #define __MEM_EVENT_H__   +/* Pauses VCPU while marking pause flag for mem event */ +void mem_event_mark_and_pause(struct vcpu *v); 
 int mem_event_check_ring(struct domain *d);  void mem_event_put_request(struct domain *d, mem_event_request_t *req);  void mem_event_get_response(struct domain *d, mem_event_response_t *rsp); diff -r cae1ccf5857b -r 253cc5185fb5 xen/include/asm-x86/p2m.h 
--- a/xen/include/asm-x86/p2m.h    Wed Jan 05 18:44:56 2011 -0800 +++ b/xen/include/asm-x86/p2m.h    Wed Jan 05 18:49:34 2011 -0800 @@ -522,6 +522,13 @@ static inline void p2m_mem_paging_popula  { }  #endif 
  +/* 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,  +                          bool_t access_r, bool_t access_w, bool_t access_x); 
+/* Resumes the running of the VCPU, restarting the last instruction */ +void p2m_mem_access_resume(struct p2m_domain *p2m); +  struct page_info *p2m_alloc_ptp(struct p2m_domain *p2m, unsigned long type);   
 #endif /* _XEN_P2M_H */ diff -r cae1ccf5857b -r 253cc5185fb5 xen/include/public/domctl.h --- a/xen/include/public/domctl.h    Wed Jan 05 18:44:56 2011 -0800 +++ b/xen/include/public/domctl.h    Wed Jan 05 18:49:34 2011 -0800 
@@ -714,7 +714,7 @@ struct xen_domctl_gdbsx_domstatus {  /*   * Page memory in and out.    */ -#define XEN_DOMCTL_MEM_EVENT_OP_PAGING (1 << 0) +#define XEN_DOMCTL_MEM_EVENT_OP_PAGING            1 
  
 /* Domain memory paging */  #define XEN_DOMCTL_MEM_EVENT_OP_PAGING_NOMINATE   0 @@ -722,6 +722,19 @@ struct xen_domctl_gdbsx_domstatus {  #define XEN_DOMCTL_MEM_EVENT_OP_PAGING_PREP       2  #define XEN_DOMCTL_MEM_EVENT_OP_PAGING_RESUME     3 
  +/* + * Access permissions. + * + * There are HVM hypercalls to set the per-page access permissions of every + * page in a domain.  When one of these permissions--independent, read,  + * write, and execute--is violated, the VCPU is paused and a memory event  
+ * is sent with what happened.  (See public/mem_event.h)  The memory event  + * handler can then resume the VCPU and redo the access with an  + * ACCESS_RESUME mode for the following domctl. + */ +#define XEN_DOMCTL_MEM_EVENT_OP_ACCESS            2 
+#define XEN_DOMCTL_MEM_EVENT_OP_ACCESS_RESUME     0  +  struct xen_domctl_mem_event_op {      uint32_t       op;           /* XEN_DOMCTL_MEM_EVENT_OP_* */      uint32_t       mode;         /* XEN_DOMCTL_MEM_EVENT_ENABLE_* */ 
diff -r cae1ccf5857b -r 253cc5185fb5 xen/include/public/mem_event.h --- a/xen/include/public/mem_event.h    Wed Jan 05 18:44:56 2011 -0800 +++ b/xen/include/public/mem_event.h    Wed Jan 05 18:49:34 2011 -0800 @@ -26,18 +26,40 @@ 
 #include "xen.h"  #include "io/ring.h"   +/* Memory event type */ +#define MEM_EVENT_TYPE_SHARED   0 +#define MEM_EVENT_TYPE_PAGING   1 +#define MEM_EVENT_TYPE_ACCESS   2 +  /* Memory event flags */ 
 #define MEM_EVENT_FLAG_VCPU_PAUSED  (1 << 0)   +/* Reasons for the memory event request */ +#define MEM_EVENT_REASON_UNKNOWN     0    /* typical reason */ +#define MEM_EVENT_REASON_VIOLATION   1    /* access violation, GFN is address */ 
+  typedef struct mem_event_shared_page {      uint32_t port;  } mem_event_shared_page_t;    typedef struct mem_event_st { +    uint16_t type; +    uint16_t flags; +    uint32_t vcpu_id; +      uint64_t gfn; 
+    uint64_t offset; +    uint64_t gla; /* if gla_valid */ +      uint32_t p2mt; -    uint32_t vcpu_id; -    uint64_t flags; + +    uint16_t access_r:1; +    uint16_t access_w:1; +    uint16_t access_x:1; 
+    uint16_t gla_valid:1; +    uint16_t available:12; + +    uint16_t reason;  } mem_event_request_t, mem_event_response_t;    DEFINE_RING_TYPES(mem_event, mem_event_request_t, mem_event_response_t); 
 
 
2.patch 
Description: Text Data 
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
 
 |