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

[Xen-devel] [RFC][PATCH 06/13] Kemari: Kemari receiver



This is an updated version of the following patch.  Followed the
changes in live migration code.

http://lists.xensource.com/archives/html/xen-devel/2009-03/msg00375.html

Signed-off-by: Yoshisato Yanagisawa <yanagisawa.yoshisato@xxxxxxxxxxxxx>
Signed-off-by: Yoshi Tamura <tamura.yoshiaki@xxxxxxxxxxxxx>
---
 tools/libxc/xc_dom_kemari_restore.c |  727 ++++++++++++++++++++++++++++++++++++
 tools/xcutils/xc_kemari_restore.c   |   88 ++++
 2 files changed, 815 insertions(+)

diff -r b249f3e979a5 -r cf6a910e3663 tools/xcutils/xc_kemari_restore.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/xcutils/xc_kemari_restore.c Wed Mar 11 18:03:47 2009 +0900
@@ -0,0 +1,88 @@
+/*
+ * xc_kemari_restore.c
+ *
+ * Restore the state of a running Linux session.
+ *
+ * Copyright (c) 2008 Nippon Telegraph and Telephone Corporation.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License.  See the file "COPYING" in the main directory of
+ * this archive for more details.
+ *
+ * This source code is based on xc_restore.c.
+ *
+ * Copyright (C) 2005 by Christian Limpach
+ *
+ */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <err.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <xenctrl.h>
+#include <xenguest.h>
+#include <xc_private.h>
+
+static int io_fd;
+
+static void close_handler(int sig_type)
+{
+    /* let xc_kemari_restore move build process */
+    close(io_fd);
+}
+
+int
+main(int argc, char **argv)
+{
+    unsigned int domid, store_evtchn, console_evtchn;
+    unsigned int hvm, pae, apic;
+    int xc_fd, ret, one = 1;
+    unsigned long store_mfn, console_mfn;
+    struct sigaction act;
+
+    if ( argc != 8 )
+        errx(1, "usage: %s iofd domid store_evtchn "
+             "console_evtchn hvm pae apic", argv[0]);
+
+    xc_fd = xc_interface_open();
+    if ( xc_fd < 0 )
+        errx(1, "failed to open control interface");
+
+    io_fd = atoi(argv[1]);
+    domid = atoi(argv[2]);
+    store_evtchn = atoi(argv[3]);
+    console_evtchn = atoi(argv[4]);
+    hvm  = atoi(argv[5]);
+    pae  = atoi(argv[6]);
+    apic = atoi(argv[7]);
+
+    act.sa_handler = close_handler;
+    sigemptyset(&act.sa_mask);
+    act.sa_flags = 0;
+    sigaction(SIGHUP, &act, 0);
+    sigaction(SIGINT, &act, 0);
+
+    if ( setsockopt(io_fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) < 0 )
+        DPRINTF("failed to set TCP_NODELAY");
+
+    ret = xc_kemari_restore(xc_fd, io_fd, domid, store_evtchn, &store_mfn,
+                            console_evtchn, &console_mfn, hvm, pae);
+
+    if ( ret == 0 )
+    {
+        printf("store-mfn %li\n", store_mfn);
+        if ( !hvm )
+            printf("console-mfn %li\n", console_mfn);
+        fflush(stdout);
+    }
+
+    xc_interface_close(xc_fd);
+
+    return ret;
+}
diff -r b249f3e979a5 -r cf6a910e3663 tools/libxc/xc_dom_kemari_restore.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxc/xc_dom_kemari_restore.c       Wed Mar 11 18:03:47 2009 +0900
@@ -0,0 +1,727 @@
+/******************************************************************************
+ * xc_dom_kemari_restore.c
+ *
+ * Restore the state of a guest session for kemari.
+ *
+ * Copyright (c) 2008 Nippon Telegraph and Telephone Corporation.
+ *
+ * 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.
+ *
+ * This source code is based on xc_domain_restore.c.
+ *
+ * Copyright (c) 2003, K A Fraser.
+ * Copyright (c) 2006, Intel Corporation
+ * Copyright (c) 2007, XenSource Inc.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "xg_private.h"
+#include "xg_save_restore.h"
+#include "xc_dom.h"
+
+#include <xen/hvm/ioreq.h>
+#include <xen/hvm/params.h>
+
+/* number of pfns this guest has (i.e. number of entries in the P2M) */
+static unsigned long p2m_size;
+
+/* number of 'in use' pfns in the guest (i.e. #P2M entries with a valid mfn) */
+static unsigned long nr_pfns;
+
+/* A table mapping each PFN to its new MFN. */
+static xen_pfn_t *p2m = NULL;
+
+/* A table of P2M mappings in the current region */
+static xen_pfn_t *p2m_batch = NULL;
+
+int xc_kemari_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)
+{
+    int rc = 1, frc, i, n, m;
+    unsigned long mfn, pfn;
+    unsigned int prev_pc, this_pc;
+
+    /* The new domain's shared-info frame number. */
+    unsigned long shared_info_frame;
+
+    /* A table containing the type of each PFN (/not/ MFN!). */
+    unsigned long *pfn_type = NULL;
+
+    /* A table of MFNs to map in the current region */
+    xen_pfn_t *region_mfn = NULL;
+
+    /* Types of the pfns in the current region */
+    unsigned long region_pfn_type[MAX_BATCH_SIZE];
+
+    /* Our mapping of the current region (batch) */
+    char *region_base;
+
+    /* Magic frames in HVM guests: ioreqs and xenstore comms. */
+    uint64_t magic_pfns[3]; /* ioreq_pfn, bufioreq_pfn, store_pfn */
+
+    /* Temporary buffered memory space until all pages are read. */
+    char *tmp_region = NULL;
+
+    /* if true, go into transaction mode */
+    int kemari_transaction_mode = 0;
+
+    /* index for grant table */
+    int grant_idx = 0;
+
+    /* Callback IRQ */
+    uint64_t callback_irq = 0;
+
+    /* active and non-active id of flip buffer */
+    int info_active = 0, info_non_active = 1;
+
+    /* Buffer for holding HVM context */
+    uint8_t *hvm_buf[2] = {NULL,NULL};
+    uint32_t hvm_buf_size = 0;
+
+    /* Buffer for qemu image */
+    uint8_t *qemu_image[2] = {NULL,NULL};
+    uint32_t qemu_image_size[2] = {0,0};
+    uint32_t qemu_buff_size = 0;
+
+    /* Buffer for the EPT identity PT location. */
+    uint64_t ident_pt[2] = {0,0};
+    /* Buffer for the VM86 TSS. */
+    uint64_t vm86_tss[2] = {0,0};
+
+    if ( !hvm ) {
+        ERROR("Kemari only works on HVM domain.");
+        goto out;
+    }
+
+    /* For info only */
+    nr_pfns = 0;
+
+    if ( read_exact(io_fd, &p2m_size, sizeof(unsigned long)) )
+    {
+        ERROR("read: p2m_size");
+        goto out;
+    }
+    DPRINTF("xc_kemari_restore start: p2m_size = %lx\n", p2m_size);
+
+    /* We want zeroed memory so use calloc rather than malloc. */
+    p2m        = calloc(p2m_size, sizeof(xen_pfn_t));
+    pfn_type   = calloc(p2m_size, sizeof(unsigned long));
+
+    region_mfn = xg_memalign(PAGE_SIZE, ROUNDUP(
+                              MAX_BATCH_SIZE * sizeof(xen_pfn_t), PAGE_SHIFT));
+    p2m_batch  = xg_memalign(PAGE_SIZE, ROUNDUP(
+                              MAX_BATCH_SIZE * sizeof(xen_pfn_t), PAGE_SHIFT));
+
+    /* use aligned page for speed up memmove(3) */
+    tmp_region = xg_memalign(PAGE_SIZE, PAGE_SIZE * MAX_BATCH_SIZE);
+
+    if ( (p2m == NULL) || (pfn_type == NULL) ||
+         (region_mfn == NULL) || (p2m_batch == NULL) ||
+         (tmp_region == NULL) )
+    {
+        ERROR("memory alloc failed");
+        errno = ENOMEM;
+        goto out;
+    }
+
+    memset(region_mfn, 0,
+           ROUNDUP(MAX_BATCH_SIZE * sizeof(xen_pfn_t), PAGE_SHIFT));
+    memset(p2m_batch, 0,
+           ROUNDUP(MAX_BATCH_SIZE * sizeof(xen_pfn_t), PAGE_SHIFT));
+    memset(tmp_region, 0, PAGE_SIZE * MAX_BATCH_SIZE);
+
+    if ( lock_pages(region_mfn, sizeof(xen_pfn_t) * MAX_BATCH_SIZE) )
+    {
+        ERROR("Could not lock region_mfn");
+        goto out;
+    }
+
+    if ( lock_pages(p2m_batch, sizeof(xen_pfn_t) * MAX_BATCH_SIZE) )
+    {
+        ERROR("Could not lock p2m_batch");
+        goto out;
+    }
+
+    if ( lock_pages(tmp_region, sizeof(xen_pfn_t) * MAX_BATCH_SIZE) )
+    {
+        ERROR("Could not lock region_mfn");
+        goto out;
+    }
+
+    /* Get the domain's shared-info frame. */
+    if ( read_exact(io_fd, &shared_info_frame, sizeof(unsigned long)))
+    {
+        ERROR("Error when reading shared_info_frame");
+        goto out;
+    }
+    DPRINTF("xc_kemari_restore: shared_info_frame: %lx\n", shared_info_frame);
+
+    /* read HVM-specific parameters */
+    if ( read_exact(io_fd, magic_pfns, sizeof(magic_pfns)) )
+    {
+        ERROR("error reading magic page addresses");
+        goto out;
+    }
+
+    if (read_exact(io_fd, &callback_irq, sizeof(callback_irq)))
+    {
+        ERROR("error reading magic page addresses");
+        goto out;
+    }
+
+    /* Mark all PFNs as invalid; we allocate on demand */
+    for ( pfn = 0; pfn < p2m_size; pfn++ )
+        p2m[pfn] = INVALID_P2M_ENTRY;
+
+    /*
+     * Now simply read each saved frame into its new machine frame.
+     * We uncanonicalise page tables as we go.
+     */
+    prev_pc = 0;
+
+    n = m = 0;
+    for ( ; ; )
+    {
+        int num_pages;
+        int nr_mfns;
+
+        num_pages = 0;
+        for ( ; ; ) {
+            int j;
+
+            this_pc = (n * 100) / p2m_size;
+            if ( (this_pc - prev_pc) >= 5 )
+            {
+                PPRINTF("\b\b\b\b%3d%%", this_pc);
+                prev_pc = this_pc;
+            }
+
+            if ( read_exact(io_fd, &j, sizeof(int)) )
+            {
+                ERROR("Error when reading batch size");
+                goto build;
+            }
+
+            PPRINTF("batch %d\n",j);
+
+            if (j == -1)
+            {
+                uint32_t rec_size;
+                if ( read_exact(io_fd, &rec_size, sizeof(uint32_t)) )
+                {
+                    ERROR("error read the qemu file size");
+                    goto build;
+                }
+
+                if (qemu_buff_size < rec_size)
+                {
+                    qemu_buff_size = rec_size;
+                    qemu_image[0] = realloc(qemu_image[0], qemu_buff_size);
+                    qemu_image[1] = realloc(qemu_image[1], qemu_buff_size);
+                    if ((qemu_image[0] == NULL) || (qemu_image[1] == NULL))
+                    {
+                        ERROR("error allocate memory");
+                        goto out;
+                    }
+                }
+
+                qemu_image_size[info_non_active] = rec_size;
+                if ( read_exact(io_fd, qemu_image[info_non_active],
+                    qemu_image_size[info_non_active]) )
+                {
+                    ERROR("error read the qemu image file");
+                    goto build;
+                }
+
+                continue;
+            }
+
+            if ( j == -3 )
+            {
+                /* Skip padding 4 bytes then read the EPT identity PT 
location. */
+                if ( read_exact(io_fd, &ident_pt[info_non_active],
+                                sizeof(uint32_t)) ||
+                     read_exact(io_fd, &ident_pt[info_non_active],
+                                sizeof(uint64_t)) )
+                {
+                    ERROR("error read the address of the EPT identity map");
+                    goto build;
+                }
+
+                continue;
+            }
+
+            if ( j == -4 )
+            {
+                /* Skip padding 4 bytes then read the vm86 TSS location. */
+                if ( read_exact(io_fd, &vm86_tss[info_non_active],
+                                sizeof(uint32_t)) ||
+                     read_exact(io_fd, &vm86_tss[info_non_active],
+                                sizeof(uint64_t)) )
+                {
+                    ERROR("error read the address of the vm86 TSS");
+                    goto out;
+                }
+
+                continue;
+            }
+
+            if ( j == 0 )
+                break;  /* our work here is done */
+
+            /* j > 0: Read pages here */
+            if ( (j > MAX_BATCH_SIZE) || (j < 0) )
+            {
+                ERROR("Max batch size exceeded. Giving up. %d", j);
+                goto out;
+            }
+
+            if ( read_exact(io_fd, region_pfn_type, j*sizeof(unsigned long)) )
+            {
+                ERROR("Error when reading region pfn types");
+                goto build;
+            }
+
+            if (kemari_transaction_mode) {
+                if (num_pages != 0)
+                {
+                    ERROR("Sorry!  You cannot execute page-send-phase "
+                        "twice.  We will fix this bug in the future.");
+                    DPRINTF("Sorry\n");
+                    goto out;
+                }
+                num_pages = j;
+
+                /* Since there are not invalid pages, we don't need to skip */
+                if ( read_exact(io_fd, tmp_region, PAGE_SIZE * num_pages) )
+                {
+                    ERROR("Error when reading page at kemari transaction 
mode");
+                    goto build;
+                }
+
+                continue;
+            }
+
+            /* Normal mode */
+            /* First pass for this batch: work out how much memory to alloc */
+            nr_mfns = 0;
+            for ( i = 0; i < j; i++ )
+            {
+                unsigned long pfn, pagetype;
+                pfn      = region_pfn_type[i] & ~XEN_DOMCTL_PFINFO_LTAB_MASK;
+                pagetype = region_pfn_type[i] &  XEN_DOMCTL_PFINFO_LTAB_MASK;
+
+                if ( (pagetype != XEN_DOMCTL_PFINFO_XTAB) &&
+                    (p2m[pfn] == INVALID_P2M_ENTRY) )
+                {
+                    /* Have a live PFN which hasn't had an MFN allocated */
+                    p2m_batch[nr_mfns++] = pfn;
+                    p2m[pfn]--;
+                }
+            }
+
+            /* Now allocate a bunch of mfns for this batch */
+            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.! %d\n", nr_mfns);
+                for (i = 0; i < nr_mfns; i++)
+                    DPRINTF("p2m_batch[%d] = %lx\n", i, p2m_batch[i]);
+                errno = ENOMEM;
+                goto out;
+            }
+
+            /* set special pages */
+            {
+            struct xen_add_to_physmap xatp;
+            for (i = 0; i < nr_mfns; i++)
+                if (p2m_batch[i] == shared_info_frame) {
+                    xatp.domid = dom;
+                    xatp.space = XENMAPSPACE_shared_info;
+                    xatp.idx = 0;
+                    xatp.gpfn = shared_info_frame;
+                    DPRINTF("setting up shared_info_frame: %lu\n",
+                        shared_info_frame);
+                    if (xc_memory_op(xc_handle, XENMEM_add_to_physmap, &xatp)
+                        != 0)
+                    {
+                        ERROR("Error setting shared_info_frame");
+                        goto out;
+                    }
+                } else if ((p2m_batch[i] > shared_info_frame)
+                    && (p2m_batch[i] <= shared_info_frame + 32)) {
+                    xatp.domid = dom;
+                    xatp.space = XENMAPSPACE_grant_table;
+                    xatp.idx = grant_idx;
+                    xatp.gpfn = p2m_batch[i];
+                    DPRINTF("grant[%d]: %lu\n", grant_idx, xatp.gpfn);
+                    if (xc_memory_op(xc_handle, XENMEM_add_to_physmap,
+                        &xatp) != 0)
+                    {
+                        PERROR("Cannot map grant table pfn: %lu", xatp.gpfn);
+                        goto out;
+                    }
+                    grant_idx++;
+                }
+            }
+
+            /* Second pass for this batch: update p2m[] and region_mfn[] */
+            nr_mfns = 0;
+            for ( i = 0; i < j; i++ )
+            {
+                unsigned long pfn, pagetype;
+                pfn      = region_pfn_type[i] & ~XEN_DOMCTL_PFINFO_LTAB_MASK;
+                pagetype = region_pfn_type[i] &  XEN_DOMCTL_PFINFO_LTAB_MASK;
+
+                if ( pagetype == XEN_DOMCTL_PFINFO_XTAB )
+                    region_mfn[i] = ~0UL; /* map will fail but we don't care */
+                else
+                {
+                    if ( p2m[pfn] == (INVALID_P2M_ENTRY-1) )
+                    {
+                        /* We just allocated a new mfn above; update p2m */
+                        p2m[pfn] = p2m_batch[nr_mfns++];
+                        nr_pfns++;
+                    }
+
+                    /* setup region_mfn[] for batch map.
+                     * For HVM guests, this interface takes PFNs, not MFNs */
+                    region_mfn[i] = pfn;
+                }
+            }
+
+            /* Map relevant mfns */
+            region_base = xc_map_foreign_batch(
+                xc_handle, dom, PROT_WRITE, region_mfn, j);
+
+            if ( region_base == NULL )
+            {
+                ERROR("map batch failed");
+                goto out;
+            }
+
+            for ( i = 0; i < j; i++ )
+            {
+                void *page;
+                unsigned long pagetype;
+                pfn      = region_pfn_type[i] & ~XEN_DOMCTL_PFINFO_LTAB_MASK;
+                pagetype = region_pfn_type[i] &  XEN_DOMCTL_PFINFO_LTAB_MASK;
+
+                if ( pagetype == XEN_DOMCTL_PFINFO_XTAB )
+                    /* a bogus/unmapped page: skip it */
+                    continue;
+
+                if ( pfn > p2m_size )
+                {
+                    ERROR("pfn out of range");
+                    goto out;
+                }
+
+                pfn_type[pfn] = pagetype;
+
+                mfn = p2m[pfn];
+
+                page = region_base + i*PAGE_SIZE;
+
+                if ( read_exact(io_fd, page, PAGE_SIZE) )
+                {
+                    ERROR("Error when reading page (type was %lx)", pagetype);
+                    goto out;
+                }
+
+                pagetype &= XEN_DOMCTL_PFINFO_LTABTYPE_MASK;
+
+                if ( (pagetype >= XEN_DOMCTL_PFINFO_L1TAB) &&
+                    (pagetype <= XEN_DOMCTL_PFINFO_L4TAB) )
+                {
+                    DPRINTF("uncanonicalize_pagetable pagetype = %lx pfn = 
%lu\n", pagetype, pfn);
+                }
+                else if ( pagetype != XEN_DOMCTL_PFINFO_NOTAB )
+                {
+                    ERROR("Bogus page type %lx page table is out of range: "
+                        "i=%d p2m_size=%lu", pagetype, i, p2m_size);
+                    goto out;
+
+                }
+            } /* end of 'batch' for loop */
+
+            munmap(region_base, j*PAGE_SIZE);
+            n+= j; /* crude stats */
+        }
+
+        /* HVM specific */
+        {
+            uint32_t rec_len;
+
+            /* Read HVM context */
+            if ( read_exact(io_fd, &rec_len, sizeof(uint32_t)) )
+            {
+                ERROR("error read hvm context size!\n");
+                goto build;
+            }
+
+            if (rec_len != hvm_buf_size)
+            {
+                if (hvm_buf[info_non_active] == NULL)
+                { /* hvm_buf will be reused. */
+                    hvm_buf_size = rec_len;
+                    hvm_buf[0] = malloc(hvm_buf_size);
+                    hvm_buf[1] = malloc(hvm_buf_size);
+                    if ( hvm_buf[0] == NULL || hvm_buf[1] == NULL)
+                    {
+                        ERROR("memory alloc for hvm context buffer failed");
+                        errno = ENOMEM;
+                        goto out;
+                    }
+                } else {
+                    ERROR("Sorry, we did not thought about HVM image size "
+                        "change.");
+                        goto out;
+                }
+            }
+
+            if ( read_exact(io_fd, hvm_buf[info_non_active], hvm_buf_size) )
+            {
+                ERROR("error loading the HVM context");
+                goto build;
+            }
+        }
+
+        /*
+         * Commit!
+         */
+        {
+            int zero = 0;
+
+            if ( write_exact(io_fd, &zero, sizeof(int))) {
+                ERROR("Error when replying to sender (errno %d)", errno);
+                goto out;
+            }
+        }
+
+        /* commit pages */
+        if (kemari_transaction_mode && num_pages > 0)
+        {
+            int nr_mfns;
+            /* First pass for this batch: work out how much memory to alloc */
+            nr_mfns = 0;
+            for ( i = 0; i < num_pages; i++ )
+            {
+                unsigned long pfn, pagetype;
+                pfn      = region_pfn_type[i] & ~XEN_DOMCTL_PFINFO_LTAB_MASK;
+                pagetype = region_pfn_type[i] &  XEN_DOMCTL_PFINFO_LTAB_MASK;
+
+                if ( (pagetype != XEN_DOMCTL_PFINFO_XTAB) &&
+                     (p2m[pfn] == INVALID_P2M_ENTRY) )
+                {
+                    /* Have a live PFN which hasn't had an MFN allocated */
+                    p2m_batch[nr_mfns++] = pfn;
+                    p2m[pfn]--;
+                    DPRINTF("Cannot be occur!!! no map for pfn: %lu\n", pfn);
+                }
+            }
+
+            /* Now allocate a bunch of mfns for this batch */
+            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");
+                errno = ENOMEM;
+                goto out;
+            }
+
+            /* Second pass for this batch: update p2m[] and region_mfn[] */
+            nr_mfns = 0;
+            for ( i = 0; i < num_pages; i++ )
+            {
+                unsigned long pfn, pagetype;
+                pfn      = region_pfn_type[i] & ~XEN_DOMCTL_PFINFO_LTAB_MASK;
+                pagetype = region_pfn_type[i] &  XEN_DOMCTL_PFINFO_LTAB_MASK;
+
+                if ( pagetype == XEN_DOMCTL_PFINFO_XTAB ) {
+                    DPRINTF("pfn %lu = XEN_DOMCTL_PFINFO_XTAB\n", pfn);
+                    region_mfn[i] = ~0UL; /* map will fail but we don't care */
+                }
+                else
+                {
+                    if ( p2m[pfn] == (INVALID_P2M_ENTRY-1) )
+                    {
+                        /* We just allocated a new mfn above; update p2m */
+                        p2m[pfn] = p2m_batch[nr_mfns++];
+                        nr_pfns++;
+                    }
+
+                    /* setup region_mfn[] for batch map.
+                     * For HVM guests, this interface takes PFNs, not MFNs */
+                    region_mfn[i] = pfn;
+                }
+            }
+
+            /* Map relevant mfns */
+            region_base = xc_map_foreign_batch(
+                xc_handle, dom, PROT_WRITE, region_mfn, num_pages);
+
+            if ( region_base == NULL )
+            {
+                ERROR("map batch failed");
+                goto out;
+            }
+
+            for ( i = 0; i < num_pages; i++ )
+            {
+                void *page, *spage;
+                unsigned long pagetype;
+
+                pfn      = region_pfn_type[i] & ~XEN_DOMCTL_PFINFO_LTAB_MASK;
+                pagetype = region_pfn_type[i] &  XEN_DOMCTL_PFINFO_LTAB_MASK;
+
+                if ( pfn > p2m_size )
+                {
+                    ERROR("pfn out of range");
+                    goto out;
+                }
+
+                pfn_type[pfn] = pagetype;
+
+                mfn = p2m[pfn];
+
+                page = region_base + i*PAGE_SIZE;
+                spage = tmp_region + i*PAGE_SIZE;
+
+                if ( !memmove(page, spage, PAGE_SIZE) )
+                {
+                    ERROR("Error when reading page (type was %lx)", pagetype);
+                    goto out;
+                }
+
+            } /* end of 'batch' for loop */
+
+            munmap(region_base, num_pages*PAGE_SIZE);
+            num_pages = 0; /* clear num_pages for refill */
+        }
+
+        /* commit HVM specific status */
+        info_active = info_non_active;
+        info_non_active = info_active ? 0 : 1;
+
+        /* HVM success! */
+        rc = 0;
+        kemari_transaction_mode = 1;
+    }
+
+ build: /* building HVM context */
+    DPRINTF("building status %d\n", rc);
+    if (rc == 0)
+    {
+        FILE *qemu_fp;
+        char path[128];
+
+        /* set the EPT identity PT location */
+        xc_set_hvm_param(xc_handle, dom, HVM_PARAM_IDENT_PT,
+                         ident_pt[info_active]);
+        xc_set_hvm_param(xc_handle, dom, HVM_PARAM_VM86_TSS,
+                         vm86_tss[info_active]);
+
+        if ( (frc = xc_set_hvm_param(xc_handle, dom,
+                                     HVM_PARAM_IOREQ_PFN, magic_pfns[0]))
+             || (frc = xc_set_hvm_param(xc_handle, dom,
+                                        HVM_PARAM_BUFIOREQ_PFN, magic_pfns[1]))
+             || (frc = xc_set_hvm_param(xc_handle, dom,
+                                        HVM_PARAM_STORE_PFN, magic_pfns[2]))
+             || (frc = xc_set_hvm_param(xc_handle, dom,
+                                        HVM_PARAM_PAE_ENABLED, pae))
+             || (frc = xc_set_hvm_param(xc_handle, dom,
+                                        HVM_PARAM_STORE_EVTCHN,
+                                        store_evtchn))
+             || (frc = xc_set_hvm_param(xc_handle, dom,
+                                        HVM_PARAM_CALLBACK_IRQ,
+                                        callback_irq)) )
+        {
+            ERROR("error setting HVM params: %i", frc);
+            rc = 3;
+            goto out;
+        }
+        *store_mfn = magic_pfns[2];
+        DPRINTF("kemari_restore: magic_pfns 0: %lld, 1: %lld, 2: %lld\n",
+            magic_pfns[0], magic_pfns[1], magic_pfns[2]);
+
+        frc = xc_domain_hvm_setcontext(xc_handle, dom, hvm_buf[info_active],
+            hvm_buf_size);
+        if ( frc )
+        {
+            ERROR("error setting the HVM context");
+            rc = 4;
+            goto out;
+        }
+
+        if (qemu_image_size[info_active] == 0)
+        {
+            ERROR("Did not received QEMU image");
+            rc = 5;
+            goto out;
+        }
+        snprintf(path, sizeof(path), "/var/lib/xen/qemu-save.%d", dom);
+        if ((qemu_fp = fopen(path, "w")) == NULL)
+        {
+            ERROR("error opening QEMU image");
+            rc = 5;
+            goto out;
+        }
+        if (fwrite(qemu_image[info_active], qemu_image_size[info_active],
+            1, qemu_fp) != 1)
+        {
+            ERROR("error writing QEMU image");
+            rc = 5;
+            goto out;
+        }
+        fclose(qemu_fp);
+    }
+
+ out:
+    if ( (rc != 0) && (dom != 0) )
+        xc_domain_destroy(xc_handle, dom);
+    free(p2m);
+    free(pfn_type);
+    free(region_mfn);
+    free(p2m_batch);
+    free(tmp_region);
+    free(hvm_buf[0]);
+    free(hvm_buf[1]);
+    free(qemu_image[0]);
+    free(qemu_image[1]);
+
+    /* discard cache for save file  */
+    discard_file_cache(io_fd, 1 /*flush*/);
+
+    DPRINTF("Restore exit with rc=%d\n", rc);
+
+    return rc;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
+



_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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