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

[Xen-changelog] [xen-unstable] Tools: fix save/restore of 32-bit PV guests with 64-bit tools



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1202899393 0
# Node ID 0164d924cebacfef62673a49c2f4ad395df5444b
# Parent  27314cfbcefe8ee261da3ea827eb8336c32ad987
Tools: fix save/restore of 32-bit PV guests with 64-bit tools
by removing some obvious typos, handling CR3 folding and hvirt_start
based on guest word-size, and understanding 32-bit INVALID_MFN.

Signed-off-by: Tim Deegan <Tim.Deegan@xxxxxxxxxx>
---
 tools/libxc/xc_domain_restore.c |   12 +++++-----
 tools/libxc/xc_domain_save.c    |   48 ++++++++++++++++++++--------------------
 tools/libxc/xg_private.h        |    4 ++-
 tools/libxc/xg_save_restore.h   |   17 ++++++++++++++
 4 files changed, 51 insertions(+), 30 deletions(-)

diff -r 27314cfbcefe -r 0164d924ceba tools/libxc/xc_domain_restore.c
--- a/tools/libxc/xc_domain_restore.c   Wed Feb 13 10:42:09 2008 +0000
+++ b/tools/libxc/xc_domain_restore.c   Wed Feb 13 10:43:13 2008 +0000
@@ -251,7 +251,7 @@ static xen_pfn_t *load_p2m_frame_list(
 
     /* Now that we know the guest's word-size, can safely allocate 
      * the p2m frame list */
-    if ( (p2m_frame_list = malloc(P2M_FL_SIZE)) == NULL )
+    if ( (p2m_frame_list = malloc(P2M_TOOLS_FL_SIZE)) == NULL )
     {
         ERROR("Couldn't allocate p2m_frame_list array");
         return NULL;
@@ -1040,7 +1040,7 @@ int xc_domain_restore(int xc_handle, int
             SET_FIELD(&ctxt, gdt_frames[j], p2m[pfn]);
         }
         /* Uncanonicalise the page table base pointer. */
-        pfn = xen_cr3_to_pfn(GET_FIELD(&ctxt, ctrlreg[3]));
+        pfn = UNFOLD_CR3(GET_FIELD(&ctxt, ctrlreg[3]));
 
         if ( pfn >= p2m_size )
         {
@@ -1057,12 +1057,12 @@ int xc_domain_restore(int xc_handle, int
                   (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
             goto out;
         }
-        SET_FIELD(&ctxt, ctrlreg[3], xen_pfn_to_cr3(p2m[pfn]));
+        SET_FIELD(&ctxt, ctrlreg[3], FOLD_CR3(p2m[pfn]));
 
         /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */
         if ( (pt_levels == 4) && (ctxt.x64.ctrlreg[1] & 1) )
         {
-            pfn = xen_cr3_to_pfn(ctxt.x64.ctrlreg[1] & ~1);
+            pfn = UNFOLD_CR3(ctxt.x64.ctrlreg[1] & ~1);
             if ( pfn >= p2m_size )
             {
                 ERROR("User PT base is bad: pfn=%lu p2m_size=%lu",
@@ -1077,7 +1077,7 @@ int xc_domain_restore(int xc_handle, int
                       (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
                 goto out;
             }
-            ctxt.x64.ctrlreg[1] = xen_pfn_to_cr3(p2m[pfn]);
+            ctxt.x64.ctrlreg[1] = FOLD_CR3(p2m[pfn]);
         }
         domctl.cmd = XEN_DOMCTL_setvcpucontext;
         domctl.domain = (domid_t)dom;
@@ -1158,7 +1158,7 @@ int xc_domain_restore(int xc_handle, int
     if ( guest_width > sizeof (xen_pfn_t) )
         for ( i = p2m_size - 1; i >= 0; i-- )
             ((uint64_t *)p2m)[i] = p2m[i];
-    else if ( guest_width > sizeof (xen_pfn_t) )
+    else if ( guest_width < sizeof (xen_pfn_t) )
         for ( i = 0; i < p2m_size; i++ )   
             ((uint32_t *)p2m)[i] = p2m[i];
 
diff -r 27314cfbcefe -r 0164d924ceba tools/libxc/xc_domain_save.c
--- a/tools/libxc/xc_domain_save.c      Wed Feb 13 10:42:09 2008 +0000
+++ b/tools/libxc/xc_domain_save.c      Wed Feb 13 10:43:13 2008 +0000
@@ -61,10 +61,11 @@ unsigned int guest_width;
 
 #define mfn_to_pfn(_mfn)  (live_m2p[(_mfn)])
 
-#define pfn_to_mfn(_pfn)                                \
-  ((xen_pfn_t) ((guest_width==8)                       \
-                ? (((uint64_t *)live_p2m)[(_pfn)])      \
-                : (((uint32_t *)live_p2m)[(_pfn)])))
+#define pfn_to_mfn(_pfn)                                            \
+  ((xen_pfn_t) ((guest_width==8)                                    \
+                ? (((uint64_t *)live_p2m)[(_pfn)])                  \
+                : ((((uint32_t *)live_p2m)[(_pfn)]) == 0xffffffffU  \
+                   ? (-1UL) : (((uint32_t *)live_p2m)[(_pfn)]))))
 
 /*
  * Returns TRUE if the given machine frame number has a unique mapping
@@ -496,10 +497,9 @@ static int canonicalize_pagetable(unsign
         xen_start = L3_PAGETABLE_ENTRIES_PAE;
 
     /*
-    ** in PAE only the L2 mapping the top 1GB contains Xen mappings.
-    ** We can spot this by looking for the guest linear mapping which
-    ** Xen always ensures is present in that L2. Guests must ensure
-    ** that this check will fail for other L2s.
+    ** In PAE only the L2 mapping the top 1GB contains Xen mappings.
+    ** We can spot this by looking for the guest's mappingof the m2p.
+    ** Guests must ensure that this check will fail for other L2s.
     */
     if ( (pt_levels == 3) && (type == XEN_DOMCTL_PFINFO_L2TAB) )
     {
@@ -555,7 +555,13 @@ static int canonicalize_pagetable(unsign
                 /* This will happen if the type info is stale which
                    is quite feasible under live migration */
                 pfn  = 0;  /* zap it - we'll retransmit this page later */
-                race = 1;  /* inform the caller of race; fatal if !live */ 
+                /* XXX: We can't spot Xen mappings in compat-mode L2es 
+                 * from 64-bit tools, but the only thing in them is the
+                 * compat m2p, so we quietly zap them.  This doesn't
+                 * count as a race, so don't report it. */
+                if ( !(type == XEN_DOMCTL_PFINFO_L2TAB 
+                       && sizeof (unsigned long) > guest_width) )
+                     race = 1;  /* inform the caller; fatal if !live */ 
             }
             else
                 pfn = mfn_to_pfn(mfn);
@@ -690,7 +696,7 @@ static xen_pfn_t *map_and_save_p2m_table
             else
                 p2m_frame_list_list[i] = 0;
     else if ( guest_width < sizeof(unsigned long) )
-        for ( i = PAGE_SIZE/sizeof(unsigned long) - 1; i >= 0; i++ )
+        for ( i = PAGE_SIZE/sizeof(unsigned long) - 1; i >= 0; i-- )
             p2m_frame_list_list[i] = ((uint32_t *)p2m_frame_list_list)[i];
 
     live_p2m_frame_list =
@@ -704,19 +710,20 @@ static xen_pfn_t *map_and_save_p2m_table
     }
 
     /* Get a local copy of the live_P2M_frame_list */
-    if ( !(p2m_frame_list = malloc(P2M_FL_SIZE)) )
+    if ( !(p2m_frame_list = malloc(P2M_TOOLS_FL_SIZE)) )
     {
         ERROR("Couldn't allocate p2m_frame_list array");
         goto out;
     }
-    memcpy(p2m_frame_list, live_p2m_frame_list, P2M_FL_SIZE);
+    memset(p2m_frame_list, 0, P2M_TOOLS_FL_SIZE);
+    memcpy(p2m_frame_list, live_p2m_frame_list, P2M_GUEST_FL_SIZE);
 
     /* Canonicalize guest's unsigned long vs ours */
     if ( guest_width > sizeof(unsigned long) )
         for ( i = 0; i < P2M_FL_ENTRIES; i++ )
             p2m_frame_list[i] = ((uint64_t *)p2m_frame_list)[i];
     else if ( guest_width < sizeof(unsigned long) )
-        for ( i = P2M_FL_ENTRIES - 1; i >= 0; i++ )
+        for ( i = P2M_FL_ENTRIES - 1; i >= 0; i-- )
             p2m_frame_list[i] = ((uint32_t *)p2m_frame_list)[i];
 
 
@@ -1559,31 +1566,26 @@ int xc_domain_save(int xc_handle, int io
         }
 
         /* Canonicalise the page table base pointer. */
-        if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(
-                                          GET_FIELD(&ctxt, ctrlreg[3]))) )
+        if ( !MFN_IS_IN_PSEUDOPHYS_MAP(UNFOLD_CR3(
+                                           GET_FIELD(&ctxt, ctrlreg[3]))) )
         {
             ERROR("PT base is not in range of pseudophys map");
             goto out;
         }
         SET_FIELD(&ctxt, ctrlreg[3], 
-            xen_pfn_to_cr3(
-                mfn_to_pfn(
-                    xen_cr3_to_pfn(
-                        GET_FIELD(&ctxt, ctrlreg[3])))));
+            FOLD_CR3(mfn_to_pfn(UNFOLD_CR3(GET_FIELD(&ctxt, ctrlreg[3])))));
 
         /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */
         if ( (pt_levels == 4) && ctxt.x64.ctrlreg[1] )
         {
-            if ( !MFN_IS_IN_PSEUDOPHYS_MAP(
-                     xen_cr3_to_pfn(ctxt.x64.ctrlreg[1])) )
+            if ( !MFN_IS_IN_PSEUDOPHYS_MAP(UNFOLD_CR3(ctxt.x64.ctrlreg[1])) )
             {
                 ERROR("PT base is not in range of pseudophys map");
                 goto out;
             }
             /* Least-significant bit means 'valid PFN'. */
             ctxt.x64.ctrlreg[1] = 1 |
-                xen_pfn_to_cr3(
-                    mfn_to_pfn(xen_cr3_to_pfn(ctxt.x64.ctrlreg[1])));
+                FOLD_CR3(mfn_to_pfn(UNFOLD_CR3(ctxt.x64.ctrlreg[1])));
         }
 
         if ( write_exact(io_fd, &ctxt, ((guest_width==8) 
diff -r 27314cfbcefe -r 0164d924ceba tools/libxc/xg_private.h
--- a/tools/libxc/xg_private.h  Wed Feb 13 10:42:09 2008 +0000
+++ b/tools/libxc/xg_private.h  Wed Feb 13 10:43:13 2008 +0000
@@ -155,7 +155,9 @@ typedef l4_pgentry_64_t l4_pgentry_t;
 #define P2M_FL_ENTRIES  (((p2m_size)+FPP-1)/FPP)
 
 /* Size in bytes of the pfn_to_mfn_frame_list     */
-#define P2M_FL_SIZE     ((P2M_FL_ENTRIES)*(guest_width))
+#define P2M_GUEST_FL_SIZE ((P2M_FL_ENTRIES) * (guest_width))
+#define P2M_TOOLS_FL_SIZE ((P2M_FL_ENTRIES) *                           \
+                           MAX((sizeof (xen_pfn_t)), guest_width))
 
 /* Masks for PTE<->PFN conversions */
 #define MADDR_BITS_X86  ((guest_width == 8) ? 52 : 44)
diff -r 27314cfbcefe -r 0164d924ceba tools/libxc/xg_save_restore.h
--- a/tools/libxc/xg_save_restore.h     Wed Feb 13 10:42:09 2008 +0000
+++ b/tools/libxc/xg_save_restore.h     Wed Feb 13 10:43:13 2008 +0000
@@ -68,6 +68,13 @@ static inline int get_platform_info(int 
 
     *guest_width = domctl.u.address_size.size / 8;
 
+    /* 64-bit tools will see the 64-bit hvirt_start, but 32-bit guests 
+     * will be using the compat one. */
+    if ( *guest_width < sizeof (unsigned long) )
+        /* XXX need to fix up a way of extracting this value from Xen if
+         * XXX it becomes variable for domU */
+        *hvirt_start = 0xf5800000;
+
     if (strstr(xen_caps, "xen-3.0-x86_64"))
         /* Depends on whether it's a compat 32-on-64 guest */
         *pt_levels = ( (*guest_width == 8) ? 4 : 3 );
@@ -136,6 +143,16 @@ typedef union
         (_p)->x32._f = (_v);                    \
 } while (0)
 
+#define UNFOLD_CR3(_c)                                                  \
+  ((uint64_t)((guest_width == 8)                                        \
+              ? ((_c) >> 12)                                            \
+              : (((uint32_t)(_c) >> 12) | ((uint32_t)(_c) << 20))))
+
+#define FOLD_CR3(_c)                                                    \
+  ((uint64_t)((guest_width == 8)                                        \
+              ? ((uint64_t)(_c)) << 12                                  \
+              : (((uint32_t)(_c) << 12) | ((uint32_t)(_c) >> 20))))
+
 #define MEMCPY_FIELD(_d, _s, _f) do {                              \
     if (guest_width == 8)                                          \
         memcpy(&(_d)->x64._f, &(_s)->x64._f,sizeof((_d)->x64._f)); \

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