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

[Xen-changelog] [xen-unstable] [XEN] Shadow: cache gva->gfn+rights translations between guest TLB flushes



# HG changeset patch
# User Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
# Date 1180705852 -3600
# Node ID bd3d6b4c52ec809f080c89c4ffcf61dc6e445978
# Parent  13eca4bf2c69aff4c9b689d0dff45929e44e4edb
[XEN] Shadow: cache gva->gfn+rights translations between guest TLB flushes
to make lookups faster for emulation and hvm_copy.
Signed-off-by: Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
---
 xen/arch/x86/mm/shadow/common.c  |   30 ++++++++++++++++
 xen/arch/x86/mm/shadow/multi.c   |   66 ++++++++++++++++++++++++++++++++----
 xen/arch/x86/mm/shadow/private.h |   71 +++++++++++++++++++++++++++++++++++++--
 xen/arch/x86/mm/shadow/types.h   |    3 +
 xen/include/asm-x86/domain.h     |    3 +
 5 files changed, 164 insertions(+), 9 deletions(-)

diff -r 13eca4bf2c69 -r bd3d6b4c52ec xen/arch/x86/mm/shadow/common.c
--- a/xen/arch/x86/mm/shadow/common.c   Fri Jun 01 14:32:11 2007 +0100
+++ b/xen/arch/x86/mm/shadow/common.c   Fri Jun 01 14:50:52 2007 +0100
@@ -2206,6 +2206,24 @@ static void sh_update_paging_modes(struc
 
     ASSERT(shadow_locked_by_me(d));
 
+#if (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB) 
+    /* Make sure this vcpu has a virtual TLB array allocated */
+    if ( unlikely(!v->arch.paging.vtlb) )
+    {
+        v->arch.paging.vtlb = xmalloc_array(struct shadow_vtlb, VTLB_ENTRIES);
+        if ( unlikely(!v->arch.paging.vtlb) )
+        {
+            SHADOW_ERROR("Could not allocate vTLB space for dom %u vcpu %u\n",
+                         d->domain_id, v->vcpu_id);
+            domain_crash(v->domain);
+            return;
+        }
+        memset(v->arch.paging.vtlb, 0, 
+               VTLB_ENTRIES * sizeof (struct shadow_vtlb));
+        spin_lock_init(&v->arch.paging.vtlb_lock);
+    }
+#endif /* (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB) */
+
     // Valid transitions handled by this function:
     // - For PV guests:
     //     - after a shadow mode has been changed
@@ -2513,6 +2531,18 @@ void shadow_teardown(struct domain *d)
             }
         }
     }
+
+#if (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB) 
+    /* Free the virtual-TLB array attached to each vcpu */
+    for_each_vcpu(d, v)
+    {
+        if ( v->arch.paging.vtlb )
+        {
+            xfree(v->arch.paging.vtlb);
+            v->arch.paging.vtlb = NULL;
+        }
+    }
+#endif /* (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB) */
 
     list_for_each_safe(entry, n, &d->arch.paging.shadow.p2m_freelist)
     {
diff -r 13eca4bf2c69 -r bd3d6b4c52ec xen/arch/x86/mm/shadow/multi.c
--- a/xen/arch/x86/mm/shadow/multi.c    Fri Jun 01 14:32:11 2007 +0100
+++ b/xen/arch/x86/mm/shadow/multi.c    Fri Jun 01 14:50:52 2007 +0100
@@ -2997,6 +2997,11 @@ sh_invlpg(struct vcpu *v, unsigned long 
     
     perfc_incr(shadow_invlpg);
 
+#if (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB)
+    /* No longer safe to use cached gva->gfn translations */
+    vtlb_flush(v);
+#endif
+
     /* First check that we can safely read the shadow l2e.  SMP/PAE linux can
      * run as high as 6% of invlpg calls where we haven't shadowed the l2 
      * yet. */
@@ -3057,6 +3062,7 @@ sh_invlpg(struct vcpu *v, unsigned long 
     return 1;
 }
 
+
 static unsigned long
 sh_gva_to_gfn(struct vcpu *v, unsigned long va)
 /* Called to translate a guest virtual address to what the *guest*
@@ -3064,11 +3070,24 @@ sh_gva_to_gfn(struct vcpu *v, unsigned l
 {
     walk_t gw;
     gfn_t gfn;
+    
+#if (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB)
+    struct shadow_vtlb t = {0};
+    if ( vtlb_lookup(v, va, &t) )
+        return t.frame_number;
+#endif /* (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB) */
 
     guest_walk_tables(v, va, &gw, 0);
     gfn = guest_walk_to_gfn(&gw);
+
+#if (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB)
+    t.page_number = va >> PAGE_SHIFT;
+    t.frame_number = gfn_x(gfn);
+    t.flags = accumulate_guest_flags(v, &gw); 
+    vtlb_insert(v, t);
+#endif /* (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB) */
+
     unmap_walk(v, &gw);
-
     return gfn_x(gfn);
 }
 
@@ -3694,6 +3713,11 @@ sh_update_cr3(struct vcpu *v, int do_loc
     /* Fix up the linear pagetable mappings */
     sh_update_linear_entries(v);
 
+#if (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB)
+    /* No longer safe to use cached gva->gfn translations */
+    vtlb_flush(v);
+#endif
+
     /* Release the lock, if we took it (otherwise it's the caller's problem) */
     if ( do_locking ) shadow_unlock(v->domain);
 }
@@ -3918,13 +3942,41 @@ static inline void * emulate_map_dest(st
     if ( ring_3(sh_ctxt->ctxt.regs) ) 
         return NULL;
 
-    /* Walk the guest pagetables */
-    guest_walk_tables(v, vaddr, &gw, 1);
-    flags = accumulate_guest_flags(v, &gw);
-    gfn = guest_l1e_get_gfn(gw.eff_l1e);
+#if (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB)
+    /* Try the virtual TLB first */
+    {
+        struct shadow_vtlb t = {0};
+        if ( vtlb_lookup(v, vaddr, &t) 
+             && ((t.flags & (_PAGE_PRESENT|_PAGE_RW)) 
+                 == (_PAGE_PRESENT|_PAGE_RW)) )
+        {
+            flags = t.flags;
+            gfn = _gfn(t.frame_number);
+        }
+        else
+        {
+            /* Need to do the full lookup, just in case permissions
+             * have increased since we cached this entry */
+            
+#endif /* (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB) */
+
+            /* Walk the guest pagetables */
+            guest_walk_tables(v, vaddr, &gw, 1);
+            flags = accumulate_guest_flags(v, &gw);
+            gfn = guest_l1e_get_gfn(gw.eff_l1e);
+            sh_audit_gw(v, &gw);
+            unmap_walk(v, &gw);
+            
+#if (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB)
+            /* Remember this translation for next time */
+            t.page_number = vaddr >> PAGE_SHIFT;
+            t.frame_number = gfn_x(gfn);
+            t.flags = flags;
+            vtlb_insert(v, t);
+        }
+    }
+#endif
     mfn = vcpu_gfn_to_mfn(v, gfn);
-    sh_audit_gw(v, &gw);
-    unmap_walk(v, &gw);
 
     errcode = PFEC_write_access;
     if ( !(flags & _PAGE_PRESENT) ) 
diff -r 13eca4bf2c69 -r bd3d6b4c52ec xen/arch/x86/mm/shadow/private.h
--- a/xen/arch/x86/mm/shadow/private.h  Fri Jun 01 14:32:11 2007 +0100
+++ b/xen/arch/x86/mm/shadow/private.h  Fri Jun 01 14:50:52 2007 +0100
@@ -61,8 +61,9 @@ extern int shadow_audit_enable;
 #define SHOPT_PREFETCH            0x08  /* Shadow multiple entries per fault */
 #define SHOPT_LINUX_L3_TOPLEVEL   0x10  /* Pin l3es on early 64bit linux */
 #define SHOPT_SKIP_VERIFY         0x20  /* Skip PTE v'fy when safe to do so */
-
-#define SHADOW_OPTIMIZATIONS      0x3f
+#define SHOPT_VIRTUAL_TLB         0x40  /* Cache guest v->p translations */
+
+#define SHADOW_OPTIMIZATIONS      0x7f
 
 
 /******************************************************************************
@@ -649,6 +650,72 @@ void shadow_continue_emulation(
 void shadow_continue_emulation(
     struct sh_emulate_ctxt *sh_ctxt, struct cpu_user_regs *regs);
 
+
+#if (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB)
+/**************************************************************************/
+/* Virtual TLB entries 
+ *
+ * We keep a cache of virtual-to-physical translations that we have seen 
+ * since the last TLB flush.  This is safe to use for frame translations, 
+ * but callers that use the rights need to re-check the actual guest tables
+ * before triggering a fault.
+ * 
+ * Lookups and updates are protected by a per-vTLB (and hence per-vcpu)
+ * lock.  This lock is held *only* while reading or writing the table,
+ * so it is safe to take in any non-interrupt context.  Most lookups
+ * happen with v==current, so we expect contention to be low.
+ */
+
+#define VTLB_ENTRIES 13
+
+struct shadow_vtlb {
+    unsigned long page_number;    /* Guest virtual address >> PAGE_SHIFT  */
+    unsigned long frame_number;   /* Guest physical address >> PAGE_SHIFT */
+    u32 flags;    /* Accumulated guest pte flags, or 0 for an empty slot. */
+};
+
+/* Call whenever the guest flushes hit actual TLB */
+static inline void vtlb_flush(struct vcpu *v) 
+{
+    spin_lock(&v->arch.paging.vtlb_lock);
+    memset(v->arch.paging.vtlb, 0, VTLB_ENTRIES * sizeof (struct shadow_vtlb));
+    spin_unlock(&v->arch.paging.vtlb_lock);
+}
+
+static inline int vtlb_hash(unsigned long page_number)
+{
+    return page_number % VTLB_ENTRIES;
+}
+
+/* Put a translation into the vTLB, potentially clobbering an old one */
+static inline void vtlb_insert(struct vcpu *v, struct shadow_vtlb entry)
+{
+    spin_lock(&v->arch.paging.vtlb_lock);
+    v->arch.paging.vtlb[vtlb_hash(entry.page_number)] = entry;
+    spin_unlock(&v->arch.paging.vtlb_lock);
+}
+
+/* Look a translation up in the vTLB.  Returns 0 if not found. */
+static inline int vtlb_lookup(struct vcpu *v, unsigned long va,
+                              struct shadow_vtlb *result) 
+{
+    unsigned long page_number = va >> PAGE_SHIFT;
+    int rv = 0;
+    int i = vtlb_hash(page_number);
+
+    spin_lock(&v->arch.paging.vtlb_lock);
+    if ( v->arch.paging.vtlb[i].flags != 0 
+         && v->arch.paging.vtlb[i].page_number == page_number )
+    {
+        rv = 1; 
+        result[0] = v->arch.paging.vtlb[i];
+    }
+    spin_unlock(&v->arch.paging.vtlb_lock);
+    return rv;
+}
+#endif /* (SHADOW_OPTIMIZATIONS & SHOPT_VIRTUAL_TLB) */
+
+
 #endif /* _XEN_SHADOW_PRIVATE_H */
 
 /*
diff -r 13eca4bf2c69 -r bd3d6b4c52ec xen/arch/x86/mm/shadow/types.h
--- a/xen/arch/x86/mm/shadow/types.h    Fri Jun 01 14:32:11 2007 +0100
+++ b/xen/arch/x86/mm/shadow/types.h    Fri Jun 01 14:50:52 2007 +0100
@@ -553,6 +553,9 @@ accumulate_guest_flags(struct vcpu *v, w
 {
     u32 accumulated_flags;
 
+    if ( unlikely(!(guest_l1e_get_flags(gw->eff_l1e) & _PAGE_PRESENT)) )
+        return 0;
+        
     // We accumulate the permission flags with bitwise ANDing.
     // This works for the PRESENT bit, RW bit, and USER bit.
     // For the NX bit, however, the polarity is wrong, so we accumulate the
diff -r 13eca4bf2c69 -r bd3d6b4c52ec xen/include/asm-x86/domain.h
--- a/xen/include/asm-x86/domain.h      Fri Jun 01 14:32:11 2007 +0100
+++ b/xen/include/asm-x86/domain.h      Fri Jun 01 14:50:52 2007 +0100
@@ -173,6 +173,9 @@ struct paging_vcpu {
     unsigned int translate_enabled:1;
     /* HVM guest: last emulate was to a pagetable */
     unsigned int last_write_was_pt:1;
+    /* Translated guest: virtual TLB */    
+    struct shadow_vtlb *vtlb;
+    spinlock_t          vtlb_lock; 
 
     /* paging support extension */
     struct shadow_vcpu shadow;

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


 


Rackspace

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