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

[Xen-devel] [PATCH v2] x86/mm: Suppresses vm_events caused by page-walks



The original version of the patch emulated the current instruction
(which, as a side-effect, emulated the page-walk as well), however we
need finer-grained control. We want to emulate the page-walk, but still
get an EPT violation event if the current instruction would trigger one.
This patch performs just the page-walk emulation.

Signed-off-by: Alexandru Isaila <aisaila@xxxxxxxxxxxxxxx>

---
Changes since V1:
        - Changed guest_walk_tables() to set A bit on each level and
          check if there was any A set. If not the it will set the D bit
          according to the write flags and cr0.wp
---
 xen/arch/x86/mm/guest_walk.c     | 23 ++++++++++++++++++++++-
 xen/arch/x86/mm/hap/guest_walk.c | 32 +++++++++++++++++++++++++++++++-
 xen/arch/x86/mm/hap/hap.c        | 12 ++++++++----
 xen/arch/x86/mm/hap/private.h    | 10 ++++++++++
 xen/arch/x86/mm/mem_access.c     |  5 ++++-
 xen/arch/x86/mm/shadow/multi.c   |  6 +++---
 xen/include/asm-x86/guest_pt.h   |  3 ++-
 xen/include/asm-x86/paging.h     |  5 ++++-
 8 files changed, 84 insertions(+), 12 deletions(-)

diff --git a/xen/arch/x86/mm/guest_walk.c b/xen/arch/x86/mm/guest_walk.c
index f67aeda3d0..c99c48fa8a 100644
--- a/xen/arch/x86/mm/guest_walk.c
+++ b/xen/arch/x86/mm/guest_walk.c
@@ -82,7 +82,8 @@ static bool set_ad_bits(guest_intpte_t *guest_p, 
guest_intpte_t *walk_p,
 bool
 guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m,
                   unsigned long va, walk_t *gw,
-                  uint32_t walk, mfn_t top_mfn, void *top_map)
+                  uint32_t walk, mfn_t top_mfn, void *top_map,
+                  bool set_ad)
 {
     struct domain *d = v->domain;
     p2m_type_t p2mt;
@@ -95,6 +96,7 @@ guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m,
     uint32_t gflags, rc;
     unsigned int leaf_level;
     p2m_query_t qt = P2M_ALLOC | P2M_UNSHARE;
+    bool accessed = false;
 
 #define AR_ACCUM_AND (_PAGE_USER | _PAGE_RW)
 #define AR_ACCUM_OR  (_PAGE_NX_BIT)
@@ -149,6 +151,10 @@ guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m,
     ar_and &= gflags;
     ar_or  |= gflags;
 
+    if ( set_ad && set_ad_bits(&l4p[guest_l4_table_offset(va)].l4,
+                               &gw->l4e.l4, false) )
+        accessed = true;
+
     /* Map the l3 table */
     l3p = map_domain_gfn(p2m,
                          guest_l4e_get_gfn(gw->l4e),
@@ -179,6 +185,10 @@ guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m,
     ar_and &= gflags;
     ar_or  |= gflags;
 
+    if ( set_ad && set_ad_bits(&l3p[guest_l3_table_offset(va)].l3,
+                               &gw->l3e.l3, false) )
+        accessed = true;
+
     if ( gflags & _PAGE_PSE )
     {
         /*
@@ -278,6 +288,10 @@ guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m,
     ar_and &= gflags;
     ar_or  |= gflags;
 
+    if ( set_ad && set_ad_bits(&l2p[guest_l2_table_offset(va)].l2,
+                               &gw->l2e.l2, false) )
+        accessed = true;
+
     if ( gflags & _PAGE_PSE )
     {
         /*
@@ -362,6 +376,13 @@ guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m,
      */
     ar = (ar_and & AR_ACCUM_AND) | (ar_or & AR_ACCUM_OR);
 
+    if ( set_ad )
+    {
+        set_ad_bits(&l1p[guest_l1_table_offset(va)].l1, &gw->l1e.l1,
+                    (ar & _PAGE_RW) && !accessed && !guest_wp_enabled(v));
+        goto out;
+    }
+
     /*
      * Sanity check.  If EFER.NX is disabled, _PAGE_NX_BIT is reserved and
      * should have caused a translation failure before we get here.
diff --git a/xen/arch/x86/mm/hap/guest_walk.c b/xen/arch/x86/mm/hap/guest_walk.c
index 3b8ee2efce..4cbbf69095 100644
--- a/xen/arch/x86/mm/hap/guest_walk.c
+++ b/xen/arch/x86/mm/hap/guest_walk.c
@@ -29,6 +29,10 @@ asm(".file \"" __OBJECT_FILE__ "\"");
 #define _hap_gva_to_gfn(levels) hap_gva_to_gfn_##levels##_levels
 #define hap_gva_to_gfn(levels) _hap_gva_to_gfn(levels)
 
+#define _hap_page_walk_set_ad_bits(levels)                                     
\
+        hap_page_walk_set_ad_bits_##levels##_levels
+#define hap_page_walk_set_ad_bits(levels) _hap_page_walk_set_ad_bits(levels)
+
 #define _hap_p2m_ga_to_gfn(levels) hap_p2m_ga_to_gfn_##levels##_levels
 #define hap_p2m_ga_to_gfn(levels) _hap_p2m_ga_to_gfn(levels)
 
@@ -39,6 +43,32 @@ asm(".file \"" __OBJECT_FILE__ "\"");
 #include <asm/guest_pt.h>
 #include <asm/p2m.h>
 
+void hap_page_walk_set_ad_bits(GUEST_PAGING_LEVELS)(
+    struct vcpu *v, struct p2m_domain *p2m,
+    unsigned long va, uint32_t walk, unsigned long cr3)
+{
+    walk_t gw;
+    mfn_t top_mfn;
+    void *top_map;
+    gfn_t top_gfn;
+    struct page_info *top_page;
+    p2m_type_t p2mt;
+
+    top_gfn = _gfn(cr3 >> PAGE_SHIFT);
+    top_page = p2m_get_page_from_gfn(p2m, top_gfn, &p2mt, NULL,
+                                     P2M_ALLOC | P2M_UNSHARE);
+    top_mfn = page_to_mfn(top_page);
+
+    /* Map the top-level table and call the tree-walker */
+    ASSERT(mfn_valid(top_mfn));
+    top_map = map_domain_page(top_mfn);
+#if GUEST_PAGING_LEVELS == 3
+    top_map += (cr3 & ~(PAGE_MASK | 31));
+#endif
+
+    guest_walk_tables(v, p2m, va, &gw, walk, top_mfn, top_map, true);
+}
+
 unsigned long hap_gva_to_gfn(GUEST_PAGING_LEVELS)(
     struct vcpu *v, struct p2m_domain *p2m, unsigned long gva, uint32_t *pfec)
 {
@@ -91,7 +121,7 @@ unsigned long hap_p2m_ga_to_gfn(GUEST_PAGING_LEVELS)(
 #if GUEST_PAGING_LEVELS == 3
     top_map += (cr3 & ~(PAGE_MASK | 31));
 #endif
-    walk_ok = guest_walk_tables(v, p2m, ga, &gw, *pfec, top_mfn, top_map);
+    walk_ok = guest_walk_tables(v, p2m, ga, &gw, *pfec, top_mfn, top_map, 
false);
     unmap_domain_page(top_map);
     put_page(top_page);
 
diff --git a/xen/arch/x86/mm/hap/hap.c b/xen/arch/x86/mm/hap/hap.c
index 3d651b94c3..ca046b78df 100644
--- a/xen/arch/x86/mm/hap/hap.c
+++ b/xen/arch/x86/mm/hap/hap.c
@@ -768,7 +768,8 @@ static const struct paging_mode hap_paging_real_mode = {
     .update_cr3             = hap_update_cr3,
     .update_paging_modes    = hap_update_paging_modes,
     .write_p2m_entry        = hap_write_p2m_entry,
-    .guest_levels           = 1
+    .guest_levels           = 1,
+    .page_walk_set_ad_bits  = hap_page_walk_set_ad_bits_2_levels
 };
 
 static const struct paging_mode hap_paging_protected_mode = {
@@ -779,7 +780,8 @@ static const struct paging_mode hap_paging_protected_mode = 
{
     .update_cr3             = hap_update_cr3,
     .update_paging_modes    = hap_update_paging_modes,
     .write_p2m_entry        = hap_write_p2m_entry,
-    .guest_levels           = 2
+    .guest_levels           = 2,
+    .page_walk_set_ad_bits  = hap_page_walk_set_ad_bits_2_levels
 };
 
 static const struct paging_mode hap_paging_pae_mode = {
@@ -790,7 +792,8 @@ static const struct paging_mode hap_paging_pae_mode = {
     .update_cr3             = hap_update_cr3,
     .update_paging_modes    = hap_update_paging_modes,
     .write_p2m_entry        = hap_write_p2m_entry,
-    .guest_levels           = 3
+    .guest_levels           = 3,
+    .page_walk_set_ad_bits  = hap_page_walk_set_ad_bits_3_levels
 };
 
 static const struct paging_mode hap_paging_long_mode = {
@@ -801,7 +804,8 @@ static const struct paging_mode hap_paging_long_mode = {
     .update_cr3             = hap_update_cr3,
     .update_paging_modes    = hap_update_paging_modes,
     .write_p2m_entry        = hap_write_p2m_entry,
-    .guest_levels           = 4
+    .guest_levels           = 4,
+    .page_walk_set_ad_bits  = hap_page_walk_set_ad_bits_4_levels
 };
 
 /*
diff --git a/xen/arch/x86/mm/hap/private.h b/xen/arch/x86/mm/hap/private.h
index 973fbe8be5..abb933c4f8 100644
--- a/xen/arch/x86/mm/hap/private.h
+++ b/xen/arch/x86/mm/hap/private.h
@@ -47,4 +47,14 @@ unsigned long hap_p2m_ga_to_gfn_4_levels(struct vcpu *v,
     struct p2m_domain *p2m, unsigned long cr3,
     paddr_t ga, uint32_t *pfec, unsigned int *page_order);
 
+void hap_page_walk_set_ad_bits_2_levels(struct vcpu *v, struct p2m_domain *p2m,
+                                        unsigned long va, uint32_t walk,
+                                        unsigned long cr3);
+void hap_page_walk_set_ad_bits_3_levels(struct vcpu *v, struct p2m_domain *p2m,
+                                        unsigned long va, uint32_t walk,
+                                        unsigned long cr3);
+void hap_page_walk_set_ad_bits_4_levels(struct vcpu *v, struct p2m_domain *p2m,
+                                        unsigned long va,  uint32_t walk,
+                                        unsigned long cr3);
+
 #endif /* __HAP_PRIVATE_H__ */
diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
index a8b3e99ec4..8b644946f0 100644
--- a/xen/arch/x86/mm/mem_access.c
+++ b/xen/arch/x86/mm/mem_access.c
@@ -214,7 +214,10 @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla,
          d->arch.monitor.inguest_pagefault_disabled &&
          npfec.kind != npfec_kind_with_gla ) /* don't send a mem_event */
     {
-        hvm_emulate_one_vm_event(EMUL_KIND_NORMAL, TRAP_invalid_op, 
X86_EVENT_NO_EC);
+        struct hvm_hw_cpu ctxt;
+
+        hvm_funcs.save_cpu_ctxt(v, &ctxt);
+        paging_get_hostmode(v)->page_walk_set_ad_bits(v, p2m, gla, 0, 
ctxt.cr3);
 
         return true;
     }
diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c
index 5cb216f0db..d3df9be57c 100644
--- a/xen/arch/x86/mm/shadow/multi.c
+++ b/xen/arch/x86/mm/shadow/multi.c
@@ -178,12 +178,12 @@ sh_walk_guest_tables(struct vcpu *v, unsigned long va, 
walk_t *gw,
     return guest_walk_tables(v, p2m_get_hostp2m(v->domain), va, gw, pfec,
 #if GUEST_PAGING_LEVELS == 3 /* PAE */
                              INVALID_MFN,
-                             v->arch.paging.shadow.gl3e
+                             v->arch.paging.shadow.gl3e,
 #else /* 32 or 64 */
                              pagetable_get_mfn(v->arch.guest_table),
-                             v->arch.paging.shadow.guest_vtable
+                             v->arch.paging.shadow.guest_vtable,
 #endif
-                             );
+                            false);
 }
 
 /* This validation is called with lock held, and after write permission
diff --git a/xen/include/asm-x86/guest_pt.h b/xen/include/asm-x86/guest_pt.h
index 8684b83fd6..3dfb7fa966 100644
--- a/xen/include/asm-x86/guest_pt.h
+++ b/xen/include/asm-x86/guest_pt.h
@@ -425,7 +425,8 @@ static inline unsigned int guest_walk_to_page_order(const 
walk_t *gw)
 
 bool
 guest_walk_tables(struct vcpu *v, struct p2m_domain *p2m, unsigned long va,
-                  walk_t *gw, uint32_t pfec, mfn_t top_mfn, void *top_map);
+                  walk_t *gw, uint32_t pfec, mfn_t top_mfn, void *top_map,
+                  bool set_ad);
 
 /* Pretty-print the contents of a guest-walk */
 static inline void print_gw(const walk_t *gw)
diff --git a/xen/include/asm-x86/paging.h b/xen/include/asm-x86/paging.h
index b51e1709d3..076ca204f5 100644
--- a/xen/include/asm-x86/paging.h
+++ b/xen/include/asm-x86/paging.h
@@ -127,7 +127,10 @@ struct paging_mode {
     void          (*write_p2m_entry       )(struct domain *d, unsigned long 
gfn,
                                             l1_pgentry_t *p, l1_pgentry_t new,
                                             unsigned int level);
-
+    void          (*page_walk_set_ad_bits )(struct vcpu *v,
+                                            struct p2m_domain *p2m,
+                                            unsigned long va, uint32_t walk,
+                                            unsigned long cr3);
     unsigned int guest_levels;
 
     /* paging support extension */
-- 
2.17.1


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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