From 3998afdbf99959582dcd9f9f4df5a6fe7ce4ded8 Mon Sep 17 00:00:00 2001 From: Dario Faggioli Date: Wed, 11 Sep 2013 13:06:22 +0200 Subject: [PATCH 01/18] xl: fix `xl cpupool-list' behavior in case no pool name is provided since it errors out, asking for at least one argument, and does not display any useful output, which is wrong (we want the list and the info about all the existing cpupools). IOW, the output is as follows: ~# xl cpupool-list -c 'xl cpupool-list' requires at least 1 argument. ... While it should be as follows: ~# xl cpupool-list -c Name CPU list Pool-0 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 Signed-off-by: Dario Faggioli Acked-by: Juergen Gross --- tools/libxl/xl_cmdimpl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 884f050644..35b3e290ff 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -6570,7 +6570,7 @@ int main_cpupoollist(int argc, char **argv) char *name; int ret = 0; - SWITCH_FOREACH_OPT(opt, "hc", opts, "cpupool-list", 1) { + SWITCH_FOREACH_OPT(opt, "hc", opts, "cpupool-list", 0) { case 'c': opt_cpus = 1; break; From bd9a0528ebc68ddb723feef6be57f75096d9df52 Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Fri, 30 Aug 2013 11:52:22 +0100 Subject: [PATCH 02/18] xen: arm: describe Xen boot protocol requirements Signed-off-by: Ian Campbell --- docs/misc/arm/booting.txt | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/misc/arm/booting.txt diff --git a/docs/misc/arm/booting.txt b/docs/misc/arm/booting.txt new file mode 100644 index 0000000000..9802e5e20f --- /dev/null +++ b/docs/misc/arm/booting.txt @@ -0,0 +1,30 @@ +Booting Xen +=========== + +Xen follows the zImage protocol defined for 32-bit ARM Linux[1] and the +Image protocol defined for ARM64 Linux[2]. + +In both cases the recommendation to boot in HYP/EL2 mode is a strict +requirement for Xen. + +The exceptions to this on 32-bit ARM are as follows: + + Xen does not require the machine type to be passed in r1. This + register is ignored (so may be invalid or the actual machine type). + + Xen does not support the ATAG list and requires Device + Tree. Therefore r2 must point to the physical address of device tree + block (dtb) in system RAM. + + NOTE: although Xen uses the zImage protocol there is no compression + actually used. This should be transparent to the bootloader. The + zImage protocol should still be used and not the stricter "raw + (non-zImage)" protocol described in arm/Booting. + +There are no exception on 64-bit ARM. + +[1] linux/Documentation/arm/Booting +Latest version: http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/arm/Booting + +[2] linux/Documentation/arm64/booting.txt +Latest version: http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/arm64/booting.txt From 0dd5b654107103765994243017a7f0eb15fda341 Mon Sep 17 00:00:00 2001 From: Dario Faggioli Date: Tue, 10 Sep 2013 19:53:40 +0200 Subject: [PATCH 03/18] libxc: introduce xc_domain_get_guest_width() As a wrapper to XEN_DOMCTL_get_address_size, and use it wherever the call was being issued directly via do_domctl(), saving quite some line of code. Actually, the function returns the guest width in bytes, rather than directly what XEN_DOMCTL_get_address_size provides (which is a number of bits), since that is what it is useful almost everywhere. Signed-off-by: Dario Faggioli Acked-by: Ian Campbell --- tools/libxc/xc_core.c | 20 +------------------- tools/libxc/xc_cpuid_x86.c | 8 +++----- tools/libxc/xc_dom_x86.c | 13 +++---------- tools/libxc/xc_domain.c | 16 ++++++++++++++++ tools/libxc/xc_offline_page.c | 9 +-------- tools/libxc/xc_pagetab.c | 8 +++----- tools/libxc/xc_resume.c | 21 ++++----------------- tools/libxc/xenctrl.h | 13 +++++++++++++ tools/libxc/xg_save_restore.h | 9 +-------- tools/xentrace/xenctx.c | 9 +++------ 10 files changed, 48 insertions(+), 78 deletions(-) diff --git a/tools/libxc/xc_core.c b/tools/libxc/xc_core.c index 4207eed6dc..4bc1abb441 100644 --- a/tools/libxc/xc_core.c +++ b/tools/libxc/xc_core.c @@ -417,24 +417,6 @@ elfnote_dump_format_version(xc_interface *xch, return dump_rtn(xch, args, (char*)&format_version, sizeof(format_version)); } -static int -get_guest_width(xc_interface *xch, - uint32_t domid, - unsigned int *guest_width) -{ - DECLARE_DOMCTL; - - memset(&domctl, 0, sizeof(domctl)); - domctl.domain = domid; - domctl.cmd = XEN_DOMCTL_get_address_size; - - if ( do_domctl(xch, &domctl) != 0 ) - return 1; - - *guest_width = domctl.u.address_size.size / 8; - return 0; -} - int xc_domain_dumpcore_via_callback(xc_interface *xch, uint32_t domid, @@ -478,7 +460,7 @@ xc_domain_dumpcore_via_callback(xc_interface *xch, struct xc_core_section_headers *sheaders = NULL; Elf64_Shdr *shdr; - if ( get_guest_width(xch, domid, &dinfo->guest_width) != 0 ) + if ( xc_domain_get_guest_width(xch, domid, &dinfo->guest_width) != 0 ) { PERROR("Could not get address size for domain"); return sts; diff --git a/tools/libxc/xc_cpuid_x86.c b/tools/libxc/xc_cpuid_x86.c index fa47787d3e..bbbf9b80eb 100644 --- a/tools/libxc/xc_cpuid_x86.c +++ b/tools/libxc/xc_cpuid_x86.c @@ -436,17 +436,15 @@ static void xc_cpuid_pv_policy( const unsigned int *input, unsigned int *regs) { DECLARE_DOMCTL; + unsigned int guest_width; int guest_64bit, xen_64bit = hypervisor_is_64bit(xch); char brand[13]; uint64_t xfeature_mask; xc_cpuid_brand_get(brand); - memset(&domctl, 0, sizeof(domctl)); - domctl.domain = domid; - domctl.cmd = XEN_DOMCTL_get_address_size; - do_domctl(xch, &domctl); - guest_64bit = (domctl.u.address_size.size == 64); + xc_domain_get_guest_width(xch, domid, &guest_width); + guest_64bit = (guest_width == 8); /* Detecting Xen's atitude towards XSAVE */ memset(&domctl, 0, sizeof(domctl)); diff --git a/tools/libxc/xc_dom_x86.c b/tools/libxc/xc_dom_x86.c index 41f59d3dd1..7cc2ff2411 100644 --- a/tools/libxc/xc_dom_x86.c +++ b/tools/libxc/xc_dom_x86.c @@ -54,24 +54,17 @@ const char *xc_domain_get_native_protocol(xc_interface *xch, int ret; uint32_t guest_width; const char *protocol; - DECLARE_DOMCTL; - memset(&domctl, 0, sizeof(domctl)); - domctl.domain = domid; - domctl.cmd = XEN_DOMCTL_get_address_size; - - ret = do_domctl(xch, &domctl); + ret = xc_domain_get_guest_width(xch, domid, &guest_width); if ( ret ) return NULL; - guest_width = domctl.u.address_size.size; - switch (guest_width) { - case 32: /* 32 bit guest */ + case 4: /* 32 bit guest */ protocol = XEN_IO_PROTO_ABI_X86_32; break; - case 64: /* 64 bit guest */ + case 8: /* 64 bit guest */ protocol = XEN_IO_PROTO_ABI_X86_64; break; default: diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index 3257e2af94..c0ce079e3d 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -270,6 +270,22 @@ out: return ret; } +int xc_domain_get_guest_width(xc_interface *xch, uint32_t domid, + unsigned int *guest_width) +{ + DECLARE_DOMCTL; + + memset(&domctl, 0, sizeof(domctl)); + domctl.domain = domid; + domctl.cmd = XEN_DOMCTL_get_address_size; + + if ( do_domctl(xch, &domctl) != 0 ) + return 1; + + /* We want the result in bytes */ + *guest_width = domctl.u.address_size.size / 8; + return 0; +} int xc_domain_getinfo(xc_interface *xch, uint32_t first_domid, diff --git a/tools/libxc/xc_offline_page.c b/tools/libxc/xc_offline_page.c index 36b981285c..1f6dbc6d5e 100644 --- a/tools/libxc/xc_offline_page.c +++ b/tools/libxc/xc_offline_page.c @@ -193,21 +193,14 @@ static int get_pt_level(xc_interface *xch, uint32_t domid, unsigned int *pt_level, unsigned int *gwidth) { - DECLARE_DOMCTL; xen_capabilities_info_t xen_caps = ""; if (xc_version(xch, XENVER_capabilities, &xen_caps) != 0) return -1; - memset(&domctl, 0, sizeof(domctl)); - domctl.domain = domid; - domctl.cmd = XEN_DOMCTL_get_address_size; - - if ( do_domctl(xch, &domctl) != 0 ) + if (xc_domain_get_guest_width(xch, domid, gwidth) != 0) return -1; - *gwidth = domctl.u.address_size.size / 8; - if (strstr(xen_caps, "xen-3.0-x86_64")) /* Depends on whether it's a compat 32-on-64 guest */ *pt_level = ( (*gwidth == 8) ? 4 : 3 ); diff --git a/tools/libxc/xc_pagetab.c b/tools/libxc/xc_pagetab.c index 27c4e9fcbc..8525967527 100644 --- a/tools/libxc/xc_pagetab.c +++ b/tools/libxc/xc_pagetab.c @@ -51,15 +51,13 @@ unsigned long xc_translate_foreign_address(xc_interface *xch, uint32_t dom, pt_levels = (ctx.msr_efer&EFER_LMA) ? 4 : (ctx.cr4&CR4_PAE) ? 3 : 2; paddr = ctx.cr3 & ((pt_levels == 3) ? ~0x1full : ~0xfffull); } else { - DECLARE_DOMCTL; + unsigned int gwidth; vcpu_guest_context_any_t ctx; if (xc_vcpu_getcontext(xch, dom, vcpu, &ctx) != 0) return 0; - domctl.domain = dom; - domctl.cmd = XEN_DOMCTL_get_address_size; - if ( do_domctl(xch, &domctl) != 0 ) + if (xc_domain_get_guest_width(xch, dom, &gwidth) != 0) return 0; - if (domctl.u.address_size.size == 64) { + if (gwidth == 8) { pt_levels = 4; paddr = (uint64_t)xen_cr3_to_pfn_x86_64(ctx.x64.ctrlreg[3]) << PAGE_SHIFT; diff --git a/tools/libxc/xc_resume.c b/tools/libxc/xc_resume.c index 1c43ec612d..cb6165049f 100644 --- a/tools/libxc/xc_resume.c +++ b/tools/libxc/xc_resume.c @@ -24,19 +24,6 @@ #include #include -static int pv_guest_width(xc_interface *xch, uint32_t domid) -{ - DECLARE_DOMCTL; - domctl.domain = domid; - domctl.cmd = XEN_DOMCTL_get_address_size; - if ( xc_domctl(xch, &domctl) != 0 ) - { - PERROR("Could not get guest address size"); - return -1; - } - return domctl.u.address_size.size / 8; -} - static int modify_returncode(xc_interface *xch, uint32_t domid) { vcpu_guest_context_any_t ctxt; @@ -71,8 +58,7 @@ static int modify_returncode(xc_interface *xch, uint32_t domid) else { /* Probe PV guest address width. */ - dinfo->guest_width = pv_guest_width(xch, domid); - if ( dinfo->guest_width < 0 ) + if ( xc_domain_get_guest_width(xch, domid, &dinfo->guest_width) ) return -1; } @@ -120,7 +106,8 @@ static int xc_domain_resume_any(xc_interface *xch, uint32_t domid) xc_dominfo_t info; int i, rc = -1; #if defined(__i386__) || defined(__x86_64__) - struct domain_info_context _dinfo = { .p2m_size = 0 }; + struct domain_info_context _dinfo = { .guest_width = 0, + .p2m_size = 0 }; struct domain_info_context *dinfo = &_dinfo; unsigned long mfn; vcpu_guest_context_any_t ctxt; @@ -147,7 +134,7 @@ static int xc_domain_resume_any(xc_interface *xch, uint32_t domid) return rc; } - dinfo->guest_width = pv_guest_width(xch, domid); + xc_domain_get_guest_width(xch, domid, &dinfo->guest_width); if ( dinfo->guest_width != sizeof(long) ) { ERROR("Cannot resume uncooperative cross-address-size guests"); diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index f2cebafc9d..58d51f353a 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -560,6 +560,19 @@ int xc_vcpu_getaffinity(xc_interface *xch, int vcpu, xc_cpumap_t cpumap); + +/** + * This function will return the guest_width (in bytes) for the + * specified domain. + * + * @param xch a handle to an open hypervisor interface. + * @param domid the domain id one wants the address size width of. + * @param addr_size the address size. + */ +int xc_domain_get_guest_width(xc_interface *xch, uint32_t domid, + unsigned int *guest_width); + + /** * This function will return information about one or more domains. It is * designed to iterate over the list of domains. If a single domain is diff --git a/tools/libxc/xg_save_restore.h b/tools/libxc/xg_save_restore.h index 651200339b..f859621f62 100644 --- a/tools/libxc/xg_save_restore.h +++ b/tools/libxc/xg_save_restore.h @@ -301,7 +301,6 @@ static inline int get_platform_info(xc_interface *xch, uint32_t dom, { xen_capabilities_info_t xen_caps = ""; xen_platform_parameters_t xen_params; - DECLARE_DOMCTL; if (xc_version(xch, XENVER_platform_parameters, &xen_params) != 0) return 0; @@ -313,15 +312,9 @@ static inline int get_platform_info(xc_interface *xch, uint32_t dom, *hvirt_start = xen_params.virt_start; - memset(&domctl, 0, sizeof(domctl)); - domctl.domain = dom; - domctl.cmd = XEN_DOMCTL_get_address_size; - - if ( do_domctl(xch, &domctl) != 0 ) + if ( xc_domain_get_guest_width(xch, dom, guest_width) != 0) return 0; - *guest_width = domctl.u.address_size.size / 8; - /* 64-bit tools will see the 64-bit hvirt_start, but 32-bit guests * will be using the compat one. */ if ( *guest_width < sizeof (unsigned long) ) diff --git a/tools/xentrace/xenctx.c b/tools/xentrace/xenctx.c index 060e480005..1214185bd8 100644 --- a/tools/xentrace/xenctx.c +++ b/tools/xentrace/xenctx.c @@ -771,12 +771,9 @@ static void dump_ctx(int vcpu) } ctxt_word_size = (strstr(xen_caps, "xen-3.0-x86_64")) ? 8 : 4; } else { - struct xen_domctl domctl; - memset(&domctl, 0, sizeof domctl); - domctl.domain = xenctx.domid; - domctl.cmd = XEN_DOMCTL_get_address_size; - if (xc_domctl(xenctx.xc_handle, &domctl) == 0) - ctxt_word_size = guest_word_size = domctl.u.address_size.size / 8; + unsigned int gw; + if ( !xc_domain_get_guest_width(xenctx.xc_handle, xenctx.domid, &gw) ) + ctxt_word_size = guest_word_size = gw; } } #endif From 6164856fa7300bf914fc4a53f012ff3941fe19b7 Mon Sep 17 00:00:00 2001 From: Dario Faggioli Date: Tue, 10 Sep 2013 19:53:48 +0200 Subject: [PATCH 04/18] libxc: use xc_vcpu_setcontext() instead of calling do_domctl() The wrapper is there already, so better use it in place of all the stuff required to issue a call to do_domctl() for XEN_DOMCTL_setvcpucontext. Signed-off-by: Dario Faggioli Reviewed-by: Andrew Cooper Acked-by: Ian Campbell --- tools/libxc/xc_dom_boot.c | 14 ++++---------- tools/libxc/xc_domain_restore.c | 6 +----- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/tools/libxc/xc_dom_boot.c b/tools/libxc/xc_dom_boot.c index d4d57b4649..cf509faabc 100644 --- a/tools/libxc/xc_dom_boot.c +++ b/tools/libxc/xc_dom_boot.c @@ -62,19 +62,13 @@ static int setup_hypercall_page(struct xc_dom_image *dom) return rc; } -static int launch_vm(xc_interface *xch, domid_t domid, xc_hypercall_buffer_t *ctxt) +static int launch_vm(xc_interface *xch, domid_t domid, + vcpu_guest_context_any_t *ctxt) { - DECLARE_DOMCTL; - DECLARE_HYPERCALL_BUFFER_ARGUMENT(ctxt); int rc; xc_dom_printf(xch, "%s: called, ctxt=%p", __FUNCTION__, ctxt); - memset(&domctl, 0, sizeof(domctl)); - domctl.cmd = XEN_DOMCTL_setvcpucontext; - domctl.domain = domid; - domctl.u.vcpucontext.vcpu = 0; - set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt); - rc = do_domctl(xch, &domctl); + rc = xc_vcpu_setcontext(xch, domid, 0, ctxt); if ( rc != 0 ) xc_dom_panic(xch, XC_INTERNAL_ERROR, "%s: SETVCPUCONTEXT failed (rc=%d)", __FUNCTION__, rc); @@ -270,7 +264,7 @@ int xc_dom_boot_image(struct xc_dom_image *dom) if ( (rc = dom->arch_hooks->vcpu(dom, ctxt)) != 0 ) return rc; xc_dom_unmap_all(dom); - rc = launch_vm(dom->xch, dom->guest_domid, HYPERCALL_BUFFER(ctxt)); + rc = launch_vm(dom->xch, dom->guest_domid, ctxt); xc_hypercall_buffer_free(dom->xch, ctxt); return rc; diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c index 63d36cd63f..41a63cbe26 100644 --- a/tools/libxc/xc_domain_restore.c +++ b/tools/libxc/xc_domain_restore.c @@ -2113,11 +2113,7 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom, } ctxt->x64.ctrlreg[1] = FOLD_CR3(ctx->p2m[pfn]); } - domctl.cmd = XEN_DOMCTL_setvcpucontext; - domctl.domain = (domid_t)dom; - domctl.u.vcpucontext.vcpu = i; - set_xen_guest_handle(domctl.u.vcpucontext.ctxt, ctxt); - frc = xc_domctl(xch, &domctl); + frc = xc_vcpu_setcontext(xch, dom, i, ctxt); if ( frc != 0 ) { PERROR("Couldn't build vcpu%d", i); From 2e2fa6ef6071d0369905e019b0273f3537cf5b9f Mon Sep 17 00:00:00 2001 From: Dario Faggioli Date: Tue, 10 Sep 2013 19:53:57 +0200 Subject: [PATCH 05/18] libxc: use xc_vcpu_getinfo() instead of calling do_domctl() The wrapper is there already, so better use it in place of all the stuff required to issue a call to do_domctl() for XEN_DOMCTL_getdomaininfo. Signed-off-by: Dario Faggioli Acked-by: Ian Campbell --- tools/libxc/xc_dom_boot.c | 17 ++++++++--------- tools/libxc/xc_domain_restore.c | 7 +++---- tools/libxc/xc_private.c | 8 +++----- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/tools/libxc/xc_dom_boot.c b/tools/libxc/xc_dom_boot.c index cf509faabc..71e1897bb5 100644 --- a/tools/libxc/xc_dom_boot.c +++ b/tools/libxc/xc_dom_boot.c @@ -197,8 +197,8 @@ void *xc_dom_boot_domU_map(struct xc_dom_image *dom, xen_pfn_t pfn, int xc_dom_boot_image(struct xc_dom_image *dom) { - DECLARE_DOMCTL; DECLARE_HYPERCALL_BUFFER(vcpu_guest_context_any_t, ctxt); + xc_dominfo_t info; int rc; ctxt = xc_hypercall_buffer_alloc(dom->xch, ctxt, sizeof(*ctxt)); @@ -212,23 +212,22 @@ int xc_dom_boot_image(struct xc_dom_image *dom) return rc; /* collect some info */ - domctl.cmd = XEN_DOMCTL_getdomaininfo; - domctl.domain = dom->guest_domid; - rc = do_domctl(dom->xch, &domctl); - if ( rc != 0 ) + rc = xc_domain_getinfo(dom->xch, dom->guest_domid, 1, &info); + if ( rc < 0 ) { xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, "%s: getdomaininfo failed (rc=%d)", __FUNCTION__, rc); return rc; } - if ( domctl.domain != dom->guest_domid ) + if ( rc == 0 || info.domid != dom->guest_domid ) { xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, - "%s: Huh? domid mismatch (%d != %d)", __FUNCTION__, - domctl.domain, dom->guest_domid); + "%s: Huh? No domains found (nr_domains=%d) " + "or domid mismatch (%d != %d)", __FUNCTION__, + rc, info.domid, dom->guest_domid); return -1; } - dom->shared_info_mfn = domctl.u.getdomaininfo.shared_info_frame; + dom->shared_info_mfn = info.shared_info_frame; /* sanity checks */ if ( !xc_dom_compat_check(dom) ) diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c index 41a63cbe26..b418963e4b 100644 --- a/tools/libxc/xc_domain_restore.c +++ b/tools/libxc/xc_domain_restore.c @@ -1406,6 +1406,7 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom, struct restore_callbacks *callbacks) { DECLARE_DOMCTL; + xc_dominfo_t info; int rc = 1, frc, i, j, n, m, pae_extended_cr3 = 0, ext_vcpucontext = 0; int vcpuextstate = 0; uint32_t vcpuextstate_size = 0; @@ -1562,14 +1563,12 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom, ROUNDUP(MAX_BATCH_SIZE * sizeof(xen_pfn_t), PAGE_SHIFT)); /* Get the domain's shared-info frame. */ - domctl.cmd = XEN_DOMCTL_getdomaininfo; - domctl.domain = (domid_t)dom; - if ( xc_domctl(xch, &domctl) < 0 ) + if ( xc_domain_getinfo(xch, (domid_t)dom, 1, &info) != 1 ) { PERROR("Could not get information on new domain"); goto out; } - shared_info_frame = domctl.u.getdomaininfo.shared_info_frame; + shared_info_frame = info.shared_info_frame; /* Mark all PFNs as invalid; we allocate on demand */ for ( pfn = 0; pfn < dinfo->p2m_size; pfn++ ) diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c index acaf9e0e1e..a260257cd5 100644 --- a/tools/libxc/xc_private.c +++ b/tools/libxc/xc_private.c @@ -609,11 +609,9 @@ int xc_get_pfn_list(xc_interface *xch, long xc_get_tot_pages(xc_interface *xch, uint32_t domid) { - DECLARE_DOMCTL; - domctl.cmd = XEN_DOMCTL_getdomaininfo; - domctl.domain = (domid_t)domid; - return (do_domctl(xch, &domctl) < 0) ? - -1 : domctl.u.getdomaininfo.tot_pages; + xc_dominfo_t info; + return (xc_domain_getinfo(xch, domid, 1, &info) != 1) ? + -1 : info.nr_pages; } int xc_copy_to_domain_page(xc_interface *xch, From dfdfcdc6f7c51ef7e5d0547120d0ac943ef43c67 Mon Sep 17 00:00:00 2001 From: Dario Faggioli Date: Tue, 10 Sep 2013 19:54:05 +0200 Subject: [PATCH 06/18] libxc: allow for ctxt to be NULL in xc_vcpu_setcontext Since, as can be seen in xen/common/domctl.c, that is legitimate (it results in Xen calling vcpu_reset() on the vcpu). Signed-off-by: Dario Faggioli Reviewed-by: Andrew Cooper Acked-by: Ian Campbell --- tools/libxc/xc_domain.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index c0ce079e3d..3210e34a73 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -1141,12 +1141,6 @@ int xc_vcpu_setcontext(xc_interface *xch, DECLARE_HYPERCALL_BOUNCE(ctxt, sizeof(vcpu_guest_context_any_t), XC_HYPERCALL_BUFFER_BOUNCE_IN); int rc; - if (ctxt == NULL) - { - errno = EINVAL; - return -1; - } - if ( xc_hypercall_bounce_pre(xch, ctxt) ) return -1; From 266abb240738bb37ccb28623806273c58523f422 Mon Sep 17 00:00:00 2001 From: Dario Faggioli Date: Tue, 10 Sep 2013 19:54:12 +0200 Subject: [PATCH 07/18] libxc: introduce xc_map_domain_meminfo (and xc_unmap_domain_meminfo) And use it in xc_exchange_page(). This is basically because the following change need something really similar to the set of steps that are here abstracted in these two functions. Despite of the change in the interface and in the signature of some functions, this is pure code motion. No functional changes involved. Signed-off-by: Dario Faggioli Acked-by: Ian Campbell --- tools/libxc/xc_domain.c | 127 +++++++++++++++++++++++ tools/libxc/xc_offline_page.c | 185 ++++++---------------------------- tools/libxc/xenguest.h | 17 ++++ tools/libxc/xg_private.h | 9 ++ 4 files changed, 183 insertions(+), 155 deletions(-) diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index 3210e34a73..81316d3c7f 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -21,6 +21,8 @@ */ #include "xc_private.h" +#include "xc_core.h" +#include "xg_private.h" #include "xg_save_restore.h" #include #include @@ -1477,6 +1479,131 @@ int xc_domain_bind_pt_isa_irq( PT_IRQ_TYPE_ISA, 0, 0, 0, machine_irq)); } +int xc_unmap_domain_meminfo(xc_interface *xch, struct xc_domain_meminfo *minfo) +{ + struct domain_info_context _di = { .guest_width = minfo->guest_width }; + struct domain_info_context *dinfo = &_di; + + free(minfo->pfn_type); + if ( minfo->p2m_table ) + munmap(minfo->p2m_table, P2M_FLL_ENTRIES * PAGE_SIZE); + minfo->p2m_table = NULL; + + return 0; +} + +int xc_map_domain_meminfo(xc_interface *xch, int domid, + struct xc_domain_meminfo *minfo) +{ + struct domain_info_context _di; + struct domain_info_context *dinfo = &_di; + + xc_dominfo_t info; + shared_info_any_t *live_shinfo; + xen_capabilities_info_t xen_caps = ""; + int i; + + /* Only be initialized once */ + if ( minfo->pfn_type || minfo->p2m_table ) + { + errno = EINVAL; + return -1; + } + + if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 ) + { + PERROR("Could not get domain info"); + return -1; + } + + if ( xc_domain_get_guest_width(xch, domid, &minfo->guest_width) ) + { + PERROR("Could not get domain address size"); + return -1; + } + _di.guest_width = minfo->guest_width; + + /* Get page table levels (see get_platform_info() in xg_save_restore.h */ + if ( xc_version(xch, XENVER_capabilities, &xen_caps) ) + { + PERROR("Could not get Xen capabilities (for page table levels)"); + return -1; + } + if ( strstr(xen_caps, "xen-3.0-x86_64") ) + /* Depends on whether it's a compat 32-on-64 guest */ + minfo->pt_levels = ( (minfo->guest_width == 8) ? 4 : 3 ); + else if ( strstr(xen_caps, "xen-3.0-x86_32p") ) + minfo->pt_levels = 3; + else if ( strstr(xen_caps, "xen-3.0-x86_32") ) + minfo->pt_levels = 2; + else + { + errno = EFAULT; + return -1; + } + + /* We need the shared info page for mapping the P2M */ + live_shinfo = xc_map_foreign_range(xch, domid, PAGE_SIZE, PROT_READ, + info.shared_info_frame); + if ( !live_shinfo ) + { + PERROR("Could not map the shared info frame (MFN 0x%lx)", + info.shared_info_frame); + return -1; + } + + if ( xc_core_arch_map_p2m_writable(xch, minfo->guest_width, &info, + live_shinfo, &minfo->p2m_table, + &minfo->p2m_size) ) + { + PERROR("Could not map the P2M table"); + munmap(live_shinfo, PAGE_SIZE); + return -1; + } + munmap(live_shinfo, PAGE_SIZE); + _di.p2m_size = minfo->p2m_size; + + /* Make space and prepare for getting the PFN types */ + minfo->pfn_type = calloc(sizeof(*minfo->pfn_type), minfo->p2m_size); + if ( !minfo->pfn_type ) + { + PERROR("Could not allocate memory for the PFN types"); + goto failed; + } + for ( i = 0; i < minfo->p2m_size; i++ ) + minfo->pfn_type[i] = pfn_to_mfn(i, minfo->p2m_table, + minfo->guest_width); + + /* Retrieve PFN types in batches */ + for ( i = 0; i < minfo->p2m_size ; i+=1024 ) + { + int count = ((minfo->p2m_size - i ) > 1024 ) ? + 1024: (minfo->p2m_size - i); + + if ( xc_get_pfn_type_batch(xch, domid, count, minfo->pfn_type + i) ) + { + PERROR("Could not get %d-eth batch of PFN types", (i+1)/1024); + goto failed; + } + } + + return 0; + +failed: + if ( minfo->pfn_type ) + { + free(minfo->pfn_type); + minfo->pfn_type = NULL; + } + if ( minfo->p2m_table ) + { + munmap(minfo->p2m_table, P2M_FLL_ENTRIES * PAGE_SIZE); + minfo->p2m_table = NULL; + } + + return -1; +} + int xc_domain_memory_mapping( xc_interface *xch, uint32_t domid, diff --git a/tools/libxc/xc_offline_page.c b/tools/libxc/xc_offline_page.c index 1f6dbc6d5e..fbb53f5f0f 100644 --- a/tools/libxc/xc_offline_page.c +++ b/tools/libxc/xc_offline_page.c @@ -33,17 +33,6 @@ #include "xg_private.h" #include "xg_save_restore.h" -struct domain_mem_info{ - int domid; - unsigned int pt_level; - unsigned int guest_width; - xen_pfn_t *pfn_type; - xen_pfn_t *p2m_table; - unsigned long p2m_size; - xen_pfn_t *m2p_table; - int max_mfn; -}; - struct pte_backup_entry { xen_pfn_t table_mfn; @@ -180,139 +169,6 @@ static int xc_is_page_granted_v2(xc_interface *xch, xen_pfn_t gpfn, return (i != gnt_num); } -static xen_pfn_t pfn_to_mfn(xen_pfn_t pfn, xen_pfn_t *p2m, int gwidth) -{ - return ((xen_pfn_t) ((gwidth==8)? - (((uint64_t *)p2m)[(pfn)]): - ((((uint32_t *)p2m)[(pfn)]) == 0xffffffffU ? - (-1UL) : - (((uint32_t *)p2m)[(pfn)])))); -} - -static int get_pt_level(xc_interface *xch, uint32_t domid, - unsigned int *pt_level, - unsigned int *gwidth) -{ - xen_capabilities_info_t xen_caps = ""; - - if (xc_version(xch, XENVER_capabilities, &xen_caps) != 0) - return -1; - - if (xc_domain_get_guest_width(xch, domid, gwidth) != 0) - return -1; - - if (strstr(xen_caps, "xen-3.0-x86_64")) - /* Depends on whether it's a compat 32-on-64 guest */ - *pt_level = ( (*gwidth == 8) ? 4 : 3 ); - else if (strstr(xen_caps, "xen-3.0-x86_32p")) - *pt_level = 3; - else if (strstr(xen_caps, "xen-3.0-x86_32")) - *pt_level = 2; - else - return -1; - - return 0; -} - -static int close_mem_info(xc_interface *xch, struct domain_mem_info *minfo) -{ - if (minfo->pfn_type) - free(minfo->pfn_type); - munmap(minfo->m2p_table, M2P_SIZE(minfo->max_mfn)); - munmap(minfo->p2m_table, P2M_FLL_ENTRIES * PAGE_SIZE); - minfo->p2m_table = minfo->m2p_table = NULL; - - return 0; -} - -static int init_mem_info(xc_interface *xch, int domid, - struct domain_mem_info *minfo, - xc_dominfo_t *info) -{ - uint64_aligned_t shared_info_frame; - shared_info_any_t *live_shinfo = NULL; - int i, rc; - - /* Only be initialized once */ - if (minfo->pfn_type || minfo->m2p_table || minfo->p2m_table) - return -EINVAL; - - if ( get_pt_level(xch, domid, &minfo->pt_level, - &minfo->guest_width) ) - { - ERROR("Unable to get PT level info."); - return -EFAULT; - } - dinfo->guest_width = minfo->guest_width; - - shared_info_frame = info->shared_info_frame; - - live_shinfo = xc_map_foreign_range(xch, domid, - PAGE_SIZE, PROT_READ, shared_info_frame); - if ( !live_shinfo ) - { - ERROR("Couldn't map live_shinfo"); - return -EFAULT; - } - - if ( (rc = xc_core_arch_map_p2m_writable(xch, minfo->guest_width, - info, live_shinfo, &minfo->p2m_table, &minfo->p2m_size)) ) - { - ERROR("Couldn't map p2m table %x\n", rc); - goto failed; - } - munmap(live_shinfo, PAGE_SIZE); - live_shinfo = NULL; - - dinfo->p2m_size = minfo->p2m_size; - - minfo->max_mfn = xc_maximum_ram_page(xch); - if ( !(minfo->m2p_table = - xc_map_m2p(xch, minfo->max_mfn, PROT_READ, NULL)) ) - { - ERROR("Failed to map live M2P table"); - goto failed; - } - - /* Get pfn type */ - minfo->pfn_type = calloc(sizeof(*minfo->pfn_type), minfo->p2m_size); - if (!minfo->pfn_type) - { - ERROR("Failed to malloc pfn_type\n"); - goto failed; - } - - for (i = 0; i < minfo->p2m_size; i++) - minfo->pfn_type[i] = pfn_to_mfn(i, minfo->p2m_table, - minfo->guest_width); - - for (i = 0; i < minfo->p2m_size ; i+=1024) - { - int count = ((dinfo->p2m_size - i ) > 1024 ) ? 1024: (dinfo->p2m_size - i); - if ( ( rc = xc_get_pfn_type_batch(xch, domid, count, - minfo->pfn_type + i)) ) - { - ERROR("Failed to get pfn_type %x\n", rc); - goto failed; - } - } - return 0; - -failed: - if (minfo->pfn_type) - { - free(minfo->pfn_type); - minfo->pfn_type = NULL; - } - if (live_shinfo) - munmap(live_shinfo, PAGE_SIZE); - munmap(minfo->m2p_table, M2P_SIZE(minfo->max_mfn)); - munmap(minfo->p2m_table, P2M_FLL_ENTRIES * PAGE_SIZE); - minfo->p2m_table = minfo->m2p_table = NULL; - - return -1; -} - static int backup_ptes(xen_pfn_t table_mfn, int offset, struct pte_backup *backup) { @@ -402,7 +258,7 @@ static int __update_pte(xc_interface *xch, } static int change_pte(xc_interface *xch, int domid, - struct domain_mem_info *minfo, + struct xc_domain_meminfo *minfo, struct pte_backup *backup, struct xc_mmu *mmu, pte_func func, @@ -412,7 +268,7 @@ static int change_pte(xc_interface *xch, int domid, uint64_t i; void *content = NULL; - pte_num = PAGE_SIZE / ((minfo->pt_level == 2) ? 4 : 8); + pte_num = PAGE_SIZE / ((minfo->pt_levels == 2) ? 4 : 8); for (i = 0; i < minfo->p2m_size; i++) { @@ -435,7 +291,7 @@ static int change_pte(xc_interface *xch, int domid, for (j = 0; j < pte_num; j++) { - if ( minfo->pt_level == 2 ) + if ( minfo->pt_levels == 2 ) pte = ((const uint32_t*)content)[j]; else pte = ((const uint64_t*)content)[j]; @@ -447,7 +303,7 @@ static int change_pte(xc_interface *xch, int domid, case 1: if ( xc_add_mmu_update(xch, mmu, table_mfn << PAGE_SHIFT | - j * ( (minfo->pt_level == 2) ? + j * ( (minfo->pt_levels == 2) ? sizeof(uint32_t): sizeof(uint64_t)) | MMU_PT_UPDATE_PRESERVE_AD, new_pte) ) @@ -480,7 +336,7 @@ failed: } static int update_pte(xc_interface *xch, int domid, - struct domain_mem_info *minfo, + struct xc_domain_meminfo *minfo, struct pte_backup *backup, struct xc_mmu *mmu, unsigned long new_mfn) @@ -490,7 +346,7 @@ static int update_pte(xc_interface *xch, int domid, } static int clear_pte(xc_interface *xch, int domid, - struct domain_mem_info *minfo, + struct xc_domain_meminfo *minfo, struct pte_backup *backup, struct xc_mmu *mmu, xen_pfn_t mfn) @@ -538,7 +394,7 @@ static int is_page_exchangable(xc_interface *xch, int domid, xen_pfn_t mfn, int xc_exchange_page(xc_interface *xch, int domid, xen_pfn_t mfn) { xc_dominfo_t info; - struct domain_mem_info minfo; + struct xc_domain_meminfo minfo; struct xc_mmu *mmu = NULL; struct pte_backup old_ptes = {NULL, 0, 0}; grant_entry_v1_t *gnttab_v1 = NULL; @@ -549,6 +405,8 @@ int xc_exchange_page(xc_interface *xch, int domid, xen_pfn_t mfn) int rc, result = -1; uint32_t status; xen_pfn_t new_mfn, gpfn; + xen_pfn_t *m2p_table; + int max_mfn; if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 ) { @@ -568,10 +426,26 @@ int xc_exchange_page(xc_interface *xch, int domid, xen_pfn_t mfn) return -EINVAL; } - /* Get domain's memory information */ + /* Map M2P and obtain gpfn */ + max_mfn = xc_maximum_ram_page(xch); + if ( !(m2p_table = xc_map_m2p(xch, max_mfn, PROT_READ, NULL)) ) + { + PERROR("Failed to map live M2P table"); + return -EFAULT; + } + gpfn = m2p_table[mfn]; + + /* Map domain's memory information */ memset(&minfo, 0, sizeof(minfo)); - init_mem_info(xch, domid, &minfo, &info); - gpfn = minfo.m2p_table[mfn]; + if ( xc_map_domain_meminfo(xch, domid, &minfo) ) + { + PERROR("Could not map domain's memory information\n"); + return -EFAULT; + } + + /* For translation macros */ + dinfo->guest_width = minfo.guest_width; + dinfo->p2m_size = minfo.p2m_size; /* Don't exchange CR3 for PAE guest in PAE host environment */ if (minfo.guest_width > sizeof(long)) @@ -766,7 +640,8 @@ failed: if (gnttab_v2) munmap(gnttab_v2, gnt_num / (PAGE_SIZE/sizeof(grant_entry_v2_t))); - close_mem_info(xch, &minfo); + xc_unmap_domain_meminfo(xch, &minfo); + munmap(m2p_table, M2P_SIZE(max_mfn)); return result; } diff --git a/tools/libxc/xenguest.h b/tools/libxc/xenguest.h index 4714bd2249..c12091f52b 100644 --- a/tools/libxc/xenguest.h +++ b/tools/libxc/xenguest.h @@ -275,6 +275,23 @@ int xc_query_page_offline_status(xc_interface *xch, unsigned long start, int xc_exchange_page(xc_interface *xch, int domid, xen_pfn_t mfn); +/** + * Memory related information, such as PFN types, the P2M table, + * the guest word width and the guest page table levels. + */ +struct xc_domain_meminfo { + unsigned int pt_levels; + unsigned int guest_width; + xen_pfn_t *pfn_type; + xen_pfn_t *p2m_table; + unsigned long p2m_size; +}; + +int xc_map_domain_meminfo(xc_interface *xch, int domid, + struct xc_domain_meminfo *minfo); + +int xc_unmap_domain_meminfo(xc_interface *xch, struct xc_domain_meminfo *mem); + /** * This function map m2p table * @parm xch a handle to an open hypervisor interface diff --git a/tools/libxc/xg_private.h b/tools/libxc/xg_private.h index db02ccf470..5ff2124346 100644 --- a/tools/libxc/xg_private.h +++ b/tools/libxc/xg_private.h @@ -136,6 +136,15 @@ struct domain_info_context { unsigned long p2m_size; }; +static inline xen_pfn_t pfn_to_mfn(xen_pfn_t pfn, xen_pfn_t *p2m, int gwidth) +{ + return ((xen_pfn_t) ((gwidth==8)? + (((uint64_t *)p2m)[(pfn)]): + ((((uint32_t *)p2m)[(pfn)]) == 0xffffffffU ? + (-1UL) : + (((uint32_t *)p2m)[(pfn)])))); +} + /* Number of xen_pfn_t in a page */ #define FPP (PAGE_SIZE/(dinfo->guest_width)) From ae763e4224304983a1cde2fbb3d6e0c4d60b2688 Mon Sep 17 00:00:00 2001 From: Dario Faggioli Date: Tue, 10 Sep 2013 19:54:20 +0200 Subject: [PATCH 08/18] tools/misc: introduce xen-mfndump. A little development and debugging tool, useful when looking for information about MFN to PFN mappings, MFN/PFN mappings in a guest's PTEs, etc. This is what it can do as of now: $ /usr/sbin/xen-mfndump Usage: xen-mfndump [args] Commands: help show this help dump-m2p show M2P dump-p2m show P2M of dump-ptes show the PTEs in lookup-pte find the PTE mapping memcmp-mfns (str)compare content of & Signed-off-by: Dario Faggioli Acked-by: Ian Campbell --- tools/misc/Makefile | 7 +- tools/misc/xen-mfndump.c | 425 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 430 insertions(+), 2 deletions(-) create mode 100644 tools/misc/xen-mfndump.c diff --git a/tools/misc/Makefile b/tools/misc/Makefile index 59def7af94..17aeda57d1 100644 --- a/tools/misc/Makefile +++ b/tools/misc/Makefile @@ -10,7 +10,7 @@ CFLAGS += $(CFLAGS_libxenstore) 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 +TARGETS-$(CONFIG_X86) += xen-detect xen-hvmctx xen-hvmcrash xen-lowmemd xen-mfndump TARGETS-$(CONFIG_MIGRATE) += xen-hptool TARGETS := $(TARGETS-y) @@ -22,7 +22,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 +INSTALL_SBIN-$(CONFIG_X86) += xen-hvmctx xen-hvmcrash xen-lowmemd xen-mfndump INSTALL_SBIN-$(CONFIG_MIGRATE) += xen-hptool INSTALL_SBIN := $(INSTALL_SBIN-y) @@ -75,6 +75,9 @@ xenlockprof: xenlockprof.o xen-hptool: xen-hptool.o $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(LDLIBS_libxenguest) $(LDLIBS_libxenstore) $(APPEND_LDFLAGS) +xen-mfndump: xen-mfndump.o + $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(LDLIBS_libxenguest) $(LDLIBS_libxenstore) $(APPEND_LDFLAGS) + xenwatchdogd: xenwatchdogd.o $(CC) $(LDFLAGS) -o $@ $< $(LDLIBS_libxenctrl) $(APPEND_LDFLAGS) diff --git a/tools/misc/xen-mfndump.c b/tools/misc/xen-mfndump.c new file mode 100644 index 0000000000..3e8302eb05 --- /dev/null +++ b/tools/misc/xen-mfndump.c @@ -0,0 +1,425 @@ +#include +#include +#include +#include +#include + +#include "xg_save_restore.h" + +#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) + +static xc_interface *xch; + +int help_func(int argc, char *argv[]) +{ + fprintf(stderr, + "Usage: xen-mfndump [args]\n" + "Commands:\n" + " help show this help\n" + " dump-m2p show M2P\n" + " dump-p2m show P2M of \n" + " dump-ptes show the PTEs in \n" + " lookup-pte find the PTE mapping \n" + " memcmp-mfns \n" + " compare content of & \n" + ); + + return 0; +} + +int dump_m2p_func(int argc, char *argv[]) +{ + unsigned long i, max_mfn; + xen_pfn_t *m2p_table; + + if ( argc > 0 ) + { + help_func(0, NULL); + return 1; + } + + /* Map M2P and obtain gpfn */ + max_mfn = xc_maximum_ram_page(xch); + if ( !(m2p_table = xc_map_m2p(xch, max_mfn, PROT_READ, NULL)) ) + { + ERROR("Failed to map live M2P table"); + return -1; + } + + printf(" --- Dumping M2P ---\n"); + printf(" Max MFN: %lu\n", max_mfn); + for ( i = 0; i < max_mfn; i++ ) + { + printf(" mfn=0x%lx ==> pfn=0x%lx\n", i, m2p_table[i]); + } + printf(" --- End of M2P ---\n"); + + munmap(m2p_table, M2P_SIZE(max_mfn)); + return 0; +} + +int dump_p2m_func(int argc, char *argv[]) +{ + struct xc_domain_meminfo minfo; + xc_dominfo_t info; + unsigned long i; + int domid; + + if ( argc < 1 ) + { + help_func(0, NULL); + return 1; + } + domid = atoi(argv[0]); + + if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 || + info.domid != domid ) + { + ERROR("Failed to obtain info for domain %d\n", domid); + return -1; + } + + /* Retrieve all the info about the domain's memory */ + memset(&minfo, 0, sizeof(minfo)); + if ( xc_map_domain_meminfo(xch, domid, &minfo) ) + { + ERROR("Could not map domain %d memory information\n", domid); + return -1; + } + + printf(" --- Dumping P2M for domain %d ---\n", domid); + printf(" Guest Width: %u, PT Levels: %u P2M size: = %lu\n", + minfo.guest_width, minfo.pt_levels, minfo.p2m_size); + for ( i = 0; i < minfo.p2m_size; i++ ) + { + unsigned long pagetype = minfo.pfn_type[i] & + XEN_DOMCTL_PFINFO_LTAB_MASK; + + printf(" pfn=0x%lx ==> mfn=0x%lx (type 0x%lx)", i, minfo.p2m_table[i], + pagetype >> XEN_DOMCTL_PFINFO_LTAB_SHIFT); + + if ( is_mapped(minfo.p2m_table[i]) ) + printf(" [mapped]"); + + if ( pagetype & XEN_DOMCTL_PFINFO_LPINTAB ) + printf (" [pinned]"); + + if ( pagetype == XEN_DOMCTL_PFINFO_XTAB ) + printf(" [xtab]"); + if ( pagetype == XEN_DOMCTL_PFINFO_BROKEN ) + printf(" [broken]"); + if ( pagetype == XEN_DOMCTL_PFINFO_XALLOC ) + printf( " [xalloc]"); + + switch ( pagetype & XEN_DOMCTL_PFINFO_LTABTYPE_MASK ) + { + case XEN_DOMCTL_PFINFO_L1TAB: + printf(" L1 table"); + break; + + case XEN_DOMCTL_PFINFO_L2TAB: + printf(" L2 table"); + break; + + case XEN_DOMCTL_PFINFO_L3TAB: + printf(" L3 table"); + break; + + case XEN_DOMCTL_PFINFO_L4TAB: + printf(" L4 table"); + break; + } + + printf("\n"); + } + printf(" --- End of P2M for domain %d ---\n", domid); + + xc_unmap_domain_meminfo(xch, &minfo); + return 0; +} + +int dump_ptes_func(int argc, char *argv[]) +{ + struct xc_domain_meminfo minfo; + xc_dominfo_t info; + void *page = NULL; + unsigned long i, max_mfn; + int domid, pte_num, rc = 0; + xen_pfn_t pfn, mfn, *m2p_table; + + if ( argc < 2 ) + { + help_func(0, NULL); + return 1; + } + domid = atoi(argv[0]); + mfn = strtoul(argv[1], NULL, 16); + + if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 || + info.domid != domid ) + { + ERROR("Failed to obtain info for domain %d\n", domid); + return -1; + } + + /* Retrieve all the info about the domain's memory */ + memset(&minfo, 0, sizeof(minfo)); + if ( xc_map_domain_meminfo(xch, domid, &minfo) ) + { + ERROR("Could not map domain %d memory information\n", domid); + return -1; + } + + /* Map M2P and obtain gpfn */ + max_mfn = xc_maximum_ram_page(xch); + if ( (mfn > max_mfn) || + !(m2p_table = xc_map_m2p(xch, max_mfn, PROT_READ, NULL)) ) + { + xc_unmap_domain_meminfo(xch, &minfo); + ERROR("Failed to map live M2P table"); + return -1; + } + + pfn = m2p_table[mfn]; + if ( pfn >= minfo.p2m_size ) + { + ERROR("pfn 0x%lx out of range for domain %d\n", pfn, domid); + rc = -1; + goto out; + } + + if ( !(minfo.pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) ) + { + ERROR("pfn 0x%lx for domain %d is not a PT\n", pfn, domid); + rc = -1; + goto out; + } + + page = xc_map_foreign_range(xch, domid, PAGE_SIZE, PROT_READ, + minfo.p2m_table[pfn]); + if ( !page ) + { + ERROR("Failed to map 0x%lx\n", minfo.p2m_table[pfn]); + rc = -1; + goto out; + } + + pte_num = PAGE_SIZE / 8; + + printf(" --- Dumping %d PTEs for domain %d ---\n", pte_num, domid); + printf(" Guest Width: %u, PT Levels: %u P2M size: = %lu\n", + minfo.guest_width, minfo.pt_levels, minfo.p2m_size); + printf(" pfn: 0x%lx, mfn: 0x%lx", + pfn, minfo.p2m_table[pfn]); + switch ( minfo.pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK ) + { + case XEN_DOMCTL_PFINFO_L1TAB: + printf(", L1 table"); + break; + case XEN_DOMCTL_PFINFO_L2TAB: + printf(", L2 table"); + break; + case XEN_DOMCTL_PFINFO_L3TAB: + printf(", L3 table"); + break; + case XEN_DOMCTL_PFINFO_L4TAB: + printf(", L4 table"); + break; + } + if ( minfo.pfn_type[pfn] & XEN_DOMCTL_PFINFO_LPINTAB ) + printf (" [pinned]"); + if ( is_mapped(minfo.p2m_table[pfn]) ) + printf(" [mapped]"); + printf("\n"); + + for ( i = 0; i < pte_num; i++ ) + printf(" pte[%lu]: 0x%lx\n", i, ((const uint64_t*)page)[i]); + + printf(" --- End of PTEs for domain %d, pfn=0x%lx (mfn=0x%lx) ---\n", + domid, pfn, minfo.p2m_table[pfn]); + + out: + munmap(page, PAGE_SIZE); + xc_unmap_domain_meminfo(xch, &minfo); + munmap(m2p_table, M2P_SIZE(max_mfn)); + return rc; +} + +int lookup_pte_func(int argc, char *argv[]) +{ + struct xc_domain_meminfo minfo; + xc_dominfo_t info; + void *page = NULL; + unsigned long i, j; + int domid, pte_num; + xen_pfn_t mfn; + + if ( argc < 2 ) + { + help_func(0, NULL); + return 1; + } + domid = atoi(argv[0]); + mfn = strtoul(argv[1], NULL, 16); + + if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 || + info.domid != domid ) + { + ERROR("Failed to obtain info for domain %d\n", domid); + return -1; + } + + /* Retrieve all the info about the domain's memory */ + memset(&minfo, 0, sizeof(minfo)); + if ( xc_map_domain_meminfo(xch, domid, &minfo) ) + { + ERROR("Could not map domain %d memory information\n", domid); + return -1; + } + + pte_num = PAGE_SIZE / 8; + + printf(" --- Lookig for PTEs mapping mfn 0x%lx for domain %d ---\n", + mfn, domid); + printf(" Guest Width: %u, PT Levels: %u P2M size: = %lu\n", + minfo.guest_width, minfo.pt_levels, minfo.p2m_size); + + for ( i = 0; i < minfo.p2m_size; i++ ) + { + if ( !(minfo.pfn_type[i] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) ) + continue; + + page = xc_map_foreign_range(xch, domid, PAGE_SIZE, PROT_READ, + minfo.p2m_table[i]); + if ( !page ) + continue; + + for ( j = 0; j < pte_num; j++ ) + { + uint64_t pte = ((const uint64_t*)page)[j]; + +#define __MADDR_BITS_X86 ((minfo.guest_width == 8) ? 52 : 44) +#define __MFN_MASK_X86 ((1ULL << (__MADDR_BITS_X86 - PAGE_SHIFT_X86)) - 1) + if ( ((pte >> PAGE_SHIFT_X86) & __MFN_MASK_X86) == mfn) + printf(" 0x%lx <-- [0x%lx][%lu]: 0x%lx\n", + mfn, minfo.p2m_table[i], j, pte); +#undef __MADDR_BITS_X86 +#undef __MFN_MASK_X8 + } + + munmap(page, PAGE_SIZE); + page = NULL; + } + + xc_unmap_domain_meminfo(xch, &minfo); + + return 1; +} + +int memcmp_mfns_func(int argc, char *argv[]) +{ + xc_dominfo_t info1, info2; + void *page1 = NULL, *page2 = NULL; + int domid1, domid2; + xen_pfn_t mfn1, mfn2; + int rc = 0; + + if ( argc < 4 ) + { + help_func(0, NULL); + return 1; + } + domid1 = atoi(argv[0]); + domid2 = atoi(argv[2]); + mfn1 = strtoul(argv[1], NULL, 16); + mfn2 = strtoul(argv[3], NULL, 16); + + if ( xc_domain_getinfo(xch, domid1, 1, &info1) != 1 || + xc_domain_getinfo(xch, domid2, 1, &info2) != 1 || + info1.domid != domid1 || info2.domid != domid2) + { + ERROR("Failed to obtain info for domains\n"); + return -1; + } + + page1 = xc_map_foreign_range(xch, domid1, PAGE_SIZE, PROT_READ, mfn1); + page2 = xc_map_foreign_range(xch, domid2, PAGE_SIZE, PROT_READ, mfn2); + if ( !page1 || !page2 ) + { + ERROR("Failed to map either 0x%lx[dom %d] or 0x%lx[dom %d]\n", + mfn1, domid1, mfn2, domid2); + rc = -1; + goto out; + } + + printf(" --- Comparing the content of 2 MFNs ---\n"); + printf(" 1: 0x%lx[dom %d], 2: 0x%lx[dom %d]\n", + mfn1, domid1, mfn2, domid2); + printf(" memcpy(1, 2) = %d\n", memcmp(page1, page2, PAGE_SIZE)); + + out: + munmap(page1, PAGE_SIZE); + munmap(page2, PAGE_SIZE); + return rc; +} + + + +struct { + const char *name; + int (*func)(int argc, char *argv[]); +} opts[] = { + { "help", help_func }, + { "dump-m2p", dump_m2p_func }, + { "dump-p2m", dump_p2m_func }, + { "dump-ptes", dump_ptes_func }, + { "lookup-pte", lookup_pte_func }, + { "memcmp-mfns", memcmp_mfns_func}, +}; + +int main(int argc, char *argv[]) +{ + int i, ret; + + if (argc < 2) + { + help_func(0, NULL); + return 1; + } + + xch = xc_interface_open(0, 0, 0); + if ( !xch ) + { + ERROR("Failed to open an xc handler"); + return 1; + } + + for ( i = 0; i < ARRAY_SIZE(opts); i++ ) + { + if ( !strncmp(opts[i].name, argv[1], strlen(argv[1])) ) + break; + } + + if ( i == ARRAY_SIZE(opts) ) + { + fprintf(stderr, "Unknown option '%s'", argv[1]); + help_func(0, NULL); + return 1; + } + + ret = opts[i].func(argc - 2, argv + 2); + + xc_interface_close(xch); + + return !!ret; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ From 1438d36f96e90d1116bebc6b3013634ca21c49c8 Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Tue, 10 Sep 2013 11:08:30 -0400 Subject: [PATCH 09/18] xenstat: Fix buffer over-run with new_domains being negative. Coverity identified this as: CID 1055740 Out-of-bounds read - "In xenstat_get_node: Out-of-bounds read from a buffer (CWE-125)" And sure enough, if xc_domain_getinfolist returns us -1, we will try to use it later on in the for (i = 0; i < new_domains; ..) loop. Signed-off-by: Konrad Rzeszutek Wilk Reviewed-by: Andrew Cooper --- tools/xenstat/libxenstat/src/xenstat.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/xenstat/libxenstat/src/xenstat.c b/tools/xenstat/libxenstat/src/xenstat.c index 104655d5f1..e5facb84f5 100644 --- a/tools/xenstat/libxenstat/src/xenstat.c +++ b/tools/xenstat/libxenstat/src/xenstat.c @@ -208,15 +208,15 @@ xenstat_node *xenstat_get_node(xenstat_handle * handle, unsigned int flags) node->num_domains, DOMAIN_CHUNK_SIZE, domaininfo); + if (new_domains < 0) + goto err; tmp = realloc(node->domains, (node->num_domains + new_domains) * sizeof(xenstat_domain)); - if (tmp == NULL) { - free(node->domains); - free(node); - return NULL; - } + if (tmp == NULL) + goto err; + node->domains = tmp; domain = node->domains + node->num_domains; @@ -280,6 +280,10 @@ xenstat_node *xenstat_get_node(xenstat_handle * handle, unsigned int flags) } return node; +err: + free(node->domains); + free(node); + return NULL; } void xenstat_free_node(xenstat_node * node) From a508caf0ebc4f834bd44c1d607e5b7bfabe43e3d Mon Sep 17 00:00:00 2001 From: Roger Pau Monne Date: Fri, 6 Sep 2013 12:36:26 +0200 Subject: [PATCH 10/18] libxl: fix libxl__device_disk_from_xs_be to parse backend domid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit libxl__device_disk_from_xs_be was ignoring the backend domid, setting it to 0 by default. Fix this by parsing the backend disk path in order to fetch the backend domid. This fixes the issue reported when trying to block-detach disks that have it's backend on a driver domain. Signed-off-by: Roger Pau Monné Reported-by: G.R. Cc: Ian Jackson Acked-by: Ian Campbell --- tools/libxl/libxl.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 1bce4bb46f..7a7aaf90fe 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -2234,9 +2234,16 @@ static int libxl__device_disk_from_xs_be(libxl__gc *gc, libxl_ctx *ctx = libxl__gc_owner(gc); unsigned int len; char *tmp; + int rc; libxl_device_disk_init(disk); + rc = sscanf(be_path, "/local/domain/%d/", &disk->backend_domid); + if (rc != 1) { + LOG(ERROR, "Unable to fetch device backend domid from %s", be_path); + goto cleanup; + } + /* "params" may not be present; but everything else must be. */ tmp = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(gc, "%s/params", be_path), &len); From ceb556178d59d6e06871b1b921e5c8b9be084582 Mon Sep 17 00:00:00 2001 From: Matthew Daley Date: Wed, 11 Sep 2013 02:34:17 +1200 Subject: [PATCH 11/18] libxl: fix use-after-free in discard_events iteration We need to use the foreach variant which gets the next pointer before the loop body is executed. Coverity-ID: 1056193 Signed-off-by: Matthew Daley Acked-by: Ian Jackson --- tools/libxl/libxl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 7a7aaf90fe..0879f2331f 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -122,8 +122,8 @@ static void free_disable_deaths(libxl__gc *gc, static void discard_events(struct libxl__event_list *l) { /* doesn't bother unlinking from the list, so l is corrupt on return */ - libxl_event *ev; - LIBXL_TAILQ_FOREACH(ev, l, link) + libxl_event *ev, *next; + LIBXL_TAILQ_FOREACH_SAFE(ev, l, link, next) libxl_event_free(0, ev); } From ad6aa096e49a4ea78ca7816f6385c4d23c498fcd Mon Sep 17 00:00:00 2001 From: Matthew Daley Date: Wed, 11 Sep 2013 02:34:18 +1200 Subject: [PATCH 12/18] libxl: correctly handle readlink() errors readlink() returns a ssize_t with a negative value on failure. Coverity-ID: 1055566 Signed-off-by: Matthew Daley Acked-by: Ian Jackson --- tools/libxl/libxl_exec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/libxl/libxl_exec.c b/tools/libxl/libxl_exec.c index 98bfd716ac..7eddaef2e3 100644 --- a/tools/libxl/libxl_exec.c +++ b/tools/libxl/libxl_exec.c @@ -33,7 +33,7 @@ static void check_open_fds(const char *what) for (i = 4; i < 256; i++) { #ifdef __linux__ - size_t len; + ssize_t len; char path[PATH_MAX]; char linkpath[PATH_MAX+1]; #endif From 72b9c3e88c1cd205b39b178ce5e684868a1117c2 Mon Sep 17 00:00:00 2001 From: Matthew Daley Date: Wed, 11 Sep 2013 02:34:19 +1200 Subject: [PATCH 13/18] mini-os: fix use-after-free in xs_daemon_close event iteration We need to get the next pointer before the freeing of the event. Coverity-ID: 1056173 Signed-off-by: Matthew Daley Acked-By: Samuel Thibault --- extras/mini-os/lib/xs.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/extras/mini-os/lib/xs.c b/extras/mini-os/lib/xs.c index a2a122098c..c603d178bf 100644 --- a/extras/mini-os/lib/xs.c +++ b/extras/mini-os/lib/xs.c @@ -29,9 +29,12 @@ struct xs_handle *xs_daemon_open() void xs_daemon_close(struct xs_handle *h) { int fd = _xs_fileno(h); - struct xenbus_event *event; - for (event = files[fd].xenbus.events; event; event = event->next) + struct xenbus_event *event, *next; + for (event = files[fd].xenbus.events; event; event = next) + { + next = event->next; free(event); + } files[fd].type = FTYPE_NONE; } From 6425b20c0f10eff1843807f83d9cc0895bf91082 Mon Sep 17 00:00:00 2001 From: Matthew Daley Date: Wed, 11 Sep 2013 02:34:20 +1200 Subject: [PATCH 14/18] mini-os: handle possibly overlong _nodename in init_consfront The only current user that passes a non-NULL _nodename limits it to 64 bytes anyway. Coverity-ID: 1054993 Signed-off-by: Matthew Daley Acked-by: Samuel Thibault --- extras/mini-os/console/xenbus.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/extras/mini-os/console/xenbus.c b/extras/mini-os/console/xenbus.c index 23d4d32aea..41949824af 100644 --- a/extras/mini-os/console/xenbus.c +++ b/extras/mini-os/console/xenbus.c @@ -70,8 +70,10 @@ struct consfront_dev *init_consfront(char *_nodename) if (!_nodename) snprintf(nodename, sizeof(nodename), "device/console/%d", consfrontends); - else - strncpy(nodename, _nodename, sizeof(nodename)); + else { + strncpy(nodename, _nodename, sizeof(nodename) - 1); + nodename[sizeof(nodename) - 1] = 0; + } printk("******************* CONSFRONT for %s **********\n\n\n", nodename); From da89e7ef29c2e310e620d3ee05e86e9c164cf17b Mon Sep 17 00:00:00 2001 From: Matthew Daley Date: Wed, 11 Sep 2013 02:34:21 +1200 Subject: [PATCH 15/18] kdd: fix free of array-typed value g->id is an array and is allocated as part of g itself; it's not a separate allocation. Coverity-ID: 1054980 Signed-off-by: Matthew Daley Acked-by: Tim Deegan Reviewed-by: Andrew Cooper --- tools/debugger/kdd/kdd-xen.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/debugger/kdd/kdd-xen.c b/tools/debugger/kdd/kdd-xen.c index 4fbea7df73..f3f9529f9f 100644 --- a/tools/debugger/kdd/kdd-xen.c +++ b/tools/debugger/kdd/kdd-xen.c @@ -619,7 +619,6 @@ void kdd_guest_teardown(kdd_guest *g) { flush_maps(g); xc_interface_close(g->xc_handle); - free(g->id); free(g->hvm_buf); free(g); } From ba033a204b022cd4a2a8fd2c836d874090cb78e9 Mon Sep 17 00:00:00 2001 From: Matthew Daley Date: Wed, 11 Sep 2013 02:34:22 +1200 Subject: [PATCH 16/18] xenstored: fix possible, but unlikely, stack overflow ...when reading xenbus port from xenfs. Coverity-ID: 1055741 Signed-off-by: Matthew Daley Reviewed-by: Andrew Cooper Acked-by: Ian Jackson --- tools/xenstore/xenstored_linux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/xenstore/xenstored_linux.c b/tools/xenstore/xenstored_linux.c index 5460ca5573..cf40213b3b 100644 --- a/tools/xenstore/xenstored_linux.c +++ b/tools/xenstore/xenstored_linux.c @@ -32,7 +32,7 @@ evtchn_port_t xenbus_evtchn(void) if (fd == -1) return -1; - rc = read(fd, str, sizeof(str)); + rc = read(fd, str, sizeof(str) - 1); if (rc == -1) { int err = errno; From 17b29c1cd830acf8b8ecbc6080264cc5b8ad3c6f Mon Sep 17 00:00:00 2001 From: Fabio Fantoni Date: Tue, 10 Sep 2013 16:46:13 +0200 Subject: [PATCH 17/18] libxl: Spice vdagent support for upstream qemu Usage: - spicevdagent=1|0 (default=0) Enables spice vdagent. The Spice vdagent is an optional component for enhancing user experience and performing guest-oriented management tasks. Its features includes: client mouse mode (no need to grab mouse by client, no mouse lag), automatic adjustment of screen resolution, copy and paste (text and image) between client and domU. It also requires vdagent service installed on domU o.s. to work. - spice_clipboard_sharing=1|0 (default=0) Enables Spice clipboard sharing (copy/paste). It requires spicevdagent enabled. Signed-off-by: Fabio Fantoni Acked-by: Ian Campbell --- docs/man/xl.cfg.pod.5 | 14 ++++++++++++++ tools/libxl/libxl.h | 11 +++++++++++ tools/libxl/libxl_create.c | 3 +++ tools/libxl/libxl_dm.c | 10 ++++++++++ tools/libxl/libxl_types.idl | 2 ++ tools/libxl/xl_cmdimpl.c | 4 ++++ 6 files changed, 44 insertions(+) diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5 index 08d6cc45db..769767b02d 100644 --- a/docs/man/xl.cfg.pod.5 +++ b/docs/man/xl.cfg.pod.5 @@ -1130,6 +1130,20 @@ Specify the ticket password which is used by a client for connection. Whether SPICE agent is used for client mouse mode. The default is true (1) (turn on) +=item B + +Enables spice vdagent. The Spice vdagent is an optional component for +enhancing user experience and performing guest-oriented management +tasks. Its features includes: client mouse mode (no need to grab mouse +by client, no mouse lag), automatic adjustment of screen resolution, +copy and paste (text and image) between client and domU. It also +requires vdagent service installed on domU o.s. to work. The default is 0. + +=item B + +Enables Spice clipboard sharing (copy/paste). It requires spicevdagent +enabled. The default is false (0). + =back =head3 Miscellaneous Emulated Hardware diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h index be19bf5186..4cab2947e7 100644 --- a/tools/libxl/libxl.h +++ b/tools/libxl/libxl.h @@ -344,6 +344,17 @@ */ #define LIBXL_HAVE_DOMINFO_OUTSTANDING_MEMKB 1 +/* + * LIBXL_HAVE_SPICE_VDAGENT + * + * If defined, then the libxl_spice_info structure will contain a boolean type: + * vdagent and clipboard_sharing. These values define if Spice vdagent and + * clipboard sharing are enabled. + * + * If this is not defined, the Spice vdagent support is ignored. + */ +#define LIBXL_HAVE_SPICE_VDAGENT 1 + /* Functions annotated with LIBXL_EXTERNAL_CALLERS_ONLY may not be * called from within libxl itself. Callers outside libxl, who * do not #include libxl_internal.h, are fine. */ diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index 0c32d0b143..7567238f75 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -272,6 +272,9 @@ int libxl__domain_build_info_setdefault(libxl__gc *gc, libxl_defbool_setdefault(&b_info->u.hvm.spice.disable_ticketing, false); libxl_defbool_setdefault(&b_info->u.hvm.spice.agent_mouse, true); + libxl_defbool_setdefault(&b_info->u.hvm.spice.vdagent, false); + libxl_defbool_setdefault(&b_info->u.hvm.spice.clipboard_sharing, + false); } libxl_defbool_setdefault(&b_info->u.hvm.nographic, false); diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c index 4035b6db62..43c3becc7a 100644 --- a/tools/libxl/libxl_dm.c +++ b/tools/libxl/libxl_dm.c @@ -351,6 +351,10 @@ static char *dm_spice_options(libxl__gc *gc, opt = libxl__sprintf(gc, "%s,password=%s", opt, spice->passwd); opt = libxl__sprintf(gc, "%s,agent-mouse=%s", opt, libxl_defbool_val(spice->agent_mouse) ? "on" : "off"); + + if (!libxl_defbool_val(spice->clipboard_sharing)) + opt = libxl__sprintf(gc, "%s,disable-copy-paste", opt); + return opt; } @@ -472,6 +476,12 @@ static char ** libxl__build_device_model_args_new(libxl__gc *gc, flexarray_append(dm_args, "-spice"); flexarray_append(dm_args, spiceoptions); + if (libxl_defbool_val(b_info->u.hvm.spice.vdagent)) { + flexarray_vappend(dm_args, "-device", "virtio-serial", + "-chardev", "spicevmc,id=vdagent,name=vdagent", "-device", + "virtserialport,chardev=vdagent,name=com.redhat.spice.0", + NULL); + } } switch (b_info->u.hvm.vga.kind) { diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 10f95f42e3..049dbb50b5 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -181,6 +181,8 @@ libxl_spice_info = Struct("spice_info", [ ("disable_ticketing", libxl_defbool), ("passwd", string), ("agent_mouse", libxl_defbool), + ("vdagent", libxl_defbool), + ("clipboard_sharing", libxl_defbool), ]) libxl_sdl_info = Struct("sdl_info", [ diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 35b3e290ff..3d7eaad5e0 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -1495,6 +1495,10 @@ skip_vfb: &b_info->u.hvm.spice.passwd, 0); xlu_cfg_get_defbool(config, "spiceagent_mouse", &b_info->u.hvm.spice.agent_mouse, 0); + xlu_cfg_get_defbool(config, "spicevdagent", + &b_info->u.hvm.spice.vdagent, 0); + xlu_cfg_get_defbool(config, "spice_clipboard_sharing", + &b_info->u.hvm.spice.clipboard_sharing, 0); xlu_cfg_get_defbool(config, "nographic", &b_info->u.hvm.nographic, 0); xlu_cfg_get_defbool(config, "gfx_passthru", &b_info->u.hvm.gfx_passthru, 0); From 255d252c0afafd0d2b6a9e4c2ad4dadbd2f00051 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Tue, 10 Sep 2013 14:53:50 +0100 Subject: [PATCH 18/18] tools/tests: tweak .gitignore c/s e7803f184a moved x86_emulate and friends into their own subdirectory. c/s cc8ad39c1f introduced xen-access, but seemingly without an ingore. For both of the above add/adjust the ingore rules for generated files. Signed-off-by: Andrew Cooper CC: Ian Campbell CC: Ian Jackson --- .gitignore | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index c82a372f02..8e539b42b6 100644 --- a/.gitignore +++ b/.gitignore @@ -230,10 +230,11 @@ tools/remus/kmod/*(.cmd|.mod|.ko|.mod.c|.symvers|.xen) tools/security/secpol_tool tools/security/xen/* tools/security/xensec_tool -tools/tests/blowfish.bin -tools/tests/blowfish.h -tools/tests/test_x86_emulator -tools/tests/x86_emulate +tools/tests/x86_emulator/blowfish.bin +tools/tests/x86_emulator/blowfish.h +tools/tests/x86_emulator/test_x86_emulator +tools/tests/x86_emulator/x86_emulate +tools/tests/xen-access/xen-access tools/tests/regression/installed/* tools/tests/regression/build/* tools/tests/regression/downloads/*