[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v6 5/5] xen/arm: Implement toolstack for xl restore/save and migrate



Implement for xl restore/save (which are also used for migrate) operation in 
xc_arm_migrate.c and make it compilable.
The overall process of save is the following:
1) save guest parameters (i.e., memory map, console and store pfn, etc)
2) save memory (if it is live, perform dirty-page tracing)
3) save hvm states (i.e., gic, timer, vcpu etc)

Signed-off-by: Evgeny Fedotov <e.fedotov@xxxxxxxxxxx>
Signed-off-by: Junghyun Yoo <yjhyun.yoo@xxxxxxxxxxx>
---
 config/arm32.mk                   |   1 +
 tools/libxc/Makefile              |   5 +-
 tools/libxc/xc_arm_migrate.c      | 736 ++++++++++++++++++++++++++++++++++++++
 tools/libxc/xc_dom_arm.c          |   4 +-
 tools/libxc/xg_arm_save_restore.h | 106 ++++++
 tools/libxl/libxl.h               |   1 -
 tools/misc/Makefile               |   4 +-
 7 files changed, 851 insertions(+), 6 deletions(-)
 create mode 100644 tools/libxc/xc_arm_migrate.c
 create mode 100644 tools/libxc/xg_arm_save_restore.h

diff --git a/config/arm32.mk b/config/arm32.mk
index aa79d22..01374c9 100644
--- a/config/arm32.mk
+++ b/config/arm32.mk
@@ -1,6 +1,7 @@
 CONFIG_ARM := y
 CONFIG_ARM_32 := y
 CONFIG_ARM_$(XEN_OS) := y
+CONFIG_MIGRATE := y
 
 CONFIG_XEN_INSTALL_SUFFIX :=
 
diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index a74b19e..3923cd9 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -43,8 +43,9 @@ CTRL_SRCS-$(CONFIG_MiniOS) += xc_minios.c
 GUEST_SRCS-y :=
 GUEST_SRCS-y += xg_private.c xc_suspend.c
 ifeq ($(CONFIG_MIGRATE),y)
-GUEST_SRCS-y += xc_domain_restore.c xc_domain_save.c
-GUEST_SRCS-y += xc_offline_page.c xc_compression.c
+GUEST_SRCS-$(CONFIG_X86) += xc_domain_restore.c xc_domain_save.c
+GUEST_SRCS-$(CONFIG_X86) += xc_offline_page.c xc_compression.c
+GUEST_SRCS-$(CONFIG_ARM) += xc_arm_migrate.c
 else
 GUEST_SRCS-y += xc_nomigrate.c
 endif
diff --git a/tools/libxc/xc_arm_migrate.c b/tools/libxc/xc_arm_migrate.c
new file mode 100644
index 0000000..9c0a819
--- /dev/null
+++ b/tools/libxc/xc_arm_migrate.c
@@ -0,0 +1,736 @@
+/******************************************************************************
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+ *
+ * Copyright (c) 2013, Samsung Electronics
+ */
+
+#include <inttypes.h>
+#include <errno.h>
+#include <xenctrl.h>
+#include <xenguest.h>
+
+#include <unistd.h>
+#include "xg_arm_save_restore.h"
+#include <xc_dom.h>
+#include "xc_bitops.h"
+#include "xg_private.h"
+
+
+static int suspend_and_state(int (*suspend)(void*), void *data,
+                             xc_interface *xch, int dom)
+{
+    xc_dominfo_t info;
+    if ( !(*suspend)(data) )
+    {
+        ERROR("Suspend request failed");
+        return -1;
+    }
+
+    if ( (xc_domain_getinfo(xch, dom, 1, &info) != 1) ||
+         !info.shutdown || (info.shutdown_reason != SHUTDOWN_suspend) )
+    {
+        ERROR("Domain is not in suspended state after suspend attempt");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int write_exact_handled(xc_interface *xch, int fd, const void *data,
+                               size_t size)
+{
+    if ( write_exact(fd, data, size) )
+    {
+        ERROR("Write failed, check space");
+        return -1;
+    }
+    return 0;
+}
+
+/* =================== Memory (BODY PHASE) ===================== */
+static int save_memory(xc_interface *xch, int io_fd, uint32_t dom,
+                       struct save_callbacks *callbacks,
+                       uint32_t max_iters, uint32_t max_factor,
+                       xen_pfn_t* p2m, unsigned long p2m_size, uint32_t flags)
+{
+    int live =  !!(flags & XCFLAGS_LIVE);
+    int debug =  !!(flags & XCFLAGS_DEBUG);
+    xen_pfn_t i;
+    char reportbuf[80];
+    int iter = 0;
+    int last_iter = !live;
+    int total_dirty_pages_num = 0;
+    int dirty_pages_on_prev_iter_num = 0;
+    int count = 0;
+    char *page = 0;
+    int  pages_count = 1;
+    unsigned long pfn = 0;
+
+    DECLARE_HYPERCALL_BUFFER(unsigned long, to_send);
+
+    const xen_pfn_t start = (GUEST_RAM_BASE >> PAGE_SHIFT);
+    const xen_pfn_t end = start + p2m_size;
+    const xen_pfn_t mem_size = p2m_size;
+
+    if ( debug ) IPRINTF("(save mem) start=%llx end=%llx!\n", start, end);
+
+    if ( live )
+    {
+        if ( xc_shadow_control(xch, dom, XEN_DOMCTL_SHADOW_OP_ENABLE_LOGDIRTY,
+                    NULL, 0, NULL, 0, NULL) < 0 )
+        {
+            ERROR("Couldn't enable log-dirty mode !\n");
+            return -1;
+        }
+
+        max_iters  = max_iters  ? : DEF_MAX_ITERS;
+        max_factor = max_factor ? : DEF_MAX_FACTOR;
+
+        if ( debug )
+            IPRINTF("Log-dirty mode enabled, max_iters=%d, max_factor=%d!\n",
+                    max_iters, max_factor);
+    }
+
+    to_send = xc_hypercall_buffer_alloc_pages(xch, to_send,
+                                              NRPAGES(bitmap_size(mem_size)));
+    if ( !to_send )
+    {
+        ERROR("Couldn't allocate to_send array!\n");
+        return -1;
+    }
+
+    /* send all pages on first iter */
+    memset(to_send, 0xff, bitmap_size(mem_size));
+
+    for ( ; ; )
+    {
+        int dirty_pages_on_current_iter_num = 0;
+        int frc;
+        iter++;
+
+        snprintf(reportbuf, sizeof(reportbuf),
+                 "Saving memory: iter %d (last sent %u)",
+                 iter, dirty_pages_on_prev_iter_num);
+
+        xc_report_progress_start(xch, reportbuf, mem_size);
+
+        if ( (iter > 1 &&
+              dirty_pages_on_prev_iter_num < DEF_MIN_DIRTY_PER_ITER) ||
+             (iter == max_iters) ||
+             (total_dirty_pages_num >= mem_size * max_factor) )
+        {
+            if ( debug )
+                IPRINTF("Last iteration");
+            last_iter = 1;
+        }
+
+        if ( last_iter )
+        {
+            if ( suspend_and_state(callbacks->suspend, callbacks->data,
+                                   xch, dom) )
+            {
+                ERROR("Domain appears not to have suspended");
+                return -1;
+            }
+        }
+        if ( live && iter > 1 )
+        {
+            frc = xc_shadow_control(xch, dom, XEN_DOMCTL_SHADOW_OP_CLEAN,
+                                    HYPERCALL_BUFFER(to_send), mem_size,
+                                                     NULL, 0, NULL);
+            if ( frc != mem_size )
+            {
+                ERROR("Error peeking shadow bitmap");
+                xc_hypercall_buffer_free_pages(xch, to_send,
+                                               NRPAGES(bitmap_size(mem_size)));
+                return -1;
+            }
+        }
+
+        for ( i = start; i < end; ++i )
+        {
+            if ( test_bit(i - start, to_send) )
+            {
+                /* TODO: batch p2m processing */
+                page = xc_map_foreign_range(xch, dom, PAGE_SIZE, PROT_READ, i);
+                if ( !page )
+                {
+                    if ( debug )
+                        IPRINTF("WARNING: page mapping failed, pfn=%llx", i);
+                    continue;
+
+                }
+                pfn = (unsigned long ) i;
+                if ( write_exact_handled(xch, io_fd,
+                        &pages_count, sizeof(pages_count)) ||
+                     write_exact_handled(xch, io_fd, &pfn, sizeof(pfn)) ||
+                     write_exact_handled(xch, io_fd, page, PAGE_SIZE) )
+                {
+                    munmap(page, PAGE_SIZE);
+                    return -1;
+                }
+                count++;
+                munmap(page, PAGE_SIZE);
+
+                if ( (i % DEF_PROGRESS_RATE) == 0 )
+                    xc_report_progress_step(xch, i - start, mem_size);
+                dirty_pages_on_current_iter_num++;
+            }
+        }
+
+        if ( debug )
+            IPRINTF("Dirty pages=%d", dirty_pages_on_current_iter_num);
+
+        xc_report_progress_step(xch, mem_size, mem_size);
+
+        dirty_pages_on_prev_iter_num = dirty_pages_on_current_iter_num;
+        total_dirty_pages_num += dirty_pages_on_current_iter_num;
+
+        if ( last_iter )
+        {
+            xc_hypercall_buffer_free_pages(xch, to_send,
+                                           NRPAGES(bitmap_size(mem_size)));
+            if ( live )
+            {
+                if ( xc_shadow_control(xch, dom, XEN_DOMCTL_SHADOW_OP_OFF,
+                                       NULL, 0, NULL, 0, NULL) < 0 )
+                    ERROR("Couldn't disable log-dirty mode");
+            }
+            break;
+        }
+    }
+    if ( debug ) IPRINTF("save mem: pages count = %d\n", count);
+
+    pages_count = 0; /* end body phase */
+    return write_exact_handled(xch, io_fd, &pages_count, sizeof(pages_count));
+}
+
+static int restore_memory(xc_interface *xch, int io_fd, uint32_t dom,
+     xen_pfn_t* p2m, unsigned long p2m_size, int debug)
+{
+    xen_pfn_t start = (GUEST_RAM_BASE >> PAGE_SHIFT);
+    xen_pfn_t end = start + p2m_size;
+    xen_pfn_t gpfn;
+    unsigned long pfn = 0;
+    int count = 0, pages_count = 0;
+    char *page;
+    int rc;
+    xen_pfn_t allocsz, i, mem_size = p2m_size;
+
+    /* allocate guest memory */
+
+    for ( i = rc = allocsz = 0;
+              (i < mem_size) && !rc;
+              i += allocsz )
+    {
+        allocsz = mem_size - i;
+        if ( allocsz > XC_ALLOCATE_MAX_PAGES )
+            allocsz = XC_ALLOCATE_MAX_PAGES;
+        rc = xc_domain_populate_physmap_exact(xch, dom, allocsz,
+                0, 0, &p2m[i]);
+    }
+
+    if ( rc < 0 )
+    {
+        PERROR("Memory allocation failed for Domain %d", dom);
+        return rc;
+    }
+
+    while ( 1 )
+    {
+
+        if ( read_exact(io_fd, &pages_count, sizeof(pages_count)) )
+        {
+           PERROR("Chunk ID read failed, count=%d", count);
+           return -1;
+        }
+
+        if ( pages_count == 0 ) break; /* end page marker */
+
+        if ( read_exact(io_fd, &pfn, sizeof(pfn)) )
+        {
+            PERROR("GPFN read failed during memory transfer, count=%d", count);
+            return -1;
+        }
+        gpfn = (xen_pfn_t) pfn;
+
+
+        if ( gpfn < start || gpfn >= end )
+        {
+            ERROR("GPFN %llx doesn't belong to RAM address space, count=%d",
+                    gpfn, count);
+            return -1;
+        }
+
+        /* TODO batch mapping */
+        page = xc_map_foreign_range(xch, dom, PAGE_SIZE,
+                                    PROT_READ | PROT_WRITE, gpfn);
+        if ( !page )
+        {
+            PERROR("xc_map_foreign_range failed, pfn=%llx", gpfn);
+            return -1;
+        }
+        if ( read_exact(io_fd, page, PAGE_SIZE) )
+        {
+            PERROR("Page data read failed during memory transfer, pfn=%llx",
+                    gpfn);
+            return -1;
+        }
+        munmap(page, PAGE_SIZE);
+        count++;
+    }
+
+    if ( debug ) IPRINTF("Memory restored, pages count=%d", count);
+
+    return 0;
+}
+
+/* ============ HVM context =========== */
+static int save_armhvm(xc_interface *xch, int io_fd, uint32_t dom, int debug)
+{
+    /* HVM: a buffer for holding HVM context */
+    uint32_t hvm_buf_size = 0;
+    uint8_t *hvm_buf = NULL;
+    uint32_t rec_size;
+    int retval = -1;
+
+    /* Need another buffer for HVM context */
+    hvm_buf_size = xc_domain_hvm_getcontext(xch, dom, 0, 0);
+    if ( hvm_buf_size == -1 )
+    {
+        ERROR("Couldn't get HVM context size from Xen");
+        goto out;
+    }
+    hvm_buf = malloc(hvm_buf_size);
+
+    if ( !hvm_buf )
+    {
+        ERROR("Couldn't allocate memory for hvm buffer");
+        goto out;
+    }
+
+    /* Get HVM context from Xen and save it too */
+    if ( (rec_size = xc_domain_hvm_getcontext(xch, dom, hvm_buf,
+                    hvm_buf_size)) == -1 )
+    {
+        ERROR("HVM:Could not get hvm buffer");
+        goto out;
+    }
+
+    if ( debug )
+        IPRINTF("HVM save size %d %d", hvm_buf_size, rec_size);
+
+    if ( write_exact_handled(xch, io_fd, &rec_size, sizeof(uint32_t)) )
+        goto out;
+
+    if ( write_exact_handled(xch, io_fd, hvm_buf, rec_size) )
+    {
+        goto out;
+    }
+    retval = 0;
+
+out:
+    if ( hvm_buf )
+        free (hvm_buf);
+    return retval;
+}
+
+static int restore_armhvm(xc_interface *xch, int io_fd,
+                          uint32_t dom, int debug)
+{
+    uint32_t rec_size;
+    uint32_t hvm_buf_size = 0;
+    uint8_t *hvm_buf = NULL;
+    int frc = 0;
+    int retval = -1;
+
+    if ( read_exact(io_fd, &rec_size, sizeof(uint32_t)) )
+    {
+        PERROR("Could not read HVM size");
+        goto out;
+    }
+
+    if ( !rec_size )
+    {
+        ERROR("Zero HVM size");
+        goto out;
+    }
+
+    hvm_buf_size = xc_domain_hvm_getcontext(xch, dom, 0, 0);
+    if ( hvm_buf_size != rec_size )
+    {
+        ERROR("HVM size for this domain is not the same as stored");
+    }
+
+    hvm_buf = malloc(hvm_buf_size);
+    if ( !hvm_buf )
+    {
+        ERROR("Couldn't allocate memory");
+        goto out;
+    }
+
+    if ( read_exact(io_fd, hvm_buf, hvm_buf_size) )
+    {
+        PERROR("Could not read HVM context");
+        goto out;
+    }
+
+    frc = xc_domain_hvm_setcontext(xch, dom, hvm_buf, hvm_buf_size);
+    if ( frc )
+    {
+        ERROR("error setting the HVM context");
+        goto out;
+    }
+    retval = 0;
+
+    if ( debug )
+        IPRINTF("HVM restore size %d, recorded %d", hvm_buf_size, rec_size);
+
+out:
+    if ( hvm_buf )
+        free (hvm_buf);
+    return retval;
+}
+
+/* ================= Magic Pages =========== */
+
+/*
+ * Magic pages (tail)
+ */
+typedef struct magic_pages
+{
+
+    uint64_t  ioreq_pfn;
+    uint64_t  bufioreq_pfn;
+    uint64_t  store_pfn;
+    uint64_t  console_pfn;
+
+} magic_pages_t;
+
+static int save_magic_pages(xc_interface *xch, int io_fd,
+                             uint32_t dom)
+{
+
+    magic_pages_t mpages;
+
+    /* Save magic-page locations. */
+    memset(&mpages, 0, sizeof(mpages));
+    xc_get_hvm_param(xch, dom, HVM_PARAM_IOREQ_PFN,
+        (unsigned long *)&mpages.ioreq_pfn);
+    xc_get_hvm_param(xch, dom, HVM_PARAM_BUFIOREQ_PFN,
+        (unsigned long *)&mpages.bufioreq_pfn);
+    xc_get_hvm_param(xch, dom, HVM_PARAM_STORE_PFN,
+        (unsigned long *)&mpages.store_pfn);
+    xc_get_hvm_param(xch, dom, HVM_PARAM_CONSOLE_PFN,
+            (unsigned long *)&mpages.console_pfn);
+
+    return write_exact_handled(xch, io_fd, &mpages, sizeof(mpages) );
+
+}
+
+static int restore_magic_pages(xc_interface *xch, int io_fd,
+                             uint32_t dom, unsigned int store_evtchn,
+                             unsigned long *store_gpfn,
+                             unsigned int console_evtchn,
+                             unsigned long *console_gpfn)
+{
+
+    magic_pages_t mpages;
+    int frc = 0;
+
+    if ( read_exact(io_fd, &mpages, sizeof(mpages)) )
+    {
+        PERROR("error reading magic pages");
+        return -1;
+    }
+
+    /* These comms pages need to be zeroed at the start of day */
+    if ( xc_clear_domain_page(xch, dom, mpages.store_pfn) ||
+            xc_clear_domain_page(xch, dom, mpages.console_pfn))
+    {
+        /* XXX: clear magic pages : IOREQ_PFN, BUFIOREQ_PFN
+         * when they will be enabled for ARM guest */
+        PERROR("error zeroing magic pages");
+        return -1;
+    }
+
+    if ( (frc = xc_set_hvm_param(xch, dom,
+            HVM_PARAM_IOREQ_PFN, mpages.ioreq_pfn))
+        || (frc = xc_set_hvm_param(xch, dom,
+                HVM_PARAM_BUFIOREQ_PFN, mpages.bufioreq_pfn))
+        || (frc = xc_set_hvm_param(xch, dom,
+                HVM_PARAM_STORE_PFN, mpages.store_pfn))
+        || (frc = xc_set_hvm_param(xch, dom,
+                HVM_PARAM_STORE_EVTCHN, store_evtchn))
+        || (frc = xc_set_hvm_param(xch, dom,
+                HVM_PARAM_CONSOLE_PFN, mpages.console_pfn))
+        || (frc = xc_set_hvm_param(xch, dom,
+                HVM_PARAM_CONSOLE_EVTCHN, console_evtchn)) )
+    {
+        PERROR("error setting HVM params: %i", frc);
+        return -1;
+    }
+
+    if ( store_gpfn )
+        *store_gpfn = (unsigned long) mpages.store_pfn;
+    if ( console_gpfn )
+        *console_gpfn = (unsigned long) mpages.console_pfn;
+
+    return 0;
+
+}
+
+/* ================= xc_domain_save & xc_domain_restore (Main) =========== */
+
+typedef struct migrate_options
+{
+    /* only flags are saved for extended debug info */
+    uint32_t ext_info_size;
+    char block_id[4];
+    uint32_t size;
+    uint32_t flags;
+} migrate_options_t;
+
+int xc_domain_save(xc_interface *xch, int io_fd, uint32_t dom,
+                   uint32_t max_iters, uint32_t max_factor, uint32_t flags,
+                   struct save_callbacks *callbacks, int hvm,
+                   unsigned long vm_generationid_addr)
+{
+    int debug, rc;
+    xc_dominfo_t dom_info;
+    unsigned long i, p2m_size = 0;
+    unsigned long opt_signature = 0;
+    xen_pfn_t *p2m = NULL;
+    migrate_options_t opts;
+
+    debug = !!(flags & XCFLAGS_DEBUG);
+    rc = -1;
+    /* save options (flags) */
+
+    strncpy(opts.block_id, "opts", 4);
+    opts.size = sizeof(opts.flags);
+    opts.flags = flags;
+    opts.ext_info_size = sizeof(migrate_options_t) - sizeof(unsigned long);
+
+    if ( write_exact_handled(xch, io_fd,
+            &opt_signature, sizeof(opt_signature)) ||
+        write_exact_handled(xch, io_fd, &opts, sizeof(opts)) )
+    {
+        goto out;
+    }
+
+
+    /* get domain info */
+
+    if ( xc_domain_getinfo(xch, dom, 1, &dom_info ) < 0)
+    {
+       ERROR("Can't get domain info for dom %d", dom);
+       goto out;
+    }
+
+    p2m_size = KB_TO_PFN(dom_info.max_memkb);
+
+    /* allocate p2m */
+    p2m = (xen_pfn_t*) malloc(sizeof(xen_pfn_t) * p2m_size);
+
+    if ( !p2m )
+    {
+       PERROR("p2m allocation error");
+       goto out;
+    }
+
+    if ( flags & XCFLAGS_DEBUG )
+    {
+        IPRINTF("p2m_size: %lx ", p2m_size);
+    }
+    /* save p2m_size */
+    if ( write_exact_handled(xch, io_fd, &p2m_size, sizeof(p2m_size)) )
+    {
+        goto out;
+    }
+
+    /* fill default p2m */
+    for ( i = 0; i < p2m_size; i++)
+        p2m[i] = (GUEST_RAM_BASE >> PAGE_SHIFT) + i;
+
+    /* save p2m */
+    if ( write_exact_handled(xch, io_fd, p2m, sizeof(xen_pfn_t) * p2m_size) )
+    {
+       goto out;
+    }
+
+    if ( save_memory(xch, io_fd, dom, callbacks, max_iters,
+            max_factor, p2m, p2m_size, flags) )
+    {
+        ERROR("Memory is not saved");
+        goto out;
+    }
+
+    if ( save_magic_pages(xch, io_fd, dom) )
+    {
+        ERROR("Magic pages is not saved");
+        goto out;
+    }
+
+    if ( save_armhvm(xch, io_fd, dom, debug) )
+    {
+        ERROR("HVM is not saved");
+        goto out;
+    }
+    rc = 0;
+out:
+    free(p2m);
+
+    if ( debug ) IPRINTF("Domain %d save return code is %d", dom, rc);
+
+    discard_file_cache(xch, io_fd, 1 /* flush */);
+
+    return rc;
+}
+
+int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom,
+                      unsigned int store_evtchn, unsigned long *store_gpfn,
+                      domid_t store_domid, unsigned int console_evtchn,
+                      unsigned long *console_gpfn, domid_t console_domid,
+                      unsigned int hvm, unsigned int pae, int superpages,
+                      int no_incr_generationid, int checkpointed_stream,
+                      unsigned long *vm_generationid_addr,
+                      struct restore_callbacks *callbacks)
+{
+    int debug = 0;
+    int rc = -1;
+    xen_pfn_t nr_pfns;
+    unsigned int maxmemkb;
+    unsigned long p2m_size = 0;
+    migrate_options_t opts;
+    xen_pfn_t *p2m = NULL;
+    int orig_io_fd_flags;
+
+    if ( (orig_io_fd_flags = fcntl(io_fd, F_GETFL, 0)) < 0 )
+    {
+        PERROR("unable to read IO FD flags");
+        goto out;
+    }
+
+    if ( read_exact(io_fd, &p2m_size, sizeof(p2m_size)) )
+    {
+        PERROR("Can't read p2m_size");
+        goto out;
+    }
+
+    if ( !p2m_size )
+    {
+        /* options passed */
+        if ( read_exact(io_fd, &opts, sizeof(opts)) )
+        {
+            PERROR("Can't read options");
+            goto out;
+        }
+        debug = opts.flags & XCFLAGS_DEBUG;
+
+        if ( read_exact(io_fd, &p2m_size, sizeof(p2m_size)) )
+        {
+            PERROR("Can't read p2m_size");
+            goto out;
+        }
+    }
+    /* allocate p2m */
+    p2m = (xen_pfn_t*) malloc(sizeof(xen_pfn_t) * p2m_size);
+
+    if ( !p2m )
+    {
+        PERROR("p2m allocation error");
+        goto out;
+    }
+    /* read p2m */
+    rc = read_exact(io_fd, p2m, sizeof(xen_pfn_t) * p2m_size);
+    if ( rc )
+    {
+        PERROR("Can't read p2m");
+        goto out;
+    }
+
+    nr_pfns = p2m_size;
+    maxmemkb = (unsigned int) PFN_TO_KB(nr_pfns);
+
+    if ( debug )
+    {
+        IPRINTF("Restore memory size: %d MB, p2m: %lx pages ",
+                maxmemkb >> 10, p2m_size);
+    }
+
+    rc = xc_domain_setmaxmem(xch, dom, maxmemkb);
+    if ( rc )
+    {
+        ERROR("Can't set VM memory size");
+        goto out;
+    }
+
+    rc = restore_memory(xch, io_fd, dom, p2m, p2m_size, debug);
+    if ( rc )
+    {
+        ERROR("Can't restore memory");
+        goto out;
+    }
+
+    rc = restore_magic_pages(xch, io_fd, dom, store_evtchn, store_gpfn,
+                console_evtchn, console_gpfn);
+    if ( rc )
+    {
+        ERROR("Can't restore magic pages");
+        goto out;
+    }
+
+    rc = restore_armhvm(xch, io_fd, dom, debug);
+    if ( rc )
+    {
+        ERROR("HVM not restored");
+        goto out;
+    }
+
+    /* seeding grant tables */
+    rc = xc_dom_gnttab_hvm_seed(xch, dom, *console_gpfn, *store_gpfn,
+                                    console_domid, store_domid);
+    if ( rc )
+    {
+        ERROR("error seeding grant table");
+        goto out;
+    }
+
+out:
+    if ( p2m ) free(p2m);
+
+    if ( (rc != 0) && (dom != 0) )
+            xc_domain_destroy(xch, dom);
+
+    /* discard cache for save file  */
+    discard_file_cache(xch, io_fd, 1 /*flush*/);
+
+    fcntl(io_fd, F_SETFL, orig_io_fd_flags);
+
+    if ( debug ) IPRINTF("Domain %d restore return code is %d", dom, rc);
+
+    return rc;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
\ No newline at end of file
diff --git a/tools/libxc/xc_dom_arm.c b/tools/libxc/xc_dom_arm.c
index 60ac51a..7fd6967 100644
--- a/tools/libxc/xc_dom_arm.c
+++ b/tools/libxc/xc_dom_arm.c
@@ -348,7 +348,9 @@ int arch_setup_meminit(struct xc_dom_image *dom)
         modbase += dtb_size;
     }
 
-    return 0;
+    return rc ? rc: xc_domain_setmaxmem(dom->xch, dom->guest_domid,
+                               (dom->total_pages + NR_MAGIC_PAGES)
+                                << (PAGE_SHIFT - 10));
 }
 
 int arch_setup_bootearly(struct xc_dom_image *dom)
diff --git a/tools/libxc/xg_arm_save_restore.h 
b/tools/libxc/xg_arm_save_restore.h
new file mode 100644
index 0000000..c07fae5
--- /dev/null
+++ b/tools/libxc/xg_arm_save_restore.h
@@ -0,0 +1,106 @@
+/*
+ * Definitions and utilities for ARM save / restore.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  
USA
+ */
+
+#include "xc_private.h"
+
+
+/*
+ * SAVE/RESTORE/MIGRATE PROTOCOL (ARM VERSION)
+ * ===========================================
+ *
+ * The general form of a stream of chunks is a header followed by a
+ * body consisting of a variable number of chunks (terminated by a
+ * chunk with type 0) followed by a trailer.
+ *
+ * NB: Checkpoint (remus) compression is not implemented for ARM yet.
+ *
+ * HEADER
+ * ------
+ *
+ * unsigned long        : p2m_size
+ *
+ * p2m:
+ *
+ *   consists of p2m_size bytes comprising an array of xen_pfn_t sized entries.
+ *
+ * extended-info (optional):
+ *
+ *   If first unsigned long == ~0UL then extended info is present,
+ *   otherwise unsigned long is part of p2m. Note that p2m_size above
+ *   does not include the length of the extended info.
+ *
+ *   extended-info:
+ *
+ *     unsigned long    : signature == ~0UL
+ *     uint32_t         : number of bytes remaining in extended-info
+ *  1 or more extended-info blocks of form:
+ *     char[4]          : block identifier
+ *     uint32_t         : block data size
+ *     bytes            : block data
+ *
+ *     defined extended-info blocks:
+ *     "opts"           :  migration options (uint_32)
+ *
+ * BODY PHASE
+ * ----------
+ *
+ * A series of chunks with a common header:
+ *   int              : chunk type
+ *
+ * If the chunk type is +ve then chunk contains guest memory data, and the
+ * type contains the number of pages in the batch:
+ *
+ *     unsigned long[]  : PFN array, length == number of pages in batch
+ *                        Each element is the PFN number.
+ *     page data        : PAGE_SIZE bytes for each page in PFN array
+ *
+ *
+ * The chunk types -ve can be reserved as
+ * metadata types (not present yet)
+ *
+ * If chunk type is 0 then body phase is complete.
+ *
+ * TAIL PHASE
+ * ----------
+ *
+ *  "Magic" pages:
+ *     uint64_t         : I/O req PFN
+ *     uint64_t         : Buffered I/O req PFN
+ *     uint64_t         : Store PFN
+ *     uint64_t         : Console PFN
+ *  Xen HVM Context:
+ *     uint32_t         : Length of context in bytes
+ *     bytes            : Context data
+ *
+ * NB: Shared info page is transferred as a part of general memory
+ */
+
+
+/* Default values */
+#define DEF_MAX_ITERS          29 /* limit us to 30 times round loop   */
+#define DEF_MAX_FACTOR         3  /* never send more than 3x p2m_size  */
+#define DEF_MIN_DIRTY_PER_ITER 50 /* dirty page count to define last iter */
+#define DEF_PROGRESS_RATE      50 /* progress bar update rate */
+
+#define PFN_TO_KB(_pfn) ((_pfn) << (PAGE_SHIFT - 10))
+#define KB_TO_PFN(_kb) ((_kb) >> (PAGE_SHIFT - 10))
+
+/* Maximum allocation size for domain memory */
+#define XC_ALLOCATE_MAX_PAGES (1 << 20)
+
+
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 80947c3..5f37345 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -469,7 +469,6 @@
  *  - libxl_domain_remus_start
  */
 #if defined(__arm__) || defined(__aarch64__)
-#define LIBXL_HAVE_NO_SUSPEND_RESUME 1
 #endif
 
 /*
diff --git a/tools/misc/Makefile b/tools/misc/Makefile
index 69b1817..f4ea7ab 100644
--- a/tools/misc/Makefile
+++ b/tools/misc/Makefile
@@ -11,7 +11,7 @@ HDRS     = $(wildcard *.h)
 
 TARGETS-y := xenperf xenpm xen-tmem-list-parse gtraceview gtracestat 
xenlockprof xenwatchdogd xencov
 TARGETS-$(CONFIG_X86) += xen-detect xen-hvmctx xen-hvmcrash xen-lowmemd 
xen-mfndump
-TARGETS-$(CONFIG_MIGRATE) += xen-hptool
+TARGETS-$(CONFIG_X86) += xen-hptool
 TARGETS := $(TARGETS-y)
 
 SUBDIRS := $(SUBDIRS-y)
@@ -23,7 +23,7 @@ INSTALL_BIN := $(INSTALL_BIN-y)
 INSTALL_SBIN-y := xen-bugtool xen-python-path xenperf xenpm 
xen-tmem-list-parse gtraceview \
        gtracestat xenlockprof xenwatchdogd xen-ringwatch xencov
 INSTALL_SBIN-$(CONFIG_X86) += xen-hvmctx xen-hvmcrash xen-lowmemd xen-mfndump
-INSTALL_SBIN-$(CONFIG_MIGRATE) += xen-hptool
+INSTALL_SBIN-$(CONFIG_X86) += xen-hptool
 INSTALL_SBIN := $(INSTALL_SBIN-y)
 
 INSTALL_PRIVBIN-y := xenpvnetboot
-- 
1.8.1.2


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.