aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Deegan <Tim.Deegan@xensource.com>2007-04-05 15:11:22 +0100
committerTim Deegan <Tim.Deegan@xensource.com>2007-04-05 15:11:22 +0100
commit538a65bcc3279e4539599de04d3317a5373c3b9f (patch)
treeddff11cb6bb1ddd0822d4e64cafd0c84bb1690c3
parente1290b1524218d977a98825c8cec8c2cc12427ef (diff)
downloadxen-538a65bcc3279e4539599de04d3317a5373c3b9f.tar.gz
xen-538a65bcc3279e4539599de04d3317a5373c3b9f.tar.bz2
xen-538a65bcc3279e4539599de04d3317a5373c3b9f.zip
[HVM] Save/restore: merge xc_linux_restore and xc_hvm_restore
into one function (and one file) since they share a lot of code Signed-off-by: Tim Deegan <Tim.Deegan@øensource.com> --HG-- rename : tools/libxc/xc_linux_restore.c => tools/libxc/xc_domain_restore.c
-rw-r--r--tools/libxc/Makefile4
-rw-r--r--tools/libxc/xc_domain_restore.c (renamed from tools/libxc/xc_linux_restore.c)321
-rw-r--r--tools/libxc/xc_hvm_restore.c351
-rw-r--r--tools/libxc/xc_hvm_save.c57
-rw-r--r--tools/libxc/xenguest.h22
-rw-r--r--tools/libxc/xg_private.c10
-rw-r--r--tools/xcutils/xc_restore.c10
7 files changed, 277 insertions, 498 deletions
diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index c924ea509a..5e23bef968 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -26,8 +26,8 @@ CTRL_SRCS-$(CONFIG_X86_Linux) += xc_ptrace.c xc_ptrace_core.c
GUEST_SRCS-y :=
GUEST_SRCS-y += xg_private.c
-GUEST_SRCS-$(CONFIG_MIGRATE) += xc_linux_restore.c xc_linux_save.c
-GUEST_SRCS-$(CONFIG_HVM) += xc_hvm_build.c xc_hvm_restore.c xc_hvm_save.c
+GUEST_SRCS-$(CONFIG_MIGRATE) += xc_domain_restore.c xc_linux_save.c
+GUEST_SRCS-$(CONFIG_HVM) += xc_hvm_build.c xc_hvm_save.c
# symlink libelf from xen/common/libelf/
LIBELF_SRCS := libelf-tools.c libelf-loader.c
diff --git a/tools/libxc/xc_linux_restore.c b/tools/libxc/xc_domain_restore.c
index 02342b4509..624c675b9e 100644
--- a/tools/libxc/xc_linux_restore.c
+++ b/tools/libxc/xc_domain_restore.c
@@ -1,9 +1,25 @@
/******************************************************************************
- * xc_linux_restore.c
+ * xc_domain_restore.c
*
- * Restore the state of a Linux session.
+ * Restore the state of a guest session.
*
* Copyright (c) 2003, K A Fraser.
+ * Copyright (c) 2006, Intel Corporation
+ * Copyright (c) 2007, XenSource Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
*/
#include <stdlib.h>
@@ -13,6 +29,9 @@
#include "xg_save_restore.h"
#include "xc_dom.h"
+#include <xen/hvm/ioreq.h>
+#include <xen/hvm/params.h>
+
/* max mfn of the current host machine */
static unsigned long max_mfn;
@@ -102,7 +121,7 @@ static int uncanonicalize_pagetable(int xc_handle, uint32_t dom,
}
- /* Alllocate the requistite number of mfns */
+ /* Allocate the requistite number of mfns */
if (nr_mfns && xc_domain_memory_populate_physmap(
xc_handle, dom, nr_mfns, 0, 0, p2m_batch) != 0) {
ERROR("Failed to allocate memory for batch.!\n");
@@ -141,9 +160,93 @@ static int uncanonicalize_pagetable(int xc_handle, uint32_t dom,
}
-int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
- unsigned int store_evtchn, unsigned long *store_mfn,
- unsigned int console_evtchn, unsigned long *console_mfn)
+/* Load the p2m frame list, plus potential extended info chunk */
+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;
+
+ if (!(p2m_frame_list = malloc(P2M_FL_SIZE))) {
+ 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))) {
+ ERROR("read extended-info signature failed");
+ return NULL;
+ }
+
+ if (p2m_frame_list[0] == ~0UL) {
+ uint32_t tot_bytes;
+
+ /* Next 4 bytes: total size of following extended info. */
+ if (!read_exact(io_fd, &tot_bytes, sizeof(tot_bytes))) {
+ ERROR("read extended-info size failed");
+ return NULL;
+ }
+
+ while (tot_bytes) {
+ uint32_t chunk_bytes;
+ char chunk_sig[4];
+
+ /* 4-character chunk signature + 4-byte remaining chunk size. */
+ if (!read_exact(io_fd, chunk_sig, sizeof(chunk_sig)) ||
+ !read_exact(io_fd, &chunk_bytes, sizeof(chunk_bytes))) {
+ ERROR("read extended-info chunk signature failed");
+ return NULL;
+ }
+ tot_bytes -= 8;
+
+ /* VCPU context structure? */
+ if (!strncmp(chunk_sig, "vcpu", 4)) {
+ if (!read_exact(io_fd, &ctxt, sizeof(ctxt))) {
+ 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))
+ *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)) {
+ ERROR("read-and-discard extended-info chunk bytes failed");
+ return NULL;
+ }
+ chunk_bytes -= sz;
+ tot_bytes -= sz;
+ }
+ }
+
+ /* Now read the real first entry of P2M list. */
+ if (!read_exact(io_fd, p2m_frame_list, sizeof(long))) {
+ 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))) {
+ ERROR("read p2m_frame_list failed");
+ return NULL;
+ }
+
+ return p2m_frame_list;
+}
+
+
+
+int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
+ unsigned int store_evtchn, unsigned long *store_mfn,
+ unsigned int console_evtchn, unsigned long *console_mfn,
+ unsigned int hvm, unsigned int pae)
{
DECLARE_DOMCTL;
int rc = 1, i, j, n, m, pae_extended_cr3 = 0;
@@ -174,7 +277,7 @@ int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
/* A copy of the pfn-to-mfn table frame list. */
xen_pfn_t *p2m_frame_list = NULL;
-
+
/* A temporary mapping of the guest's start_info page. */
start_info_t *start_info;
@@ -193,6 +296,12 @@ int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
unsigned int max_vcpu_id = 0;
int new_ctxt_format = 0;
+ /* Magic frames in HVM guests: ioreqs and xenstore comms. */
+ uint64_t magic_pfns[3]; /* ioreq_pfn, bufioreq_pfn, store_pfn */
+
+ /* Buffer for holding HVM context */
+ uint8_t *hvm_buf = NULL;
+
/* For info only */
nr_pfns = 0;
@@ -201,20 +310,24 @@ int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
ERROR("read: p2m_size");
goto out;
}
- DPRINTF("xc_linux_restore start: p2m_size = %lx\n", p2m_size);
+ DPRINTF("xc_domain_restore start: p2m_size = %lx\n", p2m_size);
- /*
- * XXX For now, 32bit dom0's can only save/restore 32bit domUs
- * on 64bit hypervisors.
- */
- memset(&domctl, 0, sizeof(domctl));
- domctl.domain = dom;
- domctl.cmd = XEN_DOMCTL_set_address_size;
- domctl.u.address_size.size = sizeof(unsigned long) * 8;
- rc = do_domctl(xc_handle, &domctl);
- if ( rc != 0 ) {
- ERROR("Unable to set guest address size.");
- goto out;
+ if ( !hvm )
+ {
+ /*
+ * XXX For now, 32bit dom0's can only save/restore 32bit domUs
+ * on 64bit hypervisors.
+ */
+ memset(&domctl, 0, sizeof(domctl));
+ domctl.domain = dom;
+ domctl.cmd = XEN_DOMCTL_set_address_size;
+ domctl.u.address_size.size = sizeof(unsigned long) * 8;
+ rc = do_domctl(xc_handle, &domctl);
+ if ( rc != 0 ) {
+ ERROR("Unable to set guest address size.");
+ goto out;
+ }
+ rc = 1;
}
if(!get_platform_info(xc_handle, dom,
@@ -229,76 +342,12 @@ int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
return 1;
}
- if (!(p2m_frame_list = malloc(P2M_FL_SIZE))) {
- ERROR("Couldn't allocate p2m_frame_list array");
- goto out;
- }
-
- /* Read first entry of P2M list, or extended-info signature (~0UL). */
- if (!read_exact(io_fd, p2m_frame_list, sizeof(long))) {
- ERROR("read extended-info signature failed");
- goto out;
- }
-
- if (p2m_frame_list[0] == ~0UL) {
- uint32_t tot_bytes;
-
- /* Next 4 bytes: total size of following extended info. */
- if (!read_exact(io_fd, &tot_bytes, sizeof(tot_bytes))) {
- ERROR("read extended-info size failed");
- goto out;
- }
-
- while (tot_bytes) {
- uint32_t chunk_bytes;
- char chunk_sig[4];
-
- /* 4-character chunk signature + 4-byte remaining chunk size. */
- if (!read_exact(io_fd, chunk_sig, sizeof(chunk_sig)) ||
- !read_exact(io_fd, &chunk_bytes, sizeof(chunk_bytes))) {
- ERROR("read extended-info chunk signature failed");
- goto out;
- }
- tot_bytes -= 8;
-
- /* VCPU context structure? */
- if (!strncmp(chunk_sig, "vcpu", 4)) {
- if (!read_exact(io_fd, &ctxt, sizeof(ctxt))) {
- ERROR("read extended-info vcpu context failed");
- goto out;
- }
- tot_bytes -= sizeof(struct vcpu_guest_context);
- chunk_bytes -= sizeof(struct vcpu_guest_context);
-
- if (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)) {
- ERROR("read-and-discard extended-info chunk bytes failed");
- goto out;
- }
- chunk_bytes -= sz;
- tot_bytes -= sz;
- }
- }
-
- /* Now read the real first entry of P2M list. */
- if (!read_exact(io_fd, p2m_frame_list, sizeof(long))) {
- ERROR("read first entry of p2m_frame_list failed");
+ /* 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;
- }
- }
-
- /* First entry is already read into the p2m array. */
- if (!read_exact(io_fd, &p2m_frame_list[1], P2M_FL_SIZE - sizeof(long))) {
- ERROR("read p2m_frame_list failed");
- goto out;
}
/* We want zeroed memory so use calloc rather than malloc. */
@@ -442,8 +491,9 @@ int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
nr_pfns++;
}
- /* setup region_mfn[] for batch map */
- region_mfn[i] = p2m[pfn];
+ /* setup region_mfn[] for batch map.
+ * For HVM guests, this interface takes PFNs, not MFNs */
+ region_mfn[i] = hvm ? pfn : p2m[pfn];
}
}
@@ -551,9 +601,10 @@ int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
}
}
- if (xc_add_mmu_update(xc_handle, mmu,
- (((unsigned long long)mfn) << PAGE_SHIFT)
- | MMU_MACHPHYS_UPDATE, pfn)) {
+ if (!hvm
+ && xc_add_mmu_update(xc_handle, mmu,
+ (((unsigned long long)mfn) << PAGE_SHIFT)
+ | MMU_MACHPHYS_UPDATE, pfn)) {
ERROR("failed machpys update mfn=%lx pfn=%lx", mfn, pfn);
goto out;
}
@@ -578,13 +629,90 @@ int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
* Ensure we flush all machphys updates before potential PAE-specific
* reallocations below.
*/
- if (xc_finish_mmu_updates(xc_handle, mmu)) {
+ if (!hvm && xc_finish_mmu_updates(xc_handle, mmu)) {
ERROR("Error doing finish_mmu_updates()");
goto out;
}
DPRINTF("Received all pages (%d races)\n", nraces);
+ if ( hvm )
+ {
+ uint32_t rec_len;
+
+ /* Set HVM-specific parameters */
+ if ( !read_exact(io_fd, magic_pfns, sizeof(magic_pfns)) )
+ {
+ ERROR("error reading magic page addresses");
+ goto out;
+ }
+
+ /* These comms pages need to be zeroed at the start of day */
+ if ( xc_clear_domain_page(xc_handle, dom, magic_pfns[0]) ||
+ xc_clear_domain_page(xc_handle, dom, magic_pfns[1]) ||
+ xc_clear_domain_page(xc_handle, dom, magic_pfns[2]) )
+ {
+ ERROR("error zeroing magic pages");
+ goto out;
+ }
+
+ xc_set_hvm_param(xc_handle, dom, HVM_PARAM_IOREQ_PFN, magic_pfns[0]);
+ xc_set_hvm_param(xc_handle, dom, HVM_PARAM_BUFIOREQ_PFN, magic_pfns[1]);
+ xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, magic_pfns[2]);
+ xc_set_hvm_param(xc_handle, dom, HVM_PARAM_PAE_ENABLED, pae);
+ xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_EVTCHN, store_evtchn);
+ *store_mfn = magic_pfns[2];
+
+ /* Read vcpu contexts */
+ for (i = 0; i <= max_vcpu_id; i++)
+ {
+ if (!(vcpumap & (1ULL << i)))
+ continue;
+
+ if ( !read_exact(io_fd, &(ctxt), sizeof(ctxt)) )
+ {
+ ERROR("error read vcpu context.\n");
+ goto out;
+ }
+
+ if ( (rc = xc_vcpu_setcontext(xc_handle, dom, i, &ctxt)) )
+ {
+ ERROR("Could not set vcpu context, rc=%d", rc);
+ goto out;
+ }
+ rc = 1;
+ }
+
+ /* Read HVM context */
+ if ( !read_exact(io_fd, &rec_len, sizeof(uint32_t)) )
+ {
+ ERROR("error read hvm context size!\n");
+ goto out;
+ }
+
+ hvm_buf = malloc(rec_len);
+ if ( hvm_buf == NULL )
+ {
+ ERROR("memory alloc for hvm context buffer failed");
+ errno = ENOMEM;
+ goto out;
+ }
+
+ if ( !read_exact(io_fd, hvm_buf, rec_len) )
+ {
+ ERROR("error loading the HVM context");
+ goto out;
+ }
+
+ rc = xc_domain_hvm_setcontext(xc_handle, dom, hvm_buf, rec_len);
+ if ( rc )
+ ERROR("error setting the HVM context");
+
+ goto out;
+ }
+
+ /* Non-HVM guests only from here on */
+
if ((pt_levels == 3) && !pae_extended_cr3) {
/*
@@ -897,6 +1025,7 @@ int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
ERROR("Couldn't build vcpu%d", i);
goto out;
}
+ rc = 1;
}
if (!read_exact(io_fd, shared_info_page, PAGE_SIZE)) {
@@ -938,6 +1067,7 @@ int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
munmap(live_p2m, ROUNDUP(p2m_size * sizeof(xen_pfn_t), PAGE_SHIFT));
DPRINTF("Domain ready to be built.\n");
+ rc = 0;
out:
if ( (rc != 0) && (dom != 0) )
@@ -945,6 +1075,7 @@ int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
free(mmu);
free(p2m);
free(pfn_type);
+ free(hvm_buf);
/* discard cache for save file */
discard_file_cache(io_fd, 1 /*flush*/);
diff --git a/tools/libxc/xc_hvm_restore.c b/tools/libxc/xc_hvm_restore.c
deleted file mode 100644
index d9f7435951..0000000000
--- a/tools/libxc/xc_hvm_restore.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/******************************************************************************
- * xc_hvm_restore.c
- *
- * Restore the state of a HVM guest.
- *
- * Copyright (c) 2003, K A Fraser.
- * Copyright (c) 2006 Intel Corperation
- * rewriten for hvm guest by Zhai Edwin <edwin.zhai@intel.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "xg_private.h"
-#include "xg_save_restore.h"
-
-#include <xen/hvm/ioreq.h>
-#include <xen/hvm/params.h>
-#include <xen/hvm/e820.h>
-
-static ssize_t
-read_exact(int fd, void *buf, size_t count)
-{
- int r = 0, s;
- unsigned char *b = buf;
-
- while ( r < count )
- {
- s = read(fd, &b[r], count - r);
- if ( (s == -1) && (errno == EINTR) )
- continue;
- if ( s <= 0 )
- break;
- r += s;
- }
-
- return (r == count) ? 1 : 0;
-}
-
-#define BPL (sizeof(long)*8)
-#define test_bit(bit, map) !!((map)[(bit)/BPL] & (1UL << ((bit) % BPL)))
-#define set_bit(bit, map) ((map)[(bit)/BPL] |= (1UL << ((bit) % BPL)))
-static int test_and_set_bit(unsigned long nr, unsigned long *map)
-{
- int rc = test_bit(nr, map);
- if ( !rc )
- set_bit(nr, map);
- return rc;
-}
-
-int xc_hvm_restore(int xc_handle, int io_fd, uint32_t dom,
- unsigned int store_evtchn, unsigned long *store_mfn,
- unsigned int pae, unsigned int apic)
-{
- DECLARE_DOMCTL;
-
- /* A copy of the CPU context of the guest. */
- vcpu_guest_context_t ctxt;
-
- char *region_base;
-
- unsigned long buf[PAGE_SIZE/sizeof(unsigned long)];
-
- xc_dominfo_t info;
- unsigned int rc = 1, n, i;
- uint32_t rec_len, nr_vcpus;
- uint8_t *hvm_buf = NULL;
-
- /* Magic frames: ioreqs and xenstore comms. */
- uint64_t magic_pfns[3]; /* ioreq_pfn, bufioreq_pfn, store_pfn */
-
- unsigned long pfn;
- int verify = 0;
-
- /* Types of the pfns in the current region */
- unsigned long region_pfn_type[MAX_BATCH_SIZE];
- xen_pfn_t pfn_alloc_batch[MAX_BATCH_SIZE];
- unsigned int pfn_alloc_batch_size;
-
- /* The size of an array big enough to contain all guest pfns */
- unsigned long max_pfn = 0xfffffUL; /* initial memory map guess: 4GB */
- unsigned long *pfn_bitmap = NULL, *new_pfn_bitmap;
-
- DPRINTF("xc_hvm_restore:dom=%d, store_evtchn=%d, "
- "pae=%u, apic=%u.\n", dom, store_evtchn, pae, apic);
-
- DPRINTF("xc_hvm_restore start: max_pfn = %lx\n", max_pfn);
-
- if ( mlock(&ctxt, sizeof(ctxt)) )
- {
- /* needed for build dom0 op, but might as well do early */
- ERROR("Unable to mlock ctxt");
- return 1;
- }
-
- if ( xc_domain_getinfo(xc_handle, dom, 1, &info) != 1 )
- {
- ERROR("Could not get domain info");
- return 1;
- }
-
- domctl.cmd = XEN_DOMCTL_getdomaininfo;
- domctl.domain = (domid_t)dom;
- if ( xc_domctl(xc_handle, &domctl) < 0 )
- {
- ERROR("Could not get information on new domain");
- goto out;
- }
-
- pfn_bitmap = calloc((max_pfn+1)/8, 1);
- if ( pfn_bitmap == NULL )
- {
- ERROR("Could not allocate pfn bitmap");
- goto out;
- }
-
- n = 0;
- for ( ; ; )
- {
- int j;
-
- if ( !read_exact(io_fd, &j, sizeof(int)) )
- {
- ERROR("HVM restore Error when reading batch size");
- goto out;
- }
-
- PPRINTF("batch %d\n",j);
-
- if ( j == -1 )
- {
- verify = 1;
- DPRINTF("Entering page verify mode\n");
- continue;
- }
-
- if ( j == 0 )
- break; /* our work here is done */
-
- if ( j > MAX_BATCH_SIZE )
- {
- ERROR("Max batch size exceeded. Giving up.");
- goto out;
- }
-
- if ( !read_exact(io_fd, region_pfn_type, j*sizeof(unsigned long)) )
- {
- ERROR("Error when reading region pfn types");
- goto out;
- }
-
- pfn_alloc_batch_size = 0;
- for ( i = 0; i < j; i++ )
- {
- pfn = region_pfn_type[i];
- if ( pfn & XEN_DOMCTL_PFINFO_LTAB_MASK )
- continue;
-
- while ( pfn > max_pfn )
- {
- if ( max_pfn >= 0xfffffff )
- {
- ERROR("Maximum PFN beyond reason (1TB) %lx\n", pfn);
- goto out;
- }
- max_pfn = 2*max_pfn + 1;
- new_pfn_bitmap = realloc(pfn_bitmap, (max_pfn+1)/8);
- if ( new_pfn_bitmap == NULL )
- {
- ERROR("Could not realloc pfn bitmap for max_pfn=%lx\n",
- max_pfn);
- goto out;
- }
- pfn_bitmap = new_pfn_bitmap;
- memset(&pfn_bitmap[(max_pfn+1)/(2*BPL)], 0, (max_pfn+1)/(2*8));
- }
-
- if ( !test_and_set_bit(pfn, pfn_bitmap) )
- pfn_alloc_batch[pfn_alloc_batch_size++] = pfn;
- }
-
- if ( pfn_alloc_batch_size != 0 )
- {
- rc = xc_domain_memory_populate_physmap(
- xc_handle, dom, pfn_alloc_batch_size, 0, 0, pfn_alloc_batch);
- if ( rc != 0 )
- {
- PERROR("Could not allocate %u pages for HVM guest.\n",
- pfn_alloc_batch_size);
- goto out;
- }
- }
-
- region_base = xc_map_foreign_batch(
- xc_handle, dom, PROT_WRITE, region_pfn_type, j);
-
- for ( i = 0; i < j; i++ )
- {
- void *page;
-
- pfn = region_pfn_type[i];
- if ( pfn & XEN_DOMCTL_PFINFO_LTAB_MASK )
- continue;
-
- /* In verify mode, we use a copy; otherwise we work in place */
- page = verify ? (void *)buf : (region_base + i*PAGE_SIZE);
-
- if ( !read_exact(io_fd, page, PAGE_SIZE) )
- {
- ERROR("Error when reading page (%x)", i);
- goto out;
- }
-
- if ( verify )
- {
- int res = memcmp(buf, (region_base + i*PAGE_SIZE), PAGE_SIZE);
- if ( res )
- {
- int v;
-
- DPRINTF("************** pfn=%lx gotcs=%08lx "
- "actualcs=%08lx\n", pfn,
- csum_page(region_base + i*PAGE_SIZE),
- csum_page(buf));
-
- for ( v = 0; v < 4; v++ )
- {
- unsigned long *p = (unsigned long *)
- (region_base + i*PAGE_SIZE);
- if (buf[v] != p[v])
- DPRINTF(" %d: %08lx %08lx\n", v, buf[v], p[v]);
- }
- }
- }
-
- } /* end of 'batch' for loop */
-
- munmap(region_base, j*PAGE_SIZE);
- n += j; /* crude stats */
- }
-
- xc_set_hvm_param(xc_handle, dom, HVM_PARAM_PAE_ENABLED, pae);
- xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_EVTCHN, store_evtchn);
-
- if ( !read_exact(io_fd, magic_pfns, sizeof(magic_pfns)) )
- {
- ERROR("error reading magic page addresses\n");
- goto out;
- }
-
- if ( xc_clear_domain_page(xc_handle, dom, magic_pfns[0]) ||
- xc_clear_domain_page(xc_handle, dom, magic_pfns[1]) ||
- xc_clear_domain_page(xc_handle, dom, magic_pfns[2]) )
- {
- rc = -1;
- goto out;
- }
-
- xc_set_hvm_param(xc_handle, dom, HVM_PARAM_IOREQ_PFN, magic_pfns[0]);
- xc_set_hvm_param(xc_handle, dom, HVM_PARAM_BUFIOREQ_PFN, magic_pfns[1]);
- xc_set_hvm_param(xc_handle, dom, HVM_PARAM_STORE_PFN, magic_pfns[2]);
- *store_mfn = magic_pfns[2];
- DPRINTF("hvm restore: calculate new store_mfn=0x%lx.\n", *store_mfn);
-
- if ( !read_exact(io_fd, &nr_vcpus, sizeof(uint32_t)) )
- {
- ERROR("error read nr vcpu !\n");
- goto out;
- }
- DPRINTF("hvm restore:get nr_vcpus=%d.\n", nr_vcpus);
-
- for ( i = 0; i < nr_vcpus; i++ )
- {
- if ( !read_exact(io_fd, &rec_len, sizeof(uint32_t)) )
- {
- ERROR("error read vcpu context size!\n");
- goto out;
- }
- if ( rec_len != sizeof(ctxt) )
- {
- ERROR("vcpu context size dismatch!\n");
- goto out;
- }
-
- if ( !read_exact(io_fd, &(ctxt), sizeof(ctxt)) )
- {
- ERROR("error read vcpu context.\n");
- goto out;
- }
-
- if ( (rc = xc_vcpu_setcontext(xc_handle, dom, i, &ctxt)) )
- {
- ERROR("Could not set vcpu context, rc=%d", rc);
- goto out;
- }
- }
-
- /* restore hvm context including pic/pit/shpage */
- if ( !read_exact(io_fd, &rec_len, sizeof(uint32_t)) )
- {
- ERROR("error read hvm context size!\n");
- goto out;
- }
-
- hvm_buf = malloc(rec_len);
- if ( hvm_buf == NULL )
- {
- ERROR("memory alloc for hvm context buffer failed");
- errno = ENOMEM;
- goto out;
- }
-
- if ( !read_exact(io_fd, hvm_buf, rec_len) )
- {
- ERROR("error read hvm buffer!\n");
- goto out;
- }
-
- if ( (rc = xc_domain_hvm_setcontext(xc_handle, dom, hvm_buf, rec_len)) )
- {
- ERROR("error set hvm buffer!\n");
- goto out;
- }
-
- rc = 0;
- goto out;
-
- out:
- if ( (rc != 0) && (dom != 0) )
- xc_domain_destroy(xc_handle, dom);
- free(hvm_buf);
- free(pfn_bitmap);
-
- DPRINTF("Restore exit with rc=%d\n", rc);
-
- return rc;
-}
diff --git a/tools/libxc/xc_hvm_save.c b/tools/libxc/xc_hvm_save.c
index 1b3ad5d356..8d34bf6643 100644
--- a/tools/libxc/xc_hvm_save.c
+++ b/tools/libxc/xc_hvm_save.c
@@ -305,6 +305,8 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
unsigned long total_sent = 0;
+ uint64_t vcpumap = 1ULL;
+
DPRINTF("xc_hvm_save: dom=%d, max_iters=%d, max_factor=%d, flags=0x%x, "
"live=%d, debug=%d.\n", dom, max_iters, max_factor, flags,
live, debug);
@@ -371,6 +373,12 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
/* Size of any array that covers 0 ... max_pfn */
pfn_array_size = max_pfn + 1;
+ if ( !write_exact(io_fd, &pfn_array_size, sizeof(unsigned long)) )
+ {
+ ERROR("Error when writing to state file (1)");
+ goto out;
+ }
+
/* pretend we sent all the pages last iteration */
sent_last_iter = pfn_array_size;
@@ -644,6 +652,32 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
DPRINTF("All HVM memory is saved\n");
+ {
+ struct {
+ int minustwo;
+ int max_vcpu_id;
+ uint64_t vcpumap;
+ } chunk = { -2, info.max_vcpu_id };
+
+ if (info.max_vcpu_id >= 64) {
+ ERROR("Too many VCPUS in guest!");
+ goto out;
+ }
+
+ for (i = 1; i <= info.max_vcpu_id; i++) {
+ xc_vcpuinfo_t vinfo;
+ if ((xc_vcpu_getinfo(xc_handle, dom, i, &vinfo) == 0) &&
+ vinfo.online)
+ vcpumap |= 1ULL << i;
+ }
+
+ chunk.vcpumap = vcpumap;
+ if(!write_exact(io_fd, &chunk, sizeof(chunk))) {
+ ERROR("Error when writing to state file (errno %d)", errno);
+ goto out;
+ }
+ }
+
/* Zero terminate */
i = 0;
if ( !write_exact(io_fd, &i, sizeof(int)) )
@@ -666,33 +700,22 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
goto out;
}
- /* save vcpu/vmcs context */
- if ( !write_exact(io_fd, &nr_vcpus, sizeof(uint32_t)) )
- {
- ERROR("error write nr vcpus");
- goto out;
- }
-
- /*XXX: need a online map to exclude down cpu */
+ /* save vcpu/vmcs contexts */
for ( i = 0; i < nr_vcpus; i++ )
{
+ if (!(vcpumap & (1ULL << i)))
+ continue;
+
if ( xc_vcpu_getcontext(xc_handle, dom, i, &ctxt) )
{
ERROR("HVM:Could not get vcpu context");
goto out;
}
- rec_size = sizeof(ctxt);
- DPRINTF("write %d vcpucontext of total %d.\n", i, nr_vcpus);
- if ( !write_exact(io_fd, &rec_size, sizeof(uint32_t)) )
- {
- ERROR("error write vcpu ctxt size");
- goto out;
- }
-
+ DPRINTF("write vcpu %d context.\n", i);
if ( !write_exact(io_fd, &(ctxt), sizeof(ctxt)) )
{
- ERROR("write vmcs failed!\n");
+ ERROR("write vcpu context failed!\n");
goto out;
}
}
diff --git a/tools/libxc/xenguest.h b/tools/libxc/xenguest.h
index 988c85feb6..8b636abb81 100644
--- a/tools/libxc/xenguest.h
+++ b/tools/libxc/xenguest.h
@@ -38,29 +38,21 @@ int xc_hvm_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters,
void (*qemu_flip_buffer)(int, int));
/**
- * This function will restore a saved domain running Linux.
+ * This function will restore a saved domain.
*
* @parm xc_handle a handle to an open hypervisor interface
* @parm fd the file descriptor to restore a domain from
* @parm dom the id of the domain
* @parm store_evtchn the store event channel for this domain to use
* @parm store_mfn returned with the mfn of the store page
+ * @parm hvm non-zero if this is a HVM restore
+ * @parm pae non-zero if this HVM domain has PAE support enabled
* @return 0 on success, -1 on failure
*/
-int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom,
- unsigned int store_evtchn, unsigned long *store_mfn,
- unsigned int console_evtchn, unsigned long *console_mfn);
-
-/**
- * This function will restore a saved hvm domain running unmodified guest.
- *
- * @parm store_mfn pass mem size & returned with the mfn of the store page
- * @return 0 on success, -1 on failure
- */
-int xc_hvm_restore(int xc_handle, int io_fd, uint32_t dom,
- unsigned int store_evtchn,
- unsigned long *store_mfn,
- unsigned int pae, unsigned int apic);
+int xc_domain_restore(int xc_handle, int io_fd, uint32_t dom,
+ unsigned int store_evtchn, unsigned long *store_mfn,
+ unsigned int console_evtchn, unsigned long *console_mfn,
+ unsigned int hvm, unsigned int pae);
/**
* This function will create a domain for a paravirtualized Linux
diff --git a/tools/libxc/xg_private.c b/tools/libxc/xg_private.c
index 9110518d69..5ca3302479 100644
--- a/tools/libxc/xg_private.c
+++ b/tools/libxc/xg_private.c
@@ -209,16 +209,6 @@ __attribute__((weak))
return -1;
}
-__attribute__((weak))
- int xc_hvm_restore(int xc_handle, int io_fd, uint32_t dom,
- unsigned int store_evtchn,
- unsigned long *store_mfn,
- unsigned int pae, unsigned int apic)
-{
- errno = ENOSYS;
- return -1;
-}
-
__attribute__((weak)) int xc_get_hvm_param(
int handle, domid_t dom, int param, unsigned long *value)
{
diff --git a/tools/xcutils/xc_restore.c b/tools/xcutils/xc_restore.c
index fc1a59073e..e769c0be31 100644
--- a/tools/xcutils/xc_restore.c
+++ b/tools/xcutils/xc_restore.c
@@ -39,14 +39,8 @@ main(int argc, char **argv)
pae = atoi(argv[6]);
apic = atoi(argv[7]);
- if ( hvm )
- ret = xc_hvm_restore(xc_fd, io_fd, domid,
- store_evtchn, &store_mfn,
- pae, apic);
- else
- ret = xc_linux_restore(xc_fd, io_fd, domid,
- store_evtchn, &store_mfn,
- console_evtchn, &console_mfn);
+ ret = xc_domain_restore(xc_fd, io_fd, domid, store_evtchn, &store_mfn,
+ console_evtchn, &console_mfn, hvm, pae);
if ( ret == 0 )
{