# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1203344025 0
# Node ID 630a044658f47804b2bd83a03f1dc7ee28df0ecf
# Parent 53c5a4af744e87998b5776403e0a97bd3266f276
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>
xen-unstable changeset: 17036:0164d924cebacfef62673a49c2f4ad395df5444b
xen-unstable date: Wed Feb 13 10:43:13 2008 +0000
---
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 53c5a4af744e -r 630a044658f4 tools/libxc/xc_domain_restore.c
--- a/tools/libxc/xc_domain_restore.c Mon Feb 18 14:13:15 2008 +0000
+++ b/tools/libxc/xc_domain_restore.c Mon Feb 18 14:13:45 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 53c5a4af744e -r 630a044658f4 tools/libxc/xc_domain_save.c
--- a/tools/libxc/xc_domain_save.c Mon Feb 18 14:13:15 2008 +0000
+++ b/tools/libxc/xc_domain_save.c Mon Feb 18 14:13:45 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 53c5a4af744e -r 630a044658f4 tools/libxc/xg_private.h
--- a/tools/libxc/xg_private.h Mon Feb 18 14:13:15 2008 +0000
+++ b/tools/libxc/xg_private.h Mon Feb 18 14:13:45 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 53c5a4af744e -r 630a044658f4 tools/libxc/xg_save_restore.h
--- a/tools/libxc/xg_save_restore.h Mon Feb 18 14:13:15 2008 +0000
+++ b/tools/libxc/xg_save_restore.h Mon Feb 18 14:13:45 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
|