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

[Xen-changelog] [xen-unstable] Memory paging support for HVM guest emulation.



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1261031275 0
# Node ID 410eb65969cb142b8b32490d7f1454859cc3a7f2
# Parent  1165acfea711ef33798d12fb5078e3b31faa3e44
Memory paging support for HVM guest emulation.

A new HVMCOPY return value, HVMCOPY_gfn_paged_out is defined to indicate that
a gfn was paged out. This value and PFEC_page_paged, as appropriate, are
caught and passed up as X86EMUL_RETRY to the emulator. This will cause the
emulator to keep retrying the operation until is succeeds (once the page has
been paged in).

Signed-off-by: Patrick Colp <Patrick.Colp@xxxxxxxxxx>
---
 xen/arch/x86/hvm/emulate.c        |   21 +++++++++++++++++
 xen/arch/x86/hvm/hvm.c            |   22 ++++++++++++++++++
 xen/arch/x86/hvm/intercept.c      |   45 +++++++++++++++++++++-----------------
 xen/arch/x86/hvm/io.c             |   42 ++++++++++++++++++++++-------------
 xen/include/asm-x86/hvm/support.h |    3 +-
 5 files changed, 97 insertions(+), 36 deletions(-)

diff -r 1165acfea711 -r 410eb65969cb xen/arch/x86/hvm/emulate.c
--- a/xen/arch/x86/hvm/emulate.c        Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/arch/x86/hvm/emulate.c        Thu Dec 17 06:27:55 2009 +0000
@@ -56,7 +56,18 @@ static int hvmemul_do_io(
     int value_is_ptr = (p_data == NULL);
     struct vcpu *curr = current;
     ioreq_t *p = get_ioreq(curr);
+    unsigned long ram_gfn = paddr_to_pfn(ram_gpa);
+    p2m_type_t p2mt;
+    mfn_t ram_mfn;
     int rc;
+
+    /* Check for paged out page */
+    ram_mfn = gfn_to_mfn(current->domain, ram_gfn, &p2mt);
+    if ( p2m_is_paging(p2mt) )
+    {
+        p2m_mem_paging_populate(curr->domain, ram_gfn);
+        return X86EMUL_RETRY;
+    }
 
     /*
      * Weird-sized accesses have undefined behaviour: we discard writes
@@ -271,6 +282,8 @@ static int hvmemul_linear_to_phys(
     }
     else if ( (pfn = paging_gva_to_gfn(curr, addr, &pfec)) == INVALID_GFN )
     {
+        if ( pfec == PFEC_page_paged )
+            return X86EMUL_RETRY;
         hvm_inject_exception(TRAP_page_fault, pfec, addr);
         return X86EMUL_EXCEPTION;
     }
@@ -286,6 +299,8 @@ static int hvmemul_linear_to_phys(
         /* Is it contiguous with the preceding PFNs? If not then we're done. */
         if ( (npfn == INVALID_GFN) || (npfn != (pfn + (reverse ? -i : i))) )
         {
+            if ( pfec == PFEC_page_paged )
+                return X86EMUL_RETRY;
             done /= bytes_per_rep;
             if ( done == 0 )
             {
@@ -424,6 +439,8 @@ static int __hvmemul_read(
         if ( rc != X86EMUL_OKAY )
             return rc;
         return hvmemul_do_mmio(gpa, &reps, bytes, 0, IOREQ_READ, 0, p_data);
+    case HVMCOPY_gfn_paged_out:
+        return X86EMUL_RETRY;
     default:
         break;
     }
@@ -514,6 +531,8 @@ static int hvmemul_write(
             return rc;
         return hvmemul_do_mmio(gpa, &reps, bytes, 0,
                                IOREQ_WRITE, 0, p_data);
+    case HVMCOPY_gfn_paged_out:
+        return X86EMUL_RETRY;
     default:
         break;
     }
@@ -687,6 +706,8 @@ static int hvmemul_rep_movs(
 
     xfree(buf);
 
+    if ( rc == HVMCOPY_gfn_paged_out )
+        return X86EMUL_RETRY;
     if ( rc != HVMCOPY_okay )
     {
         gdprintk(XENLOG_WARNING, "Failed memory-to-memory REP MOVS: sgpa=%"
diff -r 1165acfea711 -r 410eb65969cb xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/arch/x86/hvm/hvm.c    Thu Dec 17 06:27:55 2009 +0000
@@ -314,6 +314,11 @@ static int hvm_set_ioreq_page(
     mfn = mfn_x(gfn_to_mfn(d, gmfn, &p2mt));
     if ( !p2m_is_ram(p2mt) )
         return -EINVAL;
+    if ( p2m_is_paging(p2mt) )
+    {
+        p2m_mem_paging_populate(d, gmfn);
+        return -ENOENT;
+    }
     ASSERT(mfn_valid(mfn));
 
     page = mfn_to_page(mfn);
@@ -1318,6 +1323,8 @@ static void *hvm_map_entry(unsigned long
      * we still treat it as a kernel-mode read (i.e. no access checks). */
     pfec = PFEC_page_present;
     gfn = paging_gva_to_gfn(current, va, &pfec);
+    if ( pfec == PFEC_page_paged )
+        return NULL;
     mfn = mfn_x(gfn_to_mfn_current(gfn, &p2mt));
     if ( p2m_is_paging(p2mt) )
     {
@@ -1546,6 +1553,8 @@ void hvm_task_switch(
         &tss, prev_tr.base, sizeof(tss), PFEC_page_present);
     if ( rc == HVMCOPY_bad_gva_to_gfn )
         goto out;
+    if ( rc == HVMCOPY_gfn_paged_out )
+        goto out;
 
     eflags = regs->eflags;
     if ( taskswitch_reason == TSW_iret )
@@ -1582,10 +1591,14 @@ void hvm_task_switch(
         prev_tr.base, &tss, sizeof(tss), PFEC_page_present);
     if ( rc == HVMCOPY_bad_gva_to_gfn )
         goto out;
+    if ( rc == HVMCOPY_gfn_paged_out )
+        goto out;
 
     rc = hvm_copy_from_guest_virt(
         &tss, tr.base, sizeof(tss), PFEC_page_present);
     if ( rc == HVMCOPY_bad_gva_to_gfn )
+        goto out;
+    if ( rc == HVMCOPY_gfn_paged_out )
         goto out;
 
     if ( hvm_set_cr3(tss.cr3) )
@@ -1622,6 +1635,8 @@ void hvm_task_switch(
         tr.base, &tss, sizeof(tss), PFEC_page_present);
     if ( rc == HVMCOPY_bad_gva_to_gfn )
         exn_raised = 1;
+    if ( rc == HVMCOPY_gfn_paged_out )
+        goto out;
 
     if ( (tss.trace & 1) && !exn_raised )
         hvm_inject_exception(TRAP_debug, tss_sel & 0xfff8, 0);
@@ -1681,6 +1696,8 @@ static enum hvm_copy_result __hvm_copy(
             gfn = paging_gva_to_gfn(curr, addr, &pfec);
             if ( gfn == INVALID_GFN )
             {
+                if ( pfec == PFEC_page_paged )
+                    return HVMCOPY_gfn_paged_out;
                 if ( flags & HVMCOPY_fault )
                     hvm_inject_exception(TRAP_page_fault, pfec, addr);
                 return HVMCOPY_bad_gva_to_gfn;
@@ -1693,6 +1710,11 @@ static enum hvm_copy_result __hvm_copy(
 
         mfn = mfn_x(gfn_to_mfn_current(gfn, &p2mt));
 
+        if ( p2m_is_paging(p2mt) )
+        {
+            p2m_mem_paging_populate(curr->domain, gfn);
+            return HVMCOPY_gfn_paged_out;
+        }
         if ( p2m_is_grant(p2mt) )
             return HVMCOPY_unhandleable;
         if ( !p2m_is_ram(p2mt) )
diff -r 1165acfea711 -r 410eb65969cb xen/arch/x86/hvm/intercept.c
--- a/xen/arch/x86/hvm/intercept.c      Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/arch/x86/hvm/intercept.c      Thu Dec 17 06:27:55 2009 +0000
@@ -72,30 +72,31 @@ static int hvm_mmio_access(struct vcpu *
     {
         for ( i = 0; i < p->count; i++ )
         {
-            rc = read_handler(
-                v,
-                p->addr + (sign * i * p->size),
-                p->size, &data);
-            if ( rc != X86EMUL_OKAY )
-                break;
-            (void)hvm_copy_to_guest_phys(
-                p->data + (sign * i * p->size),
-                &data,
-                p->size);
+            rc = read_handler(v, p->addr + (sign * i * p->size), p->size,
+                              &data);
+            if ( rc != X86EMUL_OKAY )
+                break;
+            if ( hvm_copy_to_guest_phys(p->data + (sign * i * p->size), &data,
+                                        p->size) == HVMCOPY_gfn_paged_out )
+            {
+                rc = X86EMUL_RETRY;
+                break;
+            }
         }
     }
     else
     {
         for ( i = 0; i < p->count; i++ )
         {
-            (void)hvm_copy_from_guest_phys(
-                &data,
-                p->data + (sign * i * p->size),
-                p->size);
-            rc = write_handler(
-                v,
-                p->addr + (sign * i * p->size),
-                p->size, data);
+            if ( hvm_copy_from_guest_phys(&data,
+                                          p->data + (sign * i * p->size),
+                                          p->size) == HVMCOPY_gfn_paged_out )
+            {
+                rc = X86EMUL_RETRY;
+                break;
+            }
+            rc = write_handler(v, p->addr + (sign * i * p->size), p->size,
+                               data);
             if ( rc != X86EMUL_OKAY )
                 break;
         }
@@ -190,8 +191,12 @@ int hvm_io_intercept(ioreq_t *p, int typ
     int i;
     unsigned long addr, size;
 
-    if ( (type == HVM_PORTIO) && (dpci_ioport_intercept(p)) )
-        return X86EMUL_OKAY;
+    if ( type == HVM_PORTIO )
+    {
+        int rc = dpci_ioport_intercept(p);
+        if ( (rc == X86EMUL_OKAY) || (rc == X86EMUL_RETRY) )
+            return rc;
+    }
 
     for ( i = 0; i < handler->num_slot; i++ )
     {
diff -r 1165acfea711 -r 410eb65969cb xen/arch/x86/hvm/io.c
--- a/xen/arch/x86/hvm/io.c     Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/arch/x86/hvm/io.c     Thu Dec 17 06:27:55 2009 +0000
@@ -239,7 +239,7 @@ void hvm_io_assist(void)
         vcpu_end_shutdown_deferral(curr);
 }
 
-static void dpci_ioport_read(uint32_t mport, ioreq_t *p)
+static int dpci_ioport_read(uint32_t mport, ioreq_t *p)
 {
     int i, sign = p->df ? -1 : 1;
     uint32_t data = 0;
@@ -262,14 +262,19 @@ static void dpci_ioport_read(uint32_t mp
         }
 
         if ( p->data_is_ptr )
-            (void)hvm_copy_to_guest_phys(
-                p->data + (sign * i * p->size), &data, p->size);
+        {
+            if ( hvm_copy_to_guest_phys(p->data + (sign * i * p->size), &data,
+                                        p->size) ==  HVMCOPY_gfn_paged_out )
+                return X86EMUL_RETRY;
+        }
         else
             p->data = data;
     }
-}
-
-static void dpci_ioport_write(uint32_t mport, ioreq_t *p)
+    
+    return X86EMUL_OKAY;
+}
+
+static int dpci_ioport_write(uint32_t mport, ioreq_t *p)
 {
     int i, sign = p->df ? -1 : 1;
     uint32_t data;
@@ -278,8 +283,11 @@ static void dpci_ioport_write(uint32_t m
     {
         data = p->data;
         if ( p->data_is_ptr )
-            (void)hvm_copy_from_guest_phys(
-                &data, p->data + (sign * i * p->size), p->size);
+        {
+            if ( hvm_copy_from_guest_phys(&data, p->data + (sign * i * 
p->size),
+                                          p->size) ==  HVMCOPY_gfn_paged_out )
+                return X86EMUL_RETRY;
+        }
 
         switch ( p->size )
         {
@@ -296,6 +304,8 @@ static void dpci_ioport_write(uint32_t m
             BUG();
         }
     }
+
+    return X86EMUL_OKAY;
 }
 
 int dpci_ioport_intercept(ioreq_t *p)
@@ -305,6 +315,7 @@ int dpci_ioport_intercept(ioreq_t *p)
     struct g2m_ioport *g2m_ioport;
     unsigned int mport, gport = p->addr;
     unsigned int s = 0, e = 0;
+    int rc;
 
     list_for_each_entry( g2m_ioport, &hd->g2m_ioport_list, list )
     {
@@ -314,7 +325,7 @@ int dpci_ioport_intercept(ioreq_t *p)
             goto found;
     }
 
-    return 0;
+    return X86EMUL_UNHANDLEABLE;
 
  found:
     mport = (gport - s) + g2m_ioport->mport;
@@ -323,22 +334,23 @@ int dpci_ioport_intercept(ioreq_t *p)
     {
         gdprintk(XENLOG_ERR, "Error: access to gport=0x%x denied!\n",
                  (uint32_t)p->addr);
-        return 0;
+        return X86EMUL_UNHANDLEABLE;
     }
 
     switch ( p->dir )
     {
     case IOREQ_READ:
-        dpci_ioport_read(mport, p);
+        rc = dpci_ioport_read(mport, p);
         break;
     case IOREQ_WRITE:
-        dpci_ioport_write(mport, p);
+        rc = dpci_ioport_write(mport, p);
         break;
     default:
         gdprintk(XENLOG_ERR, "Error: couldn't handle p->dir = %d", p->dir);
-    }
-
-    return 1;
+        rc = X86EMUL_UNHANDLEABLE;
+    }
+
+    return rc;
 }
 
 /*
diff -r 1165acfea711 -r 410eb65969cb xen/include/asm-x86/hvm/support.h
--- a/xen/include/asm-x86/hvm/support.h Thu Dec 17 06:27:55 2009 +0000
+++ b/xen/include/asm-x86/hvm/support.h Thu Dec 17 06:27:55 2009 +0000
@@ -72,7 +72,8 @@ enum hvm_copy_result {
     HVMCOPY_okay = 0,
     HVMCOPY_bad_gva_to_gfn,
     HVMCOPY_bad_gfn_to_mfn,
-    HVMCOPY_unhandleable
+    HVMCOPY_unhandleable,
+    HVMCOPY_gfn_paged_out,
 };
 
 /*

_______________________________________________
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®.