[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |