[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v10 07/15] tools/libxc: x86 PV common code
Add functions common to save and restore of x86 PV guests. This includes functions for dealing with the P2M and M2P and the VCPU context. Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> Acked-by: Ian Campbell <Ian.Campbell@xxxxxxxxxx> CC: Ian Jackson <Ian.Jackson@xxxxxxxxxxxxx> CC: Wei Liu <wei.liu2@xxxxxxxxxx> --- tools/libxc/Makefile | 1 + tools/libxc/xc_sr_common_x86_pv.c | 210 +++++++++++++++++++++++++++++++++++++ tools/libxc/xc_sr_common_x86_pv.h | 102 ++++++++++++++++++ 3 files changed, 313 insertions(+) create mode 100644 tools/libxc/xc_sr_common_x86_pv.c create mode 100644 tools/libxc/xc_sr_common_x86_pv.h diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile index 5e12e9a..c2e62a8 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -56,6 +56,7 @@ ifeq ($(CONFIG_MIGRATE),y) GUEST_SRCS-y += xc_domain_restore.c xc_domain_save.c GUEST_SRCS-y += xc_sr_common.c GUEST_SRCS-$(CONFIG_X86) += xc_sr_common_x86.c +GUEST_SRCS-$(CONFIG_X86) += xc_sr_common_x86_pv.c GUEST_SRCS-y += xc_sr_restore.c GUEST_SRCS-y += xc_sr_save.c GUEST_SRCS-y += xc_offline_page.c xc_compression.c diff --git a/tools/libxc/xc_sr_common_x86_pv.c b/tools/libxc/xc_sr_common_x86_pv.c new file mode 100644 index 0000000..eb68c07 --- /dev/null +++ b/tools/libxc/xc_sr_common_x86_pv.c @@ -0,0 +1,210 @@ +#include <assert.h> + +#include "xc_sr_common_x86_pv.h" + +xen_pfn_t mfn_to_pfn(struct xc_sr_context *ctx, xen_pfn_t mfn) +{ + assert(mfn <= ctx->x86_pv.max_mfn); + return ctx->x86_pv.m2p[mfn]; +} + +bool mfn_in_pseudophysmap(struct xc_sr_context *ctx, xen_pfn_t mfn) +{ + return ( (mfn <= ctx->x86_pv.max_mfn) && + (mfn_to_pfn(ctx, mfn) <= ctx->x86_pv.max_pfn) && + (xc_pfn_to_mfn(mfn_to_pfn(ctx, mfn), ctx->x86_pv.p2m, + ctx->x86_pv.width) == mfn) ); +} + +void dump_bad_pseudophysmap_entry(struct xc_sr_context *ctx, xen_pfn_t mfn) +{ + xc_interface *xch = ctx->xch; + xen_pfn_t pfn = ~0UL; + + ERROR("mfn %#lx, max %#lx", mfn, ctx->x86_pv.max_mfn); + + if ( (mfn != ~0UL) && (mfn <= ctx->x86_pv.max_mfn) ) + { + pfn = ctx->x86_pv.m2p[mfn]; + ERROR(" m2p[%#lx] = %#lx, max_pfn %#lx", + mfn, pfn, ctx->x86_pv.max_pfn); + } + + if ( (pfn != ~0UL) && (pfn <= ctx->x86_pv.max_pfn) ) + ERROR(" p2m[%#lx] = %#lx", + pfn, xc_pfn_to_mfn(pfn, ctx->x86_pv.p2m, ctx->x86_pv.width)); +} + +xen_pfn_t cr3_to_mfn(struct xc_sr_context *ctx, uint64_t cr3) +{ + if ( ctx->x86_pv.width == 8 ) + return cr3 >> 12; + else + { + /* 32bit guests can't represent mfns wider than 32 bits */ + if ( cr3 & 0xffffffff00000000UL ) + return ~0UL; + else + return (uint32_t)((cr3 >> 12) | (cr3 << 20)); + } +} + +uint64_t mfn_to_cr3(struct xc_sr_context *ctx, xen_pfn_t _mfn) +{ + uint64_t mfn = _mfn; + + if ( ctx->x86_pv.width == 8 ) + return mfn << 12; + else + { + /* 32bit guests can't represent mfns wider than 32 bits */ + if ( mfn & 0xffffffff00000000UL ) + return ~0UL; + else + return (uint32_t)((mfn << 12) | (mfn >> 20)); + } +} + +int x86_pv_domain_info(struct xc_sr_context *ctx) +{ + xc_interface *xch = ctx->xch; + unsigned int guest_width, guest_levels, fpp; + xen_pfn_t max_pfn; + + /* Get the domain width */ + if ( xc_domain_get_guest_width(xch, ctx->domid, &guest_width) ) + { + PERROR("Unable to determine dom%d's width", ctx->domid); + return -1; + } + + if ( guest_width == 4 ) + guest_levels = 3; + else if ( guest_width == 8 ) + guest_levels = 4; + else + { + ERROR("Invalid guest width %d. Expected 32 or 64", guest_width * 8); + return -1; + } + ctx->x86_pv.width = guest_width; + ctx->x86_pv.levels = guest_levels; + fpp = PAGE_SIZE / ctx->x86_pv.width; + + DPRINTF("%d bits, %d levels", guest_width * 8, guest_levels); + + /* Get the domain's size */ + if ( xc_domain_maximum_gpfn(xch, ctx->domid, &max_pfn) < 0 ) + { + PERROR("Unable to obtain guests max pfn"); + return -1; + } + + if ( max_pfn > 0 ) + { + ctx->x86_pv.max_pfn = max_pfn; + ctx->x86_pv.p2m_frames = (ctx->x86_pv.max_pfn + fpp) / fpp; + + DPRINTF("max_pfn %#lx, p2m_frames %d", max_pfn, ctx->x86_pv.p2m_frames); + } + + return 0; +} + +int x86_pv_map_m2p(struct xc_sr_context *ctx) +{ + xc_interface *xch = ctx->xch; + xen_pfn_t m2p_chunks, m2p_size, max_page; + privcmd_mmap_entry_t *entries = NULL; + xen_pfn_t *extents_start = NULL; + int rc = -1, i; + + if ( xc_maximum_ram_page(xch, &max_page) < 0 ) + { + PERROR("Failed to get maximum ram page"); + goto err; + } + + ctx->x86_pv.max_mfn = max_page; + m2p_size = M2P_SIZE(ctx->x86_pv.max_mfn); + m2p_chunks = M2P_CHUNKS(ctx->x86_pv.max_mfn); + + extents_start = malloc(m2p_chunks * sizeof(xen_pfn_t)); + if ( !extents_start ) + { + ERROR("Unable to allocate %lu bytes for m2p mfns", + m2p_chunks * sizeof(xen_pfn_t)); + goto err; + } + + if ( xc_machphys_mfn_list(xch, m2p_chunks, extents_start) ) + { + PERROR("Failed to get m2p mfn list"); + goto err; + } + + entries = malloc(m2p_chunks * sizeof(privcmd_mmap_entry_t)); + if ( !entries ) + { + ERROR("Unable to allocate %lu bytes for m2p mapping mfns", + m2p_chunks * sizeof(privcmd_mmap_entry_t)); + goto err; + } + + for ( i = 0; i < m2p_chunks; ++i ) + entries[i].mfn = extents_start[i]; + + ctx->x86_pv.m2p = xc_map_foreign_ranges( + xch, DOMID_XEN, m2p_size, PROT_READ, + M2P_CHUNK_SIZE, entries, m2p_chunks); + + if ( !ctx->x86_pv.m2p ) + { + PERROR("Failed to mmap() m2p ranges"); + goto err; + } + + ctx->x86_pv.nr_m2p_frames = (M2P_CHUNK_SIZE >> PAGE_SHIFT) * m2p_chunks; + +#ifdef __i386__ + /* 32 bit toolstacks automatically get the compat m2p */ + ctx->x86_pv.compat_m2p_mfn0 = entries[0].mfn; +#else + /* 64 bit toolstacks need to ask Xen specially for it */ + { + struct xen_machphys_mfn_list xmml = { + .max_extents = 1, + .extent_start = { &ctx->x86_pv.compat_m2p_mfn0 } + }; + + rc = do_memory_op(xch, XENMEM_machphys_compat_mfn_list, + &xmml, sizeof(xmml)); + if ( rc || xmml.nr_extents != 1 ) + { + PERROR("Failed to get compat mfn list from Xen"); + rc = -1; + goto err; + } + } +#endif + + /* All Done */ + rc = 0; + DPRINTF("max_mfn %#lx", ctx->x86_pv.max_mfn); + +err: + free(entries); + free(extents_start); + + return rc; +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tools/libxc/xc_sr_common_x86_pv.h b/tools/libxc/xc_sr_common_x86_pv.h new file mode 100644 index 0000000..3234944 --- /dev/null +++ b/tools/libxc/xc_sr_common_x86_pv.h @@ -0,0 +1,102 @@ +#ifndef __COMMON_X86_PV_H +#define __COMMON_X86_PV_H + +#include "xc_sr_common_x86.h" + +/* + * Convert an mfn to a pfn, given Xen's m2p table. + * + * Caller must ensure that the requested mfn is in range. + */ +xen_pfn_t mfn_to_pfn(struct xc_sr_context *ctx, xen_pfn_t mfn); + +/* + * Query whether a particular mfn is valid in the physmap of a guest. + */ +bool mfn_in_pseudophysmap(struct xc_sr_context *ctx, xen_pfn_t mfn); + +/* + * Debug a particular mfn by walking the p2m and m2p. + */ +void dump_bad_pseudophysmap_entry(struct xc_sr_context *ctx, xen_pfn_t mfn); + +/* + * Convert a PV cr3 field to an mfn. + * + * Adjusts for Xen's extended-cr3 format to pack a 44bit physical address into + * a 32bit architectural cr3. + */ +xen_pfn_t cr3_to_mfn(struct xc_sr_context *ctx, uint64_t cr3); + +/* + * Convert an mfn to a PV cr3 field. + * + * Adjusts for Xen's extended-cr3 format to pack a 44bit physical address into + * a 32bit architectural cr3. + */ +uint64_t mfn_to_cr3(struct xc_sr_context *ctx, xen_pfn_t mfn); + +/* Bits 12 through 51 of a PTE point at the frame */ +#define PTE_FRAME_MASK 0x000ffffffffff000ULL + +/* + * Extract an mfn from a Pagetable Entry. May return INVALID_MFN if the pte + * would overflow a 32bit xen_pfn_t. + */ +static inline xen_pfn_t pte_to_frame(uint64_t pte) +{ + uint64_t frame = (pte & PTE_FRAME_MASK) >> PAGE_SHIFT; + +#ifdef __i386__ + if ( frame >= INVALID_MFN ) + return INVALID_MFN; +#endif + + return frame; +} + +/* + * Change the frame in a Pagetable Entry while leaving the flags alone. + */ +static inline uint64_t merge_pte(uint64_t pte, xen_pfn_t mfn) +{ + return (pte & ~PTE_FRAME_MASK) | ((uint64_t)mfn << PAGE_SHIFT); +} + +/* + * Get current domain information. + * + * Fills ctx->x86_pv + * - .width + * - .levels + * - .fpp + * - .p2m_frames + * + * Used by the save side to create the X86_PV_INFO record, and by the restore + * side to verify the incoming stream. + * + * Returns 0 on success and non-zero on error. + */ +int x86_pv_domain_info(struct xc_sr_context *ctx); + +/* + * Maps the Xen M2P. + * + * Fills ctx->x86_pv. + * - .max_mfn + * - .m2p + * + * Returns 0 on success and non-zero on error. + */ +int x86_pv_map_m2p(struct xc_sr_context *ctx); + +#endif +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ -- 1.7.10.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |