WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

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

To: xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [RFC][PATCH 06/13] Kemari: Kemari receiver
From: Yoshiaki Tamura <tamura.yoshiaki@xxxxxxxxxxxxx>
Date: Thu, 12 Mar 2009 10:18:39 +0900
Cc: "柳澤佳里(yanagisawa yoshisato)" <yanagisawa.yoshisato@xxxxxxxxxxxxx>, Ian Pratt <ian.pratt@xxxxxxxxxx>, ian.jackson@xxxxxxxxxxxxx, Keir Fraser <keir.fraser@xxxxxxxxxxxxx>, Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
Delivery-date: Wed, 11 Mar 2009 18:39:44 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <49B86208.2020205@xxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <49B86208.2020205@xxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Thunderbird 2.0.0.19 (Windows/20081209)
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