mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
[TOOLS] Make xc_domain_{save, restore} understand compat guests
Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
This commit is contained in:
1 parent
72f379b5b2
commit
120bafda14
7 files changed
+365
-214
No files matched your search
@@ -58,6 +58,9 @@
|
||||
/* number of pages to write at a time */
|
||||
#define DUMP_INCREMENT (4 * 1024)
|
||||
|
||||
/* Don't yet support cross-address-size core dump */
|
||||
#define guest_width (sizeof (unsigned long))
|
||||
|
||||
/* string table */
|
||||
struct xc_core_strtab {
|
||||
char *strings;
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
#include "xg_private.h"
|
||||
#include "xc_core.h"
|
||||
|
||||
/* Don't yet support cross-address-size core dump */
|
||||
#define guest_width (sizeof (unsigned long))
|
||||
|
||||
static int nr_gpfns(int xc_handle, domid_t domid)
|
||||
{
|
||||
return xc_memory_op(xc_handle, XENMEM_maximum_gpfn, &domid) + 1;
|
||||
|
||||
+127
-101
@@ -56,6 +56,10 @@ static xen_pfn_t *p2m = NULL;
|
||||
/* A table of P2M mappings in the current region */
|
||||
static xen_pfn_t *p2m_batch = NULL;
|
||||
|
||||
/* Address size of the guest, in bytes */
|
||||
unsigned int guest_width;
|
||||
|
||||
|
||||
static ssize_t
|
||||
read_exact(int fd, void *buf, size_t count)
|
||||
{
|
||||
@@ -168,22 +172,17 @@ static int uncanonicalize_pagetable(int xc_handle, uint32_t dom,
|
||||
static xen_pfn_t *load_p2m_frame_list(int io_fd, int *pae_extended_cr3)
|
||||
{
|
||||
xen_pfn_t *p2m_frame_list;
|
||||
vcpu_guest_context_t ctxt;
|
||||
vcpu_guest_context_either_t ctxt;
|
||||
xen_pfn_t p2m_fl_zero;
|
||||
|
||||
if ( (p2m_frame_list = malloc(P2M_FL_SIZE)) == NULL )
|
||||
{
|
||||
ERROR("Couldn't allocate p2m_frame_list array");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read first entry of P2M list, or extended-info signature (~0UL). */
|
||||
if ( !read_exact(io_fd, p2m_frame_list, sizeof(long)) )
|
||||
if ( !read_exact(io_fd, &p2m_fl_zero, sizeof(long)) )
|
||||
{
|
||||
ERROR("read extended-info signature failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( p2m_frame_list[0] == ~0UL )
|
||||
if ( p2m_fl_zero == ~0UL )
|
||||
{
|
||||
uint32_t tot_bytes;
|
||||
|
||||
@@ -211,25 +210,42 @@ static xen_pfn_t *load_p2m_frame_list(int io_fd, int *pae_extended_cr3)
|
||||
/* VCPU context structure? */
|
||||
if ( !strncmp(chunk_sig, "vcpu", 4) )
|
||||
{
|
||||
if ( !read_exact(io_fd, &ctxt, sizeof(ctxt)) )
|
||||
/* Pick a guest word-size and PT depth from the ctxt size */
|
||||
if ( chunk_bytes == sizeof (ctxt.x32) )
|
||||
{
|
||||
guest_width = 4;
|
||||
if ( pt_levels > 2 )
|
||||
pt_levels = 3;
|
||||
}
|
||||
else if ( chunk_bytes == sizeof (ctxt.x64) )
|
||||
{
|
||||
guest_width = 8;
|
||||
pt_levels = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR("bad extended-info context size %d", chunk_bytes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( !read_exact(io_fd, &ctxt, chunk_bytes) )
|
||||
{
|
||||
ERROR("read extended-info vcpu context failed");
|
||||
return NULL;
|
||||
}
|
||||
tot_bytes -= sizeof(struct vcpu_guest_context);
|
||||
chunk_bytes -= sizeof(struct vcpu_guest_context);
|
||||
|
||||
if ( ctxt.vm_assist & (1UL << VMASST_TYPE_pae_extended_cr3) )
|
||||
tot_bytes -= chunk_bytes;
|
||||
chunk_bytes = 0;
|
||||
|
||||
if ( GET_FIELD(&ctxt, vm_assist)
|
||||
& (1UL << VMASST_TYPE_pae_extended_cr3) )
|
||||
*pae_extended_cr3 = 1;
|
||||
}
|
||||
|
||||
/* Any remaining bytes of this chunk: read and discard. */
|
||||
while ( chunk_bytes )
|
||||
{
|
||||
unsigned long sz = chunk_bytes;
|
||||
if ( sz > P2M_FL_SIZE )
|
||||
sz = P2M_FL_SIZE;
|
||||
if ( !read_exact(io_fd, p2m_frame_list, sz) )
|
||||
unsigned long sz = MIN(chunk_bytes, sizeof(xen_pfn_t));
|
||||
if ( !read_exact(io_fd, &p2m_fl_zero, sz) )
|
||||
{
|
||||
ERROR("read-and-discard extended-info chunk bytes failed");
|
||||
return NULL;
|
||||
@@ -240,15 +256,25 @@ static xen_pfn_t *load_p2m_frame_list(int io_fd, int *pae_extended_cr3)
|
||||
}
|
||||
|
||||
/* Now read the real first entry of P2M list. */
|
||||
if ( !read_exact(io_fd, p2m_frame_list, sizeof(long)) )
|
||||
if ( !read_exact(io_fd, &p2m_fl_zero, sizeof(xen_pfn_t)) )
|
||||
{
|
||||
ERROR("read first entry of p2m_frame_list failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* First entry is already read into the p2m array. */
|
||||
if ( !read_exact(io_fd, &p2m_frame_list[1], P2M_FL_SIZE - sizeof(long)) )
|
||||
/* 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 )
|
||||
{
|
||||
ERROR("Couldn't allocate p2m_frame_list array");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* First entry has already been read. */
|
||||
p2m_frame_list[0] = p2m_fl_zero;
|
||||
if ( !read_exact(io_fd, &p2m_frame_list[1],
|
||||
(P2M_FL_ENTRIES - 1) * sizeof(xen_pfn_t)) )
|
||||
{
|
||||
ERROR("read p2m_frame_list failed");
|
||||
return NULL;
|
||||
@@ -272,11 +298,11 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
|
||||
/* The new domain's shared-info frame number. */
|
||||
unsigned long shared_info_frame;
|
||||
unsigned char shared_info_page[PAGE_SIZE]; /* saved contents from file */
|
||||
shared_info_t *old_shared_info = (shared_info_t *)shared_info_page;
|
||||
shared_info_t *new_shared_info;
|
||||
shared_info_either_t *old_shared_info = (shared_info_either_t *)shared_info_page;
|
||||
shared_info_either_t *new_shared_info;
|
||||
|
||||
/* A copy of the CPU context of the guest. */
|
||||
vcpu_guest_context_t ctxt;
|
||||
vcpu_guest_context_either_t ctxt;
|
||||
|
||||
/* A table containing the type of each PFN (/not/ MFN!). */
|
||||
unsigned long *pfn_type = NULL;
|
||||
@@ -291,7 +317,7 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
|
||||
xen_pfn_t *p2m_frame_list = NULL;
|
||||
|
||||
/* A temporary mapping of the guest's start_info page. */
|
||||
start_info_t *start_info;
|
||||
start_info_either_t *start_info;
|
||||
|
||||
/* Our mapping of the current region (batch) */
|
||||
char *region_base;
|
||||
@@ -324,16 +350,38 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
|
||||
}
|
||||
DPRINTF("xc_domain_restore start: p2m_size = %lx\n", p2m_size);
|
||||
|
||||
if ( !hvm )
|
||||
if ( !get_platform_info(xc_handle, dom,
|
||||
&max_mfn, &hvirt_start, &pt_levels, &guest_width) )
|
||||
{
|
||||
/*
|
||||
* XXX For now, 32bit dom0's can only save/restore 32bit domUs
|
||||
* on 64bit hypervisors.
|
||||
*/
|
||||
ERROR("Unable to get platform info.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* The *current* word size of the guest isn't very interesting; for now
|
||||
* assume the guest will be the same as we are. We'll fix that later
|
||||
* if we discover otherwise. */
|
||||
guest_width = sizeof(unsigned long);
|
||||
pt_levels = (guest_width == 8) ? 4 : (pt_levels == 2) ? 2 : 3;
|
||||
|
||||
if ( lock_pages(&ctxt, sizeof(ctxt)) )
|
||||
{
|
||||
/* needed for build domctl, but might as well do early */
|
||||
ERROR("Unable to lock ctxt");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( !hvm )
|
||||
{
|
||||
/* Load the p2m frame list, plus potential extended info chunk */
|
||||
p2m_frame_list = load_p2m_frame_list(io_fd, &pae_extended_cr3);
|
||||
if ( !p2m_frame_list )
|
||||
goto out;
|
||||
|
||||
/* Now that we know the word size, tell Xen about it */
|
||||
memset(&domctl, 0, sizeof(domctl));
|
||||
domctl.domain = dom;
|
||||
domctl.cmd = XEN_DOMCTL_set_address_size;
|
||||
domctl.u.address_size.size = sizeof(unsigned long) * 8;
|
||||
domctl.u.address_size.size = guest_width * 8;
|
||||
rc = do_domctl(xc_handle, &domctl);
|
||||
if ( rc != 0 )
|
||||
{
|
||||
@@ -343,30 +391,8 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
if ( !get_platform_info(xc_handle, dom,
|
||||
&max_mfn, &hvirt_start, &pt_levels) )
|
||||
{
|
||||
ERROR("Unable to get platform info.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( lock_pages(&ctxt, sizeof(ctxt)) )
|
||||
{
|
||||
/* needed for build domctl, but might as well do early */
|
||||
ERROR("Unable to lock ctxt");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Load the p2m frame list, plus potential extended info chunk */
|
||||
if ( !hvm )
|
||||
{
|
||||
p2m_frame_list = load_p2m_frame_list(io_fd, &pae_extended_cr3);
|
||||
if ( !p2m_frame_list )
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We want zeroed memory so use calloc rather than malloc. */
|
||||
p2m = calloc(p2m_size, sizeof(xen_pfn_t));
|
||||
p2m = calloc(p2m_size, MAX(guest_width, sizeof (xen_pfn_t)));
|
||||
pfn_type = calloc(p2m_size, sizeof(unsigned long));
|
||||
region_mfn = calloc(MAX_BATCH_SIZE, sizeof(xen_pfn_t));
|
||||
p2m_batch = calloc(MAX_BATCH_SIZE, sizeof(xen_pfn_t));
|
||||
@@ -963,14 +989,16 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
|
||||
if ( !(vcpumap & (1ULL << i)) )
|
||||
continue;
|
||||
|
||||
if ( !read_exact(io_fd, &ctxt, sizeof(ctxt)) )
|
||||
if ( !read_exact(io_fd, &ctxt, ((guest_width == 8)
|
||||
? sizeof(ctxt.x64)
|
||||
: sizeof(ctxt.x32))) )
|
||||
{
|
||||
ERROR("Error when reading ctxt %d", i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( !new_ctxt_format )
|
||||
ctxt.flags |= VGCF_online;
|
||||
SET_FIELD(&ctxt, flags, GET_FIELD(&ctxt, flags) | VGCF_online);
|
||||
|
||||
if ( i == 0 )
|
||||
{
|
||||
@@ -978,48 +1006,49 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
|
||||
* Uncanonicalise the suspend-record frame number and poke
|
||||
* resume record.
|
||||
*/
|
||||
pfn = ctxt.user_regs.edx;
|
||||
pfn = GET_FIELD(&ctxt, user_regs.edx);
|
||||
if ( (pfn >= p2m_size) ||
|
||||
(pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB) )
|
||||
{
|
||||
ERROR("Suspend record frame number is bad");
|
||||
goto out;
|
||||
}
|
||||
ctxt.user_regs.edx = mfn = p2m[pfn];
|
||||
mfn = p2m[pfn];
|
||||
SET_FIELD(&ctxt, user_regs.edx, mfn);
|
||||
start_info = xc_map_foreign_range(
|
||||
xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
|
||||
start_info->nr_pages = p2m_size;
|
||||
start_info->shared_info = shared_info_frame << PAGE_SHIFT;
|
||||
start_info->flags = 0;
|
||||
*store_mfn = start_info->store_mfn = p2m[start_info->store_mfn];
|
||||
start_info->store_evtchn = store_evtchn;
|
||||
start_info->console.domU.mfn = p2m[start_info->console.domU.mfn];
|
||||
start_info->console.domU.evtchn = console_evtchn;
|
||||
*console_mfn = start_info->console.domU.mfn;
|
||||
SET_FIELD(start_info, nr_pages, p2m_size);
|
||||
SET_FIELD(start_info, shared_info, shared_info_frame<<PAGE_SHIFT);
|
||||
SET_FIELD(start_info, flags, 0);
|
||||
*store_mfn = p2m[GET_FIELD(start_info, store_mfn)];
|
||||
SET_FIELD(start_info, store_mfn, *store_mfn);
|
||||
SET_FIELD(start_info, store_evtchn, store_evtchn);
|
||||
*console_mfn = p2m[GET_FIELD(start_info, console.domU.mfn)];
|
||||
SET_FIELD(start_info, console.domU.mfn, *console_mfn);
|
||||
SET_FIELD(start_info, console.domU.evtchn, console_evtchn);
|
||||
munmap(start_info, PAGE_SIZE);
|
||||
}
|
||||
|
||||
/* Uncanonicalise each GDT frame number. */
|
||||
if ( ctxt.gdt_ents > 8192 )
|
||||
if ( GET_FIELD(&ctxt, gdt_ents) > 8192 )
|
||||
{
|
||||
ERROR("GDT entry count out of range");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for ( j = 0; (512*j) < ctxt.gdt_ents; j++ )
|
||||
for ( j = 0; (512*j) < GET_FIELD(&ctxt, gdt_ents); j++ )
|
||||
{
|
||||
pfn = ctxt.gdt_frames[j];
|
||||
pfn = GET_FIELD(&ctxt, gdt_frames[j]);
|
||||
if ( (pfn >= p2m_size) ||
|
||||
(pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB) )
|
||||
{
|
||||
ERROR("GDT frame number is bad");
|
||||
ERROR("GDT frame number %i (0x%lx) is bad",
|
||||
j, (unsigned long)pfn);
|
||||
goto out;
|
||||
}
|
||||
ctxt.gdt_frames[j] = p2m[pfn];
|
||||
SET_FIELD(&ctxt, gdt_frames[j], p2m[pfn]);
|
||||
}
|
||||
|
||||
/* Uncanonicalise the page table base pointer. */
|
||||
pfn = xen_cr3_to_pfn(ctxt.ctrlreg[3]);
|
||||
pfn = xen_cr3_to_pfn(GET_FIELD(&ctxt, ctrlreg[3]));
|
||||
|
||||
if ( pfn >= p2m_size )
|
||||
{
|
||||
@@ -1036,21 +1065,18 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
|
||||
(unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctxt.ctrlreg[3] = xen_pfn_to_cr3(p2m[pfn]);
|
||||
SET_FIELD(&ctxt, ctrlreg[3], xen_pfn_to_cr3(p2m[pfn]));
|
||||
|
||||
/* Guest pagetable (x86/64) stored in otherwise-unused CR1. */
|
||||
if ( (pt_levels == 4) && ctxt.ctrlreg[1] )
|
||||
if ( (pt_levels == 4) && (ctxt.x64.ctrlreg[1] & 1) )
|
||||
{
|
||||
pfn = xen_cr3_to_pfn(ctxt.ctrlreg[1]);
|
||||
|
||||
pfn = xen_cr3_to_pfn(ctxt.x64.ctrlreg[1] & ~1);
|
||||
if ( pfn >= p2m_size )
|
||||
{
|
||||
ERROR("User PT base is bad: pfn=%lu p2m_size=%lu type=%08lx",
|
||||
pfn, p2m_size, pfn_type[pfn]);
|
||||
ERROR("User PT base is bad: pfn=%lu p2m_size=%lu",
|
||||
pfn, p2m_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( (pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) !=
|
||||
((unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT) )
|
||||
{
|
||||
@@ -1059,14 +1085,12 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
|
||||
(unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctxt.ctrlreg[1] = xen_pfn_to_cr3(p2m[pfn]);
|
||||
ctxt.x64.ctrlreg[1] = xen_pfn_to_cr3(p2m[pfn]);
|
||||
}
|
||||
|
||||
domctl.cmd = XEN_DOMCTL_setvcpucontext;
|
||||
domctl.domain = (domid_t)dom;
|
||||
domctl.u.vcpucontext.vcpu = i;
|
||||
set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &ctxt);
|
||||
set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &ctxt.c);
|
||||
rc = xc_domctl(xc_handle, &domctl);
|
||||
if ( rc != 0 )
|
||||
{
|
||||
@@ -1087,22 +1111,16 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
|
||||
xc_handle, dom, PAGE_SIZE, PROT_WRITE, shared_info_frame);
|
||||
|
||||
/* restore saved vcpu_info and arch specific info */
|
||||
memcpy(&new_shared_info->vcpu_info,
|
||||
&old_shared_info->vcpu_info,
|
||||
sizeof(new_shared_info->vcpu_info));
|
||||
memcpy(&new_shared_info->arch,
|
||||
&old_shared_info->arch,
|
||||
sizeof(new_shared_info->arch));
|
||||
MEMCPY_FIELD(new_shared_info, old_shared_info, vcpu_info);
|
||||
MEMCPY_FIELD(new_shared_info, old_shared_info, arch);
|
||||
|
||||
/* clear any pending events and the selector */
|
||||
memset(&(new_shared_info->evtchn_pending[0]), 0,
|
||||
sizeof (new_shared_info->evtchn_pending));
|
||||
MEMSET_ARRAY_FIELD(new_shared_info, evtchn_pending, 0);
|
||||
for ( i = 0; i < MAX_VIRT_CPUS; i++ )
|
||||
new_shared_info->vcpu_info[i].evtchn_pending_sel = 0;
|
||||
SET_FIELD(new_shared_info, vcpu_info[i].evtchn_pending_sel, 0);
|
||||
|
||||
/* mask event channels */
|
||||
memset(&(new_shared_info->evtchn_mask[0]), 0xff,
|
||||
sizeof (new_shared_info->evtchn_mask));
|
||||
MEMSET_ARRAY_FIELD(new_shared_info, evtchn_mask, 0xff);
|
||||
|
||||
/* leave wallclock time. set by hypervisor */
|
||||
munmap(new_shared_info, PAGE_SIZE);
|
||||
@@ -1113,10 +1131,9 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
|
||||
pfn = p2m_frame_list[i];
|
||||
if ( (pfn >= p2m_size) || (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB) )
|
||||
{
|
||||
ERROR("PFN-to-MFN frame number is bad");
|
||||
ERROR("PFN-to-MFN frame number %i (%#lx) is bad", i, pfn);
|
||||
goto out;
|
||||
}
|
||||
|
||||
p2m_frame_list[i] = p2m[pfn];
|
||||
}
|
||||
|
||||
@@ -1128,8 +1145,17 @@ int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(live_p2m, p2m, ROUNDUP(p2m_size * sizeof(xen_pfn_t), PAGE_SHIFT));
|
||||
munmap(live_p2m, ROUNDUP(p2m_size * sizeof(xen_pfn_t), PAGE_SHIFT));
|
||||
/* If the domain we're restoring has a different word size to ours,
|
||||
* we need to repack the p2m appropriately */
|
||||
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) )
|
||||
for ( i = 0; i < p2m_size; i++ )
|
||||
((uint32_t *)p2m)[i] = p2m[i];
|
||||
|
||||
memcpy(live_p2m, p2m, ROUNDUP(p2m_size * guest_width, PAGE_SHIFT));
|
||||
munmap(live_p2m, ROUNDUP(p2m_size * guest_width, PAGE_SHIFT));
|
||||
|
||||
DPRINTF("Domain ready to be built.\n");
|
||||
rc = 0;
|
||||
|
||||
+141
-80
@@ -54,9 +54,17 @@ static xen_pfn_t *live_p2m = NULL;
|
||||
static xen_pfn_t *live_m2p = NULL;
|
||||
static unsigned long m2p_mfn0;
|
||||
|
||||
/* Address size of the guest */
|
||||
unsigned int guest_width;
|
||||
|
||||
/* grep fodder: machine_to_phys */
|
||||
|
||||
#define mfn_to_pfn(_mfn) live_m2p[(_mfn)]
|
||||
#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)])))
|
||||
|
||||
/*
|
||||
* Returns TRUE if the given machine frame number has a unique mapping
|
||||
@@ -65,19 +73,7 @@ static unsigned long m2p_mfn0;
|
||||
#define MFN_IS_IN_PSEUDOPHYS_MAP(_mfn) \
|
||||
(((_mfn) < (max_mfn)) && \
|
||||
((mfn_to_pfn(_mfn) < (p2m_size)) && \
|
||||
(live_p2m[mfn_to_pfn(_mfn)] == (_mfn))))
|
||||
|
||||
/* Returns TRUE if MFN is successfully converted to a PFN. */
|
||||
#define translate_mfn_to_pfn(_pmfn) \
|
||||
({ \
|
||||
unsigned long mfn = *(_pmfn); \
|
||||
int _res = 1; \
|
||||
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) ) \
|
||||
_res = 0; \
|
||||
else \
|
||||
*(_pmfn) = mfn_to_pfn(mfn); \
|
||||
_res; \
|
||||
})
|
||||
(pfn_to_mfn(mfn_to_pfn(_mfn)) == (_mfn))))
|
||||
|
||||
/*
|
||||
** During (live) save/migrate, we maintain a number of bitmaps to track
|
||||
@@ -451,22 +447,25 @@ static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd,
|
||||
** it to update the MFN to a reasonable value.
|
||||
*/
|
||||
static void *map_frame_list_list(int xc_handle, uint32_t dom,
|
||||
shared_info_t *shinfo)
|
||||
shared_info_either_t *shinfo)
|
||||
{
|
||||
int count = 100;
|
||||
void *p;
|
||||
uint64_t fll = GET_FIELD(shinfo, arch.pfn_to_mfn_frame_list_list);
|
||||
|
||||
while ( count-- && (shinfo->arch.pfn_to_mfn_frame_list_list == 0) )
|
||||
while ( count-- && (fll == 0) )
|
||||
{
|
||||
usleep(10000);
|
||||
fll = GET_FIELD(shinfo, arch.pfn_to_mfn_frame_list_list);
|
||||
}
|
||||
|
||||
if ( shinfo->arch.pfn_to_mfn_frame_list_list == 0 )
|
||||
if ( fll == 0 )
|
||||
{
|
||||
ERROR("Timed out waiting for frame list updated.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ,
|
||||
shinfo->arch.pfn_to_mfn_frame_list_list);
|
||||
p = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, fll);
|
||||
if ( p == NULL )
|
||||
ERROR("Couldn't map p2m_frame_list_list (errno %d)", errno);
|
||||
|
||||
@@ -659,15 +658,16 @@ static xen_pfn_t *map_and_save_p2m_table(int xc_handle,
|
||||
int io_fd,
|
||||
uint32_t dom,
|
||||
unsigned long p2m_size,
|
||||
shared_info_t *live_shinfo)
|
||||
shared_info_either_t *live_shinfo)
|
||||
{
|
||||
vcpu_guest_context_t ctxt;
|
||||
vcpu_guest_context_either_t ctxt;
|
||||
|
||||
/* Double and single indirect references to the live P2M table */
|
||||
xen_pfn_t *live_p2m_frame_list_list = NULL;
|
||||
xen_pfn_t *live_p2m_frame_list = NULL;
|
||||
void *live_p2m_frame_list_list = NULL;
|
||||
void *live_p2m_frame_list = NULL;
|
||||
|
||||
/* A copy of the pfn-to-mfn table frame list. */
|
||||
/* Copies of the above. */
|
||||
xen_pfn_t *p2m_frame_list_list = NULL;
|
||||
xen_pfn_t *p2m_frame_list = NULL;
|
||||
|
||||
/* The mapping of the live p2m table itself */
|
||||
@@ -680,9 +680,28 @@ static xen_pfn_t *map_and_save_p2m_table(int xc_handle,
|
||||
if ( !live_p2m_frame_list_list )
|
||||
goto out;
|
||||
|
||||
/* Get a local copy of the live_P2M_frame_list_list */
|
||||
if ( !(p2m_frame_list_list = malloc(PAGE_SIZE)) )
|
||||
{
|
||||
ERROR("Couldn't allocate p2m_frame_list_list array");
|
||||
goto out;
|
||||
}
|
||||
memcpy(p2m_frame_list_list, live_p2m_frame_list_list, PAGE_SIZE);
|
||||
|
||||
/* Canonicalize guest's unsigned long vs ours */
|
||||
if ( guest_width > sizeof(unsigned long) )
|
||||
for ( i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++ )
|
||||
if ( i < PAGE_SIZE/guest_width )
|
||||
p2m_frame_list_list[i] = ((uint64_t *)p2m_frame_list_list)[i];
|
||||
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++ )
|
||||
p2m_frame_list_list[i] = ((uint32_t *)p2m_frame_list_list)[i];
|
||||
|
||||
live_p2m_frame_list =
|
||||
xc_map_foreign_batch(xc_handle, dom, PROT_READ,
|
||||
live_p2m_frame_list_list,
|
||||
p2m_frame_list_list,
|
||||
P2M_FLL_ENTRIES);
|
||||
if ( !live_p2m_frame_list )
|
||||
{
|
||||
@@ -690,22 +709,6 @@ static xen_pfn_t *map_and_save_p2m_table(int xc_handle,
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
||||
/* Map all the frames of the pfn->mfn table. For migrate to succeed,
|
||||
the guest must not change which frames are used for this purpose.
|
||||
(its not clear why it would want to change them, and we'll be OK
|
||||
from a safety POV anyhow. */
|
||||
|
||||
p2m = xc_map_foreign_batch(xc_handle, dom, PROT_READ,
|
||||
live_p2m_frame_list,
|
||||
P2M_FL_ENTRIES);
|
||||
if ( !p2m )
|
||||
{
|
||||
ERROR("Couldn't map p2m table");
|
||||
goto out;
|
||||
}
|
||||
live_p2m = p2m; /* So that translation macros will work */
|
||||
|
||||
/* Get a local copy of the live_P2M_frame_list */
|
||||
if ( !(p2m_frame_list = malloc(P2M_FL_SIZE)) )
|
||||
{
|
||||
@@ -714,19 +717,54 @@ static xen_pfn_t *map_and_save_p2m_table(int xc_handle,
|
||||
}
|
||||
memcpy(p2m_frame_list, live_p2m_frame_list, P2M_FL_SIZE);
|
||||
|
||||
/* Canonicalise the pfn-to-mfn table frame-number list. */
|
||||
for ( i = 0; i < p2m_size; i += fpp )
|
||||
/* 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++ )
|
||||
p2m_frame_list[i] = ((uint32_t *)p2m_frame_list)[i];
|
||||
|
||||
|
||||
/* Map all the frames of the pfn->mfn table. For migrate to succeed,
|
||||
the guest must not change which frames are used for this purpose.
|
||||
(its not clear why it would want to change them, and we'll be OK
|
||||
from a safety POV anyhow. */
|
||||
|
||||
p2m = xc_map_foreign_batch(xc_handle, dom, PROT_READ,
|
||||
p2m_frame_list,
|
||||
P2M_FL_ENTRIES);
|
||||
if ( !p2m )
|
||||
{
|
||||
if ( !translate_mfn_to_pfn(&p2m_frame_list[i/fpp]) )
|
||||
ERROR("Couldn't map p2m table");
|
||||
goto out;
|
||||
}
|
||||
live_p2m = p2m; /* So that translation macros will work */
|
||||
|
||||
/* Canonicalise the pfn-to-mfn table frame-number list. */
|
||||
for ( i = 0; i < p2m_size; i += FPP )
|
||||
{
|
||||
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(p2m_frame_list[i/FPP]) )
|
||||
{
|
||||
ERROR("Frame# in pfn-to-mfn frame list is not in pseudophys");
|
||||
ERROR("entry %d: p2m_frame_list[%ld] is 0x%"PRIx64, i, i/fpp,
|
||||
(uint64_t)p2m_frame_list[i/fpp]);
|
||||
ERROR("entry %d: p2m_frame_list[%ld] is 0x%"PRIx64", max 0x%lx",
|
||||
i, i/FPP, (uint64_t)p2m_frame_list[i/FPP], max_mfn);
|
||||
if ( p2m_frame_list[i/FPP] < max_mfn )
|
||||
{
|
||||
ERROR("m2p[0x%"PRIx64"] = 0x%"PRIx64,
|
||||
(uint64_t)p2m_frame_list[i/FPP],
|
||||
(uint64_t)live_m2p[p2m_frame_list[i/FPP]]);
|
||||
ERROR("p2m[0x%"PRIx64"] = 0x%"PRIx64,
|
||||
(uint64_t)live_m2p[p2m_frame_list[i/FPP]],
|
||||
(uint64_t)p2m[live_m2p[p2m_frame_list[i/FPP]]]);
|
||||
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
p2m_frame_list[i/FPP] = mfn_to_pfn(p2m_frame_list[i/FPP]);
|
||||
}
|
||||
|
||||
if ( xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt) )
|
||||
if ( xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt.c) )
|
||||
{
|
||||
ERROR("Could not get vcpu context");
|
||||
goto out;
|
||||
@@ -737,25 +775,26 @@ static xen_pfn_t *map_and_save_p2m_table(int xc_handle,
|
||||
* a PAE guest understands extended CR3 (PDPTs above 4GB). Turns off
|
||||
* slow paths in the restore code.
|
||||
*/
|
||||
if ( (pt_levels == 3) &&
|
||||
(ctxt.vm_assist & (1UL << VMASST_TYPE_pae_extended_cr3)) )
|
||||
{
|
||||
unsigned long signature = ~0UL;
|
||||
uint32_t tot_sz = sizeof(struct vcpu_guest_context) + 8;
|
||||
uint32_t chunk_sz = sizeof(struct vcpu_guest_context);
|
||||
uint32_t chunk_sz = ((guest_width==8)
|
||||
? sizeof(ctxt.x64)
|
||||
: sizeof(ctxt.x32));
|
||||
uint32_t tot_sz = chunk_sz + 8;
|
||||
char chunk_sig[] = "vcpu";
|
||||
if ( !write_exact(io_fd, &signature, sizeof(signature)) ||
|
||||
!write_exact(io_fd, &tot_sz, sizeof(tot_sz)) ||
|
||||
!write_exact(io_fd, &chunk_sig, 4) ||
|
||||
!write_exact(io_fd, &chunk_sz, sizeof(chunk_sz)) ||
|
||||
!write_exact(io_fd, &ctxt, sizeof(ctxt)) )
|
||||
!write_exact(io_fd, &ctxt, chunk_sz) )
|
||||
{
|
||||
ERROR("write: extended info");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !write_exact(io_fd, p2m_frame_list, P2M_FL_SIZE) )
|
||||
if ( !write_exact(io_fd, p2m_frame_list,
|
||||
P2M_FL_ENTRIES * sizeof(xen_pfn_t)) )
|
||||
{
|
||||
ERROR("write: p2m_frame_list");
|
||||
goto out;
|
||||
@@ -774,6 +813,9 @@ static xen_pfn_t *map_and_save_p2m_table(int xc_handle,
|
||||
if ( live_p2m_frame_list )
|
||||
munmap(live_p2m_frame_list, P2M_FLL_ENTRIES * PAGE_SIZE);
|
||||
|
||||
if ( p2m_frame_list_list )
|
||||
free(p2m_frame_list_list);
|
||||
|
||||
if ( p2m_frame_list )
|
||||
free(p2m_frame_list);
|
||||
|
||||
@@ -798,7 +840,7 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
unsigned long shared_info_frame;
|
||||
|
||||
/* A copy of the CPU context of the guest. */
|
||||
vcpu_guest_context_t ctxt;
|
||||
vcpu_guest_context_either_t ctxt;
|
||||
|
||||
/* A table containing the type of each PFN (/not/ MFN!). */
|
||||
unsigned long *pfn_type = NULL;
|
||||
@@ -808,7 +850,7 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
char page[PAGE_SIZE];
|
||||
|
||||
/* Live mapping of shared info structure */
|
||||
shared_info_t *live_shinfo = NULL;
|
||||
shared_info_either_t *live_shinfo = NULL;
|
||||
|
||||
/* base of the region in which domain memory is mapped */
|
||||
unsigned char *region_base = NULL;
|
||||
@@ -836,6 +878,8 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
/* HVM: magic frames for ioreqs and xenstore comms. */
|
||||
uint64_t magic_pfns[3]; /* ioreq_pfn, bufioreq_pfn, store_pfn */
|
||||
|
||||
unsigned long mfn;
|
||||
|
||||
/* If no explicit control parameters given, use defaults */
|
||||
max_iters = max_iters ? : DEF_MAX_ITERS;
|
||||
max_factor = max_factor ? : DEF_MAX_FACTOR;
|
||||
@@ -843,7 +887,7 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
initialize_mbit_rate();
|
||||
|
||||
if ( !get_platform_info(xc_handle, dom,
|
||||
&max_mfn, &hvirt_start, &pt_levels) )
|
||||
&max_mfn, &hvirt_start, &pt_levels, &guest_width) )
|
||||
{
|
||||
ERROR("Unable to get platform info.");
|
||||
return 1;
|
||||
@@ -1006,7 +1050,6 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
if ( !hvm )
|
||||
{
|
||||
int err = 0;
|
||||
unsigned long mfn;
|
||||
|
||||
/* Map the P2M table, and write the list of P2M frames */
|
||||
live_p2m = map_and_save_p2m_table(xc_handle, io_fd, dom,
|
||||
@@ -1023,7 +1066,7 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
|
||||
for ( i = 0; i < p2m_size; i++ )
|
||||
{
|
||||
mfn = live_p2m[i];
|
||||
mfn = pfn_to_mfn(i);
|
||||
if( (mfn != INVALID_P2M_ENTRY) && (mfn_to_pfn(mfn) != i) )
|
||||
{
|
||||
DPRINTF("i=0x%x mfn=%lx live_m2p=%lx\n", i,
|
||||
@@ -1083,11 +1126,16 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
int n = permute(N, p2m_size, order_nr);
|
||||
|
||||
if ( debug )
|
||||
DPRINTF("%d pfn= %08lx mfn= %08lx %d [mfn]= %08lx\n",
|
||||
iter, (unsigned long)n, hvm ? 0 : live_p2m[n],
|
||||
test_bit(n, to_send),
|
||||
hvm ? 0 : mfn_to_pfn(live_p2m[n]&0xFFFFF));
|
||||
|
||||
{
|
||||
DPRINTF("%d pfn= %08lx mfn= %08lx %d",
|
||||
iter, (unsigned long)n,
|
||||
hvm ? 0 : pfn_to_mfn(n),
|
||||
test_bit(n, to_send));
|
||||
if ( !hvm && is_mapped(pfn_to_mfn(n)) )
|
||||
DPRINTF(" [mfn]= %08lx",
|
||||
mfn_to_pfn(pfn_to_mfn(n)&0xFFFFF));
|
||||
DPRINTF("\n");
|
||||
}
|
||||
if ( !last_iter &&
|
||||
test_bit(n, to_send) &&
|
||||
test_bit(n, to_skip) )
|
||||
@@ -1118,7 +1166,7 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
if ( hvm )
|
||||
pfn_type[batch] = n;
|
||||
else
|
||||
pfn_type[batch] = live_p2m[n];
|
||||
pfn_type[batch] = pfn_to_mfn(n);
|
||||
|
||||
if ( !is_mapped(pfn_type[batch]) )
|
||||
{
|
||||
@@ -1451,7 +1499,7 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
|
||||
for ( i = 0, j = 0; i < p2m_size; i++ )
|
||||
{
|
||||
if ( !is_mapped(live_p2m[i]) )
|
||||
if ( !is_mapped(pfn_to_mfn(i)) )
|
||||
j++;
|
||||
}
|
||||
|
||||
@@ -1463,7 +1511,7 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
|
||||
for ( i = 0, j = 0; i < p2m_size; )
|
||||
{
|
||||
if ( !is_mapped(live_p2m[i]) )
|
||||
if ( !is_mapped(pfn_to_mfn(i)) )
|
||||
pfntab[j++] = i;
|
||||
|
||||
i++;
|
||||
@@ -1480,63 +1528,75 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
}
|
||||
}
|
||||
|
||||
if ( xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt) )
|
||||
if ( xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt.c) )
|
||||
{
|
||||
ERROR("Could not get vcpu context");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Canonicalise the suspend-record frame number. */
|
||||
if ( !translate_mfn_to_pfn(&ctxt.user_regs.edx) )
|
||||
mfn = GET_FIELD(&ctxt, user_regs.edx);
|
||||
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
|
||||
{
|
||||
ERROR("Suspend record is not in range of pseudophys map");
|
||||
goto out;
|
||||
}
|
||||
SET_FIELD(&ctxt, user_regs.edx, mfn_to_pfn(mfn));
|
||||
|
||||
for ( i = 0; i <= info.max_vcpu_id; i++ )
|
||||
{
|
||||
if ( !(vcpumap & (1ULL << i)) )
|
||||
continue;
|
||||
|
||||
if ( (i != 0) && xc_vcpu_getcontext(xc_handle, dom, i, &ctxt) )
|
||||
if ( (i != 0) && xc_vcpu_getcontext(xc_handle, dom, i, &ctxt.c) )
|
||||
{
|
||||
ERROR("No context for VCPU%d", i);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Canonicalise each GDT frame number. */
|
||||
for ( j = 0; (512*j) < ctxt.gdt_ents; j++ )
|
||||
for ( j = 0; (512*j) < GET_FIELD(&ctxt, gdt_ents); j++ )
|
||||
{
|
||||
if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[j]) )
|
||||
mfn = GET_FIELD(&ctxt, gdt_frames[j]);
|
||||
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
|
||||
{
|
||||
ERROR("GDT frame is not in range of pseudophys map");
|
||||
goto out;
|
||||
}
|
||||
SET_FIELD(&ctxt, gdt_frames[j], mfn_to_pfn(mfn));
|
||||
}
|
||||
|
||||
/* Canonicalise the page table base pointer. */
|
||||
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[3])) )
|
||||
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(
|
||||
GET_FIELD(&ctxt, ctrlreg[3]))) )
|
||||
{
|
||||
ERROR("PT base is not in range of pseudophys map");
|
||||
goto out;
|
||||
}
|
||||
ctxt.ctrlreg[3] =
|
||||
xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[3])));
|
||||
SET_FIELD(&ctxt, ctrlreg[3],
|
||||
xen_pfn_to_cr3(
|
||||
mfn_to_pfn(
|
||||
xen_cr3_to_pfn(
|
||||
GET_FIELD(&ctxt, ctrlreg[3])))));
|
||||
|
||||
/* Guest pagetable (x86/64) stored in otherwise-unused CR1. */
|
||||
if ( (pt_levels == 4) && ctxt.ctrlreg[1] )
|
||||
if ( (pt_levels == 4) && ctxt.x64.ctrlreg[1] )
|
||||
{
|
||||
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[1])) )
|
||||
if ( !MFN_IS_IN_PSEUDOPHYS_MAP(
|
||||
xen_cr3_to_pfn(ctxt.x64.ctrlreg[1])) )
|
||||
{
|
||||
ERROR("PT base is not in range of pseudophys map");
|
||||
goto out;
|
||||
}
|
||||
/* Least-significant bit means 'valid PFN'. */
|
||||
ctxt.ctrlreg[1] = 1 |
|
||||
xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[1])));
|
||||
ctxt.x64.ctrlreg[1] = 1 |
|
||||
xen_pfn_to_cr3(
|
||||
mfn_to_pfn(xen_cr3_to_pfn(ctxt.x64.ctrlreg[1])));
|
||||
}
|
||||
|
||||
if ( !write_exact(io_fd, &ctxt, sizeof(ctxt)) )
|
||||
if ( !write_exact(io_fd, &ctxt, ((guest_width==8)
|
||||
? sizeof(ctxt.x64)
|
||||
: sizeof(ctxt.x32))) )
|
||||
{
|
||||
ERROR("Error when writing to state file (1) (errno %d)", errno);
|
||||
goto out;
|
||||
@@ -1547,7 +1607,8 @@ int xc_domain_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
|
||||
* Reset the MFN to be a known-invalid value. See map_frame_list_list().
|
||||
*/
|
||||
memcpy(page, live_shinfo, PAGE_SIZE);
|
||||
((shared_info_t *)page)->arch.pfn_to_mfn_frame_list_list = 0;
|
||||
SET_FIELD(((shared_info_either_t *)page),
|
||||
arch.pfn_to_mfn_frame_list_list, 0);
|
||||
if ( !write_exact(io_fd, page, PAGE_SIZE) )
|
||||
{
|
||||
ERROR("Error when writing to state file (1) (errno %d)", errno);
|
||||
|
||||
@@ -8,13 +8,8 @@
|
||||
#include <xen/foreign/x86_64.h>
|
||||
#include <xen/hvm/params.h>
|
||||
|
||||
/* Need to provide the right flavour of vcpu context for Xen */
|
||||
typedef union
|
||||
{
|
||||
vcpu_guest_context_x86_64_t c64;
|
||||
vcpu_guest_context_x86_32_t c32;
|
||||
vcpu_guest_context_t c;
|
||||
} vcpu_guest_context_either_t;
|
||||
/* Don't yet support cross-address-size uncooperative resume */
|
||||
#define guest_width (sizeof (unsigned long))
|
||||
|
||||
static int modify_returncode(int xc_handle, uint32_t domid)
|
||||
{
|
||||
@@ -50,9 +45,9 @@ static int modify_returncode(int xc_handle, uint32_t domid)
|
||||
if ( !info.hvm )
|
||||
ctxt.c.user_regs.eax = 1;
|
||||
else if ( strstr(caps, "x86_64") )
|
||||
ctxt.c64.user_regs.eax = 1;
|
||||
ctxt.x64.user_regs.eax = 1;
|
||||
else
|
||||
ctxt.c32.user_regs.eax = 1;
|
||||
ctxt.x32.user_regs.eax = 1;
|
||||
|
||||
if ( (rc = xc_vcpu_setcontext(xc_handle, domid, 0, &ctxt.c)) != 0 )
|
||||
return rc;
|
||||
|
||||
+15
-13
@@ -133,13 +133,6 @@ typedef l4_pgentry_64_t l4_pgentry_t;
|
||||
#define PAGE_SHIFT_X86 12
|
||||
#define PAGE_SIZE_X86 (1UL << PAGE_SHIFT_X86)
|
||||
#define PAGE_MASK_X86 (~(PAGE_SIZE_X86-1))
|
||||
#if defined(__i386__)
|
||||
#define MADDR_BITS_X86 44
|
||||
#elif defined(__x86_64__)
|
||||
#define MADDR_BITS_X86 52
|
||||
#endif
|
||||
#define MFN_MASK_X86 ((1ULL << (MADDR_BITS_X86 - PAGE_SHIFT_X86)) - 1)
|
||||
#define MADDR_MASK_X86 (MFN_MASK_X86 << PAGE_SHIFT_X86)
|
||||
|
||||
#define PAGE_SHIFT_IA64 14
|
||||
#define PAGE_SIZE_IA64 (1UL << PAGE_SHIFT_IA64)
|
||||
@@ -147,19 +140,28 @@ typedef l4_pgentry_64_t l4_pgentry_t;
|
||||
|
||||
#define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
|
||||
|
||||
/* Number of xen_pfn_t in a page */
|
||||
#define fpp (PAGE_SIZE/sizeof(xen_pfn_t))
|
||||
|
||||
/* XXX SMH: following 3 skanky macros rely on variable p2m_size being set */
|
||||
/* XXX SMH: following skanky macros rely on variable p2m_size being set */
|
||||
/* XXX TJD: also, "guest_width" should be the guest's sizeof(unsigned long) */
|
||||
|
||||
/* Number of xen_pfn_t in a page */
|
||||
|
||||
#define FPP (PAGE_SIZE/(guest_width))
|
||||
|
||||
/* Number of entries in the pfn_to_mfn_frame_list_list */
|
||||
#define P2M_FLL_ENTRIES (((p2m_size)+(fpp*fpp)-1)/(fpp*fpp))
|
||||
#define P2M_FLL_ENTRIES (((p2m_size)+(FPP*FPP)-1)/(FPP*FPP))
|
||||
|
||||
/* Number of entries in the pfn_to_mfn_frame_list */
|
||||
#define P2M_FL_ENTRIES (((p2m_size)+fpp-1)/fpp)
|
||||
#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)*sizeof(unsigned long))
|
||||
#define P2M_FL_SIZE ((P2M_FL_ENTRIES)*(guest_width))
|
||||
|
||||
/* Masks for PTE<->PFN conversions */
|
||||
#define MADDR_BITS_X86 ((guest_width == 8) ? 52 : 44)
|
||||
#define MFN_MASK_X86 ((1ULL << (MADDR_BITS_X86 - PAGE_SHIFT_X86)) - 1)
|
||||
#define MADDR_MASK_X86 (MFN_MASK_X86 << PAGE_SHIFT_X86)
|
||||
|
||||
|
||||
#define PAEKERN_no 0
|
||||
#define PAEKERN_yes 1
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
|
||||
#include "xc_private.h"
|
||||
|
||||
#include <xen/foreign/x86_32.h>
|
||||
#include <xen/foreign/x86_64.h>
|
||||
|
||||
/*
|
||||
** We process save/restore/migrate in batches of pages; the below
|
||||
** determines how many pages we (at maximum) deal with in each batch.
|
||||
@@ -32,15 +35,19 @@
|
||||
** be a property of the domain, but for the moment we just read it
|
||||
** from the hypervisor.
|
||||
**
|
||||
** - The width of a guest word (unsigned long), in bytes.
|
||||
**
|
||||
** Returns 1 on success, 0 on failure.
|
||||
*/
|
||||
static inline int get_platform_info(int xc_handle, uint32_t dom,
|
||||
/* OUT */ unsigned long *max_mfn,
|
||||
/* OUT */ unsigned long *hvirt_start,
|
||||
/* OUT */ unsigned int *pt_levels)
|
||||
/* OUT */ unsigned int *pt_levels,
|
||||
/* OUT */ unsigned int *guest_width)
|
||||
{
|
||||
xen_capabilities_info_t xen_caps = "";
|
||||
xen_platform_parameters_t xen_params;
|
||||
DECLARE_DOMCTL;
|
||||
|
||||
if (xc_version(xc_handle, XENVER_platform_parameters, &xen_params) != 0)
|
||||
return 0;
|
||||
@@ -52,17 +59,18 @@ static inline int get_platform_info(int xc_handle, uint32_t dom,
|
||||
|
||||
*hvirt_start = xen_params.virt_start;
|
||||
|
||||
/*
|
||||
* XXX For now, 32bit dom0's can only save/restore 32bit domUs
|
||||
* on 64bit hypervisors, so no need to check which type of domain
|
||||
* we're dealing with.
|
||||
*/
|
||||
memset(&domctl, 0, sizeof(domctl));
|
||||
domctl.domain = dom;
|
||||
domctl.cmd = XEN_DOMCTL_get_address_size;
|
||||
|
||||
if ( do_domctl(xc_handle, &domctl) != 0 )
|
||||
return 0;
|
||||
|
||||
*guest_width = domctl.u.address_size.size / 8;
|
||||
|
||||
if (strstr(xen_caps, "xen-3.0-x86_64"))
|
||||
#if defined(__i386__)
|
||||
*pt_levels = 3;
|
||||
#else
|
||||
*pt_levels = 4;
|
||||
#endif
|
||||
/* Depends on whether it's a compat 32-on-64 guest */
|
||||
*pt_levels = ( (*guest_width == 8) ? 4 : 3 );
|
||||
else if (strstr(xen_caps, "xen-3.0-x86_32p"))
|
||||
*pt_levels = 3;
|
||||
else if (strstr(xen_caps, "xen-3.0-x86_32"))
|
||||
@@ -95,3 +103,56 @@ static inline int get_platform_info(int xc_handle, uint32_t dom,
|
||||
|
||||
/* Returns TRUE if the PFN is currently mapped */
|
||||
#define is_mapped(pfn_type) (!((pfn_type) & 0x80000000UL))
|
||||
|
||||
|
||||
/* 32-on-64 support: saving 32bit guests from 64bit tools and vice versa */
|
||||
typedef union
|
||||
{
|
||||
vcpu_guest_context_x86_64_t x64;
|
||||
vcpu_guest_context_x86_32_t x32;
|
||||
vcpu_guest_context_t c;
|
||||
} vcpu_guest_context_either_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
shared_info_x86_64_t x64;
|
||||
shared_info_x86_32_t x32;
|
||||
shared_info_t s;
|
||||
} shared_info_either_t;
|
||||
|
||||
typedef union
|
||||
{
|
||||
start_info_x86_64_t x64;
|
||||
start_info_x86_32_t x32;
|
||||
start_info_t s;
|
||||
} start_info_either_t;
|
||||
|
||||
#define GET_FIELD(_p, _f) ((guest_width==8) ? ((_p)->x64._f) : ((_p)->x32._f))
|
||||
|
||||
#define SET_FIELD(_p, _f, _v) do { \
|
||||
if (guest_width == 8) \
|
||||
(_p)->x64._f = (_v); \
|
||||
else \
|
||||
(_p)->x32._f = (_v); \
|
||||
} while (0)
|
||||
|
||||
#define MEMCPY_FIELD(_d, _s, _f) do { \
|
||||
if (guest_width == 8) \
|
||||
memcpy(&(_d)->x64._f, &(_s)->x64._f,sizeof((_d)->x64._f)); \
|
||||
else \
|
||||
memcpy(&(_d)->x32._f, &(_s)->x32._f,sizeof((_d)->x32._f)); \
|
||||
} while (0)
|
||||
|
||||
#define MEMSET_ARRAY_FIELD(_p, _f, _v) do { \
|
||||
if (guest_width == 8) \
|
||||
memset(&(_p)->x64._f[0], (_v), sizeof((_p)->x64._f)); \
|
||||
else \
|
||||
memset(&(_p)->x32._f[0], (_v), sizeof((_p)->x32._f)); \
|
||||
} while (0)
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(_a, _b) ((_a) >= (_b) ? (_a) : (_b))
|
||||
#endif
|
||||
#ifndef MIN
|
||||
#define MIN(_a, _b) ((_a) <= (_b) ? (_a) : (_b))
|
||||
#endif
|
||||