[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |