WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] vmx: Enable live-migration with EPT

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] vmx: Enable live-migration with EPT
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 10 Apr 2008 04:10:13 -0700
Delivery-date: Thu, 10 Apr 2008 04:10:11 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1207818041 -3600
# Node ID 9153b99a7066b6b5098f61483e3147e81ad7258e
# Parent  1d3aaa6a8b870805e16dcf162223fb2edd9de26d
vmx: Enable live-migration with EPT

Signed-off-by: Xin Li <xin.b.li@xxxxxxxxx>
Signed-off-by: Jun Nakajima <jun.nakajima@xxxxxxxxx>
Signed-off-by: Xiaohui Xin <Xiaohui.xin@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 xen/arch/x86/hvm/vmx/vmx.c        |   40 ++++++++++++++++--
 xen/arch/x86/mm/hap/hap.c         |    6 +-
 xen/arch/x86/mm/hap/p2m-ept.c     |   84 ++++++++++++++++++++++++++++++++++----
 xen/arch/x86/mm/p2m.c             |   16 ++++++-
 xen/include/asm-x86/hvm/vmx/vmx.h |   43 +++++++++++++++++++
 xen/include/asm-x86/p2m.h         |    4 +
 6 files changed, 178 insertions(+), 15 deletions(-)

diff -r 1d3aaa6a8b87 -r 9153b99a7066 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Thu Apr 10 09:22:38 2008 +0100
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Thu Apr 10 10:00:41 2008 +0100
@@ -2053,13 +2053,47 @@ static void vmx_wbinvd_intercept(void)
 
 static void ept_handle_violation(unsigned long qualification, paddr_t gpa)
 {
-    if ( unlikely(((qualification >> 7) & 0x3) != 0x3) )
-    {
-        domain_crash(current->domain);
+    unsigned long gla_validity = qualification & EPT_GLA_VALIDITY_MASK;
+    struct domain *d = current->domain;
+    unsigned long gfn = gpa >> PAGE_SHIFT;
+    mfn_t mfn;
+    p2m_type_t t;
+
+    if ( unlikely(qualification & EPT_GAW_VIOLATION) )
+    {
+        gdprintk(XENLOG_ERR, "EPT violation: guest physical address %"PRIpaddr
+                 " exceeded its width limit.\n", gpa);
+        goto crash;
+    }
+
+    if ( unlikely(gla_validity == EPT_GLA_VALIDITY_RSVD) ||
+         unlikely(gla_validity == EPT_GLA_VALIDITY_PDPTR_LOAD) )
+    {
+        gdprintk(XENLOG_ERR, "EPT violation: reserved bit or "
+                 "pdptr load violation.\n");
+        goto crash;
+    }
+
+    mfn = gfn_to_mfn(d, gfn, &t);
+    if ( p2m_is_ram(t) && paging_mode_log_dirty(d) )
+    {
+        paging_mark_dirty(d, mfn_x(mfn));
+        p2m_change_type(d, gfn, p2m_ram_logdirty, p2m_ram_rw);
+        flush_tlb_mask(d->domain_dirty_cpumask);
         return;
     }
 
+    /* This can only happen in log-dirty mode, writing back A/D bits. */
+    if ( unlikely(gla_validity == EPT_GLA_VALIDITY_GPT_WALK) )
+        goto crash;
+
+    ASSERT(gla_validity == EPT_GLA_VALIDITY_MATCH);
     handle_mmio();
+
+    return;
+
+ crash:
+    domain_crash(d);
 }
 
 static void vmx_failed_vmentry(unsigned int exit_reason,
diff -r 1d3aaa6a8b87 -r 9153b99a7066 xen/arch/x86/mm/hap/hap.c
--- a/xen/arch/x86/mm/hap/hap.c Thu Apr 10 09:22:38 2008 +0100
+++ b/xen/arch/x86/mm/hap/hap.c Thu Apr 10 10:00:41 2008 +0100
@@ -62,7 +62,7 @@ int hap_enable_log_dirty(struct domain *
     hap_unlock(d);
 
     /* set l1e entries of P2M table to be read-only. */
-    p2m_change_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
+    p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
     flush_tlb_mask(d->domain_dirty_cpumask);
     return 0;
 }
@@ -74,14 +74,14 @@ int hap_disable_log_dirty(struct domain 
     hap_unlock(d);
 
     /* set l1e entries of P2M table with normal mode */
-    p2m_change_type_global(d, p2m_ram_logdirty, p2m_ram_rw);
+    p2m_change_entry_type_global(d, p2m_ram_logdirty, p2m_ram_rw);
     return 0;
 }
 
 void hap_clean_dirty_bitmap(struct domain *d)
 {
     /* set l1e entries of P2M table to be read-only. */
-    p2m_change_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
+    p2m_change_entry_type_global(d, p2m_ram_rw, p2m_ram_logdirty);
     flush_tlb_mask(d->domain_dirty_cpumask);
 }
 
diff -r 1d3aaa6a8b87 -r 9153b99a7066 xen/arch/x86/mm/hap/p2m-ept.c
--- a/xen/arch/x86/mm/hap/p2m-ept.c     Thu Apr 10 09:22:38 2008 +0100
+++ b/xen/arch/x86/mm/hap/p2m-ept.c     Thu Apr 10 10:00:41 2008 +0100
@@ -26,6 +26,26 @@
 #include <asm/hvm/vmx/vmx.h>
 #include <xen/iommu.h>
 
+static void ept_p2m_type_to_flags(ept_entry_t *entry, p2m_type_t type)
+{
+    switch(type)
+    {
+        case p2m_invalid:
+        case p2m_mmio_dm:
+        default:
+            return;
+        case p2m_ram_rw:
+        case p2m_mmio_direct:
+             entry->r = entry->w = entry->x = 1;
+            return;
+        case p2m_ram_logdirty:
+        case p2m_ram_ro:
+             entry->r = entry->x = 1;
+             entry->w = 0;
+            return;
+    }
+}
+
 static int ept_next_level(struct domain *d, bool_t read_only,
                           ept_entry_t **table, unsigned long *gfn_remainder,
                           u32 shift)
@@ -104,6 +124,7 @@ ept_set_entry(struct domain *d, unsigned
         ept_entry->avail2 = 0;
         /* last step */
         ept_entry->r = ept_entry->w = ept_entry->x = 1;
+        ept_p2m_type_to_flags(ept_entry, p2mt);
     }
     else
         ept_entry->epte = 0;
@@ -150,13 +171,10 @@ static mfn_t ept_get_entry(struct domain
     index = gfn_remainder;
     ept_entry = table + index;
 
-    if ( (ept_entry->epte & 0x7) == 0x7 )
-    {
-        if ( ept_entry->avail1 != p2m_invalid )
-        {
-            *t = ept_entry->avail1;
-            mfn = _mfn(ept_entry->mfn);
-        }
+    if ( ept_entry->avail1 != p2m_invalid )
+    {
+        *t = ept_entry->avail1;
+        mfn = _mfn(ept_entry->mfn);
     }
 
  out:
@@ -169,11 +187,63 @@ static mfn_t ept_get_entry_current(unsig
     return ept_get_entry(current->domain, gfn, t);
 }
 
+/* Walk the whole p2m table, changing any entries of the old type
+ * to the new type.  This is used in hardware-assisted paging to
+ * quickly enable or diable log-dirty tracking */
+
+static void ept_change_entry_type_global(struct domain *d,
+                                            p2m_type_t ot, p2m_type_t nt)
+{
+    ept_entry_t *l4e, *l3e, *l2e, *l1e;
+    int i4, i3, i2, i1;
+
+    if ( pagetable_get_pfn(d->arch.phys_table) == 0 )
+        return;
+
+    BUG_ON(EPT_DEFAULT_GAW != 3);
+
+    l4e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table)));
+    for (i4 = 0; i4 < EPT_PAGETABLE_ENTRIES; i4++ )
+    {
+        if ( !l4e[i4].epte || l4e[i4].sp_avail )
+            continue;
+        l3e = map_domain_page(l4e[i4].mfn);
+        for ( i3 = 0; i3 < EPT_PAGETABLE_ENTRIES; i3++ )
+        {
+            if ( !l3e[i3].epte || l3e[i3].sp_avail )
+                continue;
+            l2e = map_domain_page(l3e[i3].mfn);
+            for ( i2 = 0; i2 < EPT_PAGETABLE_ENTRIES; i2++ )
+            {
+                if ( !l2e[i2].epte || l2e[i2].sp_avail )
+                    continue;
+                l1e = map_domain_page(l2e[i2].mfn);
+                for ( i1  = 0; i1 < EPT_PAGETABLE_ENTRIES; i1++ )
+                {
+                    if ( !l1e[i1].epte )
+                        continue;
+                    if ( l1e[i1].avail1 != ot )
+                        continue;
+                    l1e[i1].avail1 = nt;
+                    ept_p2m_type_to_flags(l1e+i1, nt);
+                }
+                unmap_domain_page(l1e);
+            }
+            unmap_domain_page(l2e);
+        }
+        unmap_domain_page(l3e);
+    }
+    unmap_domain_page(l4e);
+
+    ept_sync_domain(d);
+}
+
 void ept_p2m_init(struct domain *d)
 {
     d->arch.p2m->set_entry = ept_set_entry;
     d->arch.p2m->get_entry = ept_get_entry;
     d->arch.p2m->get_entry_current = ept_get_entry_current;
+    d->arch.p2m->change_entry_type_global = ept_change_entry_type_global;
 }
 
 /*
diff -r 1d3aaa6a8b87 -r 9153b99a7066 xen/arch/x86/mm/p2m.c
--- a/xen/arch/x86/mm/p2m.c     Thu Apr 10 09:22:38 2008 +0100
+++ b/xen/arch/x86/mm/p2m.c     Thu Apr 10 10:00:41 2008 +0100
@@ -71,6 +71,8 @@
         spin_unlock(&(_p2m)->lock);                     \
     } while (0)
 
+#define p2m_locked_by_me(_p2m)                            \
+    (current->processor == (_p2m)->locker)
 
 /* Printouts */
 #define P2M_PRINTK(_f, _a...)                                \
@@ -418,12 +420,23 @@ int p2m_init(struct domain *d)
     p2m->set_entry = p2m_set_entry;
     p2m->get_entry = p2m_gfn_to_mfn;
     p2m->get_entry_current = p2m_gfn_to_mfn_current;
+    p2m->change_entry_type_global = p2m_change_type_global;
 
     if ( is_hvm_domain(d) && d->arch.hvm_domain.hap_enabled &&
          (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) )
         ept_p2m_init(d);
 
     return 0;
+}
+
+void p2m_change_entry_type_global(struct domain *d,
+                                  p2m_type_t ot, p2m_type_t nt)
+{
+    struct p2m_domain *p2m = d->arch.p2m;
+
+    p2m_lock(p2m);
+    p2m->change_entry_type_global(d, ot, nt);
+    p2m_unlock(p2m);
 }
 
 static inline
@@ -880,7 +893,7 @@ void p2m_change_type_global(struct domai
     if ( pagetable_get_pfn(d->arch.phys_table) == 0 )
         return;
 
-    p2m_lock(d->arch.p2m);
+    ASSERT(p2m_locked_by_me(d->arch.p2m));
 
 #if CONFIG_PAGING_LEVELS == 4
     l4e = map_domain_page(mfn_x(pagetable_get_mfn(d->arch.phys_table)));
@@ -952,7 +965,6 @@ void p2m_change_type_global(struct domai
     unmap_domain_page(l2e);
 #endif
 
-    p2m_unlock(d->arch.p2m);
 }
 
 /* Modify the p2m type of a single gfn from ot to nt, returning the 
diff -r 1d3aaa6a8b87 -r 9153b99a7066 xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h Thu Apr 10 09:22:38 2008 +0100
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h Thu Apr 10 10:00:41 2008 +0100
@@ -344,4 +344,47 @@ void vmx_inject_nmi(struct vcpu *v);
 
 void ept_p2m_init(struct domain *d);
 
+/* EPT violation qualifications definitions */
+/* bit offset 0 in exit qualification */
+#define _EPT_READ_VIOLATION         0
+#define EPT_READ_VIOLATION          (1UL<<_EPT_READ_VIOLATION)
+/* bit offset 1 in exit qualification */
+#define _EPT_WRITE_VIOLATION        1
+#define EPT_WRITE_VIOLATION         (1UL<<_EPT_WRITE_VIOLATION)
+/* bit offset 2 in exit qualification */
+#define _EPT_EXEC_VIOLATION         2
+#define EPT_EXEC_VIOLATION          (1UL<<_EPT_EXEC_VIOLATION)
+
+/* bit offset 3 in exit qualification */
+#define _EPT_EFFECTIVE_READ         3
+#define EPT_EFFECTIVE_READ          (1UL<<_EPT_EFFECTIVE_READ)
+/* bit offset 4 in exit qualification */
+#define _EPT_EFFECTIVE_WRITE        4
+#define EPT_EFFECTIVE_WRITE         (1UL<<_EPT_EFFECTIVE_WRITE)
+/* bit offset 5 in exit qualification */
+#define _EPT_EFFECTIVE_EXEC         5
+#define EPT_EFFECTIVE_EXEC          (1UL<<_EPT_EFFECTIVE_EXEC)
+
+/* bit offset 6 in exit qualification */
+#define _EPT_GAW_VIOLATION          6
+#define EPT_GAW_VIOLATION           (1UL<<_EPT_GAW_VIOLATION)
+
+/* bits offset 7 & 8 in exit qualification */
+#define _EPT_GLA_VALIDITY           7
+#define EPT_GLA_VALIDITY_MASK       (3UL<<_EPT_GLA_VALIDITY)
+/* gla != gpa, when load PDPTR */
+#define EPT_GLA_VALIDITY_PDPTR_LOAD (0UL<<_EPT_GLA_VALIDITY)
+/* gla != gpa, during guest page table walking */
+#define EPT_GLA_VALIDITY_GPT_WALK   (1UL<<_EPT_GLA_VALIDITY)
+/* reserved */
+#define EPT_GLA_VALIDITY_RSVD       (2UL<<_EPT_GLA_VALIDITY)
+/* gla == gpa, normal case */
+#define EPT_GLA_VALIDITY_MATCH      (3UL<<_EPT_GLA_VALIDITY)
+
+#define EPT_EFFECTIVE_MASK          (EPT_EFFECTIVE_READ  |  \
+                                     EPT_EFFECTIVE_WRITE |  \
+                                     EPT_EFFECTIVE_EXEC)
+
+#define EPT_PAGETABLE_ENTRIES       512
+
 #endif /* __ASM_X86_HVM_VMX_VMX_H__ */
diff -r 1d3aaa6a8b87 -r 9153b99a7066 xen/include/asm-x86/p2m.h
--- a/xen/include/asm-x86/p2m.h Thu Apr 10 09:22:38 2008 +0100
+++ b/xen/include/asm-x86/p2m.h Thu Apr 10 10:00:41 2008 +0100
@@ -107,6 +107,9 @@ struct p2m_domain {
                                        p2m_type_t *p2mt);
     mfn_t              (*get_entry_current)(unsigned long gfn,
                                             p2m_type_t *p2mt);
+    void               (*change_entry_type_global)(struct domain *d,
+                                                   p2m_type_t ot,
+                                                   p2m_type_t nt);
 
     /* Highest guest frame that's ever been mapped in the p2m */
     unsigned long max_mapped_pfn;
@@ -218,6 +221,7 @@ void guest_physmap_remove_page(struct do
 
 /* Change types across all p2m entries in a domain */
 void p2m_change_type_global(struct domain *d, p2m_type_t ot, p2m_type_t nt);
+void p2m_change_entry_type_global(struct domain *d, p2m_type_t ot, p2m_type_t 
nt);
 
 /* Compare-exchange the type of a single p2m entry */
 p2m_type_t p2m_change_type(struct domain *d, unsigned long gfn,

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] vmx: Enable live-migration with EPT, Xen patchbot-unstable <=