diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5 index 069b73f..ff48653 100644 --- a/docs/man/xl.cfg.pod.5 +++ b/docs/man/xl.cfg.pod.5 @@ -634,6 +634,9 @@ if your particular guest kernel does not require this behaviour then it is safe to allow this to be enabled but you may wish to disable it anyway. +=item B +Selects whether to run this guest in an HVM container. Default is 0. + =back =head2 Fully-virtualised (HVM) Guest Specific Options diff --git a/tools/debugger/gdbsx/xg/xg_main.c b/tools/debugger/gdbsx/xg/xg_main.c index 64c7484..5736b86 100644 --- a/tools/debugger/gdbsx/xg/xg_main.c +++ b/tools/debugger/gdbsx/xg/xg_main.c @@ -81,6 +81,7 @@ int xgtrc_on = 0; struct xen_domctl domctl; /* just use a global domctl */ static int _hvm_guest; /* hvm guest? 32bit HVMs have 64bit context */ +static int _pvh_guest; /* PV guest in HVM container */ static domid_t _dom_id; /* guest domid */ static int _max_vcpu_id; /* thus max_vcpu_id+1 VCPUs */ static int _dom0_fd; /* fd of /dev/privcmd */ @@ -309,6 +310,7 @@ xg_attach(int domid, int guest_bitness) _max_vcpu_id = domctl.u.getdomaininfo.max_vcpu_id; _hvm_guest = (domctl.u.getdomaininfo.flags & XEN_DOMINF_hvm_guest); + _pvh_guest = (domctl.u.getdomaininfo.flags & XEN_DOMINF_pvh_guest); return _max_vcpu_id; } @@ -369,7 +371,7 @@ _change_TF(vcpuid_t which_vcpu, int guest_bitness, int setit) int sz = sizeof(anyc); /* first try the MTF for hvm guest. otherwise do manually */ - if (_hvm_guest) { + if (_hvm_guest || _pvh_guest) { domctl.u.debug_op.vcpu = which_vcpu; domctl.u.debug_op.op = setit ? XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_ON : XEN_DOMCTL_DEBUG_OP_SINGLE_STEP_OFF; diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile index 512a994..a92e823 100644 --- a/tools/libxc/Makefile +++ b/tools/libxc/Makefile @@ -86,7 +86,7 @@ OSDEP_SRCS-y += xenctrl_osdep_ENOSYS.c -include $(XEN_TARGET_ARCH)/Makefile CFLAGS += -Werror -Wmissing-prototypes -CFLAGS += -I. $(CFLAGS_xeninclude) +CFLAGS += -I. $(CFLAGS_xeninclude) -g -O0 # Needed for posix_fadvise64() in xc_linux.c CFLAGS-$(CONFIG_Linux) += -D_GNU_SOURCE diff --git a/tools/libxc/xc_dom.h b/tools/libxc/xc_dom.h index 86e23ee..5168bcd 100644 --- a/tools/libxc/xc_dom.h +++ b/tools/libxc/xc_dom.h @@ -130,6 +130,7 @@ struct xc_dom_image { domid_t console_domid; domid_t xenstore_domid; xen_pfn_t shared_info_mfn; + int pvh_enabled; xc_interface *xch; domid_t guest_domid; diff --git a/tools/libxc/xc_dom_elfloader.c b/tools/libxc/xc_dom_elfloader.c index 9843b1f..40b99f6 100644 --- a/tools/libxc/xc_dom_elfloader.c +++ b/tools/libxc/xc_dom_elfloader.c @@ -362,6 +362,18 @@ static elf_errorstatus xc_dom_parse_elf_kernel(struct xc_dom_image *dom) rc = -EINVAL; goto out; } + if ( dom->pvh_enabled ) + { + if ( !elf_xen_feature_get(XENFEAT_auto_translated_physmap, + dom->parms.f_supported) ) + { + xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: Kernel does not" + " support PVH mode. Supported: %x", __FUNCTION__, + *dom->parms.f_supported); + rc = -EINVAL; + goto out; + } + } /* find kernel segment */ dom->kernel_seg.vstart = dom->parms.virt_kstart; diff --git a/tools/libxc/xc_dom_x86.c b/tools/libxc/xc_dom_x86.c index 126c0f8..111f001 100644 --- a/tools/libxc/xc_dom_x86.c +++ b/tools/libxc/xc_dom_x86.c @@ -415,7 +415,8 @@ static int setup_pgtables_x86_64(struct xc_dom_image *dom) pgpfn = (addr - dom->parms.virt_base) >> PAGE_SHIFT_X86; l1tab[l1off] = pfn_to_paddr(xc_dom_p2m_guest(dom, pgpfn)) | L1_PROT; - if ( (addr >= dom->pgtables_seg.vstart) && + if ( (!dom->pvh_enabled) && + (addr >= dom->pgtables_seg.vstart) && (addr < dom->pgtables_seg.vend) ) l1tab[l1off] &= ~_PAGE_RW; /* page tables are r/o */ if ( l1off == (L1_PAGETABLE_ENTRIES_X86_64 - 1) ) @@ -629,12 +630,6 @@ static int vcpu_x86_64(struct xc_dom_image *dom, void *ptr) /* clear everything */ memset(ctxt, 0, sizeof(*ctxt)); - ctxt->user_regs.ds = FLAT_KERNEL_DS_X86_64; - ctxt->user_regs.es = FLAT_KERNEL_DS_X86_64; - ctxt->user_regs.fs = FLAT_KERNEL_DS_X86_64; - ctxt->user_regs.gs = FLAT_KERNEL_DS_X86_64; - ctxt->user_regs.ss = FLAT_KERNEL_SS_X86_64; - ctxt->user_regs.cs = FLAT_KERNEL_CS_X86_64; ctxt->user_regs.rip = dom->parms.virt_entry; ctxt->user_regs.rsp = dom->parms.virt_base + (dom->bootstack_pfn + 1) * PAGE_SIZE_X86; @@ -642,15 +637,25 @@ static int vcpu_x86_64(struct xc_dom_image *dom, void *ptr) dom->parms.virt_base + (dom->start_info_pfn) * PAGE_SIZE_X86; ctxt->user_regs.rflags = 1 << 9; /* Interrupt Enable */ - ctxt->kernel_ss = ctxt->user_regs.ss; - ctxt->kernel_sp = ctxt->user_regs.esp; - ctxt->flags = VGCF_in_kernel_X86_64 | VGCF_online_X86_64; cr3_pfn = xc_dom_p2m_guest(dom, dom->pgtables_seg.pfn); ctxt->ctrlreg[3] = xen_pfn_to_cr3_x86_64(cr3_pfn); DOMPRINTF("%s: cr3: pfn 0x%" PRIpfn " mfn 0x%" PRIpfn "", __FUNCTION__, dom->pgtables_seg.pfn, cr3_pfn); + if ( dom->pvh_enabled ) + return 0; + + ctxt->user_regs.ds = FLAT_KERNEL_DS_X86_64; + ctxt->user_regs.es = FLAT_KERNEL_DS_X86_64; + ctxt->user_regs.fs = FLAT_KERNEL_DS_X86_64; + ctxt->user_regs.gs = FLAT_KERNEL_DS_X86_64; + ctxt->user_regs.ss = FLAT_KERNEL_SS_X86_64; + ctxt->user_regs.cs = FLAT_KERNEL_CS_X86_64; + + ctxt->kernel_ss = ctxt->user_regs.ss; + ctxt->kernel_sp = ctxt->user_regs.esp; + return 0; } @@ -751,7 +756,7 @@ int arch_setup_meminit(struct xc_dom_image *dom) rc = x86_compat(dom->xch, dom->guest_domid, dom->guest_type); if ( rc ) return rc; - if ( xc_dom_feature_translated(dom) ) + if ( xc_dom_feature_translated(dom) && !dom->pvh_enabled ) { dom->shadow_enabled = 1; rc = x86_shadow(dom->xch, dom->guest_domid); @@ -827,6 +832,35 @@ int arch_setup_bootearly(struct xc_dom_image *dom) return 0; } +/* Map grant table frames into guest physmap. */ +static int map_grant_table_frames(struct xc_dom_image *dom) +{ + int i, rc; + + if ( dom->pvh_enabled ) + return 0; + + for ( i = 0; ; i++ ) + { + rc = xc_domain_add_to_physmap(dom->xch, dom->guest_domid, + XENMAPSPACE_grant_table, + i, dom->total_pages + i); + if ( rc != 0 ) + { + if ( (i > 0) && (errno == EINVAL) ) + { + DOMPRINTF("%s: %d grant tables mapped", __FUNCTION__, i); + break; + } + xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, + "%s: mapping grant tables failed " "(pfn=0x%" PRIpfn + ", rc=%d)", __FUNCTION__, dom->total_pages + i, rc); + return rc; + } + } + return 0; +} + int arch_setup_bootlate(struct xc_dom_image *dom) { static const struct { @@ -865,7 +899,6 @@ int arch_setup_bootlate(struct xc_dom_image *dom) else { /* paravirtualized guest with auto-translation */ - int i; /* Map shared info frame into guest physmap. */ rc = xc_domain_add_to_physmap(dom->xch, dom->guest_domid, @@ -879,25 +912,10 @@ int arch_setup_bootlate(struct xc_dom_image *dom) return rc; } - /* Map grant table frames into guest physmap. */ - for ( i = 0; ; i++ ) - { - rc = xc_domain_add_to_physmap(dom->xch, dom->guest_domid, - XENMAPSPACE_grant_table, - i, dom->total_pages + i); - if ( rc != 0 ) - { - if ( (i > 0) && (errno == EINVAL) ) - { - DOMPRINTF("%s: %d grant tables mapped", __FUNCTION__, i); - break; - } - xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, - "%s: mapping grant tables failed " "(pfn=0x%" - PRIpfn ", rc=%d)", __FUNCTION__, dom->total_pages + i, rc); - return rc; - } - } + rc = map_grant_table_frames(dom); + if ( rc != 0 ) + return rc; + shinfo = dom->shared_info_pfn; } diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile index cf214bb..941f37b 100644 --- a/tools/libxl/Makefile +++ b/tools/libxl/Makefile @@ -13,7 +13,7 @@ XLUMINOR = 0 CFLAGS += -Werror -Wno-format-zero-length -Wmissing-declarations \ -Wno-declaration-after-statement -Wformat-nonliteral -CFLAGS += -I. -fPIC +CFLAGS += -I. -fPIC -g -O0 ifeq ($(CONFIG_Linux),y) LIBUUID_LIBS += -luuid diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index 0c32d0b..77d1a34 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -405,6 +405,8 @@ int libxl__domain_make(libxl__gc *gc, libxl_domain_create_info *info, flags |= XEN_DOMCTL_CDF_hvm_guest; flags |= libxl_defbool_val(info->hap) ? XEN_DOMCTL_CDF_hap : 0; flags |= libxl_defbool_val(info->oos) ? 0 : XEN_DOMCTL_CDF_oos_off; + } else if ( libxl_defbool_val(info->pvh) ) { + flags |= XEN_DOMCTL_CDF_hap; } *domid = -1; diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index b38d0a7..cefbf76 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -329,9 +329,23 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid, struct xc_dom_image *dom; int ret; int flags = 0; + int is_pvh = libxl_defbool_val(info->pvh); xc_dom_loginit(ctx->xch); + if (is_pvh) { + char *pv_feats = "writable_descriptor_tables|auto_translated_physmap" + "|supervisor_mode_kernel|hvm_callback_vector"; + + if (info->u.pv.features && info->u.pv.features[0] != '\0') + { + LOG(ERROR, "Didn't expect info->u.pv.features to contain string\n"); + LOG(ERROR, "String: %s\n", info->u.pv.features); + return ERROR_FAIL; + } + info->u.pv.features = strdup(pv_feats); + } + dom = xc_dom_allocate(ctx->xch, state->pv_cmdline, info->u.pv.features); if (!dom) { LOGE(ERROR, "xc_dom_allocate failed"); @@ -370,6 +384,7 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid, } dom->flags = flags; + dom->pvh_enabled = is_pvh; dom->console_evtchn = state->console_port; dom->console_domid = state->console_domid; dom->xenstore_evtchn = state->store_port; @@ -400,7 +415,8 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid, LOGE(ERROR, "xc_dom_boot_image failed"); goto out; } - if ( (ret = xc_dom_gnttab_init(dom)) != 0 ) { + /* PVH sets up its own grant during boot via hvm mechanisms */ + if ( !is_pvh && (ret = xc_dom_gnttab_init(dom)) != 0 ) { LOGE(ERROR, "xc_dom_gnttab_init failed"); goto out; } diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index d218a2d..2e100f9 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -244,6 +244,7 @@ libxl_domain_create_info = Struct("domain_create_info",[ ("platformdata", libxl_key_value_list), ("poolid", uint32), ("run_hotplug_scripts",libxl_defbool), + ("pvh", libxl_defbool), ], dir=DIR_IN) MemKB = UInt(64, init_val = "LIBXL_MEMKB_DEFAULT") @@ -345,6 +346,7 @@ libxl_domain_build_info = Struct("domain_build_info",[ ])), ("invalid", Struct(None, [])), ], keyvar_init_val = "LIBXL_DOMAIN_TYPE_INVALID")), + ("pvh", libxl_defbool), ], dir=DIR_IN ) diff --git a/tools/libxl/libxl_x86.c b/tools/libxl/libxl_x86.c index a78c91d..a136f70 100644 --- a/tools/libxl/libxl_x86.c +++ b/tools/libxl/libxl_x86.c @@ -290,7 +290,9 @@ int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config, if (rtc_timeoffset) xc_domain_set_time_offset(ctx->xch, domid, rtc_timeoffset); - if (d_config->b_info.type == LIBXL_DOMAIN_TYPE_HVM) { + if (d_config->b_info.type == LIBXL_DOMAIN_TYPE_HVM || + libxl_defbool_val(d_config->b_info.pvh)) { + unsigned long shadow; shadow = (d_config->b_info.shadow_memkb + 1023) / 1024; xc_shadow_control(ctx->xch, domid, XEN_DOMCTL_SHADOW_OP_SET_ALLOCATION, NULL, 0, &shadow, 0, NULL); diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index 5bef969..20b171d 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -610,8 +610,18 @@ static void parse_config_data(const char *config_source, !strncmp(buf, "hvm", strlen(buf))) c_info->type = LIBXL_DOMAIN_TYPE_HVM; + libxl_defbool_setdefault(&c_info->pvh, false); + libxl_defbool_setdefault(&c_info->hap, false); + xlu_cfg_get_defbool(config, "pvh", &c_info->pvh, 0); xlu_cfg_get_defbool(config, "hap", &c_info->hap, 0); + if (libxl_defbool_val(c_info->pvh) && + !libxl_defbool_val(c_info->hap)) { + + fprintf(stderr, "hap is required for PVH domain\n"); + exit(1); + } + if (xlu_cfg_replace_string (config, "name", &c_info->name, 0)) { fprintf(stderr, "Domain name must be specified.\n"); exit(1); @@ -918,6 +928,7 @@ static void parse_config_data(const char *config_source, b_info->u.pv.cmdline = cmdline; xlu_cfg_replace_string (config, "ramdisk", &b_info->u.pv.ramdisk, 0); + libxl_defbool_set(&b_info->pvh, libxl_defbool_val(c_info->pvh)); break; } default: diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c index bf83d58..10c23a1 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -168,13 +168,15 @@ static int readchn(struct connection *conn, void *data, unsigned int len) static void *map_interface(domid_t domid, unsigned long mfn) { if (*xcg_handle != NULL) { - /* this is the preferred method */ - return xc_gnttab_map_grant_ref(*xcg_handle, domid, + void *addr; + /* this is the preferred method */ + addr = xc_gnttab_map_grant_ref(*xcg_handle, domid, GNTTAB_RESERVED_XENSTORE, PROT_READ|PROT_WRITE); - } else { - return xc_map_foreign_range(*xc_handle, domid, - getpagesize(), PROT_READ|PROT_WRITE, mfn); + if (addr) + return addr; } + return xc_map_foreign_range(*xc_handle, domid, + getpagesize(), PROT_READ|PROT_WRITE, mfn); } static void unmap_interface(void *interface) diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 4c5b2bb..6b1aa11 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -89,6 +89,9 @@ struct xen_domctl_getdomaininfo { /* Being debugged. */ #define _XEN_DOMINF_debugged 6 #define XEN_DOMINF_debugged (1U<<_XEN_DOMINF_debugged) +/* domain is PVH */ +#define _XEN_DOMINF_pvh_guest 7 +#define XEN_DOMINF_pvh_guest (1U<<_XEN_DOMINF_pvh_guest) /* XEN_DOMINF_shutdown guest-supplied code. */ #define XEN_DOMINF_shutdownmask 255 #define XEN_DOMINF_shutdownshift 16