From: Don Slutz <dslutz@verizon.com> See http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 for info on detecting VMware. Linux does not follow this exactly. It checks for CPUID 1st. If that fails, it checks for SMBIOS containing "VMware" (not VMware- or VMW). So this patch set provides: SMBIOS -- Add string VMware- CPUID -- Add VMware''s CPUID (Note: currently HyperV (viridian support) breaks this check.) Add the magic VMware port Allow VMware tools poweroff and reboot Enable access to VMware''s guest info Provide the VMware tools build number Don Slutz (10): smbios: Add "plus VMware-Tools" to HVM_XS_SYSTEM_PRODUCT_NAME. Add VMware HVM params Add cpuid_vmware_leaves tools: Add support for new HVM params vmport: Add VMware provided include files. Add vmport structs Add new vmport code. connect vmport up libxl: Add VTPOWER, VTREBOOT and VTPING Add VMware guest info access tools/firmware/hvmloader/smbios.c | 2 +- tools/libxc/xc_domain.c | 112 +++++ tools/libxc/xc_domain_restore.c | 27 ++ tools/libxc/xc_domain_save.c | 24 ++ tools/libxc/xenctrl.h | 24 ++ tools/libxc/xg_save_restore.h | 2 + tools/libxl/libxl.c | 12 + tools/libxl/libxl_create.c | 4 +- tools/libxl/libxl_dom.c | 5 + tools/libxl/libxl_types.idl | 5 + tools/libxl/xl_cmdimpl.c | 10 + tools/libxl/xl_cmdtable.c | 2 +- tools/libxl/xl_sxp.c | 4 + xen/arch/x86/domctl.c | 34 ++ xen/arch/x86/hvm/Makefile | 1 + xen/arch/x86/hvm/hvm.c | 209 ++++++++- xen/arch/x86/hvm/io.c | 4 + xen/arch/x86/hvm/svm/svm.c | 104 +++++ xen/arch/x86/hvm/svm/vmcb.c | 1 + xen/arch/x86/hvm/vmport/Makefile | 1 + xen/arch/x86/hvm/vmport/backdoor_def.h | 167 +++++++ xen/arch/x86/hvm/vmport/guest_msg_def.h | 87 ++++ xen/arch/x86/hvm/vmport/includeCheck.h | 17 + xen/arch/x86/hvm/vmport/vmport.c | 719 +++++++++++++++++++++++++++++++ xen/arch/x86/hvm/vmport/xen_vmport_def.h | 36 ++ xen/arch/x86/hvm/vmx/vmcs.c | 1 + xen/arch/x86/hvm/vmx/vmx.c | 125 ++++++ xen/arch/x86/hvm/vmx/vvmx.c | 13 + xen/arch/x86/traps.c | 58 ++- xen/include/asm-x86/hvm/domain.h | 4 + xen/include/asm-x86/hvm/hvm.h | 3 + xen/include/asm-x86/hvm/trace.h | 3 + xen/include/asm-x86/hvm/vmport.h | 77 ++++ xen/include/asm-x86/processor.h | 2 + xen/include/public/domctl.h | 3 + xen/include/public/hvm/hvm_op.h | 18 + xen/include/public/hvm/params.h | 11 +- xen/include/public/trace.h | 1 + 38 files changed, 1926 insertions(+), 6 deletions(-) create mode 100644 xen/arch/x86/hvm/vmport/Makefile create mode 100644 xen/arch/x86/hvm/vmport/backdoor_def.h create mode 100644 xen/arch/x86/hvm/vmport/guest_msg_def.h create mode 100644 xen/arch/x86/hvm/vmport/includeCheck.h create mode 100644 xen/arch/x86/hvm/vmport/vmport.c create mode 100644 xen/arch/x86/hvm/vmport/xen_vmport_def.h create mode 100644 xen/include/asm-x86/hvm/vmport.h -- 1.8.4
Don Slutz
2013-Dec-12 19:15 UTC
[RFC PATCH 01/10] smbios: Add "plus VMware-Tools" to HVM_XS_SYSTEM_PRODUCT_NAME.
From: Don Slutz <dslutz@verizon.com> Some code checks for VMware support by looking for the string "VMware" in DMI info. So the string VMwareTools matches. Signed-off-by: Don Slutz <dslutz@verizon.com> --- tools/firmware/hvmloader/smbios.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/firmware/hvmloader/smbios.c b/tools/firmware/hvmloader/smbios.c index 4d3d692..c479272 100644 --- a/tools/firmware/hvmloader/smbios.c +++ b/tools/firmware/hvmloader/smbios.c @@ -476,7 +476,7 @@ smbios_type_1_init(void *start, const char *xen_version, strcpy((char *)start, s); start += strlen(s) + 1; - s = xenstore_read(HVM_XS_SYSTEM_PRODUCT_NAME, "HVM domU"); + s = xenstore_read(HVM_XS_SYSTEM_PRODUCT_NAME, "HVM domU plus VMware-Tools"); strcpy((char *)start, s); start += strlen(s) + 1; -- 1.8.4
From: Don Slutz <dslutz@verizon.com> Signed-off-by: Don Slutz <dslutz@verizon.com> --- xen/include/public/hvm/params.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h index 517a184..c571a1e 100644 --- a/xen/include/public/hvm/params.h +++ b/xen/include/public/hvm/params.h @@ -145,6 +145,15 @@ /* SHUTDOWN_* action in case of a triple fault */ #define HVM_PARAM_TRIPLE_FAULT_REASON 31 -#define HVM_NR_PARAMS 32 +/* Params for VMware */ +#define HVM_PARAM_VMWARE_HW 32 +#define HVM_PARAM_VMPORT_LOGMASK 33 +#define HVM_PARAM_VMPORT_STATUS 34 +#define HVM_PARAM_VMPORT_BUILD_NUMBER_TIME 35 +#define HVM_PARAM_VMPORT_BUILD_NUMBER_VALUE 36 +#define HVM_PARAM_VMPORT_RESET_TIME 37 + +#define HVM_NR_PARAMS 38 + #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */ -- 1.8.4
From: Don Slutz <dslutz@verizon.com> Signed-off-by: Don Slutz <dslutz@verizon.com> --- xen/arch/x86/hvm/hvm.c | 3 +++ xen/arch/x86/traps.c | 58 ++++++++++++++++++++++++++++++++++++++++- xen/include/asm-x86/hvm/hvm.h | 3 +++ xen/include/asm-x86/processor.h | 2 ++ 4 files changed, 65 insertions(+), 1 deletion(-) diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 69f7e74..6a7a781 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -2878,6 +2878,9 @@ void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx, if ( cpuid_viridian_leaves(input, eax, ebx, ecx, edx) ) return; + if ( cpuid_vmware_leaves(input, count, eax, ebx, ecx, edx) ) + return; + if ( cpuid_hypervisor_leaves(input, count, eax, ebx, ecx, edx) ) return; diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index 940bc33..71a76df 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -671,14 +671,70 @@ int wrmsr_hypervisor_regs(uint32_t idx, uint64_t val) return 0; } +int cpuid_vmware_leaves(uint32_t idx, uint32_t sub_idx, + uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) +{ + struct domain *d = current->domain; + /* Optionally shift out of the way of Viridian architectural leaves. */ + uint32_t base = is_viridian_domain(d) ? 0x40000100 : 0x40000000; + uint32_t limit; + const uint32_t apic_khz = 1000000L; + + if ( !is_vmware_domain(d) ) + return 0; + + idx -= base; + + limit = 0x10; + + if ( idx > limit ) + return 0; + + switch ( idx ) + { + case 0: + *eax = base + limit; /* Largest leaf */ + *ebx = 0x61774d56; /* "VMwa" */ + *ecx = 0x4d566572; /* "reVM" */ + *edx = 0x65726177; /* "ware" */ + break; + + case 1 ... 0xf: + *eax = 0; /* Reserved */ + *ebx = 0; /* Reserved */ + *ecx = 0; /* Reserved */ + *edx = 0; /* Reserved */ + break; + + case 0x10: + /* (Virtual) TSC frequency in kHz. */ + *eax = d->arch.tsc_khz; + /* (Virtual) Bus (local apic timer) frequency in kHz. */ + *ebx = apic_khz; + *ecx = 0; /* Reserved */ + *edx = 0; /* Reserved */ + break; + + default: + BUG(); + } + + return 1; +} + int cpuid_hypervisor_leaves( uint32_t idx, uint32_t sub_idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { struct domain *d = current->domain; /* Optionally shift out of the way of Viridian architectural leaves. */ - uint32_t base = is_viridian_domain(d) ? 0x40000100 : 0x40000000; + uint32_t base = 0x40000000; uint32_t limit; + if ( is_viridian_domain(d) ) + base += 0x100; + if ( is_vmware_domain(d) ) + base += 0x100; + idx -= base; /* diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index ccca5df..ae3768c 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -332,6 +332,9 @@ static inline unsigned long hvm_get_shadow_gs_base(struct vcpu *v) #define is_viridian_domain(_d) \ (is_hvm_domain(_d) && ((_d)->arch.hvm_domain.params[HVM_PARAM_VIRIDIAN])) +#define is_vmware_domain(_d) \ + (is_hvm_domain(_d) && ((_d)->arch.hvm_domain.params[HVM_PARAM_VMWARE_HW])) + void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx); void hvm_migrate_timers(struct vcpu *v); diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index c120460..6c53e45 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -559,6 +559,8 @@ void int80_direct_trap(void); extern int hypercall(void); +int cpuid_vmware_leaves( uint32_t idx, uint32_t sub_idx, + uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); int cpuid_hypervisor_leaves( uint32_t idx, uint32_t sub_idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); int rdmsr_hypervisor_regs(uint32_t idx, uint64_t *val); -- 1.8.4
From: Don Slutz <dslutz@verizon.com> Signed-off-by: Don Slutz <dslutz@verizon.com> --- tools/libxc/xc_domain_restore.c | 27 +++++++++++++++++++++++++++ tools/libxc/xc_domain_save.c | 24 ++++++++++++++++++++++++ tools/libxc/xg_save_restore.h | 2 ++ tools/libxl/libxl_create.c | 4 +++- tools/libxl/libxl_dom.c | 5 +++++ tools/libxl/libxl_types.idl | 2 ++ tools/libxl/xl_cmdimpl.c | 10 ++++++++++ tools/libxl/xl_sxp.c | 4 ++++ xen/arch/x86/hvm/hvm.c | 1 + 9 files changed, 78 insertions(+), 1 deletion(-) diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c index 80769a7..9bfb608 100644 --- a/tools/libxc/xc_domain_restore.c +++ b/tools/libxc/xc_domain_restore.c @@ -746,6 +746,8 @@ typedef struct { uint64_t acpi_ioport_location; uint64_t viridian; uint64_t vm_generationid_addr; + uint64_t vmware_hw; + uint64_t vmport_logmask; struct toolstack_data_t tdata; } pagebuf_t; @@ -930,6 +932,26 @@ static int pagebuf_get_one(xc_interface *xch, struct restore_ctx *ctx, } return pagebuf_get_one(xch, ctx, buf, fd, dom); + case XC_SAVE_ID_HVM_VMWARE_HW: + /* Skip padding 4 bytes then read the vmware flag. */ + if ( RDEXACT(fd, &buf->vmware_hw, sizeof(uint32_t)) || + RDEXACT(fd, &buf->vmware_hw, sizeof(uint64_t)) ) + { + PERROR("error read the vmware_hw value"); + return -1; + } + return pagebuf_get_one(xch, ctx, buf, fd, dom); + + case XC_SAVE_ID_HVM_VMPORT_LOGMASK: + /* Skip padding 4 bytes then read the vmport_logmask flag. */ + if ( RDEXACT(fd, &buf->vmport_logmask, sizeof(uint32_t)) || + RDEXACT(fd, &buf->vmport_logmask, sizeof(uint64_t)) ) + { + PERROR("error read the vmport_logmask flag"); + return -1; + } + return pagebuf_get_one(xch, ctx, buf, fd, dom); + case XC_SAVE_ID_TOOLSTACK: { if ( RDEXACT(fd, &buf->tdata.len, sizeof(buf->tdata.len)) ) @@ -1755,6 +1777,11 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom, if (pagebuf.viridian != 0) xc_set_hvm_param(xch, dom, HVM_PARAM_VIRIDIAN, 1); + if (pagebuf.vmware_hw != 0) + xc_set_hvm_param(xch, dom, HVM_PARAM_VMWARE_HW, pagebuf.vmport_logmask); + if (pagebuf.vmport_logmask != 0) + xc_set_hvm_param(xch, dom, HVM_PARAM_VMPORT_LOGMASK, pagebuf.vmport_logmask); + if (pagebuf.acpi_ioport_location == 1) { DBGPRINTF("Use new firmware ioport from the checkpoint\n"); xc_set_hvm_param(xch, dom, HVM_PARAM_ACPI_IOPORTS_LOCATION, 1); diff --git a/tools/libxc/xc_domain_save.c b/tools/libxc/xc_domain_save.c index 42c4752..dac7c2c 100644 --- a/tools/libxc/xc_domain_save.c +++ b/tools/libxc/xc_domain_save.c @@ -1731,6 +1731,30 @@ int xc_domain_save(xc_interface *xch, int io_fd, uint32_t dom, uint32_t max_iter PERROR("Error when writing the viridian flag"); goto out; } + + chunk.id = XC_SAVE_ID_HVM_VMWARE_HW; + chunk.data = 0; + xc_get_hvm_param(xch, dom, HVM_PARAM_VMWARE_HW, + (unsigned long *)&chunk.data); + + if ( (chunk.data != 0) && + wrexact(io_fd, &chunk, sizeof(chunk)) ) + { + PERROR("Error when writing the vmware_hw"); + goto out; + } + + chunk.id = XC_SAVE_ID_HVM_VMPORT_LOGMASK; + chunk.data = 0; + xc_get_hvm_param(xch, dom, HVM_PARAM_VMPORT_LOGMASK, + (unsigned long *)&chunk.data); + + if ( (chunk.data != 0) && + wrexact(io_fd, &chunk, sizeof(chunk)) ) + { + PERROR("Error when writing the vmport_loglvl"); + goto out; + } } if ( callbacks != NULL && callbacks->toolstack_save != NULL ) diff --git a/tools/libxc/xg_save_restore.h b/tools/libxc/xg_save_restore.h index f859621..69f44de 100644 --- a/tools/libxc/xg_save_restore.h +++ b/tools/libxc/xg_save_restore.h @@ -259,6 +259,8 @@ #define XC_SAVE_ID_HVM_ACCESS_RING_PFN -16 #define XC_SAVE_ID_HVM_SHARING_RING_PFN -17 #define XC_SAVE_ID_TOOLSTACK -18 /* Optional toolstack specific info */ +#define XC_SAVE_ID_HVM_VMWARE_HW -19 +#define XC_SAVE_ID_HVM_VMPORT_LOGMASK -20 /* ** We process save/restore/migrate in batches of pages; the below diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c index e03bb55..8b08bbd 100644 --- a/tools/libxl/libxl_create.c +++ b/tools/libxl/libxl_create.c @@ -388,13 +388,15 @@ int libxl__domain_build(libxl__gc *gc, vments[4] = "start_time"; vments[5] = libxl__sprintf(gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000); - localents = libxl__calloc(gc, 7, sizeof(char *)); + localents = libxl__calloc(gc, 9, sizeof(char *)); localents[0] = "platform/acpi"; localents[1] = libxl_defbool_val(info->u.hvm.acpi) ? "1" : "0"; localents[2] = "platform/acpi_s3"; localents[3] = libxl_defbool_val(info->u.hvm.acpi_s3) ? "1" : "0"; localents[4] = "platform/acpi_s4"; localents[5] = libxl_defbool_val(info->u.hvm.acpi_s4) ? "1" : "0"; + localents[6] = "platform/vmware_hw"; + localents[7] = libxl__sprintf(gc, "%d", info->u.hvm.vmware_hw); break; case LIBXL_DOMAIN_TYPE_PV: diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index 078cff1..53ab6a6 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -496,6 +496,11 @@ static int hvm_build_set_params(xc_interface *handle, uint32_t domid, xc_set_hvm_param(handle, domid, HVM_PARAM_STORE_EVTCHN, store_evtchn); xc_set_hvm_param(handle, domid, HVM_PARAM_CONSOLE_EVTCHN, console_evtchn); + xc_set_hvm_param(handle, domid, HVM_PARAM_VMWARE_HW, + info->u.hvm.vmware_hw); + xc_set_hvm_param(handle, domid, HVM_PARAM_VMPORT_LOGMASK, + info->u.hvm.vmport_logmask); + xc_dom_gnttab_hvm_seed(handle, domid, *console_mfn, *store_mfn, console_domid, store_domid); return 0; } diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 649ce50..71ba64e 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -346,6 +346,8 @@ libxl_domain_build_info = Struct("domain_build_info",[ ("timeoffset", string), ("hpet", libxl_defbool), ("vpt_align", libxl_defbool), + ("vmware_hw", integer), + ("vmport_logmask", integer), ("timer_mode", libxl_timer_mode), ("nested_hvm", libxl_defbool), ("smbios_firmware", string), diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c index bd26bcc..013066d 100644 --- a/tools/libxl/xl_cmdimpl.c +++ b/tools/libxl/xl_cmdimpl.c @@ -987,6 +987,16 @@ static void parse_config_data(const char *config_source, xlu_cfg_get_defbool(config, "acpi_s4", &b_info->u.hvm.acpi_s4, 0); xlu_cfg_get_defbool(config, "nx", &b_info->u.hvm.nx, 0); xlu_cfg_get_defbool(config, "viridian", &b_info->u.hvm.viridian, 0); + if (!xlu_cfg_get_long(config, "vmware_hw", &l, 1)) { + b_info->u.hvm.vmware_hw = l; + if (dom_info->debug) + fprintf(stderr, "vmware_hw: 0x%llx\n", (unsigned long long) b_info->u.hvm.vmware_hw); + } + if (!xlu_cfg_get_long(config, "vmport_logmask", &l, 1)) { + b_info->u.hvm.vmport_logmask = l; + if (dom_info->debug) + fprintf(stderr, "vmport_logmask: 0x%llx\n", (unsigned long long) b_info->u.hvm.vmport_logmask); + } xlu_cfg_get_defbool(config, "hpet", &b_info->u.hvm.hpet, 0); xlu_cfg_get_defbool(config, "vpt_align", &b_info->u.hvm.vpt_align, 0); diff --git a/tools/libxl/xl_sxp.c b/tools/libxl/xl_sxp.c index a16a025..9010c42 100644 --- a/tools/libxl/xl_sxp.c +++ b/tools/libxl/xl_sxp.c @@ -102,6 +102,10 @@ void printf_info_sexp(int domid, libxl_domain_config *d_config) printf("\t\t\t(nx %s)\n", libxl_defbool_to_string(b_info->u.hvm.nx)); printf("\t\t\t(viridian %s)\n", libxl_defbool_to_string(b_info->u.hvm.viridian)); + printf("\t\t\t(vmware_hw %d)\n", + b_info->u.hvm.vmware_hw); + printf("\t\t\t(vmport_logmask %x)\n", + b_info->u.hvm.vmport_logmask); printf("\t\t\t(hpet %s)\n", libxl_defbool_to_string(b_info->u.hvm.hpet)); printf("\t\t\t(vpt_align %s)\n", diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 6a7a781..38641c4 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -589,6 +589,7 @@ int hvm_domain_initialise(struct domain *d) d->arch.hvm_domain.params[HVM_PARAM_HPET_ENABLED] = 1; d->arch.hvm_domain.params[HVM_PARAM_TRIPLE_FAULT_REASON] = SHUTDOWN_reboot; + d->arch.hvm_domain.params[HVM_PARAM_VMPORT_RESET_TIME] = 15; vpic_init(d); -- 1.8.4
Don Slutz
2013-Dec-12 19:15 UTC
[RFC PATCH 05/10] vmport: Add VMware provided include files.
From: Don Slutz <dslutz@verizon.com> These 2 files: backdoor_def.h and guest_msg_def.h come from: http://packages.vmware.com/tools/esx/3.5latest/rhel4/SRPMS/index.html open-vm-tools-kmod-7.4.8-396269.423167.src.rpm open-vm-tools-kmod-7.4.8.tar.gz vmhgfs/backdoor_def.h vmhgfs/guest_msg_def.h and are unchanged. Signed-off-by: Don Slutz <dslutz@verizon.com> --- xen/arch/x86/hvm/vmport/backdoor_def.h | 167 ++++++++++++++++++++++++++++++++ xen/arch/x86/hvm/vmport/guest_msg_def.h | 87 +++++++++++++++++ 2 files changed, 254 insertions(+) create mode 100644 xen/arch/x86/hvm/vmport/backdoor_def.h create mode 100644 xen/arch/x86/hvm/vmport/guest_msg_def.h diff --git a/xen/arch/x86/hvm/vmport/backdoor_def.h b/xen/arch/x86/hvm/vmport/backdoor_def.h new file mode 100644 index 0000000..e76795f --- /dev/null +++ b/xen/arch/x86/hvm/vmport/backdoor_def.h @@ -0,0 +1,167 @@ +/* ********************************************************** + * Copyright 1998 VMware, Inc. All rights reserved. + * ********************************************************** + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * backdoor_def.h -- + * + * This contains backdoor defines that can be included from + * an assembly language file. + */ + + + +#ifndef _BACKDOOR_DEF_H_ +#define _BACKDOOR_DEF_H_ + +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_VMMEXT +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMKERNEL +#include "includeCheck.h" + +/* + * If you want to add a new low-level backdoor call for a guest userland + * application, please consider using the GuestRpc mechanism instead. --hpreg + */ + +#define BDOOR_MAGIC 0x564D5868 + +/* Low-bandwidth backdoor port. --hpreg */ + +#define BDOOR_PORT 0x5658 + +#define BDOOR_CMD_GETMHZ 1 +/* + * BDOOR_CMD_APMFUNCTION is used by: + * + * o The FrobOS code, which instead should either program the virtual chipset + * (like the new BIOS code does, matthias offered to implement that), or not + * use any VM-specific code (which requires that we correctly implement + * "power off on CLI HLT" for SMP VMs, boris offered to implement that) + * + * o The old BIOS code, which will soon be jettisoned + * + * --hpreg + */ +#define BDOOR_CMD_APMFUNCTION 2 +#define BDOOR_CMD_GETDISKGEO 3 +#define BDOOR_CMD_GETPTRLOCATION 4 +#define BDOOR_CMD_SETPTRLOCATION 5 +#define BDOOR_CMD_GETSELLENGTH 6 +#define BDOOR_CMD_GETNEXTPIECE 7 +#define BDOOR_CMD_SETSELLENGTH 8 +#define BDOOR_CMD_SETNEXTPIECE 9 +#define BDOOR_CMD_GETVERSION 10 +#define BDOOR_CMD_GETDEVICELISTELEMENT 11 +#define BDOOR_CMD_TOGGLEDEVICE 12 +#define BDOOR_CMD_GETGUIOPTIONS 13 +#define BDOOR_CMD_SETGUIOPTIONS 14 +#define BDOOR_CMD_GETSCREENSIZE 15 +#define BDOOR_CMD_MONITOR_CONTROL 16 +#define BDOOR_CMD_GETHWVERSION 17 +#define BDOOR_CMD_OSNOTFOUND 18 +#define BDOOR_CMD_GETUUID 19 +#define BDOOR_CMD_GETMEMSIZE 20 +#define BDOOR_CMD_HOSTCOPY 21 /* Devel only */ +/* BDOOR_CMD_GETOS2INTCURSOR, 22, is very old and defunct. Reuse. */ +#define BDOOR_CMD_GETTIME 23 /* Deprecated. Use GETTIMEFULL. */ +#define BDOOR_CMD_STOPCATCHUP 24 +#define BDOOR_CMD_PUTCHR 25 /* Devel only */ +#define BDOOR_CMD_ENABLE_MSG 26 /* Devel only */ +#define BDOOR_CMD_GOTO_TCL 27 /* Devel only */ +#define BDOOR_CMD_INITPCIOPROM 28 +#define BDOOR_CMD_INT13 29 +#define BDOOR_CMD_MESSAGE 30 +#define BDOOR_CMD_RSVD0 31 +#define BDOOR_CMD_RSVD1 32 +#define BDOOR_CMD_RSVD2 33 +#define BDOOR_CMD_ISACPIDISABLED 34 +#define BDOOR_CMD_TOE 35 /* Not in use */ +/* BDOOR_CMD_INITLSIOPROM, 36, was merged with 28. Reuse. */ +#define BDOOR_CMD_PATCH_SMBIOS_STRUCTS 37 +#define BDOOR_CMD_MAPMEM 38 /* Devel only */ +#define BDOOR_CMD_ABSPOINTER_DATA 39 +#define BDOOR_CMD_ABSPOINTER_STATUS 40 +#define BDOOR_CMD_ABSPOINTER_COMMAND 41 +#define BDOOR_CMD_TIMER_SPONGE 42 +#define BDOOR_CMD_PATCH_ACPI_TABLES 43 +/* Catch-all to allow synchronous tests */ +#define BDOOR_CMD_DEVEL_FAKEHARDWARE 44 /* Debug only - needed in beta */ +#define BDOOR_CMD_GETHZ 45 +#define BDOOR_CMD_GETTIMEFULL 46 +#define BDOOR_CMD_STATELOGGER 47 +#define BDOOR_CMD_CHECKFORCEBIOSSETUP 48 +#define BDOOR_CMD_LAZYTIMEREMULATION 49 +#define BDOOR_CMD_BIOSBBS 50 +#define BDOOR_CMD_MAX 51 + +/* + * IMPORTANT NOTE: When modifying the behavior of an existing backdoor command, + * you must adhere to the semantics expected by the oldest Tools who use that + * command. Specifically, do not alter the way in which the command modifies + * the registers. Otherwise backwards compatibility will suffer. + */ + +/* High-bandwidth backdoor port. --hpreg */ + +#define BDOORHB_PORT 0x5659 + +#define BDOORHB_CMD_MESSAGE 0 +#define BDOORHB_CMD_MAX 1 + +/* + * There is another backdoor which allows access to certain TSC-related + * values using otherwise illegal PMC indices when the pseudo_perfctr + * control flag is set. + */ + +#define BDOOR_PMC_HW_TSC 0x10000 +#define BDOOR_PMC_REAL_NS 0x10001 +#define BDOOR_PMC_APPARENT_NS 0x10002 + +#define IS_BDOOR_PMC(index) (((index) | 3) == 0x10003) +#define BDOOR_CMD(ecx) ((ecx) & 0xffff) + + +#ifdef VMM +/* + *---------------------------------------------------------------------- + * + * Backdoor_CmdRequiresFullyValidVCPU -- + * + * A few backdoor commands require the full VCPU to be valid + * (including GDTR, IDTR, TR and LDTR). The rest get read/write + * access to GPRs and read access to Segment registers (selectors). + * + * Result: + * True iff VECX contains a command that require the full VCPU to + * be valid. + * + *---------------------------------------------------------------------- + */ +static INLINE Bool +Backdoor_CmdRequiresFullyValidVCPU(unsigned cmd) +{ + return cmd == BDOOR_CMD_RSVD0 || + cmd == BDOOR_CMD_RSVD1 || + cmd == BDOOR_CMD_RSVD2; +} +#endif + +#endif diff --git a/xen/arch/x86/hvm/vmport/guest_msg_def.h b/xen/arch/x86/hvm/vmport/guest_msg_def.h new file mode 100644 index 0000000..44ae0fa --- /dev/null +++ b/xen/arch/x86/hvm/vmport/guest_msg_def.h @@ -0,0 +1,87 @@ +/* ********************************************************** + * Copyright 1998 VMware, Inc. All rights reserved. + * ********************************************************** + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 and no later version. + * + * This program 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 General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * guest_msg_def.h -- + * + * Second layer of the internal communication channel between guest + * applications and vmware + * + */ + +#ifndef _GUEST_MSG_DEF_H_ +#define _GUEST_MSG_DEF_H_ + +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_VMMEXT +#include "includeCheck.h" + + +/* Basic request types */ +typedef enum { + MESSAGE_TYPE_OPEN, + MESSAGE_TYPE_SENDSIZE, + MESSAGE_TYPE_SENDPAYLOAD, + MESSAGE_TYPE_RECVSIZE, + MESSAGE_TYPE_RECVPAYLOAD, + MESSAGE_TYPE_RECVSTATUS, + MESSAGE_TYPE_CLOSE, +} MessageType; + + +/* Reply statuses */ +/* The basic request succeeded */ +#define MESSAGE_STATUS_SUCCESS 0x0001 +/* vmware has a message available for its party */ +#define MESSAGE_STATUS_DORECV 0x0002 +/* The channel has been closed */ +#define MESSAGE_STATUS_CLOSED 0x0004 +/* vmware removed the message before the party fetched it */ +#define MESSAGE_STATUS_UNSENT 0x0008 +/* A checkpoint occurred */ +#define MESSAGE_STATUS_CPT 0x0010 +/* An underlying device is powering off */ +#define MESSAGE_STATUS_POWEROFF 0x0020 +/* vmware has detected a timeout on the channel */ +#define MESSAGE_STATUS_TIMEOUT 0x0040 +/* vmware supports high-bandwidth for sending and receiving the payload */ +#define MESSAGE_STATUS_HB 0x0080 + +/* + * This mask defines the status bits that the guest is allowed to set; + * we use this to mask out all other bits when receiving the status + * from the guest. Otherwise, the guest can manipulate VMX state by + * setting status bits that are only supposed to be changed by the + * VMX. See bug 45385. + */ +#define MESSAGE_STATUS_GUEST_MASK MESSAGE_STATUS_SUCCESS + +/* + * Max number of channels. + * Unfortunately this has to be public because the monitor part + * of the backdoor needs it for its trivial-case optimization. [greg] + */ +#define GUESTMSG_MAX_CHANNEL 8 + +/* Flags to open a channel. --hpreg */ +#define GUESTMSG_FLAG_COOKIE 0x80000000 +#define GUESTMSG_FLAG_ALL GUESTMSG_FLAG_COOKIE + + +#endif /* _GUEST_MSG_DEF_H_ */ -- 1.8.4
From: Don Slutz <dslutz@verizon.com> Signed-off-by: Don Slutz <dslutz@verizon.com> --- xen/arch/x86/hvm/hvm.c | 59 +++++++++++++++++++++++++++++- xen/include/asm-x86/hvm/domain.h | 4 +++ xen/include/asm-x86/hvm/vmport.h | 77 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 xen/include/asm-x86/hvm/vmport.h diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 38641c4..fa5d382 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -57,6 +57,7 @@ #include <asm/hvm/cacheattr.h> #include <asm/hvm/trace.h> #include <asm/hvm/nestedhvm.h> +#include <asm/hvm/vmport.h> #include <asm/mtrr.h> #include <asm/apic.h> #include <public/sched.h> @@ -536,6 +537,7 @@ static int handle_pvh_io( int hvm_domain_initialise(struct domain *d) { int rc; + long vmport_mem = 0; if ( !hvm_enabled ) { @@ -562,6 +564,7 @@ int hvm_domain_initialise(struct domain *d) spin_lock_init(&d->arch.hvm_domain.irq_lock); spin_lock_init(&d->arch.hvm_domain.uc_lock); + spin_lock_init(&d->arch.hvm_domain.vmport_lock); INIT_LIST_HEAD(&d->arch.hvm_domain.msixtbl_list); spin_lock_init(&d->arch.hvm_domain.msixtbl_list_lock); @@ -574,11 +577,47 @@ int hvm_domain_initialise(struct domain *d) d->arch.hvm_domain.params = xzalloc_array(uint64_t, HVM_NR_PARAMS); d->arch.hvm_domain.io_handler = xmalloc(struct hvm_io_handler); + d->arch.hvm_domain.vmport_data = xzalloc(struct vmport_state); rc = -ENOMEM; - if ( !d->arch.hvm_domain.params || !d->arch.hvm_domain.io_handler ) + if ( !d->arch.hvm_domain.params || !d->arch.hvm_domain.io_handler || + !d->arch.hvm_domain.vmport_data ) goto fail1; d->arch.hvm_domain.io_handler->num_slot = 0; + vmport_mem += sizeof(struct vmport_state); + d->arch.hvm_domain.vmport_data->open_cookie = (''C'' << 8) + ''S''; + d->arch.hvm_domain.vmport_data->used_guestinfo = 10; + + for (rc = 0; rc < d->arch.hvm_domain.vmport_data->used_guestinfo; rc++) { + d->arch.hvm_domain.vmport_data->guestinfo[rc] = xzalloc(vmport_guestinfo_t); + vmport_mem += sizeof(vmport_guestinfo_t); + } + d->arch.hvm_domain.vmport_data->guestinfo[0]->key_len = 2; + memcpy(d->arch.hvm_domain.vmport_data->guestinfo[0]->key_data, "ip", 2); + + gdprintk(XENLOG_DEBUG, "vmport_mem=%ld bytes (%ld KiB, %ld MiB)\n", + vmport_mem, + (vmport_mem + (1 << 10) - 1) >> 10, + (vmport_mem + (1 << 20) - 1) >> 20); + vmport_mem += sizeof(uint64_t) * HVM_NR_PARAMS; + vmport_mem += sizeof(struct hvm_io_handler); + gdprintk(XENLOG_DEBUG, "hvm overhead=%ld bytes (%ld KiB, %ld MiB)\n", + vmport_mem, + (vmport_mem + (1 << 10) - 1) >> 10, + (vmport_mem + (1 << 20) - 1) >> 20); + gdprintk(XENLOG_DEBUG, "tot_pages=%d bytes (%d KiB, %d MiB)\n", + d->tot_pages, + (d->tot_pages + (1 << 10) - 1) >> 10, + (d->tot_pages + (1 << 20) - 1) >> 20); + gdprintk(XENLOG_DEBUG, "max_pages=%d bytes (%d KiB, %d MiB)\n", + d->max_pages, + (d->max_pages + (1 << 10) - 1) >> 10, + (d->max_pages + (1 << 20) - 1) >> 20); + +#if 0 + vmport_flush(&d->arch.hvm_domain); +#endif + if ( is_pvh_domain(d) ) { register_portio_handler(d, 0, 0x10003, handle_pvh_io); @@ -617,6 +656,15 @@ int hvm_domain_initialise(struct domain *d) stdvga_deinit(d); vioapic_deinit(d); fail1: + if (d->arch.hvm_domain.vmport_data) { + struct vmport_state *vs = d->arch.hvm_domain.vmport_data; + int idx; + + for (idx = 0; idx < vs->used_guestinfo; idx++) { + xfree(vs->guestinfo[idx]); + } + } + xfree(d->arch.hvm_domain.vmport_data); xfree(d->arch.hvm_domain.io_handler); xfree(d->arch.hvm_domain.params); fail0: @@ -626,6 +674,15 @@ int hvm_domain_initialise(struct domain *d) void hvm_domain_relinquish_resources(struct domain *d) { + if (d->arch.hvm_domain.vmport_data) { + struct vmport_state *vs = d->arch.hvm_domain.vmport_data; + int idx; + + for (idx = 0; idx < vs->used_guestinfo; idx++) { + xfree(vs->guestinfo[idx]); + } + xfree(d->arch.hvm_domain.vmport_data); + } xfree(d->arch.hvm_domain.io_handler); xfree(d->arch.hvm_domain.params); diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h index b1e3187..0ca2778 100644 --- a/xen/include/asm-x86/hvm/domain.h +++ b/xen/include/asm-x86/hvm/domain.h @@ -62,6 +62,10 @@ struct hvm_domain { /* emulated irq to pirq */ struct radix_tree_root emuirq_pirq; + /* VMware special port */ + spinlock_t vmport_lock; + struct vmport_state *vmport_data; + uint64_t *params; /* Memory ranges with pinned cache attributes. */ diff --git a/xen/include/asm-x86/hvm/vmport.h b/xen/include/asm-x86/hvm/vmport.h new file mode 100644 index 0000000..180ddac --- /dev/null +++ b/xen/include/asm-x86/hvm/vmport.h @@ -0,0 +1,77 @@ +/* + * vmport.h: HVM VMPORT emulation + * + * + * Copyright (C) 2012 Verizon Corporation + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 (GPLv2) + * as published by the Free Software Foundation. + * + * This file 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 + * General Public License for more details. <http://www.gnu.org/licenses/>. + */ + +#ifndef __ASM_X86_HVM_VMPORT_H__ +#define __ASM_X86_HVM_VMPORT_H__ + +/* Note: VMPORT_PORT and VMPORT_MAGIC is also defined as BDOOR_PORT + * and BDOOR_MAGIC in backdoor_def.h Defined here so that other + * parts of XEN can use it. + */ + +#define VMPORT_PORT 0x5658 +#define VMPORT_MAGIC 0x564D5868 + +#define VMPORT_MAX_KEY_LEN 30 +#define VMPORT_MAX_VAL_LEN 128 +#define VMPORT_MAX_NUM_KEY 128 + +#define VMPORT_MAX_SEND_BUF ((22 + VMPORT_MAX_KEY_LEN + VMPORT_MAX_VAL_LEN + 3)/4) +#define VMPORT_MAX_RECV_BUF ((2 + VMPORT_MAX_VAL_LEN + 3)/4) +#define VMPORT_MAX_CHANS 4 +#define VMPORT_MAX_BKTS 8 + + +typedef struct vmport_guestinfo_ { + uint8_t key_len; + uint8_t val_len; + char key_data[VMPORT_MAX_KEY_LEN]; + char val_data[VMPORT_MAX_VAL_LEN]; +} vmport_guestinfo_t; + +typedef struct vmport_bucket_ { + uint16_t recv_len; + uint16_t recv_idx; + uint32_t recv_buf[VMPORT_MAX_RECV_BUF + 1]; + uint8_t recv_slot; +} vmport_bucket_t; + +typedef struct vmport_channel_ { + unsigned long active_time; + uint32_t chan_id; + uint32_t cookie; + uint32_t proto_num; + uint16_t send_len; + uint16_t send_idx; + uint32_t send_buf[VMPORT_MAX_SEND_BUF + 1]; + vmport_bucket_t recv_bkt[VMPORT_MAX_BKTS]; + uint8_t recv_read; + uint8_t recv_write; +} vmport_channel_t; + +struct vmport_state { + unsigned long ping_time; + uint32_t open_cookie; + uint32_t used_guestinfo; + vmport_channel_t chans[VMPORT_MAX_CHANS]; + vmport_guestinfo_t *guestinfo[VMPORT_MAX_NUM_KEY]; +}; + +int vmport_ioport(int dir, int size, unsigned long data, struct cpu_user_regs *regs); +void vmport_ctrl_send(struct hvm_domain *hd, char *msg, int slot); +void vmport_flush(struct hvm_domain *hd); + +#endif /* __ASM_X86_HVM_VMPORT_H__ */ -- 1.8.4
From: Don Slutz <dslutz@verizon.com> enable vmport_flush call. Signed-off-by: Don Slutz <dslutz@verizon.com> --- xen/arch/x86/hvm/Makefile | 1 + xen/arch/x86/hvm/hvm.c | 2 - xen/arch/x86/hvm/vmport/Makefile | 1 + xen/arch/x86/hvm/vmport/includeCheck.h | 17 + xen/arch/x86/hvm/vmport/vmport.c | 719 +++++++++++++++++++++++++++++++ xen/arch/x86/hvm/vmport/xen_vmport_def.h | 36 ++ xen/include/asm-x86/hvm/trace.h | 3 + 7 files changed, 777 insertions(+), 2 deletions(-) create mode 100644 xen/arch/x86/hvm/vmport/Makefile create mode 100644 xen/arch/x86/hvm/vmport/includeCheck.h create mode 100644 xen/arch/x86/hvm/vmport/vmport.c create mode 100644 xen/arch/x86/hvm/vmport/xen_vmport_def.h diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile index eea5555..954a81c 100644 --- a/xen/arch/x86/hvm/Makefile +++ b/xen/arch/x86/hvm/Makefile @@ -1,5 +1,6 @@ subdir-y += svm subdir-y += vmx +subdir-y += vmport obj-y += asid.o obj-y += emulate.o diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index fa5d382..a557272 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -614,9 +614,7 @@ int hvm_domain_initialise(struct domain *d) (d->max_pages + (1 << 10) - 1) >> 10, (d->max_pages + (1 << 20) - 1) >> 20); -#if 0 vmport_flush(&d->arch.hvm_domain); -#endif if ( is_pvh_domain(d) ) { diff --git a/xen/arch/x86/hvm/vmport/Makefile b/xen/arch/x86/hvm/vmport/Makefile new file mode 100644 index 0000000..2648fae --- /dev/null +++ b/xen/arch/x86/hvm/vmport/Makefile @@ -0,0 +1 @@ +obj-y += vmport.o diff --git a/xen/arch/x86/hvm/vmport/includeCheck.h b/xen/arch/x86/hvm/vmport/includeCheck.h new file mode 100644 index 0000000..26e0d59 --- /dev/null +++ b/xen/arch/x86/hvm/vmport/includeCheck.h @@ -0,0 +1,17 @@ +/* + * includeCheck.h + * + * Copyright (C) 2012 Verizon Corporation + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 (GPLv2) + * as published by the Free Software Foundation. + * + * This file 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 + * General Public License for more details. <http://www.gnu.org/licenses/>. + */ +/* + * Nothing here. Just to use backdoor_def.h without change. + */ diff --git a/xen/arch/x86/hvm/vmport/vmport.c b/xen/arch/x86/hvm/vmport/vmport.c new file mode 100644 index 0000000..43bdf7b --- /dev/null +++ b/xen/arch/x86/hvm/vmport/vmport.c @@ -0,0 +1,719 @@ +/* + * HVM VMPORT emulation + * + * Copyright (C) 2012 Verizon Corporation + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 (GPLv2) + * as published by the Free Software Foundation. + * + * This file 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 + * General Public License for more details. <http://www.gnu.org/licenses/>. + */ + +#include "xen_vmport_def.h" +#include "backdoor_def.h" +#include "guest_msg_def.h" +#include "asm-x86/hvm/support.h" + +#define LOG_RPC 0x0000001 +#define LOG_RECV_STATUS 0x0000002 +#define LOG_SKIP_SEND 0x0000004 +#define LOG_SEND 0x0000008 +#define LOG_SEND_SIZE_ALL 0x0000010 +#define LOG_SEND_SIZE 0x0000020 +#define LOG_RECV_SIZE_ALL 0x0000040 +#define LOG_RECV_SIZE 0x0000080 +#define LOG_CLOSE 0x0000100 +#define LOG_OPEN 0x0000200 +#define LOG_FLUSH 0x0000400 +#define LOG_TRACE 0x0000800 +#define LOG_PING 0x0001000 +#define LOG_SWEEP 0x0002000 +#define LOG_BUILD 0x0004000 +#define LOG_STATUS 0x0008000 + +#define LOG_ERROR 0x0010000 + +#define LOG_INFO_GET 0x0020000 +#define LOG_INFO_SET 0x0040000 + +#define LOG_GP_UNKNOWN 0x0100000 +#define LOG_GP_NOT_VMWARE 0x0200000 +#define LOG_GP_FAIL_RD_INST 0x0400000 +#define LOG_GP_VMWARE_AFTER 0x0800000 + +#define LOG_VGP_UNKNOWN 0x1000000 +#define LOG_REALMODE_GP 0x8000000 + +extern unsigned long get_sec(void); + +/* Note: VMPORT_PORT and VMPORT_MAGIC is also defined as BDOOR_PORT + * and BDOOR_MAGIC in backdoor_def.h Defined in vmport.h also. + */ + +inline uint16_t getLowBits(uint32_t bits) +{ + return bits & 0xffff; +} + +inline uint16_t getHighBits(uint32_t bits) +{ + return bits >> 16; +} + +inline uint32_t setHighBits(uint32_t b, uint32_t val) +{ + return (val << 16) | getLowBits(b); +} + +static inline long getLogMask(struct hvm_domain *hd) +{ + return hd->params[HVM_PARAM_VMPORT_LOGMASK]; +} + +static inline char *getStatus(struct hvm_domain *hd) +{ + return (char*)&hd->params[HVM_PARAM_VMPORT_STATUS]; +} + +void vmport_safe_print(char *prefix, int len, char *msg) +{ + unsigned char c; + int end = len; + int i,k; + char out[4*(VMPORT_MAX_SEND_BUF + 1)*3 + 6]; + + if (end > (sizeof(out)/3 - 6)) + end = sizeof(out)/3 - 6; + out[0] = ''<''; + k = 1; + for (i = 0; i < end; i++) { + c = msg[i]; + if ((c == ''^'') || (c == ''\\'') || (c == ''>'')) { + out[k++] = ''\\''; + out[k++] = c; + } else if ((c >= '' '') && (c <= ''~'')) { + out[k++] = c; + } else if (c < '' '') { + out[k++] = ''^''; + out[k++] = c ^ 0x40; + } else { + snprintf(&out[k], sizeof(out) - k, "\\%02x", c); + k += 3; + } + } + out[k++] = ''>''; + if (len > end) { + out[k++] = ''.''; + out[k++] = ''.''; + out[k++] = ''.''; + } + out[k++] = 0; + gdprintk(XENLOG_DEBUG, "%s%d(%d,%d,%ld)%s\n", prefix, end, len, k, sizeof(out), out); +} + +void vmport_send(struct hvm_domain *hd, vmport_channel_t *c, char *msg, int slot) +{ + unsigned int cur_recv_len = strlen(msg) + 1; + char prefix[30]; + unsigned int my_bkt = c->recv_write; + unsigned int next_bkt = my_bkt + 1; + vmport_bucket_t *b; + + if (next_bkt >= VMPORT_MAX_BKTS) + next_bkt = 0; + + if (next_bkt == c->recv_read) { + if (getLogMask(hd) & LOG_SKIP_SEND) { + snprintf(prefix, sizeof(prefix), + "VMware _send skipped %d (%d, %d) ", c->chan_id, my_bkt, c->recv_read); + prefix[sizeof(prefix)-1] = 0; + vmport_safe_print(prefix, cur_recv_len, msg); + } + getStatus(hd)[slot] = 200; + if (getLogMask(hd) & LOG_STATUS) + gdprintk(XENLOG_DEBUG, "VMware %d getStatus[%d]=200\n", c->chan_id, slot); + return; + } + + c->recv_write = next_bkt; + b = &c->recv_bkt[my_bkt]; + if (getLogMask(hd) & LOG_SEND) { + snprintf(prefix, sizeof(prefix), + "VMware _send %d (%d) ", c->chan_id, my_bkt); + prefix[sizeof(prefix)-1] = 0; + vmport_safe_print(prefix, cur_recv_len, msg); + } + + b->recv_len = cur_recv_len; + b->recv_slot = slot; + b->recv_idx = 0; + memset(b->recv_buf, 0, sizeof(b->recv_buf)); + if (cur_recv_len >= (sizeof(b->recv_buf) - 1)) { + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_DEBUG, "VMware recv_len=%d >= %ld.\n", + cur_recv_len, sizeof(b->recv_buf) - 1); + cur_recv_len = sizeof(b->recv_buf) - 1; + } + memcpy(b->recv_buf, msg, cur_recv_len); + getStatus(hd)[b->recv_slot] = 1; + if (getLogMask(hd) & LOG_STATUS) + gdprintk(XENLOG_DEBUG, "VMware %d,%d getStatus[%d]=1\n", + c->chan_id, c->recv_read, b->recv_slot); +} + +void vmport_ctrl_send(struct hvm_domain *hd, char *msg, int slot) +{ + struct vmport_state *vs = hd->vmport_data; + int i; + + if (slot < 1 || slot > 7) + slot = 7; + hd->vmport_data->ping_time = get_sec(); + spin_lock(&hd->vmport_lock); + for (i = 0; i < VMPORT_MAX_CHANS; i++) { + if (vs->chans[i].proto_num == 0x4f4c4354) { + vmport_send(hd, &vs->chans[i], msg, slot); + } + } + spin_unlock(&hd->vmport_lock); +} + +void vmport_flush(struct hvm_domain *hd) +{ + if (getLogMask(hd) & LOG_FLUSH) + gdprintk(XENLOG_DEBUG, "VMware flush.\n"); + spin_lock(&hd->vmport_lock); + memset(&hd->vmport_data->chans, 0, sizeof(hd->vmport_data->chans)); + spin_unlock(&hd->vmport_lock); +} + +void vmport_sweep(struct hvm_domain *hd, unsigned long now_time) +{ + struct vmport_state *vs = hd->vmport_data; + int i; + + for (i = 0; i < VMPORT_MAX_CHANS; i++) { + if (vs->chans[i].proto_num) { + vmport_channel_t *c = &vs->chans[i]; + long delta = now_time - c->active_time; + + if ( delta >= 80 ) { + if (getLogMask(hd) & LOG_SWEEP) + gdprintk(XENLOG_DEBUG, "VMware flush %d. delta=%ld\n", + c->chan_id, delta); + // Return channel to free pool + c->proto_num = 0; + } + } + } +} + +vmport_channel_t *vmport_new_chan(struct vmport_state *vs, unsigned long now_time) +{ + int i; + + for (i = 0; i < VMPORT_MAX_CHANS; i++) { + if (!vs->chans[i].proto_num) { + vmport_channel_t *c = &vs->chans[i]; + + c->chan_id = i; + c->cookie = vs->open_cookie++; + c->active_time = now_time; + c->send_len = 0; + c->send_idx = 0; + c->recv_read = 0; + c->recv_write = 0; + return c; + } + } + return NULL; +} + +void vmport_process_send_size(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) +{ + // vmware tools often send a 0 byte request size. + c->send_len = ur->ebx; + c->send_idx = 0; + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + if ((getLogMask(hd) & LOG_SEND_SIZE_ALL) || + ((getLogMask(hd) & LOG_SEND_SIZE) && (c->send_len))) + gdprintk(XENLOG_DEBUG, "VMware SENDSIZE %d is %d.\n", + c->chan_id, c->send_len); +} + +void vmport_process_send_payload(struct hvm_domain *hd, vmport_channel_t *c, + struct cpu_user_regs *ur, unsigned long now_time) +{ + char prefix[30]; + + if (c->send_idx < VMPORT_MAX_SEND_BUF) { + c->send_buf[c->send_idx] = ur->ebx; + } + c->send_idx++; + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + if (c->send_idx * 4 >= c->send_len) { + if (c->send_idx < VMPORT_MAX_SEND_BUF) + ((char*)c->send_buf)[c->send_len] = 0; + if (getLogMask(hd) & LOG_RPC) { + snprintf(prefix, sizeof(prefix), + "VMware RPC %d (%d) ", c->chan_id, c->recv_read); + prefix[sizeof(prefix)-1] = 0; + vmport_safe_print(prefix, c->send_len, (char*)c->send_buf); + } + if (c->proto_num == 0x49435052) { +/* log toolbox: Version: build-341836 */ +/* SetGuestInfo 4 build-341836 */ +/* info-get guestinfo.ip */ +/* info-set guestinfo.ip joe */ + char * build = NULL; + char * info_key = NULL; + char * ret_msg = "1 "; + char ret_buffer[2 + VMPORT_MAX_VAL_LEN + 2]; + + if (strncmp((char*)c->send_buf, "log toolbox: Version: build-", + strlen("log toolbox: Version: build-")) == 0) { + build = (char*)c->send_buf + strlen("log toolbox: Version: build-"); + } else if (strncmp((char*)c->send_buf, "SetGuestInfo 4 build-", + strlen("SetGuestInfo 4 build-")) == 0) { + build = (char*)c->send_buf + strlen("SetGuestInfo 4 build-"); + } else if (strncmp((char*)c->send_buf, "info-get guestinfo.", + strlen("info-get guestinfo.")) == 0) { + int keyLen = c->send_len - strlen("info-get guestinfo."); + int idx; + struct vmport_state *vs = hd->vmport_data; + + info_key = (char*)c->send_buf + strlen("info-get guestinfo."); + if (getLogMask(hd) & LOG_INFO_GET) { + snprintf(prefix, sizeof(prefix), + "VMware info-get key:"); + vmport_safe_print(prefix, keyLen, info_key); + } + if (keyLen <= VMPORT_MAX_KEY_LEN) { + for (idx = 0; idx < vs->used_guestinfo; idx++) { + if ((vs->guestinfo[idx]->key_len == keyLen) && + (memcmp(info_key, + vs->guestinfo[idx]->key_data, + vs->guestinfo[idx]->key_len) == 0)) { + if (getLogMask(hd) & LOG_INFO_GET) { + snprintf(prefix, sizeof(prefix), + "VMware info-get val:"); + vmport_safe_print(prefix, + vs->guestinfo[idx]->val_len, + vs->guestinfo[idx]->val_data); + } + snprintf(ret_buffer, sizeof(ret_buffer) - 1, "1 %.*s", + (int)vs->guestinfo[idx]->val_len, + vs->guestinfo[idx]->val_data); + ret_msg = ret_buffer; + break; + } + } + if (idx >= vs->used_guestinfo) { + ret_msg = "0 No value found"; + } + } else { + ret_msg = "0 Key is too long"; + } + } else if (strncmp((char*)c->send_buf, "info-set guestinfo.", + strlen("info-set guestinfo.")) == 0) { + char * val; + int rest_len = c->send_len - strlen("info-set guestinfo."); + + info_key = (char*)c->send_buf + strlen("info-set guestinfo."); + val = strstr(info_key, " "); + if (val) { + int keyLen = val - info_key; + int valLen = rest_len - keyLen - 1; + int free_idx = -1; + int idx; + struct vmport_state *vs = hd->vmport_data; + + val++; + if (getLogMask(hd) & LOG_INFO_SET) { + snprintf(prefix, sizeof(prefix), + "VMware info-set key:"); + vmport_safe_print(prefix, keyLen, info_key); + snprintf(prefix, sizeof(prefix), + "VMware info-set val:"); + vmport_safe_print(prefix, valLen, val); + } + if (keyLen <= VMPORT_MAX_KEY_LEN) { + if (valLen <= VMPORT_MAX_VAL_LEN) { + for (idx = 0; idx < vs->used_guestinfo; idx++) { + if (!vs->guestinfo[idx]) { + gdprintk(XENLOG_WARNING, "idx=%d not allocated, but used_guestinfo=%d\n", + idx, vs->used_guestinfo); + } else if ((vs->guestinfo[idx]->key_len == keyLen) && + (memcmp(info_key, + vs->guestinfo[idx]->key_data, + vs->guestinfo[idx]->key_len) == 0)) { + vs->guestinfo[idx]->val_len = valLen; + memcpy(vs->guestinfo[idx]->val_data, val, valLen); + break; + } else if ((vs->guestinfo[idx]->key_len == 0) && + (free_idx == -1)) { + free_idx = idx; + } + } + if (idx >= vs->used_guestinfo) { + if (free_idx == -1) { + ret_msg = "0 Too many keys"; + } else { + vs->guestinfo[free_idx]->key_len = keyLen; + memcpy(vs->guestinfo[free_idx]->key_data, info_key, keyLen); + vs->guestinfo[free_idx]->val_len = valLen; + memcpy(vs->guestinfo[free_idx]->val_data, val, valLen); + } + } + } else { + ret_msg = "0 Value too long"; + } + } else { + ret_msg = "0 Key is too long"; + } + } else { + if (getLogMask(hd) & LOG_INFO_SET) { + snprintf(prefix, sizeof(prefix), + "VMware info-set missing val; key:"); + vmport_safe_print(prefix, rest_len, info_key); + } + ret_msg = "0 Two and exactly two arguments expected"; + } + } + + vmport_send(hd, c, ret_msg, 5); + if (build) { + long val = 0; + char *p = build; + + while (*p) { + if (*p < ''0'' || *p > ''9'') + break; + val = val * 10 + *p - ''0''; + p++; + }; + + hd->params[HVM_PARAM_VMPORT_BUILD_NUMBER_VALUE] = val; + hd->params[HVM_PARAM_VMPORT_BUILD_NUMBER_TIME] = now_time; + if (getLogMask(hd) & LOG_BUILD) { + snprintf(prefix, sizeof(prefix), + "VMware build %ld ", val); + vmport_safe_print(prefix, p - build, build); + } + } + } else { + unsigned int my_bkt = c->recv_read - 1; + vmport_bucket_t *b; + int stat = 100; + int slot; + + if (my_bkt >= VMPORT_MAX_BKTS) + my_bkt = VMPORT_MAX_BKTS - 1; + b = &c->recv_bkt[my_bkt]; + b->recv_len = 0; + slot = b->recv_slot; + if (slot < 1 || slot > 7) + slot = 7; + if ((c->send_len > 2) && ((c->send_buf[0] & 0xffff) == 0x4b4f)) + stat = 3; + if (getLogMask(hd) & LOG_STATUS) + gdprintk(XENLOG_DEBUG, "VMware %d,%d(%d) getStatus[%d(%d)]=%d <== %d hex=0x%x\n", + c->chan_id, my_bkt, c->recv_read, slot, b->recv_slot, + getStatus(hd)[slot], stat, c->send_buf[0] & 0xffff); + getStatus(hd)[slot] = stat; + } + } +} + +void vmport_process_recv_size(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) +{ + vmport_bucket_t *b = &c->recv_bkt[c->recv_read]; + + if ((getLogMask(hd) & LOG_RECV_SIZE_ALL) || + ((getLogMask(hd) & LOG_RECV_SIZE) && (b->recv_len))) + gdprintk(XENLOG_DEBUG, "VMware RECVSIZE %d is %d.\n", + c->chan_id, b->recv_len); + + if (b->recv_len) { + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_DORECV | MESSAGE_STATUS_SUCCESS); + ur->edx = setHighBits(ur->edx, MESSAGE_TYPE_SENDSIZE); + ur->ebx = b->recv_len; + } else { + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + } +} + +void vmport_process_recv_payload(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) +{ + vmport_bucket_t *b = &c->recv_bkt[c->recv_read]; + + if (b->recv_idx < VMPORT_MAX_RECV_BUF) { + ur->ebx = b->recv_buf[b->recv_idx++]; + } else { + ur->ebx = 0; + } + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + ur->edx = setHighBits(ur->edx, MESSAGE_TYPE_SENDPAYLOAD); +} + +void vmport_process_recv_status(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) +{ + vmport_bucket_t *b = &c->recv_bkt[c->recv_read]; + char prefix[30]; + + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + if (getLogMask(hd) & LOG_RECV_STATUS) { + snprintf(prefix, sizeof(prefix), + "VMware RECVSTATUS %d (%d) ", c->chan_id, c->recv_read); + prefix[sizeof(prefix)-1] = 0; + vmport_safe_print(prefix, b->recv_len, (char*)b->recv_buf); + } + getStatus(hd)[b->recv_slot] = 2; + if (getLogMask(hd) & LOG_STATUS) + gdprintk(XENLOG_DEBUG, "VMware %d,%d getStatus[%d]=2\n", + c->chan_id, c->recv_read, b->recv_slot); + c->recv_read++; + if (c->recv_read >= VMPORT_MAX_BKTS) + c->recv_read = 0; +} + +void vmport_process_close(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) +{ + // Return channel to free pool + c->proto_num = 0; + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + if (getLogMask(hd) & LOG_CLOSE) + gdprintk(XENLOG_DEBUG, "VMware CLOSE %d.\n", + c->chan_id); + if (getLogMask(hd) & LOG_STATUS) + gdprintk(XENLOG_DEBUG, "VMware %d getStatus[0]=0x%x & ~0x%x=0x%x\n", + c->chan_id, getStatus(hd)[0], 1 << c->chan_id, ~(1 << c->chan_id)); + getStatus(hd)[0] &= ~(1 << c->chan_id); +} + +void vmport_process_packet(struct hvm_domain *hd, vmport_channel_t *c, + struct cpu_user_regs *ur, int sub_cmd, + unsigned long now_time) +{ + c->active_time = now_time; + switch (sub_cmd) { + case MESSAGE_TYPE_SENDSIZE: + vmport_process_send_size(hd, c, ur); + break; + case MESSAGE_TYPE_SENDPAYLOAD: + vmport_process_send_payload(hd, c, ur, now_time); + break; + + case MESSAGE_TYPE_RECVSIZE: + vmport_process_recv_size(hd, c, ur); + break; + case MESSAGE_TYPE_RECVPAYLOAD: + vmport_process_recv_payload(hd, c, ur); + break; + case MESSAGE_TYPE_RECVSTATUS: + vmport_process_recv_status(hd, c, ur); + break; + + case MESSAGE_TYPE_CLOSE: + vmport_process_close(hd, c, ur); + break; + + default: + ur->ecx = 0; + break; + } +} + +void vmport_rpc(struct hvm_domain *hd, struct cpu_user_regs *ur) +{ + int sub_cmd = (ur->ecx >> 16) & 0xffff; + vmport_channel_t *c = NULL; + uint16_t msg_id; + uint32_t msg_cookie; + unsigned long now_time = get_sec(); + long delta = now_time - hd->vmport_data->ping_time; + + if ( delta >= hd->params[HVM_PARAM_VMPORT_RESET_TIME] ) { + if (getLogMask(hd) & LOG_PING) + gdprintk(XENLOG_DEBUG, "VMware ping. delta=%ld\n", + delta); + vmport_ctrl_send(hd, "reset", 7); + } + spin_lock(&hd->vmport_lock); + vmport_sweep(hd, now_time); + do { + // Check to see if a new open request is happening... + if (MESSAGE_TYPE_OPEN == sub_cmd) { + c = vmport_new_chan(hd->vmport_data, now_time); + if (NULL == c) { + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_ERR, "VMware failed to find a free channel.\n"); + break; + } + + // Attach the apropriate protocol the the channel + c->proto_num = ur->ebx & ~GUESTMSG_FLAG_COOKIE; + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + ur->edx = setHighBits(ur->edx, c->chan_id); + ur->edi = getLowBits(c->cookie); + ur->esi = getHighBits(c->cookie); + if (getLogMask(hd) & LOG_OPEN) + gdprintk(XENLOG_DEBUG, "VMware OPEN %d p=%x.\n", + c->chan_id, c->proto_num); + if (getLogMask(hd) & LOG_STATUS) + gdprintk(XENLOG_DEBUG, "VMware %d getStatus[0]=0x%x | 0x%x\n", + c->chan_id, getStatus(hd)[0], 1 << c->chan_id); + getStatus(hd)[0] |= 1 << c->chan_id; + if (c->proto_num == 0x4f4c4354) { + vmport_send(hd, c, "reset", 6); + } + break; + } + + msg_id = getHighBits(ur->edx); + msg_cookie = getLowBits(ur->edi) | (ur->esi << 16); + if (msg_id >= VMPORT_MAX_CHANS) { + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_ERR, "VMware chan id err %d >= %d.\n", + msg_id, VMPORT_MAX_CHANS); + break; + } + c = &hd->vmport_data->chans[msg_id]; + if (!c->proto_num) { + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_ERR, "VMware chan %d not open.\n", + msg_id); + break; + } + + // We check the cookie here since it''s possible that the + // connection timed out on us and another channel was opened + // if this happens, return error and the um tool will + // need to reopen the connection + if (msg_cookie != c->cookie) { + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_ERR, "VMware cookie err %x vs %x.\n", + msg_cookie, c->cookie); + break; + } + vmport_process_packet(hd, c, ur, sub_cmd, now_time); + } while( 0 ); + + if( NULL == c ) + ur->ecx = setHighBits(ur->ecx, 0); + + spin_unlock(&hd->vmport_lock); +} + +int vmport_ioport(int dir, int size, unsigned long data, struct cpu_user_regs *regs) +{ + uint32_t cmd = getLowBits(regs->ecx); + uint32_t magic = regs->eax; + struct hvm_domain *hd = ¤t->domain->arch.hvm_domain; + + if ( dir != IOREQ_WRITE ) + data = 0; + + if (magic == BDOOR_MAGIC) { + const uint32_t apicHz = 1000000000L; + uint64_t value; + + switch (cmd) { + case BDOOR_CMD_GETMHZ: + /* ... */ + regs->ebx = BDOOR_MAGIC; + regs->eax = (uint32_t)(current->domain->arch.tsc_khz / 1000); + break; + case BDOOR_CMD_GETVERSION: + /* ... */ + regs->ebx = BDOOR_MAGIC; + /* VERSION_MAGIC */ + regs->eax = 6; + /* Claim we are an ESX. VMX_TYPE_SCALABLE_SERVER */ + regs->ecx = 2; + break; + case BDOOR_CMD_GETHWVERSION: + /* ... */ + regs->ebx = BDOOR_MAGIC; + /* ?? */ + regs->eax = 0x4; + break; + case BDOOR_CMD_GETHZ: + value = current->domain->arch.tsc_khz * 1000; + /* apic-frequency (bus speed) */ + regs->ecx = apicHz; + /* High part of tsc-frequency */ + regs->ebx = (uint32_t)(value >> 32); + /* Low part of tsc-frequency */ + regs->eax = (uint32_t)value; + break; + case BDOOR_CMD_GETTIME: + value = get_localtime_us(current->domain); + /* hostUsecs */ + regs->ebx = (uint32_t)(value % 1000000UL); + /* hostSecs */ + regs->eax = (uint32_t)(value / 1000000ULL); + /* maxTimeLag */ + regs->ecx = 0; + break; + case BDOOR_CMD_GETTIMEFULL: + value = get_localtime_us(current->domain); + /* ... */ + regs->eax = BDOOR_MAGIC; + /* hostUsecs */ + regs->ebx = (uint32_t)(value % 1000000UL); + /* High part of hostSecs */ + regs->esi = (uint32_t)((value / 1000000ULL) >> 32); + /* Low part of hostSecs */ + regs->edx = (uint32_t)(value / 1000000ULL); + /* maxTimeLag */ + regs->ecx = 0; + break; + case BDOOR_CMD_MESSAGE: + vmport_rpc(hd, regs); + break; + + default: + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_DEBUG, "VMware size=%d dir=%d data=%lx cmd=%d.\n", + size, dir, data, cmd); + break; + } + if (getLogMask(hd) & LOG_TRACE) + gdprintk(XENLOG_DEBUG, "VMware ip=%lx cmd=%d ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx\n", + (unsigned long)regs->eip, cmd, + (unsigned long)regs->eax, (unsigned long)regs->ebx, + (unsigned long)regs->ecx, (unsigned long)regs->edx, + (unsigned long)regs->esi, (unsigned long)regs->edi); + } else + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_ERR, "Not VMware %x vs %x vs %x; ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx\n", + magic, BDOOR_MAGIC, VMPORT_MAGIC, + (unsigned long)regs->eip, + (unsigned long)regs->eax, (unsigned long)regs->ebx, + (unsigned long)regs->ecx, (unsigned long)regs->edx, + (unsigned long)regs->esi, (unsigned long)regs->edi); + + if (dir == IOREQ_READ) + HVMTRACE_ND(IOPORT_READ, 0, 1/*cycles*/, 5, VMPORT_PORT, cmd, + regs->eax, regs->ebx, regs->ecx, 0); + else + HVMTRACE_ND(IOPORT_WRITE, 0, 1/*cycles*/, 5, VMPORT_PORT, cmd, + regs->eax, regs->ebx, regs->ecx, 0); + + return 1; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/hvm/vmport/xen_vmport_def.h b/xen/arch/x86/hvm/vmport/xen_vmport_def.h new file mode 100644 index 0000000..e87845b --- /dev/null +++ b/xen/arch/x86/hvm/vmport/xen_vmport_def.h @@ -0,0 +1,36 @@ +/* + * xen_vmport_def.h: HVM VMPORT emulation + * + * + * Copyright (C) 2012 Verizon Corporation + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 (GPLv2) + * as published by the Free Software Foundation. + * + * This file 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 + * General Public License for more details. <http://www.gnu.org/licenses/>. + */ + +#ifndef __XEN_VMPORT_DEF_H__ +#define __XEN_VMPORT_DEF_H__ + +#include <xen/config.h> +#include <xen/init.h> +#include <xen/mm.h> +#include <xen/lib.h> +#include <xen/errno.h> +#include <xen/trace.h> +#include <xen/event.h> +#include <xen/hypercall.h> +#include <asm/current.h> +#include <asm/cpufeature.h> +#include <asm/processor.h> +#include <asm/hvm/hvm.h> +#include <asm/hvm/support.h> +#include <asm/hvm/trace.h> +#include <asm/hvm/vmport.h> + +#endif diff --git a/xen/include/asm-x86/hvm/trace.h b/xen/include/asm-x86/hvm/trace.h index 9d7e00b..d5c3a3e 100644 --- a/xen/include/asm-x86/hvm/trace.h +++ b/xen/include/asm-x86/hvm/trace.h @@ -52,8 +52,11 @@ #define DO_TRC_HVM_LMSW64 DEFAULT_HVM_MISC #define DO_TRC_HVM_REALMODE_EMULATE DEFAULT_HVM_MISC #define DO_TRC_HVM_TRAP DEFAULT_HVM_MISC +#define DO_TRC_HVM_TRAP64 DEFAULT_HVM_MISC #define DO_TRC_HVM_TRAP_DEBUG DEFAULT_HVM_MISC #define DO_TRC_HVM_VLAPIC DEFAULT_HVM_MISC +#define DO_TRC_HVM_IOPORT_READ DEFAULT_HVM_IO +#define DO_TRC_HVM_IOPORT_WRITE DEFAULT_HVM_IO #define TRC_PAR_LONG(par) ((par)&0xFFFFFFFF),((par)>>32) -- 1.8.4
From: Don Slutz <dslutz@verizon.com> Signed-off-by: Don Slutz <dslutz@verizon.com> --- xen/arch/x86/hvm/io.c | 4 ++ xen/arch/x86/hvm/svm/svm.c | 104 ++++++++++++++++++++++++++++++++++++ xen/arch/x86/hvm/svm/vmcb.c | 1 + xen/arch/x86/hvm/vmx/vmcs.c | 1 + xen/arch/x86/hvm/vmx/vmx.c | 125 ++++++++++++++++++++++++++++++++++++++++++++ xen/arch/x86/hvm/vmx/vvmx.c | 13 +++++ xen/include/public/trace.h | 1 + 7 files changed, 249 insertions(+) diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c index bf6309d..4bc4716 100644 --- a/xen/arch/x86/hvm/io.c +++ b/xen/arch/x86/hvm/io.c @@ -42,6 +42,7 @@ #include <asm/hvm/vlapic.h> #include <asm/hvm/trace.h> #include <asm/hvm/emulate.h> +#include <asm/hvm/vmport.h> #include <public/sched.h> #include <xen/iocap.h> #include <public/hvm/ioreq.h> @@ -236,6 +237,9 @@ int handle_pio(uint16_t port, unsigned int size, int dir) if ( dir == IOREQ_WRITE ) data = guest_cpu_user_regs()->eax; + if ( port == VMPORT_PORT ) + return vmport_ioport(dir, size, data, guest_cpu_user_regs()); + rc = hvmemul_do_pio(port, &reps, size, 0, dir, 0, &data); switch ( rc ) diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c index 406d394..80cf2bf 100644 --- a/xen/arch/x86/hvm/svm/svm.c +++ b/xen/arch/x86/hvm/svm/svm.c @@ -56,6 +56,7 @@ #include <asm/hvm/svm/nestedsvm.h> #include <asm/hvm/nestedhvm.h> #include <asm/x86_emulate.h> +#include <asm/hvm/vmport.h> #include <public/sched.h> #include <asm/hvm/vpt.h> #include <asm/hvm/trace.h> @@ -1904,6 +1905,105 @@ svm_vmexit_do_vmsave(struct vmcb_struct *vmcb, return; } +static void svm_vmexit_gp_intercept(struct cpu_user_regs *regs, struct vcpu *v) +{ + struct hvm_domain *hd = &v->domain->arch.hvm_domain; + struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; + unsigned long inst_len, bytes_len; + int frc; + unsigned char bytes[15]; + + regs->error_code = vmcb->exitinfo1; + if ( !cpu_has_svm_nrips || (vmcb->nextrip <= vmcb->rip) ) + inst_len = 0; + else + inst_len = vmcb->nextrip - vmcb->rip; + bytes_len = 2 /* inst_len < 15 ? inst_len > 1 ? inst_len : 2 : 15 */; + frc = hvm_fetch_from_guest_virt_nofault(bytes, regs->eip, + bytes_len, + PFEC_page_present); + + if ( hvm_long_mode_enabled(v) ) + HVMTRACE_LONG_4D(TRAP, TRAP_gp_fault, inst_len, + regs->error_code, + TRC_PAR_LONG(vmcb->exitinfo2) ); + else + HVMTRACE_4D(TRAP, TRAP_gp_fault, inst_len, + regs->error_code, vmcb->exitinfo2 ); + + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x400000 /* LOG_GP_FAIL_RD_INST */) + printk("[HVM:%d.%d] <%s> " + "gp: e2=%lx ec=%lx ip=%lx=>0x%x 0x%x(%ld,%ld,%d) nip(%d)=%lx(%d,%d(0x%x) 0x%x 0x%x)" + "\n", + current->domain->domain_id, current->vcpu_id, __func__, + (unsigned long)vmcb->exitinfo2, + (unsigned long)regs->error_code, + (unsigned long)regs->eip, (unsigned int)bytes[0], + (unsigned int)bytes[1], bytes_len, inst_len, frc, + cpu_has_svm_nrips, (unsigned long)vmcb->nextrip, + cpu_has_svm_decode, vmcb->guest_ins_len & 0xf, vmcb->guest_ins_len, + vmcb->guest_ins[0], vmcb->guest_ins[1]); + + if ( !frc && bytes[0] == 0xed && (regs->edx & 0xffff) == VMPORT_PORT && + vmcb->exitinfo2 == 0 && regs->error_code == 0 ) + { + /* in (%dx),%eax */ + uint32_t magic = regs->eax; + + if ( magic == VMPORT_MAGIC ) { + __update_guest_eip(regs, 1); + vmport_ioport(IOREQ_READ, 4, 0, regs); + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x800000 /* LOG_GP_VMWARE_AFTER */) + printk("[HVM:%d.%d] <%s> " + "gp: VMware ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" + "\n", + current->domain->domain_id, current->vcpu_id, __func__, + (unsigned long)regs->eip, + (unsigned long)regs->eax, (unsigned long)regs->ebx, + (unsigned long)regs->ecx, (unsigned long)regs->edx, + (unsigned long)regs->esi, (unsigned long)regs->edi); + return; + } else { + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x200000 /* LOG_GP_NOT_VMWARE */) + printk("[HVM:%d.%d] <%s> " + "gp: ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" + "\n", + current->domain->domain_id, current->vcpu_id, __func__, + (unsigned long)regs->eip, + (unsigned long)regs->eax, (unsigned long)regs->ebx, + (unsigned long)regs->ecx, (unsigned long)regs->edx, + (unsigned long)regs->esi, (unsigned long)regs->edi); + hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code); + } + } else if (!frc && regs->error_code == 0 + && bytes[0] == 0x0f && bytes[1] == 0x33 && regs->ecx == 0x10000) + { + /* "rdpmc 0x10000" */ + /* Not a very good emulation! But just not faulting is good enough + * to get NetApp booting. */ + regs->edx = regs->eax = 0; + + __update_guest_eip(regs, inst_len); + + /* Doing the log in this case was too noisy for NetApp, so I moved + * it to ''else'' */ + } else { + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x100000 /* LOG_GP_UNKNOWN */) { + printk("[HVM:%d.%d] <%s> " + "gp: e2=%lx ec=%lx ip=%lx=>0x%x 0x%x(%ld,%d) ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" + "\n", + current->domain->domain_id, current->vcpu_id, __func__, + (unsigned long)vmcb->exitinfo2, (unsigned long)regs->error_code, + (unsigned long)regs->eip, (unsigned int)bytes[0], + (unsigned int)bytes[1], inst_len, frc, + (unsigned long)regs->eax, (unsigned long)regs->ebx, + (unsigned long)regs->ecx, (unsigned long)regs->edx, + (unsigned long)regs->esi, (unsigned long)regs->edi); + } + hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code); + } +} + static void svm_vmexit_ud_intercept(struct cpu_user_regs *regs) { struct hvm_emulate_ctxt ctxt; @@ -2253,6 +2353,10 @@ void svm_vmexit_handler(struct cpu_user_regs *regs) break; } + case VMEXIT_EXCEPTION_GP: + svm_vmexit_gp_intercept(regs, v); + break; + case VMEXIT_EXCEPTION_UD: svm_vmexit_ud_intercept(regs); break; diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c index 21292bb..791c045 100644 --- a/xen/arch/x86/hvm/svm/vmcb.c +++ b/xen/arch/x86/hvm/svm/vmcb.c @@ -193,6 +193,7 @@ static int construct_vmcb(struct vcpu *v) vmcb->_exception_intercepts HVM_TRAP_MASK + | (1U << TRAP_gp_fault) | (1U << TRAP_no_device); if ( paging_mode_hap(v->domain) ) diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index 44f33cb..21cde2f 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -1074,6 +1074,7 @@ static int construct_vmcs(struct vcpu *v) v->arch.hvm_vmx.exception_bitmap = HVM_TRAP_MASK | (paging_mode_hap(d) ? 0 : (1U << TRAP_page_fault)) + | (1U << TRAP_gp_fault) | (1U << TRAP_no_device); vmx_update_exception_bitmap(v); diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index dfff628..248900d 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -44,6 +44,7 @@ #include <asm/hvm/support.h> #include <asm/hvm/vmx/vmx.h> #include <asm/hvm/vmx/vmcs.h> +#include <asm/hvm/vmport.h> #include <public/sched.h> #include <public/hvm/ioreq.h> #include <asm/hvm/vpic.h> @@ -1211,6 +1212,7 @@ static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr) v->arch.hvm_vmx.exception_bitmap = HVM_TRAP_MASK | (paging_mode_hap(v->domain) ? 0 : (1U << TRAP_page_fault)) + | (1U << TRAP_gp_fault) | (1U << TRAP_no_device); vmx_update_exception_bitmap(v); vmx_update_debug_state(v); @@ -2454,6 +2456,113 @@ static void vmx_idtv_reinject(unsigned long idtv_info) } } +void do_gp_fault(struct cpu_user_regs *regs, struct vcpu *v) +{ + struct hvm_domain *hd = &v->domain->arch.hvm_domain; + unsigned long exit_qualification; + unsigned long inst_len; + unsigned long ecode; + + __vmread(EXIT_QUALIFICATION, &exit_qualification); + __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len); + __vmread(VM_EXIT_INTR_ERROR_CODE, &ecode); + regs->error_code = ecode; + if ( hvm_long_mode_enabled(v) ) + HVMTRACE_LONG_4D(TRAP, TRAP_gp_fault, inst_len, + regs->error_code, + TRC_PAR_LONG(exit_qualification) ); + else + HVMTRACE_4D(TRAP, TRAP_gp_fault, inst_len, + regs->error_code, exit_qualification ); + + if ( inst_len == 1 && (regs->edx & 0xffff) == VMPORT_PORT && + exit_qualification == 0 && regs->error_code == 0 ) { + uint32_t magic = regs->eax; + + if ( magic == VMPORT_MAGIC ) { + unsigned char bytes[1]; + int frc = hvm_fetch_from_guest_virt_nofault(bytes, regs->eip, + 1, PFEC_page_present); + if (!frc && bytes[0] == 0xed) { /* in (%dx),%eax */ + update_guest_eip(); + vmport_ioport(IOREQ_READ, 4, 0, regs); + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x800000 /* LOG_GP_VMWARE_AFTER */) + printk("[HVM:%d.%d] <%s> " + "gp: VMware ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" + "\n", + current->domain->domain_id, current->vcpu_id, __func__, + (unsigned long)regs->eip, + (unsigned long)regs->eax, (unsigned long)regs->ebx, + (unsigned long)regs->ecx, (unsigned long)regs->edx, + (unsigned long)regs->esi, (unsigned long)regs->edi); + return; + } else { + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x400000 /* LOG_GP_FAIL_RD_INST */) + printk("[HVM:%d.%d] <%s> " + "gp: VMware? ip=%lx=>0x%x(%d) ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" + "\n", + current->domain->domain_id, current->vcpu_id, __func__, + (unsigned long)regs->eip, bytes[0], frc, + (unsigned long)regs->eax, (unsigned long)regs->ebx, + (unsigned long)regs->ecx, (unsigned long)regs->edx, + (unsigned long)regs->esi, (unsigned long)regs->edi); + } + } else { + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x200000 /* LOG_GP_NOT_VMWARE */) + printk("[HVM:%d.%d] <%s> " + "gp: ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" + "\n", + current->domain->domain_id, current->vcpu_id, __func__, + (unsigned long)regs->eip, + (unsigned long)regs->eax, (unsigned long)regs->ebx, + (unsigned long)regs->ecx, (unsigned long)regs->edx, + (unsigned long)regs->esi, (unsigned long)regs->edi); + hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code); + } + } else { + unsigned char bytes[15]; + int frc; + + /* + * We can conditionalize this call on inst_len == 2 if we decide to + * remove the following printk. + */ + frc = hvm_fetch_from_guest_virt_nofault(bytes, regs->eip, + inst_len < 15 ? inst_len : 15, + PFEC_page_present); + + /* Emulate "rdpmc 0x10000" */ + if (!frc && inst_len == 2 && regs->error_code == 0 + && bytes[0] == 0x0f && bytes[1] == 0x33 && regs->ecx == 0x10000) + { + /* Not a very good emulation! But just not faulting is good enough + * to get NetApp booting. */ + regs->edx = regs->eax = 0; + + update_guest_eip(); + + /* Doing the log in this case was too noisy for NetApp, so I moved + * it to ''else'' */ + } else { + /* We should probably turn this log off by default in production in + * case somebody decides to do a lot of #GPs. */ + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x100000 /* LOG_GP_UNKNOWN */) { + printk("[HVM:%d.%d] <%s> " + "gp: eq=%lx ec=%lx ip=%lx=>0x%x 0x%x(%ld,%d) ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" + "\n", + current->domain->domain_id, current->vcpu_id, __func__, + (unsigned long)exit_qualification, (unsigned long)regs->error_code, + (unsigned long)regs->eip, (unsigned int)bytes[0], + (unsigned int)bytes[1], inst_len, frc, + (unsigned long)regs->eax, (unsigned long)regs->ebx, + (unsigned long)regs->ecx, (unsigned long)regs->edx, + (unsigned long)regs->esi, (unsigned long)regs->edi); + } + hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code); + } + } +} + static int vmx_handle_apic_write(void) { unsigned long exit_qualification; @@ -2562,6 +2671,19 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs) && vector != TRAP_nmi && vector != TRAP_machine_check ) { + if (vector == TRAP_gp_fault ) { + struct hvm_domain *hd = &v->domain->arch.hvm_domain; + + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x8000000 /* LOG_REALMODE_GP */) + printk("[HVM:%d.%d] <%s> " + "realmode gp: ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" + "\n", + current->domain->domain_id, current->vcpu_id, __func__, + (unsigned long)regs->eip, + (unsigned long)regs->eax, (unsigned long)regs->ebx, + (unsigned long)regs->ecx, (unsigned long)regs->edx, + (unsigned long)regs->esi, (unsigned long)regs->edi); + } perfc_incr(realmode_exits); v->arch.hvm_vmx.vmx_emulate = 1; HVMTRACE_0D(REALMODE_EMULATE); @@ -2677,6 +2799,9 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs) HVMTRACE_1D(TRAP, vector); vmx_fpu_dirty_intercept(); break; + case TRAP_gp_fault: + do_gp_fault(regs, v); + break; case TRAP_page_fault: __vmread(EXIT_QUALIFICATION, &exit_qualification); __vmread(VM_EXIT_INTR_ERROR_CODE, &ecode); diff --git a/xen/arch/x86/hvm/vmx/vvmx.c b/xen/arch/x86/hvm/vmx/vvmx.c index 0daad79..fcd03dd 100644 --- a/xen/arch/x86/hvm/vmx/vvmx.c +++ b/xen/arch/x86/hvm/vmx/vvmx.c @@ -2166,6 +2166,19 @@ int nvmx_n2_vmexit_handler(struct cpu_user_regs *regs, if ( v->fpu_dirtied ) nvcpu->nv_vmexit_pending = 1; } + else if ( vector == TRAP_gp_fault ) + { + struct cpu_user_regs *ur = guest_cpu_user_regs(); + struct hvm_domain *hd = &v->domain->arch.hvm_domain; + + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x1000000 /* LOG_VGP_UNKNOWN */) + gdprintk(XENLOG_ERR, "Unexpected gp: ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx\n", + (unsigned long)ur->eip, + (unsigned long)ur->eax, (unsigned long)ur->ebx, + (unsigned long)ur->ecx, (unsigned long)ur->edx, + (unsigned long)ur->esi, (unsigned long)ur->edi); + nvcpu->nv_vmexit_pending = 1; + } else if ( (intr_info & valid_mask) == valid_mask ) { exec_bitmap =__get_vvmcs(nvcpu->nv_vvmcx, EXCEPTION_BITMAP); diff --git a/xen/include/public/trace.h b/xen/include/public/trace.h index e2f60a6..32489f0 100644 --- a/xen/include/public/trace.h +++ b/xen/include/public/trace.h @@ -223,6 +223,7 @@ #define TRC_HVM_NPF (TRC_HVM_HANDLER + 0x21) #define TRC_HVM_REALMODE_EMULATE (TRC_HVM_HANDLER + 0x22) #define TRC_HVM_TRAP (TRC_HVM_HANDLER + 0x23) +#define TRC_HVM_TRAP64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x23) #define TRC_HVM_TRAP_DEBUG (TRC_HVM_HANDLER + 0x24) #define TRC_HVM_VLAPIC (TRC_HVM_HANDLER + 0x25) -- 1.8.4
From: Don Slutz <dslutz@verizon.com> Signed-off-by: Don Slutz <dslutz@verizon.com> --- tools/libxl/libxl.c | 12 ++++++++++++ tools/libxl/libxl_types.idl | 3 +++ tools/libxl/xl_cmdtable.c | 2 +- xen/arch/x86/domctl.c | 34 ++++++++++++++++++++++++++++++++++ xen/include/public/domctl.h | 3 +++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index fd8b988..1ec8484 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -5057,6 +5057,18 @@ int libxl_send_trigger(libxl_ctx *ctx, uint32_t domid, rc = xc_domain_send_trigger(ctx->xch, domid, XEN_DOMCTL_SENDTRIGGER_SLEEP, vcpuid); break; + case LIBXL_TRIGGER_VTPOWER: + rc = xc_domain_send_trigger(ctx->xch, domid, + XEN_DOMCTL_SENDTRIGGER_VTPOWER, vcpuid); + break; + case LIBXL_TRIGGER_VTREBOOT: + rc = xc_domain_send_trigger(ctx->xch, domid, + XEN_DOMCTL_SENDTRIGGER_VTREBOOT, vcpuid); + break; + case LIBXL_TRIGGER_VTPING: + rc = xc_domain_send_trigger(ctx->xch, domid, + XEN_DOMCTL_SENDTRIGGER_VTPING, vcpuid); + break; case LIBXL_TRIGGER_NMI: rc = xc_domain_send_trigger(ctx->xch, domid, XEN_DOMCTL_SENDTRIGGER_NMI, vcpuid); diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 71ba64e..80a8ee8 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -105,6 +105,9 @@ libxl_trigger = Enumeration("trigger", [ (4, "INIT"), (5, "RESET"), (6, "S3RESUME"), + (7, "VTPOWER"), + (8, "VTREBOOT"), + (9, "VTPING"), ]) libxl_tsc_mode = Enumeration("tsc_mode", [ diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c index ebe0220..98db8ae 100644 --- a/tools/libxl/xl_cmdtable.c +++ b/tools/libxl/xl_cmdtable.c @@ -290,7 +290,7 @@ struct cmd_spec cmd_table[] = { { "trigger", &main_trigger, 0, 1, "Send a trigger to a domain", - "<Domain> <nmi|reset|init|power|sleep|s3resume> [<VCPU>]", + "<Domain> <nmi|reset|init|power|sleep|s3resume|vtpower|vtreboot|vtping> [<VCPU>]", }, { "sysrq", &main_sysrq, 0, 1, diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index ef6c140..8b77ce2 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -23,6 +23,7 @@ #include <xen/paging.h> #include <asm/irq.h> #include <asm/hvm/hvm.h> +#include <asm/hvm/vmport.h> #include <asm/hvm/support.h> #include <asm/hvm/cacheattr.h> #include <asm/processor.h> @@ -577,6 +578,39 @@ long arch_do_domctl( } break; + case XEN_DOMCTL_SENDTRIGGER_VTPOWER: + { + ret = -EINVAL; + if ( is_hvm_domain(d) ) + { + ret = 0; + vmport_ctrl_send(&d->arch.hvm_domain, "OS_Halt", 1); + } + } + break; + + case XEN_DOMCTL_SENDTRIGGER_VTREBOOT: + { + ret = -EINVAL; + if ( is_hvm_domain(d) ) + { + ret = 0; + vmport_ctrl_send(&d->arch.hvm_domain, "OS_Reboot", 2); + } + } + break; + + case XEN_DOMCTL_SENDTRIGGER_VTPING: + { + ret = -EINVAL; + if ( is_hvm_domain(d) ) + { + ret = 0; + vmport_ctrl_send(&d->arch.hvm_domain, "ping", 3); + } + } + break; + default: ret = -ENOSYS; } diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h index 01a3652..d71d57c 100644 --- a/xen/include/public/domctl.h +++ b/xen/include/public/domctl.h @@ -454,6 +454,9 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_real_mode_area_t); #define XEN_DOMCTL_SENDTRIGGER_INIT 2 #define XEN_DOMCTL_SENDTRIGGER_POWER 3 #define XEN_DOMCTL_SENDTRIGGER_SLEEP 4 +#define XEN_DOMCTL_SENDTRIGGER_VTPOWER 5 +#define XEN_DOMCTL_SENDTRIGGER_VTREBOOT 6 +#define XEN_DOMCTL_SENDTRIGGER_VTPING 7 struct xen_domctl_sendtrigger { uint32_t trigger; /* IN */ uint32_t vcpu; /* IN */ -- 1.8.4
From: Don Slutz <dslutz@verizon.com> Signed-off-by: Don Slutz <dslutz@verizon.com> --- tools/libxc/xc_domain.c | 112 ++++++++++++++++++++++++++++++ tools/libxc/xenctrl.h | 24 +++++++ xen/arch/x86/hvm/hvm.c | 148 ++++++++++++++++++++++++++++++++++++++++ xen/include/public/hvm/hvm_op.h | 18 +++++ 4 files changed, 302 insertions(+) diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index 1ccafc5..0437c6f 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -1246,6 +1246,118 @@ int xc_get_hvm_param(xc_interface *handle, domid_t dom, int param, unsigned long return rc; } +int xc_set_vmport_guest_info(xc_interface *handle, + domid_t dom, + unsigned int key_len, + char *key, + unsigned int val_len, + char *val) +{ + DECLARE_HYPERCALL; + DECLARE_HYPERCALL_BUFFER(xen_hvm_vmport_guest_info_t, arg); + int rc; + + if ((key_len < 1) || + (key_len > VMPORT_GUEST_INFO_KEY_MAX) || + (val_len > VMPORT_GUEST_INFO_VAL_MAX)) { + return -1; + } + + arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg)); + if ( arg == NULL ) + return -1; + + hypercall.op = __HYPERVISOR_hvm_op; + hypercall.arg[0] = HVMOP_set_vmport_guest_info; + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); + arg->domid = dom; + arg->key_length = key_len; + arg->value_length = val_len; + memcpy(arg->data, key, key_len); + memcpy(&arg->data[key_len], val, val_len); + rc = do_xen_hypercall(handle, &hypercall); + xc_hypercall_buffer_free(handle, arg); + return rc; +} + +int xc_get_vmport_guest_info(xc_interface *handle, + domid_t dom, + unsigned int key_len, + char *key, + unsigned int val_max, + unsigned int *val_len, + char *val) +{ + DECLARE_HYPERCALL; + DECLARE_HYPERCALL_BUFFER(xen_hvm_vmport_guest_info_t, arg); + int rc; + + if ((key_len < 1) || + (key_len > VMPORT_GUEST_INFO_KEY_MAX) ) + return -1; + + arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg)); + + hypercall.op = __HYPERVISOR_hvm_op; + hypercall.arg[0] = HVMOP_get_vmport_guest_info; + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); + arg->domid = dom; + arg->key_length = key_len; + arg->value_length = 0; + *val_len = 0; + memcpy(arg->data, key, key_len); + rc = do_xen_hypercall(handle, &hypercall); + if (rc == 0) { + if (arg->value_length > val_max) + arg->value_length = val_max; + *val_len = arg->value_length; + memcpy(val, &arg->data[key_len], arg->value_length); + } + xc_hypercall_buffer_free(handle, arg); + return rc; +} + +int xc_fetch_vmport_guest_info(xc_interface *handle, + domid_t dom, + unsigned int idx, + unsigned int key_max, + unsigned int *key_len, + char *key, + unsigned int val_max, + unsigned int *val_len, + char *val) +{ + DECLARE_HYPERCALL; + DECLARE_HYPERCALL_BUFFER(xen_hvm_vmport_guest_info_t, arg); + int rc; + + arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg)); + + hypercall.op = __HYPERVISOR_hvm_op; + hypercall.arg[0] = HVMOP_get_vmport_guest_info; + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); + arg->domid = dom; + arg->key_length = 0; + arg->value_length = idx; + *key_len = 0; + *val_len = 0; + rc = do_xen_hypercall(handle, &hypercall); + if (rc == 0) { + if (arg->key_length > key_max) + arg->key_length = key_max; + *key_len = arg->key_length; + memcpy(key, arg->data, arg->key_length); + if (arg->value_length > val_max) + arg->value_length = val_max; + *val_len = arg->value_length; + memcpy(val, + &arg->data[arg->key_length], + arg->value_length); + } + xc_hypercall_buffer_free(handle, arg); + return rc; +} + int xc_domain_setdebugging(xc_interface *xch, uint32_t domid, unsigned int enable) diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index 6e58ebe..6b22b3b 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -1774,6 +1774,30 @@ void xc_clear_last_error(xc_interface *xch); int xc_set_hvm_param(xc_interface *handle, domid_t dom, int param, unsigned long value); int xc_get_hvm_param(xc_interface *handle, domid_t dom, int param, unsigned long *value); +int xc_set_vmport_guest_info(xc_interface *handle, + domid_t dom, + unsigned int key_len, + char *key, + unsigned int val_len, + char *val); +int xc_get_vmport_guest_info(xc_interface *handle, + domid_t dom, + unsigned int key_len, + char *key, + unsigned int val_max, + unsigned int *val_len, + char *val); +int xc_fetch_vmport_guest_info(xc_interface *handle, + domid_t dom, + unsigned int idx, + unsigned int key_max, + unsigned int *key_len, + char *key, + unsigned int val_max, + unsigned int *val_len, + char *val); + + /* HVM guest pass-through */ int xc_assign_device(xc_interface *xch, uint32_t domid, diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index a557272..c6f84fc 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -4662,6 +4662,154 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) break; } + case HVMOP_get_vmport_guest_info: + case HVMOP_set_vmport_guest_info: + { + struct xen_hvm_vmport_guest_info a; + struct domain *d; + char *key = NULL; + char *value = NULL; + struct vmport_state *vs; + int idx; + vmport_guestinfo_t *add_slots[5]; + int num_slots = 0, num_free_slots = 0; + + if ( copy_from_guest(&a, arg, 1) ) + return -EFAULT; + + ASSERT(strlen("guestinfo.") == 10); +#if VMPORT_MAX_KEY_LEN + 10 != VMPORT_GUEST_INFO_KEY_MAX +#error Need to adjust VMPORT_MAX_KEY_LEN & VMPORT_GUEST_INFO_KEY_MAX +#endif +#if VMPORT_MAX_VAL_LEN != VMPORT_GUEST_INFO_VAL_MAX +#error Need to adjust VMPORT_MAX_VAL_LEN & VMPORT_GUEST_INFO_VAL_MAX +#endif + if ( a.key_length > strlen("guestinfo.") ) { + if ( (unsigned long)a.key_length + (unsigned long)a.value_length > sizeof(a.data) ) + return -EINVAL; + if ( memcmp(a.data, "guestinfo.", strlen("guestinfo.")) == 0 ) { + key = &a.data[strlen("guestinfo.")]; + a.key_length -= strlen("guestinfo."); + } else { + key = &a.data[0]; + } + value = key + a.key_length; + } else if (a.key_length > 0) { + if ( (unsigned long)a.key_length + (unsigned long)a.value_length > sizeof(a.data) ) + return -EINVAL; + key = &a.data[0]; + if ( a.key_length > VMPORT_MAX_KEY_LEN ) + return -EINVAL; + if ( a.value_length > VMPORT_MAX_VAL_LEN ) + return -EINVAL; + value = key + a.key_length; + } else if ( (a.key_length == 0) && (op == HVMOP_set_vmport_guest_info) ) { + return -EINVAL; + } + d = rcu_lock_domain_by_any_id(a.domid); + if ( d == NULL ) + return rc; + + rc = -EINVAL; + if ( !is_hvm_domain(d) ) + goto param_fail9; + + rc = xsm_hvm_param(XSM_TARGET, d, op); + if ( rc ) + goto param_fail9; + + vs = d->arch.hvm_domain.vmport_data; + if ((a.key_length == 0) && (a.value_length >= vs->used_guestinfo)) { + rc = -E2BIG; + goto param_fail9; + } + for (idx = 0; idx < vs->used_guestinfo; idx++) { + if (vs->guestinfo[idx] && + (vs->guestinfo[idx]->key_len == 0)) + num_free_slots++; + } + if (num_free_slots < 5) { + num_slots = 5 - num_free_slots; + if (vs->used_guestinfo + num_slots > VMPORT_MAX_NUM_KEY) + num_slots = VMPORT_MAX_NUM_KEY - vs->used_guestinfo; + for (idx = 0; idx < num_slots; idx++) + add_slots[idx] = xzalloc(vmport_guestinfo_t); + } + + spin_lock(&d->arch.hvm_domain.vmport_lock); + + for (idx = 0; idx < num_slots; idx++) + vs->guestinfo[vs->used_guestinfo + idx] = add_slots[idx]; + vs->used_guestinfo += num_slots; + + if ( op == HVMOP_set_vmport_guest_info ) + { + int free_idx = -1; + + for (idx = 0; idx < vs->used_guestinfo; idx++) { + if (!vs->guestinfo[idx]) { + gdprintk(XENLOG_WARNING, "idx=%d not allocated, but used_guestinfo=%d\n", + idx, vs->used_guestinfo); + } else if ((vs->guestinfo[idx]->key_len == a.key_length) && + (memcmp(key, + vs->guestinfo[idx]->key_data, + vs->guestinfo[idx]->key_len) == 0)) { + vs->guestinfo[idx]->val_len = a.value_length; + memcpy(vs->guestinfo[idx]->val_data, value, a.value_length); + break; + } else if ((vs->guestinfo[idx]->key_len == 0) && + (free_idx == -1)) { + free_idx = idx; + } + } + if (idx >= vs->used_guestinfo) { + if (free_idx == -1) { + rc = -EBUSY; + } else { + vs->guestinfo[free_idx]->key_len = a.key_length; + memcpy(vs->guestinfo[free_idx]->key_data, key, a.key_length); + vs->guestinfo[free_idx]->val_len = a.value_length; + memcpy(vs->guestinfo[free_idx]->val_data, value, a.value_length); + } + } + } + else + { + if (a.key_length == 0) { + idx = a.value_length; + a.key_length = vs->guestinfo[idx]->key_len; + memcpy(a.data, vs->guestinfo[idx]->key_data, a.key_length); + a.value_length = vs->guestinfo[idx]->val_len; + memcpy(&a.data[a.key_length], + vs->guestinfo[idx]->val_data, + a.value_length); + rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0; + } else { + for (idx = 0; idx < vs->used_guestinfo; idx++) { + if ((vs->guestinfo[idx]->key_len == a.key_length) && + (memcmp(key, + vs->guestinfo[idx]->key_data, + vs->guestinfo[idx]->key_len) == 0)) { + a.value_length = vs->guestinfo[idx]->val_len; + memcpy(value, + vs->guestinfo[idx]->val_data, + a.value_length); + rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0; + break; + } + } + if (idx >= vs->used_guestinfo) { + rc = -ENOENT; + } + } + } + spin_unlock(&d->arch.hvm_domain.vmport_lock); + + param_fail9: + rcu_unlock_domain(d); + break; + } + default: { gdprintk(XENLOG_DEBUG, "Bad HVM op %ld.\n", op); diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h index a9aab4b..a530903 100644 --- a/xen/include/public/hvm/hvm_op.h +++ b/xen/include/public/hvm/hvm_op.h @@ -272,4 +272,22 @@ DEFINE_XEN_GUEST_HANDLE(xen_hvm_inject_msi_t); #endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ +/* Get/set vmport subcommands */ +#define HVMOP_get_vmport_guest_info 17 +#define HVMOP_set_vmport_guest_info 18 +#define VMPORT_GUEST_INFO_KEY_MAX 40 +#define VMPORT_GUEST_INFO_VAL_MAX 128 +struct xen_hvm_vmport_guest_info { + /* Domain to be accessed */ + domid_t domid; + /* key length */ + uint16_t key_length; + /* value length */ + uint16_t value_length; + /* key and value data */ + char data[VMPORT_GUEST_INFO_KEY_MAX + VMPORT_GUEST_INFO_VAL_MAX]; +}; +typedef struct xen_hvm_vmport_guest_info xen_hvm_vmport_guest_info_t; +DEFINE_XEN_GUEST_HANDLE(xen_hvm_vmport_guest_info_t); + #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ -- 1.8.4
Olaf Hering
2013-Dec-12 19:35 UTC
Re: [RFC PATCH 01/10] smbios: Add "plus VMware-Tools" to HVM_XS_SYSTEM_PRODUCT_NAME.
On Thu, Dec 12, Don Slutz wrote:> - s = xenstore_read(HVM_XS_SYSTEM_PRODUCT_NAME, "HVM domU"); > + s = xenstore_read(HVM_XS_SYSTEM_PRODUCT_NAME, "HVM domU plus VMware-Tools");This will break other code which checks for the current string. (/sys/class/dmi/id/product_name) Olaf
Andrew Cooper
2013-Dec-12 22:07 UTC
Re: [RFC PATCH 01/10] smbios: Add "plus VMware-Tools" to HVM_XS_SYSTEM_PRODUCT_NAME.
On 12/12/2013 19:35, Olaf Hering wrote:> On Thu, Dec 12, Don Slutz wrote: > >> - s = xenstore_read(HVM_XS_SYSTEM_PRODUCT_NAME, "HVM domU"); >> + s = xenstore_read(HVM_XS_SYSTEM_PRODUCT_NAME, "HVM domU plus VMware-Tools"); > This will break other code which checks for the current string. > (/sys/class/dmi/id/product_name) > > OlafFurthermore, the whole point of this is so the toolstack can write the xenstore key /local/domain/$DOMID/bios-strings/system-product-name with a custom value which will be written into the SMBios table. The toolstack itself should have a big "pretend to be vmware" flag for a domain. ~Andrew
On 12/12/2013 19:15, Don Slutz wrote:> From: Don Slutz <dslutz@verizon.com> > > Signed-off-by: Don Slutz <dslutz@verizon.com> > --- > xen/arch/x86/hvm/hvm.c | 3 +++ > xen/arch/x86/traps.c | 58 ++++++++++++++++++++++++++++++++++++++++- > xen/include/asm-x86/hvm/hvm.h | 3 +++ > xen/include/asm-x86/processor.h | 2 ++ > 4 files changed, 65 insertions(+), 1 deletion(-) > > diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c > index 69f7e74..6a7a781 100644 > --- a/xen/arch/x86/hvm/hvm.c > +++ b/xen/arch/x86/hvm/hvm.c > @@ -2878,6 +2878,9 @@ void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx, > if ( cpuid_viridian_leaves(input, eax, ebx, ecx, edx) ) > return; > > + if ( cpuid_vmware_leaves(input, count, eax, ebx, ecx, edx) ) > + return; > + > if ( cpuid_hypervisor_leaves(input, count, eax, ebx, ecx, edx) ) > return; > > diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c > index 940bc33..71a76df 100644 > --- a/xen/arch/x86/traps.c > +++ b/xen/arch/x86/traps.c > @@ -671,14 +671,70 @@ int wrmsr_hypervisor_regs(uint32_t idx, uint64_t val) > return 0; > } > > +int cpuid_vmware_leaves(uint32_t idx, uint32_t sub_idx, > + uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) > +{ > + struct domain *d = current->domain; > + /* Optionally shift out of the way of Viridian architectural leaves. */ > + uint32_t base = is_viridian_domain(d) ? 0x40000100 : 0x40000000; > + uint32_t limit; > + const uint32_t apic_khz = 1000000L;Please use the proper constant for this.> + > + if ( !is_vmware_domain(d) ) > + return 0; > + > + idx -= base; > + > + limit = 0x10; > + > + if ( idx > limit ) > + return 0;This `limit` is pointless and the BUG() below is dead code (which Coverity will complain about). Please see 839b966e3f587bbb1a0d954230fb3904330dccb6 and follow its style, rather than propagating this bad style (which admittedly you have gotten from following cpuid_hypervisor_leaves() )> + > + switch ( idx ) > + { > + case 0: > + *eax = base + limit; /* Largest leaf */ > + *ebx = 0x61774d56; /* "VMwa" */ > + *ecx = 0x4d566572; /* "reVM" */ > + *edx = 0x65726177; /* "ware" */ > + break; > + > + case 1 ... 0xf: > + *eax = 0; /* Reserved */ > + *ebx = 0; /* Reserved */ > + *ecx = 0; /* Reserved */ > + *edx = 0; /* Reserved */ > + break; > + > + case 0x10: > + /* (Virtual) TSC frequency in kHz. */ > + *eax = d->arch.tsc_khz; > + /* (Virtual) Bus (local apic timer) frequency in kHz. */ > + *ebx = apic_khz; > + *ecx = 0; /* Reserved */ > + *edx = 0; /* Reserved */ > + break; > + > + default: > + BUG(); > + } > + > + return 1; > +} > + > int cpuid_hypervisor_leaves( uint32_t idx, uint32_t sub_idx, > uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) > { > struct domain *d = current->domain; > /* Optionally shift out of the way of Viridian architectural leaves. */ > - uint32_t base = is_viridian_domain(d) ? 0x40000100 : 0x40000000; > + uint32_t base = 0x40000000; > uint32_t limit; > > + if ( is_viridian_domain(d) ) > + base += 0x100; > + if ( is_vmware_domain(d) ) > + base += 0x100; > +These bases need a far more scalable solution, especially as the result of each of these clauses can be changed at runtime with a cunning hvm_param_set hypercall. I think that both "is pretending to be HyperV" and "is pretending to be VMware" need to be domain creation flags which are strictly static for the lifetime of the domain. ~Andrew> idx -= base; > > /* > diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h > index ccca5df..ae3768c 100644 > --- a/xen/include/asm-x86/hvm/hvm.h > +++ b/xen/include/asm-x86/hvm/hvm.h > @@ -332,6 +332,9 @@ static inline unsigned long hvm_get_shadow_gs_base(struct vcpu *v) > #define is_viridian_domain(_d) \ > (is_hvm_domain(_d) && ((_d)->arch.hvm_domain.params[HVM_PARAM_VIRIDIAN])) > > +#define is_vmware_domain(_d) \ > + (is_hvm_domain(_d) && ((_d)->arch.hvm_domain.params[HVM_PARAM_VMWARE_HW])) > + > void hvm_cpuid(unsigned int input, unsigned int *eax, unsigned int *ebx, > unsigned int *ecx, unsigned int *edx); > void hvm_migrate_timers(struct vcpu *v); > diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h > index c120460..6c53e45 100644 > --- a/xen/include/asm-x86/processor.h > +++ b/xen/include/asm-x86/processor.h > @@ -559,6 +559,8 @@ void int80_direct_trap(void); > > extern int hypercall(void); > > +int cpuid_vmware_leaves( uint32_t idx, uint32_t sub_idx, > + uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); > int cpuid_hypervisor_leaves( uint32_t idx, uint32_t sub_idx, > uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); > int rdmsr_hypervisor_regs(uint32_t idx, uint64_t *val);
On 12/12/2013 19:15, Don Slutz wrote:> From: Don Slutz <dslutz@verizon.com> > > Signed-off-by: Don Slutz <dslutz@verizon.com> > --- > xen/include/public/hvm/params.h | 11 ++++++++++- > 1 file changed, 10 insertions(+), 1 deletion(-) > > diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h > index 517a184..c571a1e 100644 > --- a/xen/include/public/hvm/params.h > +++ b/xen/include/public/hvm/params.h > @@ -145,6 +145,15 @@ > /* SHUTDOWN_* action in case of a triple fault */ > #define HVM_PARAM_TRIPLE_FAULT_REASON 31 > > -#define HVM_NR_PARAMS 32 > +/* Params for VMware */ > +#define HVM_PARAM_VMWARE_HW 32 > +#define HVM_PARAM_VMPORT_LOGMASK 33 > +#define HVM_PARAM_VMPORT_STATUS 34 > +#define HVM_PARAM_VMPORT_BUILD_NUMBER_TIME 35 > +#define HVM_PARAM_VMPORT_BUILD_NUMBER_VALUE 36 > +#define HVM_PARAM_VMPORT_RESET_TIME 37 > + > +#define HVM_NR_PARAMS 38 > + > > #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */STATUS at the very least sounds like it should be read-only from domains? You might want/need some extra logic in do_hvm_op(). ~Andrew
Andrew Cooper
2013-Dec-12 22:36 UTC
Re: [RFC PATCH 04/10] tools: Add support for new HVM params
On 12/12/2013 19:15, Don Slutz wrote:> From: Don Slutz <dslutz@verizon.com> > > Signed-off-by: Don Slutz <dslutz@verizon.com> > --- > tools/libxc/xc_domain_restore.c | 27 +++++++++++++++++++++++++++ > tools/libxc/xc_domain_save.c | 24 ++++++++++++++++++++++++ > tools/libxc/xg_save_restore.h | 2 ++ > tools/libxl/libxl_create.c | 4 +++- > tools/libxl/libxl_dom.c | 5 +++++ > tools/libxl/libxl_types.idl | 2 ++ > tools/libxl/xl_cmdimpl.c | 10 ++++++++++ > tools/libxl/xl_sxp.c | 4 ++++ > xen/arch/x86/hvm/hvm.c | 1 + > 9 files changed, 78 insertions(+), 1 deletion(-) > > diff --git a/tools/libxc/xc_domain_restore.c b/tools/libxc/xc_domain_restore.c > index 80769a7..9bfb608 100644 > --- a/tools/libxc/xc_domain_restore.c > +++ b/tools/libxc/xc_domain_restore.c > @@ -746,6 +746,8 @@ typedef struct { > uint64_t acpi_ioport_location; > uint64_t viridian; > uint64_t vm_generationid_addr; > + uint64_t vmware_hw; > + uint64_t vmport_logmask; > > struct toolstack_data_t tdata; > } pagebuf_t; > @@ -930,6 +932,26 @@ static int pagebuf_get_one(xc_interface *xch, struct restore_ctx *ctx, > } > return pagebuf_get_one(xch, ctx, buf, fd, dom); > > + case XC_SAVE_ID_HVM_VMWARE_HW: > + /* Skip padding 4 bytes then read the vmware flag. */ > + if ( RDEXACT(fd, &buf->vmware_hw, sizeof(uint32_t)) || > + RDEXACT(fd, &buf->vmware_hw, sizeof(uint64_t)) ) > + { > + PERROR("error read the vmware_hw value"); > + return -1; > + } > + return pagebuf_get_one(xch, ctx, buf, fd, dom); > + > + case XC_SAVE_ID_HVM_VMPORT_LOGMASK: > + /* Skip padding 4 bytes then read the vmport_logmask flag. */ > + if ( RDEXACT(fd, &buf->vmport_logmask, sizeof(uint32_t)) || > + RDEXACT(fd, &buf->vmport_logmask, sizeof(uint64_t)) ) > + { > + PERROR("error read the vmport_logmask flag"); > + return -1; > + } > + return pagebuf_get_one(xch, ctx, buf, fd, dom); > + > case XC_SAVE_ID_TOOLSTACK: > { > if ( RDEXACT(fd, &buf->tdata.len, sizeof(buf->tdata.len)) ) > @@ -1755,6 +1777,11 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom, > if (pagebuf.viridian != 0) > xc_set_hvm_param(xch, dom, HVM_PARAM_VIRIDIAN, 1); > > + if (pagebuf.vmware_hw != 0) > + xc_set_hvm_param(xch, dom, HVM_PARAM_VMWARE_HW, pagebuf.vmport_logmask); > + if (pagebuf.vmport_logmask != 0) > + xc_set_hvm_param(xch, dom, HVM_PARAM_VMPORT_LOGMASK, pagebuf.vmport_logmask); > + > if (pagebuf.acpi_ioport_location == 1) { > DBGPRINTF("Use new firmware ioport from the checkpoint\n"); > xc_set_hvm_param(xch, dom, HVM_PARAM_ACPI_IOPORTS_LOCATION, 1); > diff --git a/tools/libxc/xc_domain_save.c b/tools/libxc/xc_domain_save.c > index 42c4752..dac7c2c 100644 > --- a/tools/libxc/xc_domain_save.c > +++ b/tools/libxc/xc_domain_save.c > @@ -1731,6 +1731,30 @@ int xc_domain_save(xc_interface *xch, int io_fd, uint32_t dom, uint32_t max_iter > PERROR("Error when writing the viridian flag"); > goto out; > } > + > + chunk.id = XC_SAVE_ID_HVM_VMWARE_HW; > + chunk.data = 0; > + xc_get_hvm_param(xch, dom, HVM_PARAM_VMWARE_HW, > + (unsigned long *)&chunk.data); > + > + if ( (chunk.data != 0) && > + wrexact(io_fd, &chunk, sizeof(chunk)) ) > + { > + PERROR("Error when writing the vmware_hw"); > + goto out; > + } > + > + chunk.id = XC_SAVE_ID_HVM_VMPORT_LOGMASK; > + chunk.data = 0; > + xc_get_hvm_param(xch, dom, HVM_PARAM_VMPORT_LOGMASK, > + (unsigned long *)&chunk.data); > + > + if ( (chunk.data != 0) && > + wrexact(io_fd, &chunk, sizeof(chunk)) ) > + { > + PERROR("Error when writing the vmport_loglvl"); > + goto out; > + } > } > > if ( callbacks != NULL && callbacks->toolstack_save != NULL ) > diff --git a/tools/libxc/xg_save_restore.h b/tools/libxc/xg_save_restore.h > index f859621..69f44de 100644 > --- a/tools/libxc/xg_save_restore.h > +++ b/tools/libxc/xg_save_restore.h > @@ -259,6 +259,8 @@ > #define XC_SAVE_ID_HVM_ACCESS_RING_PFN -16 > #define XC_SAVE_ID_HVM_SHARING_RING_PFN -17 > #define XC_SAVE_ID_TOOLSTACK -18 /* Optional toolstack specific info */ > +#define XC_SAVE_ID_HVM_VMWARE_HW -19 > +#define XC_SAVE_ID_HVM_VMPORT_LOGMASK -20 > > /* > ** We process save/restore/migrate in batches of pages; the below > diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c > index e03bb55..8b08bbd 100644 > --- a/tools/libxl/libxl_create.c > +++ b/tools/libxl/libxl_create.c > @@ -388,13 +388,15 @@ int libxl__domain_build(libxl__gc *gc, > vments[4] = "start_time"; > vments[5] = libxl__sprintf(gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000); > > - localents = libxl__calloc(gc, 7, sizeof(char *)); > + localents = libxl__calloc(gc, 9, sizeof(char *)); > localents[0] = "platform/acpi"; > localents[1] = libxl_defbool_val(info->u.hvm.acpi) ? "1" : "0"; > localents[2] = "platform/acpi_s3"; > localents[3] = libxl_defbool_val(info->u.hvm.acpi_s3) ? "1" : "0"; > localents[4] = "platform/acpi_s4"; > localents[5] = libxl_defbool_val(info->u.hvm.acpi_s4) ? "1" : "0"; > + localents[6] = "platform/vmware_hw"; > + localents[7] = libxl__sprintf(gc, "%d", info->u.hvm.vmware_hw); > > break; > case LIBXL_DOMAIN_TYPE_PV: > diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c > index 078cff1..53ab6a6 100644 > --- a/tools/libxl/libxl_dom.c > +++ b/tools/libxl/libxl_dom.c > @@ -496,6 +496,11 @@ static int hvm_build_set_params(xc_interface *handle, uint32_t domid, > xc_set_hvm_param(handle, domid, HVM_PARAM_STORE_EVTCHN, store_evtchn); > xc_set_hvm_param(handle, domid, HVM_PARAM_CONSOLE_EVTCHN, console_evtchn); > > + xc_set_hvm_param(handle, domid, HVM_PARAM_VMWARE_HW, > + info->u.hvm.vmware_hw); > + xc_set_hvm_param(handle, domid, HVM_PARAM_VMPORT_LOGMASK, > + info->u.hvm.vmport_logmask); > + > xc_dom_gnttab_hvm_seed(handle, domid, *console_mfn, *store_mfn, console_domid, store_domid); > return 0; > } > diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl > index 649ce50..71ba64e 100644 > --- a/tools/libxl/libxl_types.idl > +++ b/tools/libxl/libxl_types.idl > @@ -346,6 +346,8 @@ libxl_domain_build_info = Struct("domain_build_info",[ > ("timeoffset", string), > ("hpet", libxl_defbool), > ("vpt_align", libxl_defbool), > + ("vmware_hw", integer), > + ("vmport_logmask", integer),"integer" in the IDL is 24 bit is it not? I would suggest uint64 to match the param width.> ("timer_mode", libxl_timer_mode), > ("nested_hvm", libxl_defbool), > ("smbios_firmware", string), > diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c > index bd26bcc..013066d 100644 > --- a/tools/libxl/xl_cmdimpl.c > +++ b/tools/libxl/xl_cmdimpl.c > @@ -987,6 +987,16 @@ static void parse_config_data(const char *config_source, > xlu_cfg_get_defbool(config, "acpi_s4", &b_info->u.hvm.acpi_s4, 0); > xlu_cfg_get_defbool(config, "nx", &b_info->u.hvm.nx, 0); > xlu_cfg_get_defbool(config, "viridian", &b_info->u.hvm.viridian, 0); > + if (!xlu_cfg_get_long(config, "vmware_hw", &l, 1)) { > + b_info->u.hvm.vmware_hw = l; > + if (dom_info->debug) > + fprintf(stderr, "vmware_hw: 0x%llx\n", (unsigned long long) b_info->u.hvm.vmware_hw);PRIx64 and no cast please.> + } > + if (!xlu_cfg_get_long(config, "vmport_logmask", &l, 1)) { > + b_info->u.hvm.vmport_logmask = l; > + if (dom_info->debug) > + fprintf(stderr, "vmport_logmask: 0x%llx\n", (unsigned long long) b_info->u.hvm.vmport_logmask); > + } > xlu_cfg_get_defbool(config, "hpet", &b_info->u.hvm.hpet, 0); > xlu_cfg_get_defbool(config, "vpt_align", &b_info->u.hvm.vpt_align, 0); > > diff --git a/tools/libxl/xl_sxp.c b/tools/libxl/xl_sxp.c > index a16a025..9010c42 100644 > --- a/tools/libxl/xl_sxp.c > +++ b/tools/libxl/xl_sxp.cThe sxp is strictly for xm compatibility. New features should not extend it.> @@ -102,6 +102,10 @@ void printf_info_sexp(int domid, libxl_domain_config *d_config) > printf("\t\t\t(nx %s)\n", libxl_defbool_to_string(b_info->u.hvm.nx)); > printf("\t\t\t(viridian %s)\n", > libxl_defbool_to_string(b_info->u.hvm.viridian)); > + printf("\t\t\t(vmware_hw %d)\n", > + b_info->u.hvm.vmware_hw); > + printf("\t\t\t(vmport_logmask %x)\n", > + b_info->u.hvm.vmport_logmask); > printf("\t\t\t(hpet %s)\n", > libxl_defbool_to_string(b_info->u.hvm.hpet)); > printf("\t\t\t(vpt_align %s)\n", > diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c > index 6a7a781..38641c4 100644 > --- a/xen/arch/x86/hvm/hvm.c > +++ b/xen/arch/x86/hvm/hvm.c > @@ -589,6 +589,7 @@ int hvm_domain_initialise(struct domain *d) > > d->arch.hvm_domain.params[HVM_PARAM_HPET_ENABLED] = 1; > d->arch.hvm_domain.params[HVM_PARAM_TRIPLE_FAULT_REASON] = SHUTDOWN_reboot; > + d->arch.hvm_domain.params[HVM_PARAM_VMPORT_RESET_TIME] = 15; > > vpic_init(d); >This should probably be part of the patch which introduced the params. ~Andrew
On 12/12/2013 19:15, Don Slutz wrote:> From: Don Slutz <dslutz@verizon.com> > > Signed-off-by: Don Slutz <dslutz@verizon.com> > --- > xen/arch/x86/hvm/hvm.c | 59 +++++++++++++++++++++++++++++- > xen/include/asm-x86/hvm/domain.h | 4 +++ > xen/include/asm-x86/hvm/vmport.h | 77 ++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 139 insertions(+), 1 deletion(-) > create mode 100644 xen/include/asm-x86/hvm/vmport.h > > diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c > index 38641c4..fa5d382 100644 > --- a/xen/arch/x86/hvm/hvm.c > +++ b/xen/arch/x86/hvm/hvm.c > @@ -57,6 +57,7 @@ > #include <asm/hvm/cacheattr.h> > #include <asm/hvm/trace.h> > #include <asm/hvm/nestedhvm.h> > +#include <asm/hvm/vmport.h> > #include <asm/mtrr.h> > #include <asm/apic.h> > #include <public/sched.h> > @@ -536,6 +537,7 @@ static int handle_pvh_io( > int hvm_domain_initialise(struct domain *d) > { > int rc; > + long vmport_mem = 0; > > if ( !hvm_enabled ) > { > @@ -562,6 +564,7 @@ int hvm_domain_initialise(struct domain *d) > > spin_lock_init(&d->arch.hvm_domain.irq_lock); > spin_lock_init(&d->arch.hvm_domain.uc_lock); > + spin_lock_init(&d->arch.hvm_domain.vmport_lock); > > INIT_LIST_HEAD(&d->arch.hvm_domain.msixtbl_list); > spin_lock_init(&d->arch.hvm_domain.msixtbl_list_lock); > @@ -574,11 +577,47 @@ int hvm_domain_initialise(struct domain *d) > > d->arch.hvm_domain.params = xzalloc_array(uint64_t, HVM_NR_PARAMS); > d->arch.hvm_domain.io_handler = xmalloc(struct hvm_io_handler); > + d->arch.hvm_domain.vmport_data = xzalloc(struct vmport_state); > rc = -ENOMEM; > - if ( !d->arch.hvm_domain.params || !d->arch.hvm_domain.io_handler ) > + if ( !d->arch.hvm_domain.params || !d->arch.hvm_domain.io_handler || > + !d->arch.hvm_domain.vmport_data ) > goto fail1; > d->arch.hvm_domain.io_handler->num_slot = 0; > > + vmport_mem += sizeof(struct vmport_state); > + d->arch.hvm_domain.vmport_data->open_cookie = (''C'' << 8) + ''S'';This is one place where multicharacter constants would really help. However, I suspect a change to add -Wno-multichar to the build might not go down too well.> + d->arch.hvm_domain.vmport_data->used_guestinfo = 10; > + > + for (rc = 0; rc < d->arch.hvm_domain.vmport_data->used_guestinfo; rc++) {Xen style - space inside brackets and braces lined up.> + d->arch.hvm_domain.vmport_data->guestinfo[rc] = xzalloc(vmport_guestinfo_t);xzalloc_array() of used_guestinfo entries, and needs to be checked for an allocation failure.> + vmport_mem += sizeof(vmport_guestinfo_t); > + } > + d->arch.hvm_domain.vmport_data->guestinfo[0]->key_len = 2; > + memcpy(d->arch.hvm_domain.vmport_data->guestinfo[0]->key_data, "ip", 2); > + > + gdprintk(XENLOG_DEBUG, "vmport_mem=%ld bytes (%ld KiB, %ld MiB)\n", > + vmport_mem, > + (vmport_mem + (1 << 10) - 1) >> 10, > + (vmport_mem + (1 << 20) - 1) >> 20); > + vmport_mem += sizeof(uint64_t) * HVM_NR_PARAMS; > + vmport_mem += sizeof(struct hvm_io_handler); > + gdprintk(XENLOG_DEBUG, "hvm overhead=%ld bytes (%ld KiB, %ld MiB)\n", > + vmport_mem, > + (vmport_mem + (1 << 10) - 1) >> 10, > + (vmport_mem + (1 << 20) - 1) >> 20); > + gdprintk(XENLOG_DEBUG, "tot_pages=%d bytes (%d KiB, %d MiB)\n", > + d->tot_pages, > + (d->tot_pages + (1 << 10) - 1) >> 10, > + (d->tot_pages + (1 << 20) - 1) >> 20); > + gdprintk(XENLOG_DEBUG, "max_pages=%d bytes (%d KiB, %d MiB)\n", > + d->max_pages, > + (d->max_pages + (1 << 10) - 1) >> 10, > + (d->max_pages + (1 << 20) - 1) >> 20);These two gdprintk()s do not appear to be related to the content of this patch.> + > +#if 0 > + vmport_flush(&d->arch.hvm_domain); > +#endifIs this stray debugging?> + > if ( is_pvh_domain(d) ) > { > register_portio_handler(d, 0, 0x10003, handle_pvh_io); > @@ -617,6 +656,15 @@ int hvm_domain_initialise(struct domain *d) > stdvga_deinit(d); > vioapic_deinit(d); > fail1: > + if (d->arch.hvm_domain.vmport_data) { > + struct vmport_state *vs = d->arch.hvm_domain.vmport_data; > + int idx; > + > + for (idx = 0; idx < vs->used_guestinfo; idx++) { > + xfree(vs->guestinfo[idx]); > + } > + } > + xfree(d->arch.hvm_domain.vmport_data); > xfree(d->arch.hvm_domain.io_handler); > xfree(d->arch.hvm_domain.params); > fail0: > @@ -626,6 +674,15 @@ int hvm_domain_initialise(struct domain *d) > > void hvm_domain_relinquish_resources(struct domain *d) > { > + if (d->arch.hvm_domain.vmport_data) { > + struct vmport_state *vs = d->arch.hvm_domain.vmport_data; > + int idx; > + > + for (idx = 0; idx < vs->used_guestinfo; idx++) { > + xfree(vs->guestinfo[idx]); > + } > + xfree(d->arch.hvm_domain.vmport_data); > + } > xfree(d->arch.hvm_domain.io_handler); > xfree(d->arch.hvm_domain.params); > > diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h > index b1e3187..0ca2778 100644 > --- a/xen/include/asm-x86/hvm/domain.h > +++ b/xen/include/asm-x86/hvm/domain.h > @@ -62,6 +62,10 @@ struct hvm_domain { > /* emulated irq to pirq */ > struct radix_tree_root emuirq_pirq; > > + /* VMware special port */ > + spinlock_t vmport_lock; > + struct vmport_state *vmport_data; > +Stray space between struct and vmport.> uint64_t *params; > > /* Memory ranges with pinned cache attributes. */ > diff --git a/xen/include/asm-x86/hvm/vmport.h b/xen/include/asm-x86/hvm/vmport.h > new file mode 100644 > index 0000000..180ddac > --- /dev/null > +++ b/xen/include/asm-x86/hvm/vmport.h > @@ -0,0 +1,77 @@ > +/* > + * vmport.h: HVM VMPORT emulation > + * > + * > + * Copyright (C) 2012 Verizon Corporation > + * > + * This file is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License Version 2 (GPLv2) > + * as published by the Free Software Foundation. > + * > + * This file 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 > + * General Public License for more details. <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef __ASM_X86_HVM_VMPORT_H__ > +#define __ASM_X86_HVM_VMPORT_H__ > + > +/* Note: VMPORT_PORT and VMPORT_MAGIC is also defined as BDOOR_PORT > + * and BDOOR_MAGIC in backdoor_def.h Defined here so that other > + * parts of XEN can use it. > + */ > + > +#define VMPORT_PORT 0x5658 > +#define VMPORT_MAGIC 0x564D5868You should include backdoor_def.h rather than having the same constant defined twice in the codebase.> + > +#define VMPORT_MAX_KEY_LEN 30 > +#define VMPORT_MAX_VAL_LEN 128 > +#define VMPORT_MAX_NUM_KEY 128 > + > +#define VMPORT_MAX_SEND_BUF ((22 + VMPORT_MAX_KEY_LEN + VMPORT_MAX_VAL_LEN + 3)/4) > +#define VMPORT_MAX_RECV_BUF ((2 + VMPORT_MAX_VAL_LEN + 3)/4) > +#define VMPORT_MAX_CHANS 4 > +#define VMPORT_MAX_BKTS 8 > + > + > +typedef struct vmport_guestinfo_ {Why the trailing underscores in the non-typedef''d name?> + uint8_t key_len; > + uint8_t val_len; > + char key_data[VMPORT_MAX_KEY_LEN]; > + char val_data[VMPORT_MAX_VAL_LEN]; > +} vmport_guestinfo_t; > + > +typedef struct vmport_bucket_ { > + uint16_t recv_len; > + uint16_t recv_idx; > + uint32_t recv_buf[VMPORT_MAX_RECV_BUF + 1]; > + uint8_t recv_slot; > +} vmport_bucket_t; > + > +typedef struct vmport_channel_ { > + unsigned long active_time; > + uint32_t chan_id; > + uint32_t cookie; > + uint32_t proto_num; > + uint16_t send_len; > + uint16_t send_idx; > + uint32_t send_buf[VMPORT_MAX_SEND_BUF + 1]; > + vmport_bucket_t recv_bkt[VMPORT_MAX_BKTS]; > + uint8_t recv_read; > + uint8_t recv_write; > +} vmport_channel_t; > + > +struct vmport_state { > + unsigned long ping_time; > + uint32_t open_cookie; > + uint32_t used_guestinfo; > + vmport_channel_t chans[VMPORT_MAX_CHANS]; > + vmport_guestinfo_t *guestinfo[VMPORT_MAX_NUM_KEY]; > +}; > + > +int vmport_ioport(int dir, int size, unsigned long data, struct cpu_user_regs *regs); > +void vmport_ctrl_send(struct hvm_domain *hd, char *msg, int slot); > +void vmport_flush(struct hvm_domain *hd);These declarations need to be in the same patch as defines them. ~Andrew> + > +#endif /* __ASM_X86_HVM_VMPORT_H__ */
On 12/12/2013 19:15, Don Slutz wrote:> From: Don Slutz <dslutz@verizon.com> > > enable vmport_flush call. > > Signed-off-by: Don Slutz <dslutz@verizon.com> > --- > xen/arch/x86/hvm/Makefile | 1 + > xen/arch/x86/hvm/hvm.c | 2 - > xen/arch/x86/hvm/vmport/Makefile | 1 + > xen/arch/x86/hvm/vmport/includeCheck.h | 17 + > xen/arch/x86/hvm/vmport/vmport.c | 719 +++++++++++++++++++++++++++++++ > xen/arch/x86/hvm/vmport/xen_vmport_def.h | 36 ++ > xen/include/asm-x86/hvm/trace.h | 3 + > 7 files changed, 777 insertions(+), 2 deletions(-) > create mode 100644 xen/arch/x86/hvm/vmport/Makefile > create mode 100644 xen/arch/x86/hvm/vmport/includeCheck.h > create mode 100644 xen/arch/x86/hvm/vmport/vmport.c > create mode 100644 xen/arch/x86/hvm/vmport/xen_vmport_def.h > > diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile > index eea5555..954a81c 100644 > --- a/xen/arch/x86/hvm/Makefile > +++ b/xen/arch/x86/hvm/Makefile > @@ -1,5 +1,6 @@ > subdir-y += svm > subdir-y += vmx > +subdir-y += vmport > > obj-y += asid.o > obj-y += emulate.o > diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c > index fa5d382..a557272 100644 > --- a/xen/arch/x86/hvm/hvm.c > +++ b/xen/arch/x86/hvm/hvm.c > @@ -614,9 +614,7 @@ int hvm_domain_initialise(struct domain *d) > (d->max_pages + (1 << 10) - 1) >> 10, > (d->max_pages + (1 << 20) - 1) >> 20); > > -#if 0 > vmport_flush(&d->arch.hvm_domain); > -#endif > > if ( is_pvh_domain(d) ) > { > diff --git a/xen/arch/x86/hvm/vmport/Makefile b/xen/arch/x86/hvm/vmport/Makefile > new file mode 100644 > index 0000000..2648fae > --- /dev/null > +++ b/xen/arch/x86/hvm/vmport/Makefile > @@ -0,0 +1 @@ > +obj-y += vmport.o > diff --git a/xen/arch/x86/hvm/vmport/includeCheck.h b/xen/arch/x86/hvm/vmport/includeCheck.h > new file mode 100644 > index 0000000..26e0d59 > --- /dev/null > +++ b/xen/arch/x86/hvm/vmport/includeCheck.h > @@ -0,0 +1,17 @@ > +/* > + * includeCheck.h > + * > + * Copyright (C) 2012 Verizon Corporation > + * > + * This file is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License Version 2 (GPLv2) > + * as published by the Free Software Foundation. > + * > + * This file 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 > + * General Public License for more details. <http://www.gnu.org/licenses/>. > + */ > +/* > + * Nothing here. Just to use backdoor_def.h without change.What do you mean by this?> + */ > diff --git a/xen/arch/x86/hvm/vmport/vmport.c b/xen/arch/x86/hvm/vmport/vmport.c > new file mode 100644 > index 0000000..43bdf7b > --- /dev/null > +++ b/xen/arch/x86/hvm/vmport/vmport.c > @@ -0,0 +1,719 @@ > +/* > + * HVM VMPORT emulation > + * > + * Copyright (C) 2012 Verizon Corporation > + * > + * This file is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License Version 2 (GPLv2) > + * as published by the Free Software Foundation. > + * > + * This file 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 > + * General Public License for more details. <http://www.gnu.org/licenses/>. > + */ > + > +#include "xen_vmport_def.h" > +#include "backdoor_def.h" > +#include "guest_msg_def.h" > +#include "asm-x86/hvm/support.h"#include <asm/hvm/support.h>> + > +#define LOG_RPC 0x0000001 > +#define LOG_RECV_STATUS 0x0000002 > +#define LOG_SKIP_SEND 0x0000004 > +#define LOG_SEND 0x0000008 > +#define LOG_SEND_SIZE_ALL 0x0000010 > +#define LOG_SEND_SIZE 0x0000020 > +#define LOG_RECV_SIZE_ALL 0x0000040 > +#define LOG_RECV_SIZE 0x0000080 > +#define LOG_CLOSE 0x0000100 > +#define LOG_OPEN 0x0000200 > +#define LOG_FLUSH 0x0000400 > +#define LOG_TRACE 0x0000800 > +#define LOG_PING 0x0001000 > +#define LOG_SWEEP 0x0002000 > +#define LOG_BUILD 0x0004000 > +#define LOG_STATUS 0x0008000 > + > +#define LOG_ERROR 0x0010000 > + > +#define LOG_INFO_GET 0x0020000 > +#define LOG_INFO_SET 0x0040000 > + > +#define LOG_GP_UNKNOWN 0x0100000 > +#define LOG_GP_NOT_VMWARE 0x0200000 > +#define LOG_GP_FAIL_RD_INST 0x0400000 > +#define LOG_GP_VMWARE_AFTER 0x0800000 > + > +#define LOG_VGP_UNKNOWN 0x1000000 > +#define LOG_REALMODE_GP 0x8000000 > + > +extern unsigned long get_sec(void);Please include the appropriate header files.> + > +/* Note: VMPORT_PORT and VMPORT_MAGIC is also defined as BDOOR_PORT > + * and BDOOR_MAGIC in backdoor_def.h Defined in vmport.h also. > + */ > + > +inline uint16_t getLowBits(uint32_t bits) > +{ > + return bits & 0xffff; > +} > + > +inline uint16_t getHighBits(uint32_t bits) > +{ > + return bits >> 16; > +} > + > +inline uint32_t setHighBits(uint32_t b, uint32_t val) > +{ > + return (val << 16) | getLowBits(b); > +}What is the point of these functions being separated out? setHighBits only seems to be used with regs->ecx (which is actually a 64bit value not a 32bit value) to set a status value. Why not set_status(cpu_user_regs *, uint16_t val) ?> + > +static inline long getLogMask(struct hvm_domain *hd) > +{ > + return hd->params[HVM_PARAM_VMPORT_LOGMASK];A param is unsigned long, not long...> +} > + > +static inline char *getStatus(struct hvm_domain *hd) > +{ > + return (char*)&hd->params[HVM_PARAM_VMPORT_STATUS];... And most certainly not a string.> +} > + > +void vmport_safe_print(char *prefix, int len, char *msg) > +{ > + unsigned char c; > + int end = len; > + int i,k; > + char out[4*(VMPORT_MAX_SEND_BUF + 1)*3 + 6]; > + > + if (end > (sizeof(out)/3 - 6)) > + end = sizeof(out)/3 - 6; > + out[0] = ''<''; > + k = 1; > + for (i = 0; i < end; i++) { > + c = msg[i]; > + if ((c == ''^'') || (c == ''\\'') || (c == ''>'')) { > + out[k++] = ''\\''; > + out[k++] = c; > + } else if ((c >= '' '') && (c <= ''~'')) { > + out[k++] = c; > + } else if (c < '' '') { > + out[k++] = ''^''; > + out[k++] = c ^ 0x40; > + } else { > + snprintf(&out[k], sizeof(out) - k, "\\%02x", c); > + k += 3; > + } > + } > + out[k++] = ''>''; > + if (len > end) { > + out[k++] = ''.''; > + out[k++] = ''.''; > + out[k++] = ''.''; > + } > + out[k++] = 0; > + gdprintk(XENLOG_DEBUG, "%s%d(%d,%d,%ld)%s\n", prefix, end, len, k, sizeof(out), out);the correct format for any sizeof is %zu or %zx depending on decimal/hex.> +} > + > +void vmport_send(struct hvm_domain *hd, vmport_channel_t *c, char *msg, int slot) > +{ > + unsigned int cur_recv_len = strlen(msg) + 1; > + char prefix[30]; > + unsigned int my_bkt = c->recv_write; > + unsigned int next_bkt = my_bkt + 1; > + vmport_bucket_t *b; > + > + if (next_bkt >= VMPORT_MAX_BKTS) > + next_bkt = 0; > + > + if (next_bkt == c->recv_read) { > + if (getLogMask(hd) & LOG_SKIP_SEND) { > + snprintf(prefix, sizeof(prefix), > + "VMware _send skipped %d (%d, %d) ", c->chan_id, my_bkt, c->recv_read); > + prefix[sizeof(prefix)-1] = 0; > + vmport_safe_print(prefix, cur_recv_len, msg); > + } > + getStatus(hd)[slot] = 200;This (and every use of getStatus() below) most certainly needs to guarentee that slot is strictly in the bound 0 to 7, and writing the integer 200 to a char is undefined I believe.> + if (getLogMask(hd) & LOG_STATUS) > + gdprintk(XENLOG_DEBUG, "VMware %d getStatus[%d]=200\n", c->chan_id, slot); > + return; > + } > + > + c->recv_write = next_bkt; > + b = &c->recv_bkt[my_bkt]; > + if (getLogMask(hd) & LOG_SEND) { > + snprintf(prefix, sizeof(prefix), > + "VMware _send %d (%d) ", c->chan_id, my_bkt); > + prefix[sizeof(prefix)-1] = 0; > + vmport_safe_print(prefix, cur_recv_len, msg); > + } > + > + b->recv_len = cur_recv_len; > + b->recv_slot = slot; > + b->recv_idx = 0; > + memset(b->recv_buf, 0, sizeof(b->recv_buf)); > + if (cur_recv_len >= (sizeof(b->recv_buf) - 1)) { > + if (getLogMask(hd) & LOG_ERROR) > + gdprintk(XENLOG_DEBUG, "VMware recv_len=%d >= %ld.\n", > + cur_recv_len, sizeof(b->recv_buf) - 1); > + cur_recv_len = sizeof(b->recv_buf) - 1; > + } > + memcpy(b->recv_buf, msg, cur_recv_len); > + getStatus(hd)[b->recv_slot] = 1; > + if (getLogMask(hd) & LOG_STATUS) > + gdprintk(XENLOG_DEBUG, "VMware %d,%d getStatus[%d]=1\n", > + c->chan_id, c->recv_read, b->recv_slot); > +} > + > +void vmport_ctrl_send(struct hvm_domain *hd, char *msg, int slot) > +{ > + struct vmport_state *vs = hd->vmport_data; > + int i; > + > + if (slot < 1 || slot > 7) > + slot = 7; > + hd->vmport_data->ping_time = get_sec(); > + spin_lock(&hd->vmport_lock); > + for (i = 0; i < VMPORT_MAX_CHANS; i++) { > + if (vs->chans[i].proto_num == 0x4f4c4354) { > + vmport_send(hd, &vs->chans[i], msg, slot); > + } > + } > + spin_unlock(&hd->vmport_lock); > +} > + > +void vmport_flush(struct hvm_domain *hd) > +{ > + if (getLogMask(hd) & LOG_FLUSH) > + gdprintk(XENLOG_DEBUG, "VMware flush.\n"); > + spin_lock(&hd->vmport_lock); > + memset(&hd->vmport_data->chans, 0, sizeof(hd->vmport_data->chans)); > + spin_unlock(&hd->vmport_lock); > +} > + > +void vmport_sweep(struct hvm_domain *hd, unsigned long now_time) > +{ > + struct vmport_state *vs = hd->vmport_data; > + int i; > + > + for (i = 0; i < VMPORT_MAX_CHANS; i++) { > + if (vs->chans[i].proto_num) { > + vmport_channel_t *c = &vs->chans[i]; > + long delta = now_time - c->active_time; > + > + if ( delta >= 80 ) { > + if (getLogMask(hd) & LOG_SWEEP) > + gdprintk(XENLOG_DEBUG, "VMware flush %d. delta=%ld\n", > + c->chan_id, delta); > + // Return channel to free pool > + c->proto_num = 0; > + } > + } > + } > +} > + > +vmport_channel_t *vmport_new_chan(struct vmport_state *vs, unsigned long now_time) > +{ > + int i; > + > + for (i = 0; i < VMPORT_MAX_CHANS; i++) { > + if (!vs->chans[i].proto_num) { > + vmport_channel_t *c = &vs->chans[i]; > + > + c->chan_id = i; > + c->cookie = vs->open_cookie++; > + c->active_time = now_time; > + c->send_len = 0; > + c->send_idx = 0; > + c->recv_read = 0; > + c->recv_write = 0; > + return c; > + } > + } > + return NULL; > +} > + > +void vmport_process_send_size(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) > +{ > + // vmware tools often send a 0 byte request size. > + c->send_len = ur->ebx; > + c->send_idx = 0; > + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); > + if ((getLogMask(hd) & LOG_SEND_SIZE_ALL) || > + ((getLogMask(hd) & LOG_SEND_SIZE) && (c->send_len))) > + gdprintk(XENLOG_DEBUG, "VMware SENDSIZE %d is %d.\n", > + c->chan_id, c->send_len); > +} > + > +void vmport_process_send_payload(struct hvm_domain *hd, vmport_channel_t *c, > + struct cpu_user_regs *ur, unsigned long now_time) > +{ > + char prefix[30]; > + > + if (c->send_idx < VMPORT_MAX_SEND_BUF) { > + c->send_buf[c->send_idx] = ur->ebx; > + } > + c->send_idx++; > + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); > + if (c->send_idx * 4 >= c->send_len) { > + if (c->send_idx < VMPORT_MAX_SEND_BUF) > + ((char*)c->send_buf)[c->send_len] = 0; > + if (getLogMask(hd) & LOG_RPC) { > + snprintf(prefix, sizeof(prefix), > + "VMware RPC %d (%d) ", c->chan_id, c->recv_read); > + prefix[sizeof(prefix)-1] = 0; > + vmport_safe_print(prefix, c->send_len, (char*)c->send_buf); > + } > + if (c->proto_num == 0x49435052) { > +/* log toolbox: Version: build-341836 */ > +/* SetGuestInfo 4 build-341836 */ > +/* info-get guestinfo.ip */ > +/* info-set guestinfo.ip joe */ > + char * build = NULL; > + char * info_key = NULL; > + char * ret_msg = "1 ";I cant remember offhand whether Xen is compiled with or without read-only strings,> + char ret_buffer[2 + VMPORT_MAX_VAL_LEN + 2]; > + > + if (strncmp((char*)c->send_buf, "log toolbox: Version: build-", > + strlen("log toolbox: Version: build-")) == 0) { > + build = (char*)c->send_buf + strlen("log toolbox: Version: build-"); > + } else if (strncmp((char*)c->send_buf, "SetGuestInfo 4 build-", > + strlen("SetGuestInfo 4 build-")) == 0) { > + build = (char*)c->send_buf + strlen("SetGuestInfo 4 build-"); > + } else if (strncmp((char*)c->send_buf, "info-get guestinfo.", > + strlen("info-get guestinfo.")) == 0) { > + int keyLen = c->send_len - strlen("info-get guestinfo."); > + int idx; > + struct vmport_state *vs = hd->vmport_data; > + > + info_key = (char*)c->send_buf + strlen("info-get guestinfo."); > + if (getLogMask(hd) & LOG_INFO_GET) { > + snprintf(prefix, sizeof(prefix), > + "VMware info-get key:"); > + vmport_safe_print(prefix, keyLen, info_key); > + } > + if (keyLen <= VMPORT_MAX_KEY_LEN) { > + for (idx = 0; idx < vs->used_guestinfo; idx++) { > + if ((vs->guestinfo[idx]->key_len == keyLen) && > + (memcmp(info_key, > + vs->guestinfo[idx]->key_data, > + vs->guestinfo[idx]->key_len) == 0)) { > + if (getLogMask(hd) & LOG_INFO_GET) { > + snprintf(prefix, sizeof(prefix), > + "VMware info-get val:"); > + vmport_safe_print(prefix, > + vs->guestinfo[idx]->val_len, > + vs->guestinfo[idx]->val_data); > + } > + snprintf(ret_buffer, sizeof(ret_buffer) - 1, "1 %.*s", > + (int)vs->guestinfo[idx]->val_len, > + vs->guestinfo[idx]->val_data); > + ret_msg = ret_buffer; > + break; > + } > + } > + if (idx >= vs->used_guestinfo) { > + ret_msg = "0 No value found"; > + } > + } else { > + ret_msg = "0 Key is too long"; > + } > + } else if (strncmp((char*)c->send_buf, "info-set guestinfo.", > + strlen("info-set guestinfo.")) == 0) { > + char * val; > + int rest_len = c->send_len - strlen("info-set guestinfo."); > + > + info_key = (char*)c->send_buf + strlen("info-set guestinfo."); > + val = strstr(info_key, " "); > + if (val) { > + int keyLen = val - info_key; > + int valLen = rest_len - keyLen - 1; > + int free_idx = -1; > + int idx; > + struct vmport_state *vs = hd->vmport_data; > + > + val++; > + if (getLogMask(hd) & LOG_INFO_SET) { > + snprintf(prefix, sizeof(prefix), > + "VMware info-set key:"); > + vmport_safe_print(prefix, keyLen, info_key); > + snprintf(prefix, sizeof(prefix), > + "VMware info-set val:"); > + vmport_safe_print(prefix, valLen, val); > + } > + if (keyLen <= VMPORT_MAX_KEY_LEN) { > + if (valLen <= VMPORT_MAX_VAL_LEN) { > + for (idx = 0; idx < vs->used_guestinfo; idx++) { > + if (!vs->guestinfo[idx]) { > + gdprintk(XENLOG_WARNING, "idx=%d not allocated, but used_guestinfo=%d\n", > + idx, vs->used_guestinfo); > + } else if ((vs->guestinfo[idx]->key_len == keyLen) && > + (memcmp(info_key, > + vs->guestinfo[idx]->key_data, > + vs->guestinfo[idx]->key_len) == 0)) { > + vs->guestinfo[idx]->val_len = valLen; > + memcpy(vs->guestinfo[idx]->val_data, val, valLen); > + break; > + } else if ((vs->guestinfo[idx]->key_len == 0) && > + (free_idx == -1)) { > + free_idx = idx; > + } > + } > + if (idx >= vs->used_guestinfo) { > + if (free_idx == -1) { > + ret_msg = "0 Too many keys"; > + } else { > + vs->guestinfo[free_idx]->key_len = keyLen; > + memcpy(vs->guestinfo[free_idx]->key_data, info_key, keyLen); > + vs->guestinfo[free_idx]->val_len = valLen; > + memcpy(vs->guestinfo[free_idx]->val_data, val, valLen); > + } > + } > + } else { > + ret_msg = "0 Value too long"; > + } > + } else { > + ret_msg = "0 Key is too long"; > + } > + } else { > + if (getLogMask(hd) & LOG_INFO_SET) { > + snprintf(prefix, sizeof(prefix), > + "VMware info-set missing val; key:"); > + vmport_safe_print(prefix, rest_len, info_key); > + } > + ret_msg = "0 Two and exactly two arguments expected"; > + } > + } > + > + vmport_send(hd, c, ret_msg, 5); > + if (build) { > + long val = 0; > + char *p = build; > + > + while (*p) { > + if (*p < ''0'' || *p > ''9'') > + break; > + val = val * 10 + *p - ''0''; > + p++; > + }; > + > + hd->params[HVM_PARAM_VMPORT_BUILD_NUMBER_VALUE] = val; > + hd->params[HVM_PARAM_VMPORT_BUILD_NUMBER_TIME] = now_time; > + if (getLogMask(hd) & LOG_BUILD) { > + snprintf(prefix, sizeof(prefix), > + "VMware build %ld ", val); > + vmport_safe_print(prefix, p - build, build); > + } > + } > + } else { > + unsigned int my_bkt = c->recv_read - 1; > + vmport_bucket_t *b; > + int stat = 100; > + int slot; > + > + if (my_bkt >= VMPORT_MAX_BKTS) > + my_bkt = VMPORT_MAX_BKTS - 1; > + b = &c->recv_bkt[my_bkt]; > + b->recv_len = 0; > + slot = b->recv_slot; > + if (slot < 1 || slot > 7) > + slot = 7; > + if ((c->send_len > 2) && ((c->send_buf[0] & 0xffff) == 0x4b4f)) > + stat = 3; > + if (getLogMask(hd) & LOG_STATUS) > + gdprintk(XENLOG_DEBUG, "VMware %d,%d(%d) getStatus[%d(%d)]=%d <== %d hex=0x%x\n", > + c->chan_id, my_bkt, c->recv_read, slot, b->recv_slot, > + getStatus(hd)[slot], stat, c->send_buf[0] & 0xffff); > + getStatus(hd)[slot] = stat; > + } > + } > +} > + > +void vmport_process_recv_size(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) > +{ > + vmport_bucket_t *b = &c->recv_bkt[c->recv_read]; > + > + if ((getLogMask(hd) & LOG_RECV_SIZE_ALL) || > + ((getLogMask(hd) & LOG_RECV_SIZE) && (b->recv_len))) > + gdprintk(XENLOG_DEBUG, "VMware RECVSIZE %d is %d.\n", > + c->chan_id, b->recv_len); > + > + if (b->recv_len) { > + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_DORECV | MESSAGE_STATUS_SUCCESS); > + ur->edx = setHighBits(ur->edx, MESSAGE_TYPE_SENDSIZE); > + ur->ebx = b->recv_len; > + } else { > + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); > + } > +} > + > +void vmport_process_recv_payload(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) > +{ > + vmport_bucket_t *b = &c->recv_bkt[c->recv_read]; > + > + if (b->recv_idx < VMPORT_MAX_RECV_BUF) { > + ur->ebx = b->recv_buf[b->recv_idx++]; > + } else { > + ur->ebx = 0; > + } > + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); > + ur->edx = setHighBits(ur->edx, MESSAGE_TYPE_SENDPAYLOAD); > +} > + > +void vmport_process_recv_status(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) > +{ > + vmport_bucket_t *b = &c->recv_bkt[c->recv_read]; > + char prefix[30]; > + > + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); > + if (getLogMask(hd) & LOG_RECV_STATUS) { > + snprintf(prefix, sizeof(prefix), > + "VMware RECVSTATUS %d (%d) ", c->chan_id, c->recv_read); > + prefix[sizeof(prefix)-1] = 0; > + vmport_safe_print(prefix, b->recv_len, (char*)b->recv_buf); > + } > + getStatus(hd)[b->recv_slot] = 2; > + if (getLogMask(hd) & LOG_STATUS) > + gdprintk(XENLOG_DEBUG, "VMware %d,%d getStatus[%d]=2\n", > + c->chan_id, c->recv_read, b->recv_slot); > + c->recv_read++; > + if (c->recv_read >= VMPORT_MAX_BKTS) > + c->recv_read = 0; > +} > + > +void vmport_process_close(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) > +{ > + // Return channel to free pool > + c->proto_num = 0; > + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); > + if (getLogMask(hd) & LOG_CLOSE) > + gdprintk(XENLOG_DEBUG, "VMware CLOSE %d.\n", > + c->chan_id); > + if (getLogMask(hd) & LOG_STATUS) > + gdprintk(XENLOG_DEBUG, "VMware %d getStatus[0]=0x%x & ~0x%x=0x%x\n", > + c->chan_id, getStatus(hd)[0], 1 << c->chan_id, ~(1 << c->chan_id)); > + getStatus(hd)[0] &= ~(1 << c->chan_id); > +} > + > +void vmport_process_packet(struct hvm_domain *hd, vmport_channel_t *c, > + struct cpu_user_regs *ur, int sub_cmd, > + unsigned long now_time) > +{ > + c->active_time = now_time; > + switch (sub_cmd) { > + case MESSAGE_TYPE_SENDSIZE: > + vmport_process_send_size(hd, c, ur); > + break; > + case MESSAGE_TYPE_SENDPAYLOAD: > + vmport_process_send_payload(hd, c, ur, now_time); > + break; > + > + case MESSAGE_TYPE_RECVSIZE: > + vmport_process_recv_size(hd, c, ur); > + break; > + case MESSAGE_TYPE_RECVPAYLOAD: > + vmport_process_recv_payload(hd, c, ur); > + break; > + case MESSAGE_TYPE_RECVSTATUS: > + vmport_process_recv_status(hd, c, ur); > + break; > + > + case MESSAGE_TYPE_CLOSE: > + vmport_process_close(hd, c, ur); > + break; > + > + default: > + ur->ecx = 0; > + break; > + } > +} > + > +void vmport_rpc(struct hvm_domain *hd, struct cpu_user_regs *ur) > +{ > + int sub_cmd = (ur->ecx >> 16) & 0xffff; > + vmport_channel_t *c = NULL; > + uint16_t msg_id; > + uint32_t msg_cookie; > + unsigned long now_time = get_sec(); > + long delta = now_time - hd->vmport_data->ping_time; > + > + if ( delta >= hd->params[HVM_PARAM_VMPORT_RESET_TIME] ) { > + if (getLogMask(hd) & LOG_PING) > + gdprintk(XENLOG_DEBUG, "VMware ping. delta=%ld\n", > + delta); > + vmport_ctrl_send(hd, "reset", 7); > + } > + spin_lock(&hd->vmport_lock); > + vmport_sweep(hd, now_time); > + do { > + // Check to see if a new open request is happening... > + if (MESSAGE_TYPE_OPEN == sub_cmd) { > + c = vmport_new_chan(hd->vmport_data, now_time); > + if (NULL == c) { > + if (getLogMask(hd) & LOG_ERROR) > + gdprintk(XENLOG_ERR, "VMware failed to find a free channel.\n"); > + break; > + } > + > + // Attach the apropriate protocol the the channel > + c->proto_num = ur->ebx & ~GUESTMSG_FLAG_COOKIE; > + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); > + ur->edx = setHighBits(ur->edx, c->chan_id); > + ur->edi = getLowBits(c->cookie); > + ur->esi = getHighBits(c->cookie); > + if (getLogMask(hd) & LOG_OPEN) > + gdprintk(XENLOG_DEBUG, "VMware OPEN %d p=%x.\n", > + c->chan_id, c->proto_num); > + if (getLogMask(hd) & LOG_STATUS) > + gdprintk(XENLOG_DEBUG, "VMware %d getStatus[0]=0x%x | 0x%x\n", > + c->chan_id, getStatus(hd)[0], 1 << c->chan_id); > + getStatus(hd)[0] |= 1 << c->chan_id; > + if (c->proto_num == 0x4f4c4354) { > + vmport_send(hd, c, "reset", 6); > + } > + break; > + } > + > + msg_id = getHighBits(ur->edx); > + msg_cookie = getLowBits(ur->edi) | (ur->esi << 16); > + if (msg_id >= VMPORT_MAX_CHANS) { > + if (getLogMask(hd) & LOG_ERROR) > + gdprintk(XENLOG_ERR, "VMware chan id err %d >= %d.\n", > + msg_id, VMPORT_MAX_CHANS); > + break; > + } > + c = &hd->vmport_data->chans[msg_id]; > + if (!c->proto_num) { > + if (getLogMask(hd) & LOG_ERROR) > + gdprintk(XENLOG_ERR, "VMware chan %d not open.\n", > + msg_id); > + break; > + } > + > + // We check the cookie here since it''s possible that the > + // connection timed out on us and another channel was opened > + // if this happens, return error and the um tool will > + // need to reopen the connection > + if (msg_cookie != c->cookie) { > + if (getLogMask(hd) & LOG_ERROR) > + gdprintk(XENLOG_ERR, "VMware cookie err %x vs %x.\n", > + msg_cookie, c->cookie); > + break; > + } > + vmport_process_packet(hd, c, ur, sub_cmd, now_time); > + } while( 0 ); > + > + if( NULL == c ) > + ur->ecx = setHighBits(ur->ecx, 0); > + > + spin_unlock(&hd->vmport_lock); > +} > + > +int vmport_ioport(int dir, int size, unsigned long data, struct cpu_user_regs *regs) > +{ > + uint32_t cmd = getLowBits(regs->ecx); > + uint32_t magic = regs->eax; > + struct hvm_domain *hd = ¤t->domain->arch.hvm_domain; > + > + if ( dir != IOREQ_WRITE ) > + data = 0; > + > + if (magic == BDOOR_MAGIC) { > + const uint32_t apicHz = 1000000000L;Again this hard coded constant.> + uint64_t value; > + > + switch (cmd) { > + case BDOOR_CMD_GETMHZ: > + /* ... */ > + regs->ebx = BDOOR_MAGIC; > + regs->eax = (uint32_t)(current->domain->arch.tsc_khz / 1000); > + break; > + case BDOOR_CMD_GETVERSION: > + /* ... */ > + regs->ebx = BDOOR_MAGIC; > + /* VERSION_MAGIC */ > + regs->eax = 6; > + /* Claim we are an ESX. VMX_TYPE_SCALABLE_SERVER */ > + regs->ecx = 2; > + break; > + case BDOOR_CMD_GETHWVERSION: > + /* ... */ > + regs->ebx = BDOOR_MAGIC; > + /* ?? */ > + regs->eax = 0x4; > + break; > + case BDOOR_CMD_GETHZ: > + value = current->domain->arch.tsc_khz * 1000; > + /* apic-frequency (bus speed) */ > + regs->ecx = apicHz; > + /* High part of tsc-frequency */ > + regs->ebx = (uint32_t)(value >> 32); > + /* Low part of tsc-frequency */ > + regs->eax = (uint32_t)value; > + break; > + case BDOOR_CMD_GETTIME: > + value = get_localtime_us(current->domain); > + /* hostUsecs */ > + regs->ebx = (uint32_t)(value % 1000000UL); > + /* hostSecs */ > + regs->eax = (uint32_t)(value / 1000000ULL); > + /* maxTimeLag */ > + regs->ecx = 0; > + break; > + case BDOOR_CMD_GETTIMEFULL: > + value = get_localtime_us(current->domain); > + /* ... */ > + regs->eax = BDOOR_MAGIC; > + /* hostUsecs */ > + regs->ebx = (uint32_t)(value % 1000000UL); > + /* High part of hostSecs */ > + regs->esi = (uint32_t)((value / 1000000ULL) >> 32); > + /* Low part of hostSecs */ > + regs->edx = (uint32_t)(value / 1000000ULL); > + /* maxTimeLag */ > + regs->ecx = 0; > + break; > + case BDOOR_CMD_MESSAGE: > + vmport_rpc(hd, regs); > + break; > + > + default: > + if (getLogMask(hd) & LOG_ERROR) > + gdprintk(XENLOG_DEBUG, "VMware size=%d dir=%d data=%lx cmd=%d.\n", > + size, dir, data, cmd); > + break; > + } > + if (getLogMask(hd) & LOG_TRACE) > + gdprintk(XENLOG_DEBUG, "VMware ip=%lx cmd=%d ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx\n", > + (unsigned long)regs->eip, cmd, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + } else > + if (getLogMask(hd) & LOG_ERROR) > + gdprintk(XENLOG_ERR, "Not VMware %x vs %x vs %x; ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx\n", > + magic, BDOOR_MAGIC, VMPORT_MAGIC, > + (unsigned long)regs->eip, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + > + if (dir == IOREQ_READ) > + HVMTRACE_ND(IOPORT_READ, 0, 1/*cycles*/, 5, VMPORT_PORT, cmd, > + regs->eax, regs->ebx, regs->ecx, 0); > + else > + HVMTRACE_ND(IOPORT_WRITE, 0, 1/*cycles*/, 5, VMPORT_PORT, cmd, > + regs->eax, regs->ebx, regs->ecx, 0); > + > + return 1; > +} > + > +/* > + * Local variables: > + * mode: C > + * c-set-style: "BSD" > + * c-basic-offset: 4 > + * tab-width: 4 > + * indent-tabs-mode: nil > + * End: > + */Frankly, this while file is quite nasty. There is a huge amount of pointer arithmetic and array indexing with guest data, which doesn''t appear at a glance to have sufficient validation. The vast majority of the ints should be unsigned as they are used as indices. All the times should probably be s_time_t''s The idiom if ( getLogMask(hd) & LOG_$SOMETHING ) gdprintk(XENLOG_$SOMETHING, ...); Can probably be moved into a single macro, which will simply the reading of the code quite a bit. Is there a spec for what this code is trying to accomplish? Some of the comments suggest that it has been reverse engineered? I think I have counted 4 coding styles in there. Given the Xen block on the bottom, can it settle on a single style.> diff --git a/xen/arch/x86/hvm/vmport/xen_vmport_def.h b/xen/arch/x86/hvm/vmport/xen_vmport_def.h > new file mode 100644 > index 0000000..e87845b > --- /dev/null > +++ b/xen/arch/x86/hvm/vmport/xen_vmport_def.h > @@ -0,0 +1,36 @@ > +/* > + * xen_vmport_def.h: HVM VMPORT emulation > + * > + * > + * Copyright (C) 2012 Verizon Corporation > + * > + * This file is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License Version 2 (GPLv2) > + * as published by the Free Software Foundation. > + * > + * This file 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 > + * General Public License for more details. <http://www.gnu.org/licenses/>. > + */ > + > +#ifndef __XEN_VMPORT_DEF_H__ > +#define __XEN_VMPORT_DEF_H__ > + > +#include <xen/config.h> > +#include <xen/init.h> > +#include <xen/mm.h> > +#include <xen/lib.h> > +#include <xen/errno.h> > +#include <xen/trace.h> > +#include <xen/event.h> > +#include <xen/hypercall.h> > +#include <asm/current.h> > +#include <asm/cpufeature.h> > +#include <asm/processor.h> > +#include <asm/hvm/hvm.h> > +#include <asm/hvm/support.h> > +#include <asm/hvm/trace.h> > +#include <asm/hvm/vmport.h>What is the point of this header file?> + > +#endif > diff --git a/xen/include/asm-x86/hvm/trace.h b/xen/include/asm-x86/hvm/trace.h > index 9d7e00b..d5c3a3e 100644 > --- a/xen/include/asm-x86/hvm/trace.h > +++ b/xen/include/asm-x86/hvm/trace.h > @@ -52,8 +52,11 @@ > #define DO_TRC_HVM_LMSW64 DEFAULT_HVM_MISC > #define DO_TRC_HVM_REALMODE_EMULATE DEFAULT_HVM_MISC > #define DO_TRC_HVM_TRAP DEFAULT_HVM_MISC > +#define DO_TRC_HVM_TRAP64 DEFAULT_HVM_MISC > #define DO_TRC_HVM_TRAP_DEBUG DEFAULT_HVM_MISC > #define DO_TRC_HVM_VLAPIC DEFAULT_HVM_MISC > +#define DO_TRC_HVM_IOPORT_READ DEFAULT_HVM_IO > +#define DO_TRC_HVM_IOPORT_WRITE DEFAULT_HVM_IOThere are already traps for io ports, which I believe are part of the generic vmexit traps. ~Andrew> > > #define TRC_PAR_LONG(par) ((par)&0xFFFFFFFF),((par)>>32)
On 12/12/2013 19:15, Don Slutz wrote:> From: Don Slutz <dslutz@verizon.com> > > Signed-off-by: Don Slutz <dslutz@verizon.com> > --- > xen/arch/x86/hvm/io.c | 4 ++ > xen/arch/x86/hvm/svm/svm.c | 104 ++++++++++++++++++++++++++++++++++++ > xen/arch/x86/hvm/svm/vmcb.c | 1 + > xen/arch/x86/hvm/vmx/vmcs.c | 1 + > xen/arch/x86/hvm/vmx/vmx.c | 125 ++++++++++++++++++++++++++++++++++++++++++++ > xen/arch/x86/hvm/vmx/vvmx.c | 13 +++++ > xen/include/public/trace.h | 1 + > 7 files changed, 249 insertions(+) > > diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c > index bf6309d..4bc4716 100644 > --- a/xen/arch/x86/hvm/io.c > +++ b/xen/arch/x86/hvm/io.c > @@ -42,6 +42,7 @@ > #include <asm/hvm/vlapic.h> > #include <asm/hvm/trace.h> > #include <asm/hvm/emulate.h> > +#include <asm/hvm/vmport.h> > #include <public/sched.h> > #include <xen/iocap.h> > #include <public/hvm/ioreq.h> > @@ -236,6 +237,9 @@ int handle_pio(uint16_t port, unsigned int size, int dir) > if ( dir == IOREQ_WRITE ) > data = guest_cpu_user_regs()->eax; > > + if ( port == VMPORT_PORT ) > + return vmport_ioport(dir, size, data, guest_cpu_user_regs()); > +Use register_portio_handler(), which is the already-existing infrastructure for intercepting ports.> rc = hvmemul_do_pio(port, &reps, size, 0, dir, 0, &data); > > switch ( rc ) > diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c > index 406d394..80cf2bf 100644 > --- a/xen/arch/x86/hvm/svm/svm.c > +++ b/xen/arch/x86/hvm/svm/svm.c > @@ -56,6 +56,7 @@ > #include <asm/hvm/svm/nestedsvm.h> > #include <asm/hvm/nestedhvm.h> > #include <asm/x86_emulate.h> > +#include <asm/hvm/vmport.h> > #include <public/sched.h> > #include <asm/hvm/vpt.h> > #include <asm/hvm/trace.h> > @@ -1904,6 +1905,105 @@ svm_vmexit_do_vmsave(struct vmcb_struct *vmcb, > return; > } > > +static void svm_vmexit_gp_intercept(struct cpu_user_regs *regs, struct vcpu *v) > +{ > + struct hvm_domain *hd = &v->domain->arch.hvm_domain; > + struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; > + unsigned long inst_len, bytes_len; > + int frc; > + unsigned char bytes[15]; > + > + regs->error_code = vmcb->exitinfo1; > + if ( !cpu_has_svm_nrips || (vmcb->nextrip <= vmcb->rip) ) > + inst_len = 0; > + else > + inst_len = vmcb->nextrip - vmcb->rip; > + bytes_len = 2 /* inst_len < 15 ? inst_len > 1 ? inst_len : 2 : 15 */; > + frc = hvm_fetch_from_guest_virt_nofault(bytes, regs->eip, > + bytes_len, > + PFEC_page_present); > + > + if ( hvm_long_mode_enabled(v) ) > + HVMTRACE_LONG_4D(TRAP, TRAP_gp_fault, inst_len, > + regs->error_code, > + TRC_PAR_LONG(vmcb->exitinfo2) ); > + else > + HVMTRACE_4D(TRAP, TRAP_gp_fault, inst_len, > + regs->error_code, vmcb->exitinfo2 ); > + > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x400000 /* LOG_GP_FAIL_RD_INST */) > + printk("[HVM:%d.%d] <%s> " > + "gp: e2=%lx ec=%lx ip=%lx=>0x%x 0x%x(%ld,%ld,%d) nip(%d)=%lx(%d,%d(0x%x) 0x%x 0x%x)" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)vmcb->exitinfo2, > + (unsigned long)regs->error_code, > + (unsigned long)regs->eip, (unsigned int)bytes[0], > + (unsigned int)bytes[1], bytes_len, inst_len, frc, > + cpu_has_svm_nrips, (unsigned long)vmcb->nextrip, > + cpu_has_svm_decode, vmcb->guest_ins_len & 0xf, vmcb->guest_ins_len, > + vmcb->guest_ins[0], vmcb->guest_ins[1]); > + > + if ( !frc && bytes[0] == 0xed && (regs->edx & 0xffff) == VMPORT_PORT && > + vmcb->exitinfo2 == 0 && regs->error_code == 0 ) > + { > + /* in (%dx),%eax */ > + uint32_t magic = regs->eax; > + > + if ( magic == VMPORT_MAGIC ) { > + __update_guest_eip(regs, 1); > + vmport_ioport(IOREQ_READ, 4, 0, regs);This appears to be intercepting an L2 guest doing vmport magic IO to the L1 hypervisor. Is this sane/sensible/wise?> + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x800000 /* LOG_GP_VMWARE_AFTER */) > + printk("[HVM:%d.%d] <%s> " > + "gp: VMware ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)regs->eip, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + return; > + } else { > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x200000 /* LOG_GP_NOT_VMWARE */) > + printk("[HVM:%d.%d] <%s> " > + "gp: ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)regs->eip, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code); > + } > + } else if (!frc && regs->error_code == 0 > + && bytes[0] == 0x0f && bytes[1] == 0x33 && regs->ecx == 0x10000) > + { > + /* "rdpmc 0x10000" */ > + /* Not a very good emulation! But just not faulting is good enough > + * to get NetApp booting. */ > + regs->edx = regs->eax = 0;This doesn''t look like it is logically part of "connecting vmport up" ~Andrew> + > + __update_guest_eip(regs, inst_len); > + > + /* Doing the log in this case was too noisy for NetApp, so I moved > + * it to ''else'' */ > + } else { > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x100000 /* LOG_GP_UNKNOWN */) { > + printk("[HVM:%d.%d] <%s> " > + "gp: e2=%lx ec=%lx ip=%lx=>0x%x 0x%x(%ld,%d) ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)vmcb->exitinfo2, (unsigned long)regs->error_code, > + (unsigned long)regs->eip, (unsigned int)bytes[0], > + (unsigned int)bytes[1], inst_len, frc, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + } > + hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code); > + } > +} > + > static void svm_vmexit_ud_intercept(struct cpu_user_regs *regs) > { > struct hvm_emulate_ctxt ctxt; > @@ -2253,6 +2353,10 @@ void svm_vmexit_handler(struct cpu_user_regs *regs) > break; > } > > + case VMEXIT_EXCEPTION_GP: > + svm_vmexit_gp_intercept(regs, v); > + break; > + > case VMEXIT_EXCEPTION_UD: > svm_vmexit_ud_intercept(regs); > break; > diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c > index 21292bb..791c045 100644 > --- a/xen/arch/x86/hvm/svm/vmcb.c > +++ b/xen/arch/x86/hvm/svm/vmcb.c > @@ -193,6 +193,7 @@ static int construct_vmcb(struct vcpu *v) > > vmcb->_exception_intercepts > HVM_TRAP_MASK > + | (1U << TRAP_gp_fault) > | (1U << TRAP_no_device); > > if ( paging_mode_hap(v->domain) ) > diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c > index 44f33cb..21cde2f 100644 > --- a/xen/arch/x86/hvm/vmx/vmcs.c > +++ b/xen/arch/x86/hvm/vmx/vmcs.c > @@ -1074,6 +1074,7 @@ static int construct_vmcs(struct vcpu *v) > > v->arch.hvm_vmx.exception_bitmap = HVM_TRAP_MASK > | (paging_mode_hap(d) ? 0 : (1U << TRAP_page_fault)) > + | (1U << TRAP_gp_fault) > | (1U << TRAP_no_device); > vmx_update_exception_bitmap(v); > > diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c > index dfff628..248900d 100644 > --- a/xen/arch/x86/hvm/vmx/vmx.c > +++ b/xen/arch/x86/hvm/vmx/vmx.c > @@ -44,6 +44,7 @@ > #include <asm/hvm/support.h> > #include <asm/hvm/vmx/vmx.h> > #include <asm/hvm/vmx/vmcs.h> > +#include <asm/hvm/vmport.h> > #include <public/sched.h> > #include <public/hvm/ioreq.h> > #include <asm/hvm/vpic.h> > @@ -1211,6 +1212,7 @@ static void vmx_update_guest_cr(struct vcpu *v, unsigned int cr) > v->arch.hvm_vmx.exception_bitmap = HVM_TRAP_MASK > | (paging_mode_hap(v->domain) ? > 0 : (1U << TRAP_page_fault)) > + | (1U << TRAP_gp_fault) > | (1U << TRAP_no_device); > vmx_update_exception_bitmap(v); > vmx_update_debug_state(v); > @@ -2454,6 +2456,113 @@ static void vmx_idtv_reinject(unsigned long idtv_info) > } > } > > +void do_gp_fault(struct cpu_user_regs *regs, struct vcpu *v) > +{ > + struct hvm_domain *hd = &v->domain->arch.hvm_domain; > + unsigned long exit_qualification; > + unsigned long inst_len; > + unsigned long ecode; > + > + __vmread(EXIT_QUALIFICATION, &exit_qualification); > + __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len); > + __vmread(VM_EXIT_INTR_ERROR_CODE, &ecode); > + regs->error_code = ecode; > + if ( hvm_long_mode_enabled(v) ) > + HVMTRACE_LONG_4D(TRAP, TRAP_gp_fault, inst_len, > + regs->error_code, > + TRC_PAR_LONG(exit_qualification) ); > + else > + HVMTRACE_4D(TRAP, TRAP_gp_fault, inst_len, > + regs->error_code, exit_qualification ); > + > + if ( inst_len == 1 && (regs->edx & 0xffff) == VMPORT_PORT && > + exit_qualification == 0 && regs->error_code == 0 ) { > + uint32_t magic = regs->eax; > + > + if ( magic == VMPORT_MAGIC ) { > + unsigned char bytes[1]; > + int frc = hvm_fetch_from_guest_virt_nofault(bytes, regs->eip, > + 1, PFEC_page_present); > + if (!frc && bytes[0] == 0xed) { /* in (%dx),%eax */ > + update_guest_eip(); > + vmport_ioport(IOREQ_READ, 4, 0, regs); > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x800000 /* LOG_GP_VMWARE_AFTER */) > + printk("[HVM:%d.%d] <%s> " > + "gp: VMware ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)regs->eip, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + return; > + } else { > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x400000 /* LOG_GP_FAIL_RD_INST */) > + printk("[HVM:%d.%d] <%s> " > + "gp: VMware? ip=%lx=>0x%x(%d) ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)regs->eip, bytes[0], frc, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + } > + } else { > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x200000 /* LOG_GP_NOT_VMWARE */) > + printk("[HVM:%d.%d] <%s> " > + "gp: ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)regs->eip, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code); > + } > + } else { > + unsigned char bytes[15]; > + int frc; > + > + /* > + * We can conditionalize this call on inst_len == 2 if we decide to > + * remove the following printk. > + */ > + frc = hvm_fetch_from_guest_virt_nofault(bytes, regs->eip, > + inst_len < 15 ? inst_len : 15, > + PFEC_page_present); > + > + /* Emulate "rdpmc 0x10000" */ > + if (!frc && inst_len == 2 && regs->error_code == 0 > + && bytes[0] == 0x0f && bytes[1] == 0x33 && regs->ecx == 0x10000) > + { > + /* Not a very good emulation! But just not faulting is good enough > + * to get NetApp booting. */ > + regs->edx = regs->eax = 0; > + > + update_guest_eip(); > + > + /* Doing the log in this case was too noisy for NetApp, so I moved > + * it to ''else'' */ > + } else { > + /* We should probably turn this log off by default in production in > + * case somebody decides to do a lot of #GPs. */ > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x100000 /* LOG_GP_UNKNOWN */) { > + printk("[HVM:%d.%d] <%s> " > + "gp: eq=%lx ec=%lx ip=%lx=>0x%x 0x%x(%ld,%d) ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)exit_qualification, (unsigned long)regs->error_code, > + (unsigned long)regs->eip, (unsigned int)bytes[0], > + (unsigned int)bytes[1], inst_len, frc, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + } > + hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code); > + } > + } > +} > + > static int vmx_handle_apic_write(void) > { > unsigned long exit_qualification; > @@ -2562,6 +2671,19 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs) > && vector != TRAP_nmi > && vector != TRAP_machine_check ) > { > + if (vector == TRAP_gp_fault ) { > + struct hvm_domain *hd = &v->domain->arch.hvm_domain; > + > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x8000000 /* LOG_REALMODE_GP */) > + printk("[HVM:%d.%d] <%s> " > + "realmode gp: ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)regs->eip, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + } > perfc_incr(realmode_exits); > v->arch.hvm_vmx.vmx_emulate = 1; > HVMTRACE_0D(REALMODE_EMULATE); > @@ -2677,6 +2799,9 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs) > HVMTRACE_1D(TRAP, vector); > vmx_fpu_dirty_intercept(); > break; > + case TRAP_gp_fault: > + do_gp_fault(regs, v); > + break; > case TRAP_page_fault: > __vmread(EXIT_QUALIFICATION, &exit_qualification); > __vmread(VM_EXIT_INTR_ERROR_CODE, &ecode); > diff --git a/xen/arch/x86/hvm/vmx/vvmx.c b/xen/arch/x86/hvm/vmx/vvmx.c > index 0daad79..fcd03dd 100644 > --- a/xen/arch/x86/hvm/vmx/vvmx.c > +++ b/xen/arch/x86/hvm/vmx/vvmx.c > @@ -2166,6 +2166,19 @@ int nvmx_n2_vmexit_handler(struct cpu_user_regs *regs, > if ( v->fpu_dirtied ) > nvcpu->nv_vmexit_pending = 1; > } > + else if ( vector == TRAP_gp_fault ) > + { > + struct cpu_user_regs *ur = guest_cpu_user_regs(); > + struct hvm_domain *hd = &v->domain->arch.hvm_domain; > + > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x1000000 /* LOG_VGP_UNKNOWN */) > + gdprintk(XENLOG_ERR, "Unexpected gp: ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx\n", > + (unsigned long)ur->eip, > + (unsigned long)ur->eax, (unsigned long)ur->ebx, > + (unsigned long)ur->ecx, (unsigned long)ur->edx, > + (unsigned long)ur->esi, (unsigned long)ur->edi); > + nvcpu->nv_vmexit_pending = 1; > + } > else if ( (intr_info & valid_mask) == valid_mask ) > { > exec_bitmap =__get_vvmcs(nvcpu->nv_vvmcx, EXCEPTION_BITMAP); > diff --git a/xen/include/public/trace.h b/xen/include/public/trace.h > index e2f60a6..32489f0 100644 > --- a/xen/include/public/trace.h > +++ b/xen/include/public/trace.h > @@ -223,6 +223,7 @@ > #define TRC_HVM_NPF (TRC_HVM_HANDLER + 0x21) > #define TRC_HVM_REALMODE_EMULATE (TRC_HVM_HANDLER + 0x22) > #define TRC_HVM_TRAP (TRC_HVM_HANDLER + 0x23) > +#define TRC_HVM_TRAP64 (TRC_HVM_HANDLER + TRC_64_FLAG + 0x23)Haven''t you already defined this in a previous patch?> #define TRC_HVM_TRAP_DEBUG (TRC_HVM_HANDLER + 0x24) > #define TRC_HVM_VLAPIC (TRC_HVM_HANDLER + 0x25) >
Andrew Cooper
2013-Dec-13 00:58 UTC
Re: [RFC PATCH 09/10] libxl: Add VTPOWER, VTREBOOT and VTPING
On 12/12/2013 19:15, Don Slutz wrote:> From: Don Slutz <dslutz@verizon.com> > > Signed-off-by: Don Slutz <dslutz@verizon.com> > --- > tools/libxl/libxl.c | 12 ++++++++++++ > tools/libxl/libxl_types.idl | 3 +++ > tools/libxl/xl_cmdtable.c | 2 +- > xen/arch/x86/domctl.c | 34 ++++++++++++++++++++++++++++++++++ > xen/include/public/domctl.h | 3 +++ > 5 files changed, 53 insertions(+), 1 deletion(-) > > diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c > index fd8b988..1ec8484 100644 > --- a/tools/libxl/libxl.c > +++ b/tools/libxl/libxl.c > @@ -5057,6 +5057,18 @@ int libxl_send_trigger(libxl_ctx *ctx, uint32_t domid, > rc = xc_domain_send_trigger(ctx->xch, domid, > XEN_DOMCTL_SENDTRIGGER_SLEEP, vcpuid); > break; > + case LIBXL_TRIGGER_VTPOWER: > + rc = xc_domain_send_trigger(ctx->xch, domid, > + XEN_DOMCTL_SENDTRIGGER_VTPOWER, vcpuid); > + break; > + case LIBXL_TRIGGER_VTREBOOT: > + rc = xc_domain_send_trigger(ctx->xch, domid, > + XEN_DOMCTL_SENDTRIGGER_VTREBOOT, vcpuid); > + break; > + case LIBXL_TRIGGER_VTPING: > + rc = xc_domain_send_trigger(ctx->xch, domid, > + XEN_DOMCTL_SENDTRIGGER_VTPING, vcpuid); > + break; > case LIBXL_TRIGGER_NMI: > rc = xc_domain_send_trigger(ctx->xch, domid, > XEN_DOMCTL_SENDTRIGGER_NMI, vcpuid); > diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl > index 71ba64e..80a8ee8 100644 > --- a/tools/libxl/libxl_types.idl > +++ b/tools/libxl/libxl_types.idl > @@ -105,6 +105,9 @@ libxl_trigger = Enumeration("trigger", [ > (4, "INIT"), > (5, "RESET"), > (6, "S3RESUME"), > + (7, "VTPOWER"), > + (8, "VTREBOOT"), > + (9, "VTPING"), > ]) > > libxl_tsc_mode = Enumeration("tsc_mode", [ > diff --git a/tools/libxl/xl_cmdtable.c b/tools/libxl/xl_cmdtable.c > index ebe0220..98db8ae 100644 > --- a/tools/libxl/xl_cmdtable.c > +++ b/tools/libxl/xl_cmdtable.c > @@ -290,7 +290,7 @@ struct cmd_spec cmd_table[] = { > { "trigger", > &main_trigger, 0, 1, > "Send a trigger to a domain", > - "<Domain> <nmi|reset|init|power|sleep|s3resume> [<VCPU>]", > + "<Domain> <nmi|reset|init|power|sleep|s3resume|vtpower|vtreboot|vtping> [<VCPU>]", > }, > { "sysrq", > &main_sysrq, 0, 1, > diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c > index ef6c140..8b77ce2 100644 > --- a/xen/arch/x86/domctl.c > +++ b/xen/arch/x86/domctl.c > @@ -23,6 +23,7 @@ > #include <xen/paging.h> > #include <asm/irq.h> > #include <asm/hvm/hvm.h> > +#include <asm/hvm/vmport.h> > #include <asm/hvm/support.h> > #include <asm/hvm/cacheattr.h> > #include <asm/processor.h> > @@ -577,6 +578,39 @@ long arch_do_domctl( > } > break; > > + case XEN_DOMCTL_SENDTRIGGER_VTPOWER: > + { > + ret = -EINVAL; > + if ( is_hvm_domain(d) )Surely "is_vmware_domain(d)" is the appropriate check here?> + { > + ret = 0; > + vmport_ctrl_send(&d->arch.hvm_domain, "OS_Halt", 1); > + } > + } > + break; > + > + case XEN_DOMCTL_SENDTRIGGER_VTREBOOT: > + { > + ret = -EINVAL; > + if ( is_hvm_domain(d) ) > + { > + ret = 0; > + vmport_ctrl_send(&d->arch.hvm_domain, "OS_Reboot", 2); > + } > + } > + break; > + > + case XEN_DOMCTL_SENDTRIGGER_VTPING: > + { > + ret = -EINVAL; > + if ( is_hvm_domain(d) ) > + { > + ret = 0; > + vmport_ctrl_send(&d->arch.hvm_domain, "ping", 3);POWER and REBOOT I can understand, but what is the expected actions from PING ? ~Andrew> + } > + } > + break; > + > default: > ret = -ENOSYS; > } > diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h > index 01a3652..d71d57c 100644 > --- a/xen/include/public/domctl.h > +++ b/xen/include/public/domctl.h > @@ -454,6 +454,9 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_real_mode_area_t); > #define XEN_DOMCTL_SENDTRIGGER_INIT 2 > #define XEN_DOMCTL_SENDTRIGGER_POWER 3 > #define XEN_DOMCTL_SENDTRIGGER_SLEEP 4 > +#define XEN_DOMCTL_SENDTRIGGER_VTPOWER 5 > +#define XEN_DOMCTL_SENDTRIGGER_VTREBOOT 6 > +#define XEN_DOMCTL_SENDTRIGGER_VTPING 7 > struct xen_domctl_sendtrigger { > uint32_t trigger; /* IN */ > uint32_t vcpu; /* IN */
On 12/12/2013 19:15, Don Slutz wrote:> From: Don Slutz <dslutz@verizon.com> > > Signed-off-by: Don Slutz <dslutz@verizon.com> > --- > tools/libxc/xc_domain.c | 112 ++++++++++++++++++++++++++++++ > tools/libxc/xenctrl.h | 24 +++++++ > xen/arch/x86/hvm/hvm.c | 148 ++++++++++++++++++++++++++++++++++++++++ > xen/include/public/hvm/hvm_op.h | 18 +++++ > 4 files changed, 302 insertions(+) > > diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c > index 1ccafc5..0437c6f 100644 > --- a/tools/libxc/xc_domain.c > +++ b/tools/libxc/xc_domain.c > @@ -1246,6 +1246,118 @@ int xc_get_hvm_param(xc_interface *handle, domid_t dom, int param, unsigned long > return rc; > } > > +int xc_set_vmport_guest_info(xc_interface *handle, > + domid_t dom, > + unsigned int key_len, > + char *key, > + unsigned int val_len, > + char *val) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_vmport_guest_info_t, arg); > + int rc; > + > + if ((key_len < 1) || > + (key_len > VMPORT_GUEST_INFO_KEY_MAX) || > + (val_len > VMPORT_GUEST_INFO_VAL_MAX)) { > + return -1; > + } > + > + arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg)); > + if ( arg == NULL ) > + return -1; > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_set_vmport_guest_info; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = dom; > + arg->key_length = key_len; > + arg->value_length = val_len; > + memcpy(arg->data, key, key_len); > + memcpy(&arg->data[key_len], val, val_len); > + rc = do_xen_hypercall(handle, &hypercall); > + xc_hypercall_buffer_free(handle, arg); > + return rc; > +} > + > +int xc_get_vmport_guest_info(xc_interface *handle, > + domid_t dom, > + unsigned int key_len, > + char *key, > + unsigned int val_max, > + unsigned int *val_len, > + char *val) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_vmport_guest_info_t, arg); > + int rc; > + > + if ((key_len < 1) || > + (key_len > VMPORT_GUEST_INFO_KEY_MAX) ) > + return -1; > + > + arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg)); > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_get_vmport_guest_info; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = dom; > + arg->key_length = key_len; > + arg->value_length = 0; > + *val_len = 0; > + memcpy(arg->data, key, key_len); > + rc = do_xen_hypercall(handle, &hypercall); > + if (rc == 0) { > + if (arg->value_length > val_max) > + arg->value_length = val_max; > + *val_len = arg->value_length; > + memcpy(val, &arg->data[key_len], arg->value_length); > + } > + xc_hypercall_buffer_free(handle, arg); > + return rc; > +} > + > +int xc_fetch_vmport_guest_info(xc_interface *handle, > + domid_t dom, > + unsigned int idx, > + unsigned int key_max, > + unsigned int *key_len, > + char *key, > + unsigned int val_max, > + unsigned int *val_len, > + char *val) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_vmport_guest_info_t, arg); > + int rc; > + > + arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg)); > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_get_vmport_guest_info; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = dom; > + arg->key_length = 0; > + arg->value_length = idx; > + *key_len = 0; > + *val_len = 0; > + rc = do_xen_hypercall(handle, &hypercall); > + if (rc == 0) { > + if (arg->key_length > key_max) > + arg->key_length = key_max; > + *key_len = arg->key_length; > + memcpy(key, arg->data, arg->key_length); > + if (arg->value_length > val_max) > + arg->value_length = val_max; > + *val_len = arg->value_length; > + memcpy(val, > + &arg->data[arg->key_length], > + arg->value_length); > + } > + xc_hypercall_buffer_free(handle, arg); > + return rc; > +} > + > int xc_domain_setdebugging(xc_interface *xch, > uint32_t domid, > unsigned int enable) > diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h > index 6e58ebe..6b22b3b 100644 > --- a/tools/libxc/xenctrl.h > +++ b/tools/libxc/xenctrl.h > @@ -1774,6 +1774,30 @@ void xc_clear_last_error(xc_interface *xch); > int xc_set_hvm_param(xc_interface *handle, domid_t dom, int param, unsigned long value); > int xc_get_hvm_param(xc_interface *handle, domid_t dom, int param, unsigned long *value); > > +int xc_set_vmport_guest_info(xc_interface *handle, > + domid_t dom, > + unsigned int key_len, > + char *key, > + unsigned int val_len, > + char *val); > +int xc_get_vmport_guest_info(xc_interface *handle, > + domid_t dom, > + unsigned int key_len, > + char *key, > + unsigned int val_max, > + unsigned int *val_len, > + char *val); > +int xc_fetch_vmport_guest_info(xc_interface *handle, > + domid_t dom, > + unsigned int idx, > + unsigned int key_max, > + unsigned int *key_len, > + char *key, > + unsigned int val_max, > + unsigned int *val_len, > + char *val); > + > + > /* HVM guest pass-through */ > int xc_assign_device(xc_interface *xch, > uint32_t domid, > diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c > index a557272..c6f84fc 100644 > --- a/xen/arch/x86/hvm/hvm.c > +++ b/xen/arch/x86/hvm/hvm.c > @@ -4662,6 +4662,154 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) > break; > } > > + case HVMOP_get_vmport_guest_info: > + case HVMOP_set_vmport_guest_info: > + { > + struct xen_hvm_vmport_guest_info a; > + struct domain *d; > + char *key = NULL; > + char *value = NULL; > + struct vmport_state *vs; > + int idx; > + vmport_guestinfo_t *add_slots[5]; > + int num_slots = 0, num_free_slots = 0; > + > + if ( copy_from_guest(&a, arg, 1) ) > + return -EFAULT; > + > + ASSERT(strlen("guestinfo.") == 10);Debugging code?> +#if VMPORT_MAX_KEY_LEN + 10 != VMPORT_GUEST_INFO_KEY_MAX > +#error Need to adjust VMPORT_MAX_KEY_LEN & VMPORT_GUEST_INFO_KEY_MAX > +#endif > +#if VMPORT_MAX_VAL_LEN != VMPORT_GUEST_INFO_VAL_MAX > +#error Need to adjust VMPORT_MAX_VAL_LEN & VMPORT_GUEST_INFO_VAL_MAX > +#endif > + if ( a.key_length > strlen("guestinfo.") ) {Xen braces style.> + if ( (unsigned long)a.key_length + (unsigned long)a.value_length > sizeof(a.data) ) > + return -EINVAL; > + if ( memcmp(a.data, "guestinfo.", strlen("guestinfo.")) == 0 ) { > + key = &a.data[strlen("guestinfo.")]; > + a.key_length -= strlen("guestinfo."); > + } else { > + key = &a.data[0]; > + } > + value = key + a.key_length; > + } else if (a.key_length > 0) { > + if ( (unsigned long)a.key_length + (unsigned long)a.value_length > sizeof(a.data) ) > + return -EINVAL; > + key = &a.data[0]; > + if ( a.key_length > VMPORT_MAX_KEY_LEN ) > + return -EINVAL; > + if ( a.value_length > VMPORT_MAX_VAL_LEN ) > + return -EINVAL; > + value = key + a.key_length; > + } else if ( (a.key_length == 0) && (op == HVMOP_set_vmport_guest_info) ) { > + return -EINVAL; > + } > + d = rcu_lock_domain_by_any_id(a.domid); > + if ( d == NULL ) > + return rc; > + > + rc = -EINVAL; > + if ( !is_hvm_domain(d) ) > + goto param_fail9; > + > + rc = xsm_hvm_param(XSM_TARGET, d, op); > + if ( rc ) > + goto param_fail9; > + > + vs = d->arch.hvm_domain.vmport_data; > + if ((a.key_length == 0) && (a.value_length >= vs->used_guestinfo)) { > + rc = -E2BIG; > + goto param_fail9; > + } > + for (idx = 0; idx < vs->used_guestinfo; idx++) { > + if (vs->guestinfo[idx] && > + (vs->guestinfo[idx]->key_len == 0)) > + num_free_slots++; > + } > + if (num_free_slots < 5) { > + num_slots = 5 - num_free_slots; > + if (vs->used_guestinfo + num_slots > VMPORT_MAX_NUM_KEY) > + num_slots = VMPORT_MAX_NUM_KEY - vs->used_guestinfo; > + for (idx = 0; idx < num_slots; idx++) > + add_slots[idx] = xzalloc(vmport_guestinfo_t); > + } > + > + spin_lock(&d->arch.hvm_domain.vmport_lock); > + > + for (idx = 0; idx < num_slots; idx++) > + vs->guestinfo[vs->used_guestinfo + idx] = add_slots[idx]; > + vs->used_guestinfo += num_slots; > + > + if ( op == HVMOP_set_vmport_guest_info ) > + { > + int free_idx = -1; > + > + for (idx = 0; idx < vs->used_guestinfo; idx++) { > + if (!vs->guestinfo[idx]) { > + gdprintk(XENLOG_WARNING, "idx=%d not allocated, but used_guestinfo=%d\n", > + idx, vs->used_guestinfo); > + } else if ((vs->guestinfo[idx]->key_len == a.key_length) && > + (memcmp(key, > + vs->guestinfo[idx]->key_data, > + vs->guestinfo[idx]->key_len) == 0)) { > + vs->guestinfo[idx]->val_len = a.value_length; > + memcpy(vs->guestinfo[idx]->val_data, value, a.value_length); > + break;This break will skip the spin_unlock() on the vmport_lock, as will most of the others by the looks of the code.> + } else if ((vs->guestinfo[idx]->key_len == 0) && > + (free_idx == -1)) { > + free_idx = idx; > + } > + } > + if (idx >= vs->used_guestinfo) { > + if (free_idx == -1) { > + rc = -EBUSY; > + } else { > + vs->guestinfo[free_idx]->key_len = a.key_length; > + memcpy(vs->guestinfo[free_idx]->key_data, key, a.key_length); > + vs->guestinfo[free_idx]->val_len = a.value_length; > + memcpy(vs->guestinfo[free_idx]->val_data, value, a.value_length); > + } > + } > + } > + else > + { > + if (a.key_length == 0) { > + idx = a.value_length; > + a.key_length = vs->guestinfo[idx]->key_len; > + memcpy(a.data, vs->guestinfo[idx]->key_data, a.key_length); > + a.value_length = vs->guestinfo[idx]->val_len; > + memcpy(&a.data[a.key_length], > + vs->guestinfo[idx]->val_data, > + a.value_length); > + rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0; > + } else { > + for (idx = 0; idx < vs->used_guestinfo; idx++) { > + if ((vs->guestinfo[idx]->key_len == a.key_length) && > + (memcmp(key, > + vs->guestinfo[idx]->key_data, > + vs->guestinfo[idx]->key_len) == 0)) { > + a.value_length = vs->guestinfo[idx]->val_len; > + memcpy(value, > + vs->guestinfo[idx]->val_data, > + a.value_length); > + rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0; > + break; > + } > + } > + if (idx >= vs->used_guestinfo) { > + rc = -ENOENT; > + } > + } > + } > + spin_unlock(&d->arch.hvm_domain.vmport_lock); > + > + param_fail9: > + rcu_unlock_domain(d); > + break; > + } > + > default: > { > gdprintk(XENLOG_DEBUG, "Bad HVM op %ld.\n", op); > diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h > index a9aab4b..a530903 100644 > --- a/xen/include/public/hvm/hvm_op.h > +++ b/xen/include/public/hvm/hvm_op.h > @@ -272,4 +272,22 @@ DEFINE_XEN_GUEST_HANDLE(xen_hvm_inject_msi_t); > > #endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ > > +/* Get/set vmport subcommands */ > +#define HVMOP_get_vmport_guest_info 17 > +#define HVMOP_set_vmport_guest_info 18These probably want to be domctl hypercalls not HVMOPs> +#define VMPORT_GUEST_INFO_KEY_MAX 40 > +#define VMPORT_GUEST_INFO_VAL_MAX 128 > +struct xen_hvm_vmport_guest_info { > + /* Domain to be accessed */ > + domid_t domid; > + /* key length */ > + uint16_t key_length; > + /* value length */ > + uint16_t value_length; > + /* key and value data */ > + char data[VMPORT_GUEST_INFO_KEY_MAX + VMPORT_GUEST_INFO_VAL_MAX];This wants to be a GUEST_HANDLE ~Andrew> +}; > +typedef struct xen_hvm_vmport_guest_info xen_hvm_vmport_guest_info_t; > +DEFINE_XEN_GUEST_HANDLE(xen_hvm_vmport_guest_info_t); > + > #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */
On Fri, Dec 13, 2013 at 8:15 AM, Don Slutz <dslutz@verizon.com> wrote:> From: Don Slutz <dslutz@verizon.com> > > Signed-off-by: Don Slutz <dslutz@verizon.com> > --- > tools/libxc/xc_domain.c | 112 ++++++++++++++++++++++++++++++ > tools/libxc/xenctrl.h | 24 +++++++ > xen/arch/x86/hvm/hvm.c | 148 ++++++++++++++++++++++++++++++++++++++++ > xen/include/public/hvm/hvm_op.h | 18 +++++ > 4 files changed, 302 insertions(+) > > diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c > index 1ccafc5..0437c6f 100644 > --- a/tools/libxc/xc_domain.c > +++ b/tools/libxc/xc_domain.c > @@ -1246,6 +1246,118 @@ int xc_get_hvm_param(xc_interface *handle, domid_t dom, int param, unsigned long > return rc; > } > > +int xc_set_vmport_guest_info(xc_interface *handle, > + domid_t dom, > + unsigned int key_len, > + char *key, > + unsigned int val_len, > + char *val) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_vmport_guest_info_t, arg); > + int rc; > + > + if ((key_len < 1) || > + (key_len > VMPORT_GUEST_INFO_KEY_MAX) || > + (val_len > VMPORT_GUEST_INFO_VAL_MAX)) { > + return -1; > + } > + > + arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg)); > + if ( arg == NULL ) > + return -1; > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_set_vmport_guest_info; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = dom; > + arg->key_length = key_len; > + arg->value_length = val_len; > + memcpy(arg->data, key, key_len); > + memcpy(&arg->data[key_len], val, val_len); > + rc = do_xen_hypercall(handle, &hypercall); > + xc_hypercall_buffer_free(handle, arg); > + return rc; > +} > + > +int xc_get_vmport_guest_info(xc_interface *handle, > + domid_t dom, > + unsigned int key_len, > + char *key, > + unsigned int val_max, > + unsigned int *val_len, > + char *val) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_vmport_guest_info_t, arg); > + int rc; > + > + if ((key_len < 1) || > + (key_len > VMPORT_GUEST_INFO_KEY_MAX) ) > + return -1; > + > + arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg)); > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_get_vmport_guest_info; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = dom; > + arg->key_length = key_len; > + arg->value_length = 0; > + *val_len = 0; > + memcpy(arg->data, key, key_len); > + rc = do_xen_hypercall(handle, &hypercall); > + if (rc == 0) { > + if (arg->value_length > val_max) > + arg->value_length = val_max; > + *val_len = arg->value_length; > + memcpy(val, &arg->data[key_len], arg->value_length); > + } > + xc_hypercall_buffer_free(handle, arg); > + return rc; > +} > + > +int xc_fetch_vmport_guest_info(xc_interface *handle, > + domid_t dom, > + unsigned int idx, > + unsigned int key_max, > + unsigned int *key_len, > + char *key, > + unsigned int val_max, > + unsigned int *val_len, > + char *val) > +{ > + DECLARE_HYPERCALL; > + DECLARE_HYPERCALL_BUFFER(xen_hvm_vmport_guest_info_t, arg); > + int rc; > + > + arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg)); > + > + hypercall.op = __HYPERVISOR_hvm_op; > + hypercall.arg[0] = HVMOP_get_vmport_guest_info; > + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg); > + arg->domid = dom; > + arg->key_length = 0; > + arg->value_length = idx; > + *key_len = 0; > + *val_len = 0; > + rc = do_xen_hypercall(handle, &hypercall); > + if (rc == 0) { > + if (arg->key_length > key_max) > + arg->key_length = key_max; > + *key_len = arg->key_length; > + memcpy(key, arg->data, arg->key_length); > + if (arg->value_length > val_max) > + arg->value_length = val_max; > + *val_len = arg->value_length; > + memcpy(val, > + &arg->data[arg->key_length], > + arg->value_length); > + } > + xc_hypercall_buffer_free(handle, arg); > + return rc; > +} > + > int xc_domain_setdebugging(xc_interface *xch, > uint32_t domid, > unsigned int enable) > diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h > index 6e58ebe..6b22b3b 100644 > --- a/tools/libxc/xenctrl.h > +++ b/tools/libxc/xenctrl.h > @@ -1774,6 +1774,30 @@ void xc_clear_last_error(xc_interface *xch); > int xc_set_hvm_param(xc_interface *handle, domid_t dom, int param, unsigned long value); > int xc_get_hvm_param(xc_interface *handle, domid_t dom, int param, unsigned long *value); > > +int xc_set_vmport_guest_info(xc_interface *handle, > + domid_t dom, > + unsigned int key_len, > + char *key, > + unsigned int val_len, > + char *val); > +int xc_get_vmport_guest_info(xc_interface *handle, > + domid_t dom, > + unsigned int key_len, > + char *key, > + unsigned int val_max, > + unsigned int *val_len, > + char *val); > +int xc_fetch_vmport_guest_info(xc_interface *handle, > + domid_t dom, > + unsigned int idx, > + unsigned int key_max, > + unsigned int *key_len, > + char *key, > + unsigned int val_max, > + unsigned int *val_len, > + char *val); > + > + > /* HVM guest pass-through */ > int xc_assign_device(xc_interface *xch, > uint32_t domid, > diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c > index a557272..c6f84fc 100644 > --- a/xen/arch/x86/hvm/hvm.c > +++ b/xen/arch/x86/hvm/hvm.c > @@ -4662,6 +4662,154 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) > break; > } > > + case HVMOP_get_vmport_guest_info: > + case HVMOP_set_vmport_guest_info: > + { > + struct xen_hvm_vmport_guest_info a; > + struct domain *d; > + char *key = NULL; > + char *value = NULL; > + struct vmport_state *vs; > + int idx; > + vmport_guestinfo_t *add_slots[5]; > + int num_slots = 0, num_free_slots = 0; > + > + if ( copy_from_guest(&a, arg, 1) ) > + return -EFAULT; > + > + ASSERT(strlen("guestinfo.") == 10); > +#if VMPORT_MAX_KEY_LEN + 10 != VMPORT_GUEST_INFO_KEY_MAX > +#error Need to adjust VMPORT_MAX_KEY_LEN & VMPORT_GUEST_INFO_KEY_MAX > +#endif > +#if VMPORT_MAX_VAL_LEN != VMPORT_GUEST_INFO_VAL_MAX > +#error Need to adjust VMPORT_MAX_VAL_LEN & VMPORT_GUEST_INFO_VAL_MAX > +#endifI don''t think I quite understand the need for the VMPORT_MAX_{KEY,VAL}_LEN macros as well as the VMPORT_GUEST_INFO_{KEY,VAL}_MAX ones. IIUC VMPORT_MAX_{KEY,VAL}_LEN is used for sizing the guestinfo data buffer on the Xen side, but VMPORT_GUEST_INFO_{KEY,VAL}_MAX is used for the public subop hypercall interface. Is there a need for the "guestinfo." key prefix chopping? This is being done in this new hypercall subop implemented by Xen, so shouldn''t there be no existing callers expecting this behaviour, allowing it to be dropped?> + if ( a.key_length > strlen("guestinfo.") ) { > + if ( (unsigned long)a.key_length + (unsigned long)a.value_length > sizeof(a.data) )Are the casts necessary? It looks like you''re trying to avoid overflow, but {key,value}_length are uint16''s, which will be automatically promoted to ints.> + return -EINVAL; > + if ( memcmp(a.data, "guestinfo.", strlen("guestinfo.")) == 0 ) { > + key = &a.data[strlen("guestinfo.")]; > + a.key_length -= strlen("guestinfo."); > + } else { > + key = &a.data[0]; > + } > + value = key + a.key_length; > + } else if (a.key_length > 0) { > + if ( (unsigned long)a.key_length + (unsigned long)a.value_length > sizeof(a.data) ) > + return -EINVAL; > + key = &a.data[0]; > + if ( a.key_length > VMPORT_MAX_KEY_LEN ) > + return -EINVAL; > + if ( a.value_length > VMPORT_MAX_VAL_LEN ) > + return -EINVAL;You don''t check these two maximum lengths in the a.key_length > strlen("guestinfo.") case, where one could still provide a large key and tiny value.> + value = key + a.key_length; > + } else if ( (a.key_length == 0) && (op == HVMOP_set_vmport_guest_info) ) {I wouldn''t bother checking for a.key_length == 0 explicitly here, it''s implied at this point. In addition, the check on op should be a whitelist (op != ...), not a blacklist (op == ...).> + return -EINVAL; > + }Perhaps these three cases can be shuffled around a bit. By making the a.key_length > strlen("guestinfo.") check also include the memcmp(), the two cases then become "key *is* prefixed with guestinfo." and "key is not prefixed with guestinfo." instead of the current setup, which has "key *could* be prefixed with guestinfo." and "key is not prefixed with guestinfo.". This allows factoring out the "is not prefixed with guestinfo." part into a single case. Before all this, the common length checks can be done. Something like this: if ( (op != HVMOP_get_vmport_guest_info && !a.key_length) || a.key_length > VMPORT_MAX_KEY_LEN || a.value_length > VMPORT_MAX_VAL_LEN ) return -EINVAL; key = a.data; if ( a.key_length > strlen("guestinfo.") && memcmp(a.data, "guestinfo.", strlen("guestinfo.") == 0 ) { key += strlen("guestinfo."); a.key_length -= strlen("guestinfo."); } value = key + a.key_length;> + d = rcu_lock_domain_by_any_id(a.domid); > + if ( d == NULL ) > + return rc; > + > + rc = -EINVAL; > + if ( !is_hvm_domain(d) ) > + goto param_fail9; > + > + rc = xsm_hvm_param(XSM_TARGET, d, op); > + if ( rc ) > + goto param_fail9; > + > + vs = d->arch.hvm_domain.vmport_data; > + if ((a.key_length == 0) && (a.value_length >= vs->used_guestinfo)) { > + rc = -E2BIG; > + goto param_fail9; > + } > + for (idx = 0; idx < vs->used_guestinfo; idx++) { > + if (vs->guestinfo[idx] && > + (vs->guestinfo[idx]->key_len == 0)) > + num_free_slots++; > + } > + if (num_free_slots < 5) { > + num_slots = 5 - num_free_slots; > + if (vs->used_guestinfo + num_slots > VMPORT_MAX_NUM_KEY) > + num_slots = VMPORT_MAX_NUM_KEY - vs->used_guestinfo; > + for (idx = 0; idx < num_slots; idx++) > + add_slots[idx] = xzalloc(vmport_guestinfo_t); > + }Is it really worth the extra complexity to maintain allocated but unused guestinfos? Can''t they just be allocated on demand and freed when unneeded? Speaking of which, is there a way to delete (and not just empty out) a guestinfo? If not, would it be a good thing to have?> + > + spin_lock(&d->arch.hvm_domain.vmport_lock); > + > + for (idx = 0; idx < num_slots; idx++) > + vs->guestinfo[vs->used_guestinfo + idx] = add_slots[idx]; > + vs->used_guestinfo += num_slots; > + > + if ( op == HVMOP_set_vmport_guest_info ) > + { > + int free_idx = -1; > + > + for (idx = 0; idx < vs->used_guestinfo; idx++) { > + if (!vs->guestinfo[idx]) { > + gdprintk(XENLOG_WARNING, "idx=%d not allocated, but used_guestinfo=%d\n", > + idx, vs->used_guestinfo); > + } else if ((vs->guestinfo[idx]->key_len == a.key_length) && > + (memcmp(key, > + vs->guestinfo[idx]->key_data, > + vs->guestinfo[idx]->key_len) == 0)) { > + vs->guestinfo[idx]->val_len = a.value_length; > + memcpy(vs->guestinfo[idx]->val_data, value, a.value_length); > + break; > + } else if ((vs->guestinfo[idx]->key_len == 0) && > + (free_idx == -1)) { > + free_idx = idx; > + } > + } > + if (idx >= vs->used_guestinfo) { > + if (free_idx == -1) { > + rc = -EBUSY; > + } else { > + vs->guestinfo[free_idx]->key_len = a.key_length; > + memcpy(vs->guestinfo[free_idx]->key_data, key, a.key_length); > + vs->guestinfo[free_idx]->val_len = a.value_length; > + memcpy(vs->guestinfo[free_idx]->val_data, value, a.value_length); > + } > + } > + } > + else > + { > + if (a.key_length == 0) {The use of key_length being 0 in a "get" operation confused me here (for example, I thought this was open to bad indexing if value_length was out-of-range, but I see that you check it back up where you return E2BIG). Really, there are three subops being added here; one set and two gets (looking up by key or index). Hence I think it might be a good idea to explicitly define a third subop, say HVMOP_get_by_idx_vmport_guest_info. You could then use a union for the {get,set} subops which have differing arguments to the new get_by_idx subop.> + idx = a.value_length; > + a.key_length = vs->guestinfo[idx]->key_len; > + memcpy(a.data, vs->guestinfo[idx]->key_data, a.key_length); > + a.value_length = vs->guestinfo[idx]->val_len; > + memcpy(&a.data[a.key_length], > + vs->guestinfo[idx]->val_data, > + a.value_length); > + rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0; > + } else { > + for (idx = 0; idx < vs->used_guestinfo; idx++) { > + if ((vs->guestinfo[idx]->key_len == a.key_length) && > + (memcmp(key, > + vs->guestinfo[idx]->key_data, > + vs->guestinfo[idx]->key_len) == 0)) { > + a.value_length = vs->guestinfo[idx]->val_len; > + memcpy(value, > + vs->guestinfo[idx]->val_data, > + a.value_length); > + rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0; > + break; > + } > + } > + if (idx >= vs->used_guestinfo) { > + rc = -ENOENT; > + } > + } > + } > + spin_unlock(&d->arch.hvm_domain.vmport_lock); > + > + param_fail9: > + rcu_unlock_domain(d); > + break; > + } > + > default: > { > gdprintk(XENLOG_DEBUG, "Bad HVM op %ld.\n", op); > diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h > index a9aab4b..a530903 100644 > --- a/xen/include/public/hvm/hvm_op.h > +++ b/xen/include/public/hvm/hvm_op.h > @@ -272,4 +272,22 @@ DEFINE_XEN_GUEST_HANDLE(xen_hvm_inject_msi_t); > > #endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ > > +/* Get/set vmport subcommands */ > +#define HVMOP_get_vmport_guest_info 17 > +#define HVMOP_set_vmport_guest_info 18 > +#define VMPORT_GUEST_INFO_KEY_MAX 40 > +#define VMPORT_GUEST_INFO_VAL_MAX 128 > +struct xen_hvm_vmport_guest_info { > + /* Domain to be accessed */ > + domid_t domid; > + /* key length */ > + uint16_t key_length; > + /* value length */ > + uint16_t value_length; > + /* key and value data */ > + char data[VMPORT_GUEST_INFO_KEY_MAX + VMPORT_GUEST_INFO_VAL_MAX]; > +}; > +typedef struct xen_hvm_vmport_guest_info xen_hvm_vmport_guest_info_t; > +DEFINE_XEN_GUEST_HANDLE(xen_hvm_vmport_guest_info_t); > + > #endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */ > -- > 1.8.4 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
>>> On 12.12.13 at 20:15, Don Slutz <dslutz@verizon.com> wrote: > --- a/xen/include/public/hvm/params.h > +++ b/xen/include/public/hvm/params.h > @@ -145,6 +145,15 @@ > /* SHUTDOWN_* action in case of a triple fault */ > #define HVM_PARAM_TRIPLE_FAULT_REASON 31 > > -#define HVM_NR_PARAMS 32 > +/* Params for VMware */ > +#define HVM_PARAM_VMWARE_HW 32 > +#define HVM_PARAM_VMPORT_LOGMASK 33 > +#define HVM_PARAM_VMPORT_STATUS 34 > +#define HVM_PARAM_VMPORT_BUILD_NUMBER_TIME 35 > +#define HVM_PARAM_VMPORT_BUILD_NUMBER_VALUE 36 > +#define HVM_PARAM_VMPORT_RESET_TIME 37 > + > +#define HVM_NR_PARAMS 38 > + > > #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */Both for reviewing purposes and from a consistency pov this should be in a single patch together with the hypervisor side implementation. Jan
>>> On 12.12.13 at 23:27, Andrew Cooper <andrew.cooper3@citrix.com> wrote: > On 12/12/2013 19:15, Don Slutz wrote: >> int cpuid_hypervisor_leaves( uint32_t idx, uint32_t sub_idx, >> uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) >> { >> struct domain *d = current->domain; >> /* Optionally shift out of the way of Viridian architectural leaves. */ >> - uint32_t base = is_viridian_domain(d) ? 0x40000100 : 0x40000000; >> + uint32_t base = 0x40000000; >> uint32_t limit; >> >> + if ( is_viridian_domain(d) ) >> + base += 0x100; >> + if ( is_vmware_domain(d) ) >> + base += 0x100; >> + > > These bases need a far more scalable solution, especially as the result > of each of these clauses can be changed at runtime with a cunning > hvm_param_set hypercall. > > I think that both "is pretending to be HyperV" and "is pretending to be > VMware" need to be domain creation flags which are strictly static for > the lifetime of the domain.And it seems highly questionable to me whether having both at the same time makes much sense. Plus the new function doesn''t belong in xen/arch/x86/traps.c ... Jan
>>> On 12.12.13 at 20:15, Don Slutz <dslutz@verizon.com> wrote: > From: Don Slutz <dslutz@verizon.com> > > enable vmport_flush call. > > Signed-off-by: Don Slutz <dslutz@verizon.com>Again - please be more verbose. And clean up the coding style before submitting. Jan
On 13/12/2013 10:55, Jan Beulich wrote:>>>> On 12.12.13 at 23:27, Andrew Cooper <andrew.cooper3@citrix.com> wrote: >> On 12/12/2013 19:15, Don Slutz wrote: >>> int cpuid_hypervisor_leaves( uint32_t idx, uint32_t sub_idx, >>> uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) >>> { >>> struct domain *d = current->domain; >>> /* Optionally shift out of the way of Viridian architectural leaves. */ >>> - uint32_t base = is_viridian_domain(d) ? 0x40000100 : 0x40000000; >>> + uint32_t base = 0x40000000; >>> uint32_t limit; >>> >>> + if ( is_viridian_domain(d) ) >>> + base += 0x100; >>> + if ( is_vmware_domain(d) ) >>> + base += 0x100; >>> + >> These bases need a far more scalable solution, especially as the result >> of each of these clauses can be changed at runtime with a cunning >> hvm_param_set hypercall. >> >> I think that both "is pretending to be HyperV" and "is pretending to be >> VMware" need to be domain creation flags which are strictly static for >> the lifetime of the domain. > And it seems highly questionable to me whether having both at the > same time makes much sense. > > Plus the new function doesn''t belong in xen/arch/x86/traps.c ... > > Jan >I would certainly agree on the sentiment of it not making much sense. However, as Xen needs viridian to run windows, I would be astounded if vmware VMs didn''t have viridian as well, in which case it is probably quite likely that a vmware windows vm with vmware tools would expect to find viridian and vmware extensions. ~Andrew
On 12/12/2013 02:15 PM, Don Slutz wrote:> From: Don Slutz <dslutz@verizon.com> > > Signed-off-by: Don Slutz <dslutz@verizon.com> > --- > xen/arch/x86/hvm/io.c | 4 ++ > xen/arch/x86/hvm/svm/svm.c | 104 ++++++++++++++++++++++++++++++++++++ > xen/arch/x86/hvm/svm/vmcb.c | 1 + > xen/arch/x86/hvm/vmx/vmcs.c | 1 + > xen/arch/x86/hvm/vmx/vmx.c | 125 ++++++++++++++++++++++++++++++++++++++++++++ > xen/arch/x86/hvm/vmx/vvmx.c | 13 +++++ > xen/include/public/trace.h | 1 + > 7 files changed, 249 insertions(+) > > diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c > index bf6309d..4bc4716 100644 > --- a/xen/arch/x86/hvm/io.c > +++ b/xen/arch/x86/hvm/io.c > @@ -42,6 +42,7 @@ > #include <asm/hvm/vlapic.h> > #include <asm/hvm/trace.h> > #include <asm/hvm/emulate.h> > +#include <asm/hvm/vmport.h> > #include <public/sched.h> > #include <xen/iocap.h> > #include <public/hvm/ioreq.h> > @@ -236,6 +237,9 @@ int handle_pio(uint16_t port, unsigned int size, int dir) > if ( dir == IOREQ_WRITE ) > data = guest_cpu_user_regs()->eax; > > + if ( port == VMPORT_PORT ) > + return vmport_ioport(dir, size, data, guest_cpu_user_regs()); > + > rc = hvmemul_do_pio(port, &reps, size, 0, dir, 0, &data); > > switch ( rc ) > diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c > index 406d394..80cf2bf 100644 > --- a/xen/arch/x86/hvm/svm/svm.c > +++ b/xen/arch/x86/hvm/svm/svm.c > @@ -56,6 +56,7 @@ > #include <asm/hvm/svm/nestedsvm.h> > #include <asm/hvm/nestedhvm.h> > #include <asm/x86_emulate.h> > +#include <asm/hvm/vmport.h> > #include <public/sched.h> > #include <asm/hvm/vpt.h> > #include <asm/hvm/trace.h> > @@ -1904,6 +1905,105 @@ svm_vmexit_do_vmsave(struct vmcb_struct *vmcb, > return; > } > > +static void svm_vmexit_gp_intercept(struct cpu_user_regs *regs, struct vcpu *v) > +{ > + struct hvm_domain *hd = &v->domain->arch.hvm_domain; > + struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb; > + unsigned long inst_len, bytes_len; > + int frc; > + unsigned char bytes[15]; > + > + regs->error_code = vmcb->exitinfo1; > + if ( !cpu_has_svm_nrips || (vmcb->nextrip <= vmcb->rip) ) > + inst_len = 0; > + else > + inst_len = vmcb->nextrip - vmcb->rip;You can use svm_nextrip_insn_length(), with some adjustments to NDEBUG case there.> + bytes_len = 2 /* inst_len < 15 ? inst_len > 1 ? inst_len : 2 : 15 */;Saying this in words would be preferable --- I am not sure I understand why it''s 2. Do you only expect specific instructions here? Or are you only interested in the first two bytes of the opcode?> + frc = hvm_fetch_from_guest_virt_nofault(bytes, regs->eip, > + bytes_len, > + PFEC_page_present); > + > + if ( hvm_long_mode_enabled(v) ) > + HVMTRACE_LONG_4D(TRAP, TRAP_gp_fault, inst_len, > + regs->error_code, > + TRC_PAR_LONG(vmcb->exitinfo2) ); > + else > + HVMTRACE_4D(TRAP, TRAP_gp_fault, inst_len, > + regs->error_code, vmcb->exitinfo2 ); > + > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x400000 /* LOG_GP_FAIL_RD_INST */) > + printk("[HVM:%d.%d] <%s> " > + "gp: e2=%lx ec=%lx ip=%lx=>0x%x 0x%x(%ld,%ld,%d) nip(%d)=%lx(%d,%d(0x%x) 0x%x 0x%x)" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)vmcb->exitinfo2, > + (unsigned long)regs->error_code, > + (unsigned long)regs->eip, (unsigned int)bytes[0], > + (unsigned int)bytes[1], bytes_len, inst_len, frc, > + cpu_has_svm_nrips, (unsigned long)vmcb->nextrip, > + cpu_has_svm_decode, vmcb->guest_ins_len & 0xf, vmcb->guest_ins_len, > + vmcb->guest_ins[0], vmcb->guest_ins[1]); > + > + if ( !frc && bytes[0] == 0xed && (regs->edx & 0xffff) == VMPORT_PORT && > + vmcb->exitinfo2 == 0 && regs->error_code == 0 ) > + { > + /* in (%dx),%eax */ > + uint32_t magic = regs->eax; > + > + if ( magic == VMPORT_MAGIC ) { > + __update_guest_eip(regs, 1); > + vmport_ioport(IOREQ_READ, 4, 0, regs); > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x800000 /* LOG_GP_VMWARE_AFTER */) > + printk("[HVM:%d.%d] <%s> " > + "gp: VMware ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)regs->eip, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + return; > + } else { > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x200000 /* LOG_GP_NOT_VMWARE */) > + printk("[HVM:%d.%d] <%s> " > + "gp: ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)regs->eip, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code); > + } > + } else if (!frc && regs->error_code == 0 > + && bytes[0] == 0x0f && bytes[1] == 0x33 && regs->ecx == 0x10000) > + { > + /* "rdpmc 0x10000" */ > + /* Not a very good emulation! But just not faulting is good enough > + * to get NetApp booting. */ > + regs->edx = regs->eax = 0; > + > + __update_guest_eip(regs, inst_len);What if inst_len is zero? (e.g. if NRIP is not supported?) -boris> + > + /* Doing the log in this case was too noisy for NetApp, so I moved > + * it to ''else'' */ > + } else { > + if (hd->params[HVM_PARAM_VMPORT_LOGMASK] & 0x100000 /* LOG_GP_UNKNOWN */) { > + printk("[HVM:%d.%d] <%s> " > + "gp: e2=%lx ec=%lx ip=%lx=>0x%x 0x%x(%ld,%d) ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx" > + "\n", > + current->domain->domain_id, current->vcpu_id, __func__, > + (unsigned long)vmcb->exitinfo2, (unsigned long)regs->error_code, > + (unsigned long)regs->eip, (unsigned int)bytes[0], > + (unsigned int)bytes[1], inst_len, frc, > + (unsigned long)regs->eax, (unsigned long)regs->ebx, > + (unsigned long)regs->ecx, (unsigned long)regs->edx, > + (unsigned long)regs->esi, (unsigned long)regs->edi); > + } > + hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code); > + } > +} > + >
Don Slutz
2013-Dec-13 18:03 UTC
Re: [RFC PATCH 01/10] smbios: Add "plus VMware-Tools" to HVM_XS_SYSTEM_PRODUCT_NAME.
On 12/12/13 17:07, Andrew Cooper wrote:> On 12/12/2013 19:35, Olaf Hering wrote: >> On Thu, Dec 12, Don Slutz wrote: >> >>> - s = xenstore_read(HVM_XS_SYSTEM_PRODUCT_NAME, "HVM domU"); >>> + s = xenstore_read(HVM_XS_SYSTEM_PRODUCT_NAME, "HVM domU plus VMware-Tools"); >> This will break other code which checks for the current string. >> (/sys/class/dmi/id/product_name) >> >> OlafThat is true, however since this is a xenstore_read, this is the default value. I do not know of any code that checks for just "HVM domU", and it would break on any system that uses xenstore to change this to something else.> Furthermore, the whole point of this is so the toolstack can write the > xenstore key > > /local/domain/$DOMID/bios-strings/system-product-name > > with a custom value which will be written into the SMBios table.True. The default tool stack (xl) does not change this, and so I was looking into a simple way to let xl users enable this. I can add a xenstore_read of "platform/vmware_hw", "0" (set in patch #4) to make it conditional. This is some what optional in that VMware''s stated way of using this is only after CPUID fails.> The toolstack itself should have a big "pretend to be vmware" flag for a > domain.And Verizon''s does and so we do not need this change. Maybe I should have just added this to some documentation. -Don Slutz> ~Andrew
On 12/12/13 17:32, Andrew Cooper wrote:> On 12/12/2013 19:15, Don Slutz wrote: >> From: Don Slutz <dslutz@verizon.com> >> >> Signed-off-by: Don Slutz <dslutz@verizon.com> >> --- >> xen/include/public/hvm/params.h | 11 ++++++++++- >> 1 file changed, 10 insertions(+), 1 deletion(-) >> >> diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h >> index 517a184..c571a1e 100644 >> --- a/xen/include/public/hvm/params.h >> +++ b/xen/include/public/hvm/params.h >> @@ -145,6 +145,15 @@ >> /* SHUTDOWN_* action in case of a triple fault */ >> #define HVM_PARAM_TRIPLE_FAULT_REASON 31 >> >> -#define HVM_NR_PARAMS 32 >> +/* Params for VMware */ >> +#define HVM_PARAM_VMWARE_HW 32 >> +#define HVM_PARAM_VMPORT_LOGMASK 33 >> +#define HVM_PARAM_VMPORT_STATUS 34 >> +#define HVM_PARAM_VMPORT_BUILD_NUMBER_TIME 35 >> +#define HVM_PARAM_VMPORT_BUILD_NUMBER_VALUE 36 >> +#define HVM_PARAM_VMPORT_RESET_TIME 37 >> + >> +#define HVM_NR_PARAMS 38 >> + >> >> #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */ > STATUS at the very least sounds like it should be read-only from domains?It does not need to be. It is only written to, never read by the code. So far I have only used it as a check (debugging help) while doing manual testing, and a simple program that just outputs the hex value was what I used. At this point, it and the code to modify it could be removed. -Don> > You might want/need some extra logic in do_hvm_op(). > > ~Andrew > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
On 12/13/13 05:52, Jan Beulich wrote:>>>> On 12.12.13 at 20:15, Don Slutz <dslutz@verizon.com> wrote: >> --- a/xen/include/public/hvm/params.h >> +++ b/xen/include/public/hvm/params.h >> @@ -145,6 +145,15 @@ >> /* SHUTDOWN_* action in case of a triple fault */ >> #define HVM_PARAM_TRIPLE_FAULT_REASON 31 >> >> -#define HVM_NR_PARAMS 32 >> +/* Params for VMware */ >> +#define HVM_PARAM_VMWARE_HW 32 >> +#define HVM_PARAM_VMPORT_LOGMASK 33 >> +#define HVM_PARAM_VMPORT_STATUS 34 >> +#define HVM_PARAM_VMPORT_BUILD_NUMBER_TIME 35 >> +#define HVM_PARAM_VMPORT_BUILD_NUMBER_VALUE 36 >> +#define HVM_PARAM_VMPORT_RESET_TIME 37 >> + >> +#define HVM_NR_PARAMS 38 >> + >> >> #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */ > Both for reviewing purposes and from a consistency pov this > should be in a single patch together with the hypervisor side > implementation.Thanks, I will move it there. Still learning the "split a change into set of patches". -Don Slutz> Jan >
On 12/13/13 08:38, Andrew Cooper wrote:> On 13/12/2013 10:55, Jan Beulich wrote: >>>>> On 12.12.13 at 23:27, Andrew Cooper <andrew.cooper3@citrix.com> wrote: >>> On 12/12/2013 19:15, Don Slutz wrote: >>>> int cpuid_hypervisor_leaves( uint32_t idx, uint32_t sub_idx, >>>> uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) >>>> { >>>> struct domain *d = current->domain; >>>> /* Optionally shift out of the way of Viridian architectural leaves. */ >>>> - uint32_t base = is_viridian_domain(d) ? 0x40000100 : 0x40000000; >>>> + uint32_t base = 0x40000000; >>>> uint32_t limit; >>>> >>>> + if ( is_viridian_domain(d) ) >>>> + base += 0x100; >>>> + if ( is_vmware_domain(d) ) >>>> + base += 0x100; >>>> +As a related question: Should I reply to each e-mail, or is the reply at the thread place (like here) ok?>>> These bases need a far more scalable solution, especially as the result >>> of each of these clauses can be changed at runtime with a cunning >>> hvm_param_set hypercall.I see. Did not think about HVM_PARAM_VIRIDIAN changing and the effect it has on all the related code. I just saw what was there for viridian and tried to add vmware support the same way. I will look into a patch that will make the bases more scalable, not run time changeable. I see that right now you can get the code to do strange (and maybe bad) things by changing HVM_PARAM_VIRIDIAN. So this patch (or patches) would make is_viridian_domain() an unchangable result. Same for is_vmware_domain() when I add it.>>> I think that both "is pretending to be HyperV" and "is pretending to be >>> VMware" need to be domain creation flags which are strictly static for >>> the lifetime of the domain.I agree with this.>> And it seems highly questionable to me whether having both at the >> same time makes much sense. >> >> Plus the new function doesn''t belong in xen/arch/x86/traps.c ...I read this as "Change to some sort of data structure to get the answer instead of a function". This is because I do not see how to return the correct data from a function if it is not in xen/arch/x86/traps.c (like cpuid_hypervisor_leaves is) or called from there, which I would see as more confusing.>> Jan >> > I would certainly agree on the sentiment of it not making much sense. > > However, as Xen needs viridian to run windows, I would be astounded if > vmware VMs didn''t have viridian as well, in which case it is probably > quite likely that a vmware windows vm with vmware tools would expect to > find viridian and vmware extensions.I also find it strange, but could not see a reason not to try and support it. This could be related to VMware stating that using CPUID is not 100% the way to find out you are running on VMware. -Don Slutz> ~Andrew
Don Slutz
2013-Dec-13 23:23 UTC
Re: [RFC PATCH 04/10] tools: Add support for new HVM params
On 12/12/13 17:36, Andrew Cooper wrote:> On 12/12/2013 19:15, Don Slutz wrote: >> From: Don Slutz <dslutz@verizon.com>[snip]>> >> diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl >> index 649ce50..71ba64e 100644 >> --- a/tools/libxl/libxl_types.idl >> +++ b/tools/libxl/libxl_types.idl >> @@ -346,6 +346,8 @@ libxl_domain_build_info = Struct("domain_build_info",[ >> ("timeoffset", string), >> ("hpet", libxl_defbool), >> ("vpt_align", libxl_defbool), >> + ("vmware_hw", integer), >> + ("vmport_logmask", integer), > "integer" in the IDL is 24 bit is it not? I would suggest uint64 to > match the param width. >Will do.>> ("timer_mode", libxl_timer_mode), >> ("nested_hvm", libxl_defbool), >> ("smbios_firmware", string), >> diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c >> index bd26bcc..013066d 100644 >> --- a/tools/libxl/xl_cmdimpl.c >> +++ b/tools/libxl/xl_cmdimpl.c >> @@ -987,6 +987,16 @@ static void parse_config_data(const char *config_source, >> xlu_cfg_get_defbool(config, "acpi_s4", &b_info->u.hvm.acpi_s4, 0); >> xlu_cfg_get_defbool(config, "nx", &b_info->u.hvm.nx, 0); >> xlu_cfg_get_defbool(config, "viridian", &b_info->u.hvm.viridian, 0); >> + if (!xlu_cfg_get_long(config, "vmware_hw", &l, 1)) { >> + b_info->u.hvm.vmware_hw = l; >> + if (dom_info->debug) >> + fprintf(stderr, "vmware_hw: 0x%llx\n", (unsigned long long) b_info->u.hvm.vmware_hw); > PRIx64 and no cast please.Also will do.>> + } >> + if (!xlu_cfg_get_long(config, "vmport_logmask", &l, 1)) { >> + b_info->u.hvm.vmport_logmask = l; >> + if (dom_info->debug) >> + fprintf(stderr, "vmport_logmask: 0x%llx\n", (unsigned long long) b_info->u.hvm.vmport_logmask); >> + } >> xlu_cfg_get_defbool(config, "hpet", &b_info->u.hvm.hpet, 0); >> xlu_cfg_get_defbool(config, "vpt_align", &b_info->u.hvm.vpt_align, 0); >> >> diff --git a/tools/libxl/xl_sxp.c b/tools/libxl/xl_sxp.c >> index a16a025..9010c42 100644 >> --- a/tools/libxl/xl_sxp.c >> +++ b/tools/libxl/xl_sxp.c > The sxp is strictly for xm compatibility. New features should not > extend it.Ok, will drop this file change.>> @@ -102,6 +102,10 @@ void printf_info_sexp(int domid, libxl_domain_config *d_config) >> printf("\t\t\t(nx %s)\n", libxl_defbool_to_string(b_info->u.hvm.nx)); >> printf("\t\t\t(viridian %s)\n", >> libxl_defbool_to_string(b_info->u.hvm.viridian)); >> + printf("\t\t\t(vmware_hw %d)\n", >> + b_info->u.hvm.vmware_hw); >> + printf("\t\t\t(vmport_logmask %x)\n", >> + b_info->u.hvm.vmport_logmask); >> printf("\t\t\t(hpet %s)\n", >> libxl_defbool_to_string(b_info->u.hvm.hpet)); >> printf("\t\t\t(vpt_align %s)\n", >> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c >> index 6a7a781..38641c4 100644 >> --- a/xen/arch/x86/hvm/hvm.c >> +++ b/xen/arch/x86/hvm/hvm.c >> @@ -589,6 +589,7 @@ int hvm_domain_initialise(struct domain *d) >> >> d->arch.hvm_domain.params[HVM_PARAM_HPET_ENABLED] = 1; >> d->arch.hvm_domain.params[HVM_PARAM_TRIPLE_FAULT_REASON] = SHUTDOWN_reboot; >> + d->arch.hvm_domain.params[HVM_PARAM_VMPORT_RESET_TIME] = 15; >> >> vpic_init(d); >> > This should probably be part of the patch which introduced the params. > > ~AndrewYes, patch #2 and #4 will be combined. -Don Slutz
>>> On 13.12.13 at 19:55, Don Slutz <dslutz@verizon.com> wrote: > On 12/13/13 08:38, Andrew Cooper wrote: >> On 13/12/2013 10:55, Jan Beulich wrote: >>>>>> On 12.12.13 at 23:27, Andrew Cooper <andrew.cooper3@citrix.com> wrote: >>>> On 12/12/2013 19:15, Don Slutz wrote: >>>>> + if ( is_viridian_domain(d) ) >>>>> + base += 0x100; >>>>> + if ( is_vmware_domain(d) ) >>>>> + base += 0x100; >>>>> + > As a related question: Should I reply to each e-mail, or is the reply at the > thread place (like here) ok?Generally per-mail answers are preferred, as that makes the context more obvious. Occasionally you''ll find that overall effect is better if you reply to multiple levels of contexts at once. But please, for legibility''s sake, include blank lines between quoted text and your responses.>>> And it seems highly questionable to me whether having both at the >>> same time makes much sense. >>> >>> Plus the new function doesn''t belong in xen/arch/x86/traps.c ... > I read this as "Change to some sort of data structure to get the answer > instead of a function". This is because I do not see how to return the > correct data from a function if it is not in xen/arch/x86/traps.c (like > cpuid_hypervisor_leaves is) or called from there, which I would see as more > confusing.Just like cpuid_viridian_leaves() lives in xen/arch/x86/hvm/viridian.c, your new function should live in e.g. xen/arch/x86/hvm/vmware.c. Jan