236 lines
11 KiB
Diff
236 lines
11 KiB
Diff
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# 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@citrix.com>
|
|
|
|
Index: xen-3.2-testing/tools/libxc/xc_domain_restore.c
|
|
===================================================================
|
|
--- xen-3.2-testing.orig/tools/libxc/xc_domain_restore.c
|
|
+++ xen-3.2-testing/tools/libxc/xc_domain_restore.c
|
|
@@ -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];
|
|
|
|
Index: xen-3.2-testing/tools/libxc/xc_domain_save.c
|
|
===================================================================
|
|
--- xen-3.2-testing.orig/tools/libxc/xc_domain_save.c
|
|
+++ xen-3.2-testing/tools/libxc/xc_domain_save.c
|
|
@@ -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)
|
|
Index: xen-3.2-testing/tools/libxc/xg_private.h
|
|
===================================================================
|
|
--- xen-3.2-testing.orig/tools/libxc/xg_private.h
|
|
+++ xen-3.2-testing/tools/libxc/xg_private.h
|
|
@@ -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)
|
|
Index: xen-3.2-testing/tools/libxc/xg_save_restore.h
|
|
===================================================================
|
|
--- xen-3.2-testing.orig/tools/libxc/xg_save_restore.h
|
|
+++ xen-3.2-testing/tools/libxc/xg_save_restore.h
|
|
@@ -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)); \
|