[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v12 5/8] xen: Add vmware_port support
From: Don Slutz <dslutz@xxxxxxxxxxx> This includes adding is_vmware_port_enabled This is a new xen_arch_domainconfig flag, XEN_DOMCTL_CONFIG_VMWARE_PORT_MASK. This enables limited support of VMware's hyper-call. This is both a more complete support then in currently provided by QEMU and/or KVM and less. The missing part requires QEMU changes and has been left out until the QEMU patches are accepted upstream. VMware's hyper-call is also known as VMware Backdoor I/O Port. Note: this support does not depend on vmware_hw being non-zero. Summary is that VMware treats "in (%dx),%eax" (or "out %eax,(%dx)") to port 0x5658 specially. Note: since many operations return data in EAX, "in (%dx),%eax" is the one to use. The other lengths like "in (%dx),%al" will still do things, only AL part of EAX will be changed. For "out %eax,(%dx)" of all lengths, EAX will remain unchanged. An open source example of using this is: http://open-vm-tools.sourceforge.net/ Which only uses "inl (%dx)". Also http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 Some of the best info is at: https://sites.google.com/site/chitchatvmback/backdoor Signed-off-by: Don Slutz <dslutz@xxxxxxxxxxx> Reviewed-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> CC: Don Slutz <don.slutz@xxxxxxxxx> --- v12: Surrounding code avoiding the use of "break" makes the result look rather inconsistent. Please move this up immediately after the XSM check, or drop the "break". Moved it up. v11: Dropped ASSERT(is_hvm_domain(currd)) Newline after break; v10: Probably better as EOPNOTSUPP, as it is a configuration problem. This function looks as if it should be static. I would suggest putting vmport_register declaration in hvm.h ... As indicated before, I don't think this is a good use case for a domain creation flag. Switch to the new config way. struct domain *d => struct domain *currd Are you sure you don't want to zero the high halves of 64-bit ... Comment added. Then just have this handled into the default case. Reworked new_eax handling. is_hvm_domain(currd) And - why here rather than before the switch() or even right at the start of the function? Moved to start. With that, is it really correct that OUT updates the other registers just like IN? If so, this deserves a comment, so that readers won't think this is in error. All done in comment at start. v9: Switch to x86_emulator to handle #GP code moved to next patch. Can you explain why a HVM param isn't suitable here? Issue with changing QEMU on the fly. Andrew Cooper: My recommendation is still to use a creation flag So no change. Please move SVM's identical definition into ... Did this as #1. No longer needed, but since the patch was ready I have included it. --Lots of questions about code that no long is part of this patch. -- With this, is handling other than 32-bit in/out really meaningful/correct? Added comment about this. Since you can't get here for PV, I can't see what you need this. Changed to an ASSERT. Why version 4? Added comment about this. -- Several questions about register changes. Re-coded to use new_eax and set *val to this. Change to generealy use reg->_e.. These ei1/ei2 checks belong in the callers imo - Moved. the "port" function parameter isn't even checked Add check for exact match. If dropping the code is safe without also forbidding the combination of nested and VMware emulation. Added the forbidding the combination of nested and VMware. Mostly do to the cases of the nested virtual code is the one to handle VMware stuff if needed, not the root one. Also I am having issues testing xen nested in xen and using hvm. v7: More on AMD in the commit message. Switch to only change 32bit part of registers, what VMware does. Too much logging and tracing. Dropped a lot of it. This includes vmport_debug= v6: Dropped the attempt to use svm_nextrip_insn_length via __get_instruction_length (added in v2). Just always look at upto 15 bytes on AMD. v5: we should make sure that svm_vmexit_gp_intercept is not executed for any other guest. Added an ASSERT on is_vmware_port_enabled. magic integers? Added #define for them. I am fairly certain that you need some brackets here. Added brackets. xen/arch/x86/domain.c | 2 + xen/arch/x86/hvm/hvm.c | 9 +++ xen/arch/x86/hvm/vmware/Makefile | 1 + xen/arch/x86/hvm/vmware/vmport.c | 148 ++++++++++++++++++++++++++++++++++++++ xen/include/asm-x86/hvm/domain.h | 3 + xen/include/asm-x86/hvm/hvm.h | 2 + xen/include/public/arch-x86/xen.h | 6 ++ 7 files changed, 171 insertions(+) create mode 100644 xen/arch/x86/hvm/vmware/vmport.c diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index c2bd52a..39e323b 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -555,6 +555,8 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags, d->arch.hvm_domain.hap_enabled = hvm_funcs.hap_supported && (domcr_flags & DOMCRF_hap); d->arch.hvm_domain.vmware_hwver = config->vmware_hwver; + d->arch.hvm_domain.is_vmware_port_enabled = + !!(config->arch_flags & XEN_DOMCTL_CONFIG_VMWARE_PORT_MASK); rc = create_perdomain_mapping(d, PERDOMAIN_VIRT_START, 0, NULL, NULL); } diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index c002ae7..f8ec170 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -1486,6 +1486,9 @@ int hvm_domain_initialise(struct domain *d) else d->arch.hvm_domain.io_bitmap = hvm_io_bitmap; + if ( d->arch.hvm_domain.is_vmware_port_enabled ) + vmport_register(d); + if ( is_pvh_domain(d) ) { register_portio_handler(d, 0, 0x10003, handle_pvh_io); @@ -5820,6 +5823,12 @@ static int hvmop_set_param( rc = xsm_hvm_param_nested(XSM_PRIV, d); if ( rc ) break; + /* Prevent nestedhvm with vmport */ + if ( d->arch.hvm_domain.is_vmware_port_enabled ) + { + rc = -EOPNOTSUPP; + break; + } if ( a.value > 1 ) rc = -EINVAL; /* diff --git a/xen/arch/x86/hvm/vmware/Makefile b/xen/arch/x86/hvm/vmware/Makefile index 3fb2e0b..cd8815b 100644 --- a/xen/arch/x86/hvm/vmware/Makefile +++ b/xen/arch/x86/hvm/vmware/Makefile @@ -1 +1,2 @@ obj-y += cpuid.o +obj-y += vmport.o diff --git a/xen/arch/x86/hvm/vmware/vmport.c b/xen/arch/x86/hvm/vmware/vmport.c new file mode 100644 index 0000000..f24d8e3 --- /dev/null +++ b/xen/arch/x86/hvm/vmware/vmport.c @@ -0,0 +1,148 @@ +/* + * 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/lib.h> +#include <asm/hvm/hvm.h> +#include <asm/hvm/support.h> + +#include "backdoor_def.h" + +static int vmport_ioport(int dir, uint32_t port, uint32_t bytes, uint32_t *val) +{ + struct cpu_user_regs *regs = guest_cpu_user_regs(); + + /* + * While VMware expects only 32-bit in, they do support using + * other sizes and out. However they do require only the 1 port + * and the correct value in eax. Since some of the data + * returned in eax is smaller the 32 bits and/or you only need + * the other registers the dir and bytes do not need any + * checking. The caller will handle the bytes, and dir is + * handled below for eax. + */ + if ( port == BDOOR_PORT && regs->_eax == BDOOR_MAGIC ) + { + uint32_t new_eax = ~0u; + uint64_t value; + struct vcpu *curr = current; + struct domain *currd = curr->domain; + + /* + * VMware changes the other (non eax) registers ignoring dir + * (IN vs OUT). It also changes only the 32-bit part + * leaving the high 32-bits unchanged, unlike what one would + * expect to happen. + */ + switch ( regs->_ecx & 0xffff ) + { + case BDOOR_CMD_GETMHZ: + new_eax = currd->arch.tsc_khz / 1000; + break; + + case BDOOR_CMD_GETVERSION: + /* MAGIC */ + regs->_ebx = BDOOR_MAGIC; + /* VERSION_MAGIC */ + new_eax = 6; + /* Claim we are an ESX. VMX_TYPE_SCALABLE_SERVER */ + regs->_ecx = 2; + break; + + case BDOOR_CMD_GETHWVERSION: + /* vmware_hw */ + new_eax = currd->arch.hvm_domain.vmware_hwver; + /* + * Returning zero is not the best. VMware was not at + * all consistent in the handling of this command until + * VMware hardware version 4. So it is better to claim + * 4 then 0. This should only happen in strange configs. + */ + if ( !new_eax ) + new_eax = 4; + break; + + case BDOOR_CMD_GETHZ: + { + struct segment_register sreg; + + hvm_get_segment_register(curr, x86_seg_ss, &sreg); + if ( sreg.attr.fields.dpl == 0 ) + { + value = currd->arch.tsc_khz * 1000; + /* apic-frequency (bus speed) */ + regs->_ecx = 1000000000ULL / APIC_BUS_CYCLE_NS; + /* High part of tsc-frequency */ + regs->_ebx = value >> 32; + /* Low part of tsc-frequency */ + new_eax = value; + } + break; + + } + case BDOOR_CMD_GETTIME: + value = get_localtime_us(currd) - + currd->time_offset_seconds * 1000000ULL; + /* hostUsecs */ + regs->_ebx = value % 1000000UL; + /* hostSecs */ + new_eax = value / 1000000ULL; + /* maxTimeLag */ + regs->_ecx = 1000000; + /* offset to GMT in minutes */ + regs->_edx = currd->time_offset_seconds / 60; + break; + + case BDOOR_CMD_GETTIMEFULL: + /* BDOOR_MAGIC */ + new_eax = BDOOR_MAGIC; + value = get_localtime_us(currd) - + currd->time_offset_seconds * 1000000ULL; + /* hostUsecs */ + regs->_ebx = value % 1000000UL; + /* hostSecs low 32 bits */ + regs->_edx = value / 1000000ULL; + /* hostSecs high 32 bits */ + regs->_esi = (value / 1000000ULL) >> 32; + /* maxTimeLag */ + regs->_ecx = 1000000; + break; + + default: + /* Let backing DM handle */ + return X86EMUL_UNHANDLEABLE; + } + if ( dir == IOREQ_READ ) + *val = new_eax; + } + else if ( dir == IOREQ_READ ) + *val = ~0u; + + return X86EMUL_OKAY; +} + +void vmport_register(struct domain *d) +{ + register_portio_handler(d, BDOOR_PORT, 4, vmport_ioport); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h index ada8aaa..726b977 100644 --- a/xen/include/asm-x86/hvm/domain.h +++ b/xen/include/asm-x86/hvm/domain.h @@ -125,6 +125,9 @@ struct hvm_domain { spinlock_t uc_lock; bool_t is_in_uc_mode; + /* VMware backdoor port available */ + bool_t is_vmware_port_enabled; + /* Pass-through */ struct hvm_iommu hvm_iommu; diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index a074afe..394c230 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -522,6 +522,8 @@ extern bool_t opt_hvm_fep; #define opt_hvm_fep 0 #endif +void vmport_register(struct domain *d); + #endif /* __ASM_X86_HVM_HVM_H__ */ /* diff --git a/xen/include/public/arch-x86/xen.h b/xen/include/public/arch-x86/xen.h index f84d10d..53b84da 100644 --- a/xen/include/public/arch-x86/xen.h +++ b/xen/include/public/arch-x86/xen.h @@ -267,8 +267,14 @@ typedef struct arch_shared_info arch_shared_info_t; * struct xen_arch_domainconfig's ABI is covered by * XEN_DOMCTL_INTERFACE_VERSION. */ + +/* Enable use of vmware backdoor port. */ +#define XEN_DOMCTL_CONFIG_VMWARE_PORT_BIT 0 +#define XEN_DOMCTL_CONFIG_VMWARE_PORT_MASK (1U << XEN_DOMCTL_CONFIG_VMWARE_PORT_BIT) + struct xen_arch_domainconfig { uint64_t vmware_hwver; + uint64_t arch_flags; }; #endif -- 1.8.3.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |