From mboxrd@z Thu Jan 1 00:00:00 1970 From: Boris Ostrovsky Subject: Re: [PATCH v4 08/16] xen: Add limited support of VMware's hyper-call rpc Date: Fri, 12 Sep 2014 09:37:05 -0400 Message-ID: <5412F701.4030505@oracle.com> References: <1410460610-14759-1-git-send-email-dslutz@verizon.com> <1410460610-14759-9-git-send-email-dslutz@verizon.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii"; Format="flowed" Content-Transfer-Encoding: 7bit Return-path: In-Reply-To: <1410460610-14759-9-git-send-email-dslutz@verizon.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xen.org Errors-To: xen-devel-bounces@lists.xen.org To: Don Slutz , xen-devel@lists.xen.org Cc: Kevin Tian , Keir Fraser , Ian Campbell , Stefano Stabellini , Jun Nakajima , Eddie Dong , Ian Jackson , Tim Deegan , George Dunlap , Aravind Gopalakrishnan , Jan Beulich , Andrew Cooper , Suravee Suthikulpanit List-Id: xen-devel@lists.xenproject.org On 09/11/2014 02:36 PM, Don Slutz wrote: > @@ -6142,6 +6148,43 @@ 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; > + > + if ( copy_from_guest(&a, arg, 1) ) > + return -EFAULT; > + > + rc = vmport_rpc_hvmop_precheck(op, &a); > + if ( rc ) > + return rc; > + > + d = rcu_lock_domain_by_any_id(a.domid); > + if ( d == NULL ) > + return rc; > + > + rc = -EINVAL; > + if ( !is_hvm_domain(d) ) > + goto param_fail9; Do we need this check? If you are concerned about PVH then checking explicitly for that may be better (and probably do it first thing in the case clause) > + > + rc = xsm_hvm_param(XSM_TARGET, d, op); > + if ( rc ) > + goto param_fail9; > + > + rc = vmport_rpc_hvmop_do(d, op, &a); > + if ( rc ) > + goto param_fail9; > + > + if ( op == HVMOP_get_vmport_guest_info ) > + rc = copy_to_guest(arg, &a, 1) ? -EFAULT : 0; > + > + param_fail9: > + rcu_unlock_domain(d); > + break; > + } > + > default: > { > gdprintk(XENLOG_DEBUG, "Bad HVM op %ld.\n", op); > diff --git a/xen/arch/x86/hvm/vmware/Makefile b/xen/arch/x86/hvm/vmware/Makefile > index cd8815b..4a14124 100644 > --- a/xen/arch/x86/hvm/vmware/Makefile > +++ b/xen/arch/x86/hvm/vmware/Makefile > @@ -1,2 +1,3 @@ > obj-y += cpuid.o > obj-y += vmport.o > +obj-y += vmport_rpc.o > diff --git a/xen/arch/x86/hvm/vmware/vmport.c b/xen/arch/x86/hvm/vmware/vmport.c > index 26aeb37..9e308a0 100644 > --- a/xen/arch/x86/hvm/vmware/vmport.c > +++ b/xen/arch/x86/hvm/vmware/vmport.c > @@ -139,6 +139,13 @@ int vmport_ioport(int dir, uint32_t port, uint32_t bytes, uint32_t *val) > /* maxTimeLag */ > regs->rcx = 0; > break; > + case BDOOR_CMD_MESSAGE: > + if ( !is_pv_vcpu(current) ) > + { > + /* Only supported for non pv domains */ PV vs. HVM vs. PVH. So probably 'if(is_hvm_vcpu)'? > + vmport_rpc(¤t->domain->arch.hvm_domain, regs); > + } > + break; > case BDOOR_CMD_GETGUIOPTIONS: > regs->rax = VMWARE_GUI_AUTO_GRAB | VMWARE_GUI_AUTO_UNGRAB | > VMWARE_GUI_AUTO_RAISE_DISABLED | VMWARE_GUI_SYNC_TIME | > diff --git a/xen/arch/x86/hvm/vmware/vmport_rpc.c b/xen/arch/x86/hvm/vmware/vmport_rpc.c > new file mode 100644 > index 0000000..695e58f > --- /dev/null > +++ b/xen/arch/x86/hvm/vmware/vmport_rpc.c > @@ -0,0 +1,1281 @@ > +/* > + * HVM VMPORT RPC 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. . > + */ > + > +/* > + * VMware Tools running in a DOMU will do "info-get" and "info-set" > + * guestinfo commands to get and set keys and values. Inside the VM, > + * vmtools at its lower level will feed the command string 4 bytes > + * at a time into the VMWARE magic port using the IN > + * instruction. Each 4 byte mini-rpc will get handled > + * vmport_io()-->vmport_rpc()-->vmport_process_packet()--> > + * vmport_process_send_payload()-->vmport_send() and the command > + * string will get accumulated into a channels send_buffer. When > + * the full length of the string has been accumulated, then this > + * code copies the send_buffer into a free > + * vmport_state->channel-->receive_bucket.buffer > + * VMware tools then does RECVSIZE and RECVPAYLOAD messages, the > + * latter then reads 4 bytes at a time using the IN instruction (for > + * the info-get case). Then a final RECVSTATUS message is sent to > + * finish up > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include "public/arch-x86/hvm/vmporttype.h" > + > +#include "backdoor_def.h" > +#include "guest_msg_def.h" > + > + > +#define VMWARE_PROTO_TO_GUEST 0x4f4c4354 > +#define VMWARE_PROTO_FROM_GUEST 0x49435052 > + > +#define GUESTINFO_NOTFOUND 500 > +#define GUESTINFO_VALTOOLONG 1 > +#define GUESTINFO_KEYTOOLONG 2 > +#define GUESTINFO_TOOMANYKEYS 3 > + > + > +static inline uint16_t get_low_bits(uint32_t bits) > +{ > + return bits & 0xffff; > +} > + > +static inline uint16_t get_high_bits(uint32_t bits) > +{ > + return bits >> 16; > +} > + > +static inline uint32_t set_high_bits(uint32_t b, uint32_t val) > +{ > + return (val << 16) | get_low_bits(b); > +} > + > +static inline void set_status(struct cpu_user_regs *ur, uint16_t val) > +{ > + /* VMware defines this to be only 32 bits */ > + ur->rcx = (val << 16) | (ur->rcx & 0xffff); Are you shifting val out of its size? Or will compiler automatically promote this to uint32_t? (It does for me but I don't know if this is something we can rely on). -boris > +} > + > +#ifndef NDEBUG > +static void vmport_safe_print(char *prefix, int len, const char *msg) > +{ > + unsigned char c; > + unsigned int end = len; > + unsigned 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,%zu)%s\n", prefix, end, len, k, > + sizeof(out), out); > +} > +#endif > + > +/* > + * Copy message into a jumbo bucket buffer which vmtools will use to > + * read from 4 bytes at a time until done with it > + */ > +static void vmport_send_jumbo(struct hvm_domain *hd, vmport_channel_t *c, > + const char *msg) > +{ > + unsigned int cur_recv_len = strlen(msg) + 1; > + vmport_jumbo_bucket_t *b = &(c->jumbo_recv_bkt); > + > + b->ctl.recv_len = cur_recv_len; > + b->ctl.recv_idx = 0; > + > + memset(b->recv_buf, 0, sizeof(b->recv_buf)); > + > + if ( cur_recv_len >= (sizeof(b->recv_buf) - 1) ) > + { > + VMPORT_DBG_LOG(VMPORT_LOG_ERROR, > + "VMware jumbo recv_len=%d >= %ld", > + cur_recv_len, sizeof(b->recv_buf) - 1); > + cur_recv_len = sizeof(b->recv_buf) - 1; > + } > + > + memcpy(b->recv_buf, msg, cur_recv_len); > + > + c->ctl.jumbo = 1; > +} > + > +/* > + * Copy message into a free receive bucket buffer which vmtools will use to > + * read from 4 bytes at a time until done with it > + */ > +static void vmport_send_normal(struct hvm_domain *hd, vmport_channel_t *c, > + const char *msg) > +{ > + unsigned int cur_recv_len = strlen(msg) + 1; > + unsigned int my_bkt = c->ctl.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->ctl.recv_read ) > + { > +#ifndef NDEBUG > + if ( opt_vmport_debug & VMPORT_LOG_SKIP_SEND ) > + { > + char prefix[30]; > + > + snprintf(prefix, sizeof(prefix), > + "VMware _send skipped %d (%d, %d) ", > + c->ctl.chan_id, my_bkt, c->ctl.recv_read); > + prefix[sizeof(prefix) - 1] = 0; > + vmport_safe_print(prefix, cur_recv_len, msg); > + } > +#endif > + return; > + } > + > + c->ctl.recv_write = next_bkt; > + b = &c->recv_bkt[my_bkt]; > +#ifndef NDEBUG > + if ( opt_vmport_debug & VMPORT_LOG_SEND ) > + { > + char prefix[30]; > + > + snprintf(prefix, sizeof(prefix), "VMware _send %d (%d) ", > + c->ctl.chan_id, my_bkt); > + prefix[sizeof(prefix) - 1] = 0; > + vmport_safe_print(prefix, cur_recv_len, msg); > + } > +#endif > + > + b->ctl.recv_len = cur_recv_len; > + b->ctl.recv_idx = 0; > + memset(b->recv_buf, 0, sizeof(b->recv_buf)); > + if ( cur_recv_len >= (sizeof(b->recv_buf) - 1) ) > + { > + VMPORT_DBG_LOG(VMPORT_LOG_ERROR, "VMware recv_len=%d >= %zd", > + cur_recv_len, sizeof(b->recv_buf) - 1); > + cur_recv_len = sizeof(b->recv_buf) - 1; > + } > + memcpy(b->recv_buf, msg, cur_recv_len); > +} > + > +static void vmport_send(struct hvm_domain *hd, vmport_channel_t *c, > + const char *msg) > +{ > + unsigned int cur_recv_len = strlen(msg) + 1; > + > + if ( cur_recv_len > VMPORT_MAX_VAL_LEN ) > + vmport_send_jumbo(hd, c, msg); > + else > + vmport_send_normal(hd, c, msg); > +} > + > +void vmport_ctrl_send(struct hvm_domain *hd, char *msg) > +{ > + struct vmport_state *vs = hd->vmport_data; > + unsigned int i; > + > + hd->vmport_data->ping_time = get_sec(); > + spin_lock(&hd->vmport_lock); > + for ( i = 0; i < VMPORT_MAX_CHANS; i++ ) > + { > + if ( vs->chans[i].ctl.proto_num == VMWARE_PROTO_TO_GUEST ) > + vmport_send(hd, &vs->chans[i], msg); > + } > + spin_unlock(&hd->vmport_lock); > +} > + > +static void vmport_flush(struct hvm_domain *hd) > +{ > + spin_lock(&hd->vmport_lock); > + memset(&hd->vmport_data->chans, 0, sizeof(hd->vmport_data->chans)); > + spin_unlock(&hd->vmport_lock); > +} > + > +static void vmport_sweep(struct hvm_domain *hd, unsigned long now_time) > +{ > + struct vmport_state *vs = hd->vmport_data; > + unsigned int i; > + > + for ( i = 0; i < VMPORT_MAX_CHANS; i++ ) > + { > + if ( vs->chans[i].ctl.proto_num ) > + { > + vmport_channel_t *c = &vs->chans[i]; > + long delta = now_time - c->ctl.active_time; > + > + if ( delta >= 80 ) > + { > + VMPORT_DBG_LOG(VMPORT_LOG_SWEEP, "VMware flush %d. delta=%ld", > + c->ctl.chan_id, delta); > + /* Return channel to free pool */ > + c->ctl.proto_num = 0; > + } > + } > + } > +} > + > +static vmport_channel_t *vmport_new_chan(struct vmport_state *vs, > + unsigned long now_time) > +{ > + unsigned int i; > + > + for ( i = 0; i < VMPORT_MAX_CHANS; i++ ) > + { > + if ( !vs->chans[i].ctl.proto_num ) > + { > + vmport_channel_t *c = &vs->chans[i]; > + > + c->ctl.chan_id = i; > + c->ctl.cookie = vs->open_cookie++; > + c->ctl.active_time = now_time; > + c->ctl.send_len = 0; > + c->ctl.send_idx = 0; > + c->ctl.recv_read = 0; > + c->ctl.recv_write = 0; > + return c; > + } > + } > + return NULL; > +} > + > +static 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->ctl.send_len = ur->rbx; > + c->ctl.send_idx = 0; > + > + set_status(ur, MESSAGE_STATUS_SUCCESS); > +} > + > +/* ret_buffer is in/out param */ > +static int vmport_get_guestinfo(struct hvm_domain *hd, struct vmport_state *vs, > + char *a_info_key, unsigned int a_key_len, > + char *ret_buffer, unsigned int ret_buffer_len) > +{ > + unsigned int i; > + > + for ( i = 0; i < vs->used_guestinfo; i++ ) > + { > + if ( vs->guestinfo[i] && > + (vs->guestinfo[i]->key_len == a_key_len) && > + (memcmp(a_info_key, vs->guestinfo[i]->key_data, > + vs->guestinfo[i]->key_len) == 0) ) > + { > + snprintf(ret_buffer, ret_buffer_len - 1, "1 %.*s", > + (int)vs->guestinfo[i]->val_len, > + vs->guestinfo[i]->val_data); > + return i; > + } > + } > + > + for ( i = 0; i < vs->used_guestinfo_jumbo; i++ ) > + { > + if ( vs->guestinfo_jumbo[i] && > + (vs->guestinfo_jumbo[i]->key_len == a_key_len) && > + (memcmp(a_info_key, vs->guestinfo_jumbo[i]->key_data, > + vs->guestinfo_jumbo[i]->key_len) == 0) ) > + { > + snprintf(ret_buffer, ret_buffer_len - 1, "1 %.*s", > + (int)vs->guestinfo_jumbo[i]->val_len, > + vs->guestinfo_jumbo[i]->val_data); > + return i; > + } > + } > + return GUESTINFO_NOTFOUND; > +} > + > +static void hvm_del_guestinfo_jumbo(struct vmport_state *vs, char *key, > + uint8_t len) > +{ > + int i; > + > + for ( i = 0; i < vs->used_guestinfo_jumbo; i++ ) > + { > + if ( !vs->guestinfo_jumbo[i] ) > + { > +#ifndef NDEBUG > + gdprintk(XENLOG_WARNING, > + "i=%d not allocated used_guestinfo_jumbo=%d\n", > + i, vs->used_guestinfo_jumbo); > +#endif > + } > + else if ( (vs->guestinfo_jumbo[i]->key_len == len) && > + (memcmp(key, vs->guestinfo_jumbo[i]->key_data, len) == 0) ) > + { > + vs->guestinfo_jumbo[i]->key_len = 0; > + vs->guestinfo_jumbo[i]->val_len = 0; > + break; > + } > + } > +} > + > +static void hvm_del_guestinfo(struct vmport_state *vs, char *key, uint8_t len) > +{ > + int i; > + > + for ( i = 0; i < vs->used_guestinfo; i++ ) > + { > + if ( !vs->guestinfo[i] ) > + { > +#ifndef NDEBUG > + gdprintk(XENLOG_WARNING, > + "i=%d not allocated, but used_guestinfo=%d\n", > + i, vs->used_guestinfo); > +#endif > + } > + else if ( (vs->guestinfo[i]->key_len == len) && > + (memcmp(key, vs->guestinfo[i]->key_data, len) == 0) ) > + { > + vs->guestinfo[i]->key_len = 0; > + vs->guestinfo[i]->val_len = 0; > + break; > + } > + } > +} > + > +static int vmport_set_guestinfo(struct vmport_state *vs, int a_key_len, > + unsigned int a_val_len, char *a_info_key, char *val) > +{ > + unsigned int i; > + int free_i = -1, rc = 0; > + > +#ifndef NDEBUG > + gdprintk(XENLOG_WARNING, "vmport_set_guestinfo a_val_len=%d\n", a_val_len); > +#endif > + > + if ( a_key_len <= VMPORT_MAX_KEY_LEN ) > + { > + if ( a_val_len <= VMPORT_MAX_VAL_LEN ) > + { > + for ( i = 0; i < vs->used_guestinfo; i++ ) > + { > + if ( !vs->guestinfo[i] ) > + { > +#ifndef NDEBUG > + gdprintk(XENLOG_WARNING, > + "i=%d not allocated, but used_guestinfo=%d\n", > + i, vs->used_guestinfo); > +#endif > + } > + else if ( (vs->guestinfo[i]->key_len == a_key_len) && > + (memcmp(a_info_key, vs->guestinfo[i]->key_data, > + vs->guestinfo[i]->key_len) == 0) ) > + { > + vs->guestinfo[i]->val_len = a_val_len; > + memcpy(vs->guestinfo[i]->val_data, val, a_val_len); > + break; > + } > + else if ( (vs->guestinfo[i]->key_len == 0) && > + (free_i == -1) ) > + free_i = i; > + } > + if ( i >= vs->used_guestinfo ) > + { > + if ( free_i == -1 ) > + rc = GUESTINFO_TOOMANYKEYS; > + else > + { > + vs->guestinfo[free_i]->key_len = a_key_len; > + memcpy(vs->guestinfo[free_i]->key_data, > + a_info_key, a_key_len); > + vs->guestinfo[free_i]->val_len = a_val_len; > + memcpy(vs->guestinfo[free_i]->val_data, > + val, a_val_len); > + } > + } > + } > + else > + rc = GUESTINFO_VALTOOLONG; > + } > + else > + rc = GUESTINFO_KEYTOOLONG; > + if ( !rc ) > + hvm_del_guestinfo_jumbo(vs, a_info_key, a_key_len); > + return rc; > +} > + > +static int vmport_set_guestinfo_jumbo(struct vmport_state *vs, int a_key_len, > + int a_val_len, char *a_info_key, char *val) > +{ > + unsigned int i; > + int free_i = -1, rc = 0; > + > +#ifndef NDEBUG > + gdprintk(XENLOG_WARNING, "vmport_set_guestinfo_jumbo a_val_len=%d\n", > + a_val_len); > +#endif > + > + if ( a_key_len <= VMPORT_MAX_KEY_LEN ) > + { > + if ( a_val_len <= VMPORT_MAX_VAL_JUMBO_LEN ) > + { > + for ( i = 0; i < vs->used_guestinfo_jumbo; i++ ) > + { > + if ( !vs->guestinfo_jumbo[i] ) > + { > +#ifndef NDEBUG > + gdprintk(XENLOG_WARNING, > + "i=%d not allocated; used_guestinfo_jumbo=%d\n", > + i, vs->used_guestinfo_jumbo); > +#endif > + } > + else if ( (vs->guestinfo_jumbo[i]->key_len == a_key_len) && > + (memcmp(a_info_key, > + vs->guestinfo_jumbo[i]->key_data, > + vs->guestinfo_jumbo[i]->key_len) == 0) ) > + { > + > + vs->guestinfo_jumbo[i]->val_len = a_val_len; > + memcpy(vs->guestinfo_jumbo[i]->val_data, val, a_val_len); > + break; > + } > + else if ( (vs->guestinfo_jumbo[i]->key_len == 0) && > + (free_i == -1) ) > + free_i = i; > + } > + if ( i >= vs->used_guestinfo_jumbo ) > + { > + if ( free_i == -1 ) > + rc = GUESTINFO_TOOMANYKEYS; > + else > + { > + vs->guestinfo_jumbo[free_i]->key_len = a_key_len; > + memcpy(vs->guestinfo_jumbo[free_i]->key_data, > + a_info_key, a_key_len); > + vs->guestinfo_jumbo[free_i]->val_len = a_val_len; > + memcpy(vs->guestinfo_jumbo[free_i]->val_data, > + val, a_val_len); > + } > + } > + } > + else > + rc = GUESTINFO_VALTOOLONG; > + } > + else > + rc = GUESTINFO_KEYTOOLONG; > + if ( !rc ) > + hvm_del_guestinfo(vs, a_info_key, a_key_len); > + return rc; > +} > + > +static void vmport_process_send_payload(struct hvm_domain *hd, > + vmport_channel_t *c, > + struct cpu_user_regs *ur, > + unsigned long now_time) > +{ > + /* Accumulate 4 bytes of paload into send_buf using offset */ > + if ( c->ctl.send_idx < VMPORT_MAX_SEND_BUF ) > + c->send_buf[c->ctl.send_idx] = ur->rbx; > + > + c->ctl.send_idx++; > + set_status(ur, MESSAGE_STATUS_SUCCESS); > + > + if ( c->ctl.send_idx * 4 >= c->ctl.send_len ) > + { > + > + /* We are done accumulating so handle the command */ > + > + if ( c->ctl.send_idx < VMPORT_MAX_SEND_BUF ) > + ((char *)c->send_buf)[c->ctl.send_len] = 0; > +#ifndef NDEBUG > + if ( opt_vmport_debug & VMPORT_LOG_RECV ) > + { > + char prefix[30]; > + > + snprintf(prefix, sizeof(prefix), > + "VMware RECV %d (%d) ", c->ctl.chan_id, c->ctl.recv_read); > + prefix[sizeof(prefix) - 1] = 0; > + vmport_safe_print(prefix, c->ctl.send_len, (char *)c->send_buf); > + } > +#endif > + if ( c->ctl.proto_num == VMWARE_PROTO_FROM_GUEST ) > + { > + /* > + * Eaxmples of messages: > + * > + * 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_JUMBO_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 ) > + { > + > + unsigned int a_key_len = c->ctl.send_len - > + strlen("info-get guestinfo."); > + int rc; > + struct vmport_state *vs = hd->vmport_data; > + > + info_key = (char *)c->send_buf + strlen("info-get guestinfo."); > + if ( a_key_len <= VMPORT_MAX_KEY_LEN ) > + { > + > + rc = vmport_get_guestinfo(hd, vs, info_key, a_key_len, > + ret_buffer, sizeof(ret_buffer)); > + if ( rc == GUESTINFO_NOTFOUND ) > + ret_msg = "0 No value found"; > + else > + ret_msg = ret_buffer; > + } > + 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; > + unsigned int rest_len = c->ctl.send_len - > + strlen("info-set guestinfo."); > + > + info_key = (char *)c->send_buf + strlen("info-set guestinfo."); > + val = strstr(info_key, " "); > + if ( val ) > + { > + unsigned int a_key_len = val - info_key; > + unsigned int a_val_len = rest_len - a_key_len - 1; > + int rc; > + struct vmport_state *vs = hd->vmport_data; > + > + val++; > + if ( a_val_len > VMPORT_MAX_VAL_LEN ) > + rc = vmport_set_guestinfo_jumbo(vs, a_key_len, > + a_val_len, > + info_key, val); > + else > + rc = vmport_set_guestinfo(vs, a_key_len, a_val_len, > + info_key, val); > + if ( rc == 0 ) > + ret_msg = "1 "; > + if ( rc == GUESTINFO_VALTOOLONG ) > + ret_msg = "0 Value too long"; > + if ( rc == GUESTINFO_KEYTOOLONG ) > + ret_msg = "0 Key is too long"; > + if ( rc == GUESTINFO_TOOMANYKEYS ) > + ret_msg = "0 Too many keys"; > + > + > + } > + else > + ret_msg = "0 Two and exactly two arguments expected"; > + } > + > + vmport_send(hd, c, ret_msg); > + 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; > + } > + } > + else > + { > + unsigned int my_bkt = c->ctl.recv_read - 1; > + vmport_bucket_t *b; > + > + if ( my_bkt >= VMPORT_MAX_BKTS ) > + my_bkt = VMPORT_MAX_BKTS - 1; > + b = &c->recv_bkt[my_bkt]; > + b->ctl.recv_len = 0; > + } > + } > +} > + > +static void vmport_process_recv_size(struct hvm_domain *hd, vmport_channel_t *c, > + struct cpu_user_regs *ur) > +{ > + vmport_bucket_t *b; > + vmport_jumbo_bucket_t *jb; > + int16_t recv_len; > + > + if ( c->ctl.jumbo ) > + { > + jb = &c->jumbo_recv_bkt; > + recv_len = jb->ctl.recv_len; > + } > + else > + { > + b = &c->recv_bkt[c->ctl.recv_read]; > + recv_len = b->ctl.recv_len; > + } > + if ( recv_len ) > + { > + set_status(ur, MESSAGE_STATUS_DORECV | MESSAGE_STATUS_SUCCESS); > + ur->rdx = set_high_bits(ur->rdx, MESSAGE_TYPE_SENDSIZE); > + ur->rbx = recv_len; > + } > + else > + set_status(ur, MESSAGE_STATUS_SUCCESS); > +} > + > +static void vmport_process_recv_payload(struct hvm_domain *hd, > + vmport_channel_t *c, > + struct cpu_user_regs *ur) > +{ > + vmport_bucket_t *b; > + vmport_jumbo_bucket_t *jb; > + > + if ( c->ctl.jumbo ) > + { > + jb = &c->jumbo_recv_bkt; > + ur->rbx = jb->recv_buf[jb->ctl.recv_idx++]; > + } > + else > + { > + b = &c->recv_bkt[c->ctl.recv_read]; > + if ( b->ctl.recv_idx < VMPORT_MAX_RECV_BUF ) > + ur->rbx = b->recv_buf[b->ctl.recv_idx++]; > + else > + ur->rbx = 0; > + } > + > + set_status(ur, MESSAGE_STATUS_SUCCESS); > + ur->rdx = set_high_bits(ur->rdx, MESSAGE_TYPE_SENDPAYLOAD); > +} > + > +static void vmport_process_recv_status(struct hvm_domain *hd, > + vmport_channel_t *c, > + struct cpu_user_regs *ur) > +{ > + vmport_bucket_t *b; > + vmport_jumbo_bucket_t *jb; > + > + set_status(ur, MESSAGE_STATUS_SUCCESS); > + > + if ( c->ctl.jumbo ) > + { > + c->ctl.jumbo = 0; > + /* add debug here */ > + jb = &c->jumbo_recv_bkt; > + return; > + } > + > + b = &c->recv_bkt[c->ctl.recv_read]; > + > + c->ctl.recv_read++; > + if ( c->ctl.recv_read >= VMPORT_MAX_BKTS ) > + c->ctl.recv_read = 0; > +} > + > +static void vmport_process_close(struct hvm_domain *hd, vmport_channel_t *c, > + struct cpu_user_regs *ur) > +{ > + /* Return channel to free pool */ > + c->ctl.proto_num = 0; > + set_status(ur, MESSAGE_STATUS_SUCCESS); > +} > + > +static void vmport_process_packet(struct hvm_domain *hd, vmport_channel_t *c, > + struct cpu_user_regs *ur, unsigned int sub_cmd, > + unsigned long now_time) > +{ > + c->ctl.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->rcx = 0; > + break; > + } > +} > + > +void vmport_rpc(struct hvm_domain *hd, struct cpu_user_regs *ur) > +{ > + unsigned int sub_cmd = get_high_bits(ur->rcx); > + 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] ) > + { > + VMPORT_DBG_LOG(VMPORT_LOG_PING, "VMware ping. delta=%ld", > + delta); > + vmport_ctrl_send(hd, "reset"); > + } > + 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 ) > + { > + VMPORT_DBG_LOG(VMPORT_LOG_ERROR, > + "VMware failed to find a free channel"); > + break; > + } > + > + /* Attach the apropriate protocol the the channel */ > + c->ctl.proto_num = ur->rbx & ~GUESTMSG_FLAG_COOKIE; > + set_status(ur, MESSAGE_STATUS_SUCCESS); > + ur->rdx = set_high_bits(ur->rdx, c->ctl.chan_id); > + ur->rdi = get_low_bits(c->ctl.cookie); > + ur->rsi = get_high_bits(c->ctl.cookie); > + if ( c->ctl.proto_num == VMWARE_PROTO_TO_GUEST ) > + vmport_send(hd, c, "reset"); > + break; > + } > + > + msg_id = get_high_bits(ur->rdx); > + msg_cookie = set_high_bits(ur->rdi, ur->rsi); > + if ( msg_id >= VMPORT_MAX_CHANS ) > + { > + VMPORT_DBG_LOG(VMPORT_LOG_ERROR, "VMware chan id err %d >= %d", > + msg_id, VMPORT_MAX_CHANS); > + break; > + } > + c = &hd->vmport_data->chans[msg_id]; > + if ( !c->ctl.proto_num ) > + { > + VMPORT_DBG_LOG(VMPORT_LOG_ERROR, "VMware chan %d not open", > + 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->ctl.cookie ) > + { > + VMPORT_DBG_LOG(VMPORT_LOG_ERROR, "VMware ctl.cookie err %x vs %x", > + msg_cookie, c->ctl.cookie); > + break; > + } > + vmport_process_packet(hd, c, ur, sub_cmd, now_time); > + } while ( 0 ); > + > + if ( NULL == c ) > + set_status(ur, 0); > + > + spin_unlock(&hd->vmport_lock); > +} > + > +static int hvm_set_guestinfo(struct vmport_state *vs, > + struct xen_hvm_vmport_guest_info *a, > + char *key, char *value) > +{ > + int idx; > + int free_idx = -1; > + int rc = 0; > + > + for ( idx = 0; idx < vs->used_guestinfo; idx++ ) > + { > + if ( !vs->guestinfo[idx] ) > + { > +#ifndef NDEBUG > + gdprintk(XENLOG_WARNING, > + "idx=%d not allocated, but used_guestinfo=%d\n", > + idx, vs->used_guestinfo); > +#endif > + } > + 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); > + } > + } > + > + /* Delete any duplicate entry */ > + if ( rc == 0 ) > + hvm_del_guestinfo_jumbo(vs, key, a->key_length); > + > + return rc; > +} > + > +static int hvm_set_guestinfo_jumbo(struct vmport_state *vs, > + struct xen_hvm_vmport_guest_info *a, > + char *key, char *value) > +{ > + int idx; > + int free_idx = -1; > + int rc = 0; > + > + for ( idx = 0; idx < vs->used_guestinfo_jumbo; idx++ ) > + { > + > + if ( !vs->guestinfo_jumbo[idx] ) > + { > +#ifndef NDEBUG > + gdprintk(XENLOG_WARNING, > + "idx=%d not allocated, but used_guestinfo_jumbo=%d\n", > + idx, vs->used_guestinfo_jumbo); > +#endif > + } > + else if ( (vs->guestinfo_jumbo[idx]->key_len == a->key_length) && > + (memcmp(key, vs->guestinfo_jumbo[idx]->key_data, > + vs->guestinfo_jumbo[idx]->key_len) == 0) ) > + { > + vs->guestinfo_jumbo[idx]->val_len = a->value_length; > + memcpy(vs->guestinfo_jumbo[idx]->val_data, value, a->value_length); > + break; > + > + } > + else if ( (vs->guestinfo_jumbo[idx]->key_len == 0) && > + (free_idx == -1) ) > + free_idx = idx; > + } > + > + if ( idx >= vs->used_guestinfo_jumbo ) > + { > + if ( free_idx == -1 ) > + rc = -EBUSY; > + else > + { > + vs->guestinfo_jumbo[free_idx]->key_len = a->key_length; > + memcpy(vs->guestinfo_jumbo[free_idx]->key_data, > + key, a->key_length); > + vs->guestinfo_jumbo[free_idx]->val_len = a->value_length; > + memcpy(vs->guestinfo_jumbo[free_idx]->val_data, > + value, a->value_length); > + } > + } > + > + /* Delete any duplicate entry */ > + if ( rc == 0 ) > + hvm_del_guestinfo(vs, key, a->key_length); > + > + return rc; > +} > + > +static int hvm_get_guestinfo(struct vmport_state *vs, > + struct xen_hvm_vmport_guest_info *a, > + char *key, char *value) > +{ > + int idx; > + int rc = 0; > + > + if ( a->key_length == 0 ) > + { > + /* > + * Here we are iterating on getting all guestinfo entries > + * using index > + */ > + idx = a->value_length; > + if ( idx >= vs->used_guestinfo || > + !vs->guestinfo[idx] ) > + rc = -ENOENT; > + else > + { > + 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 = 0; > + } > + } > + else > + { > + for ( idx = 0; idx < vs->used_guestinfo; idx++ ) > + { > + if ( vs->guestinfo[idx] && > + (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 = 0; > + break; > + } > + } > + if ( idx >= vs->used_guestinfo ) > + rc = -ENOENT; > + } > + return rc; > +} > + > +static int hvm_get_guestinfo_jumbo(struct vmport_state *vs, > + struct xen_hvm_vmport_guest_info *a, > + char *key, char *value) > +{ > + int idx, total_entries; > + int rc = 0; > + > + if ( a->key_length == 0 ) > + { > + /* > + * Here we are iterating on getting all guestinfo entries > + * using index > + */ > + total_entries = vs->used_guestinfo + vs->used_guestinfo_jumbo; > + > + /* Input index is in a->value_length */ > + if ( a->value_length >= total_entries ) > + { > + rc = -ENOENT; > + return rc; > + } > + idx = a->value_length - vs->used_guestinfo; > + if ( idx >= vs->used_guestinfo_jumbo || > + !vs->guestinfo_jumbo[idx] ) > + rc = -ENOENT; > + else > + { > + a->key_length = vs->guestinfo_jumbo[idx]->key_len; > + memcpy(a->data, vs->guestinfo_jumbo[idx]->key_data, a->key_length); > + a->value_length = vs->guestinfo_jumbo[idx]->val_len; > + memcpy(&a->data[a->key_length], > + vs->guestinfo_jumbo[idx]->val_data, a->value_length); > + rc = 0; > + } > + } > + else > + { > + for ( idx = 0; idx < vs->used_guestinfo_jumbo; idx++ ) > + { > + if ( vs->guestinfo_jumbo[idx] && > + (vs->guestinfo_jumbo[idx]->key_len == a->key_length) && > + (memcmp(key, vs->guestinfo_jumbo[idx]->key_data, > + vs->guestinfo_jumbo[idx]->key_len) == 0) ) > + { > + a->value_length = vs->guestinfo_jumbo[idx]->val_len; > + memcpy(value, vs->guestinfo_jumbo[idx]->val_data, > + a->value_length); > + rc = 0; > + break; > + } > + } > + if ( idx >= vs->used_guestinfo_jumbo ) > + rc = -ENOENT; > + } > + return rc; > +} > + > +int vmport_rpc_hvmop_precheck(unsigned long op, > + struct xen_hvm_vmport_guest_info *a) > +{ > + int new_key_length = a->key_length; > + > + if ( new_key_length > strlen("guestinfo.") ) > + { > + if ( (size_t)new_key_length + (size_t)a->value_length > > + sizeof(a->data) ) > + return -EINVAL; > + if ( memcmp(a->data, "guestinfo.", strlen("guestinfo.")) == 0 ) > + new_key_length -= strlen("guestinfo."); > + if ( new_key_length > VMPORT_MAX_KEY_LEN ) > + { > + gdprintk(XENLOG_ERR, "bad key len %d\n", new_key_length); > + return -EINVAL; > + } > + if ( a->value_length > VMPORT_MAX_VAL_JUMBO_LEN ) > + { > + gdprintk(XENLOG_ERR, "bad val len %d\n", a->value_length); > + return -EINVAL; > + } > + } > + else if ( new_key_length > 0 ) > + { > + if ( (size_t)new_key_length + (size_t)a->value_length > > + sizeof(a->data) ) > + return -EINVAL; > + if ( new_key_length > VMPORT_MAX_KEY_LEN ) > + { > + gdprintk(XENLOG_ERR, "bad key len %d", new_key_length); > + return -EINVAL; > + } > + if ( a->value_length > VMPORT_MAX_VAL_JUMBO_LEN ) > + { > + gdprintk(XENLOG_ERR, "bad val len %d\n", a->value_length); > + return -EINVAL; > + } > + } > + else if ( (new_key_length == 0) && (op == HVMOP_set_vmport_guest_info) ) > + return -EINVAL; > + > + return 0; > +} > + > +int vmport_rpc_hvmop_do(struct domain *d, unsigned long op, > + struct xen_hvm_vmport_guest_info *a) > +{ > + char *key = NULL; > + char *value = NULL; > + struct vmport_state *vs = d->arch.hvm_domain.vmport_data; > + int i, total_entries; > + vmport_guestinfo_t *add_slots[5]; > + vmport_guestinfo_jumbo_t *add_slots_jumbo[2]; > + int num_slots = 0, num_slots_jumbo = 0, num_free_slots = 0; > + int rc = 0; > + > + if ( a->key_length > strlen("guestinfo.") ) > + { > + 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 ) > + { > + key = &a->data[0]; > + value = key + a->key_length; > + } > + > + total_entries = vs->used_guestinfo + vs->used_guestinfo_jumbo; > + > + if ( (a->key_length == 0) && (a->value_length >= total_entries) ) > + { > + /* > + * When key length is zero, we are interating on > + * get-guest-info hypercalls to retrieve all guestinfo > + * entries using index passed in a->value_length > + */ > + return -E2BIG; > + } > + > + num_free_slots = 0; > + for ( i = 0; i < vs->used_guestinfo; i++ ) > + { > + if ( vs->guestinfo[i] && > + (vs->guestinfo[i]->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 ( i = 0; i < num_slots; i++ ) > + add_slots[i] = xzalloc(vmport_guestinfo_t); > + } > + > + num_free_slots = 0; > + for ( i = 0; i < vs->used_guestinfo_jumbo; i++ ) > + { > + if ( vs->guestinfo_jumbo[i] && > + (vs->guestinfo_jumbo[i]->key_len == 0) ) > + num_free_slots++; > + } > + if ( num_free_slots < 1 ) > + { > + num_slots_jumbo = 1 - num_free_slots; > + if ( vs->used_guestinfo_jumbo + num_slots_jumbo > > + VMPORT_MAX_NUM_JUMBO_KEY ) > + num_slots_jumbo = VMPORT_MAX_NUM_JUMBO_KEY - > + vs->used_guestinfo_jumbo; > + for ( i = 0; i < num_slots_jumbo; i++ ) > + add_slots_jumbo[i] = xzalloc(vmport_guestinfo_jumbo_t); > + } > + > + spin_lock(&d->arch.hvm_domain.vmport_lock); > + > + for ( i = 0; i < num_slots; i++ ) > + vs->guestinfo[vs->used_guestinfo + i] = add_slots[i]; > + vs->used_guestinfo += num_slots; > + > + for ( i = 0; i < num_slots_jumbo; i++ ) > + vs->guestinfo_jumbo[vs->used_guestinfo_jumbo + i] = > + add_slots_jumbo[i]; > + vs->used_guestinfo_jumbo += num_slots_jumbo; > + > + if ( op == HVMOP_set_vmport_guest_info ) > + { > + if ( a->value_length > VMPORT_MAX_VAL_LEN ) > + rc = hvm_set_guestinfo_jumbo(vs, a, key, value); > + else > + rc = hvm_set_guestinfo(vs, a, key, value); > + } > + else > + { > + /* Get Guest Info */ > + rc = hvm_get_guestinfo(vs, a, key, value); > + if ( rc != 0 ) > + rc = hvm_get_guestinfo_jumbo(vs, a, key, value); > + } > + spin_unlock(&d->arch.hvm_domain.vmport_lock); > + > + return rc; > +} > + > +int vmport_rpc_init(struct domain *d) > +{ > + struct vmport_state *vs = xzalloc(struct vmport_state); > + int i; > + > + spin_lock_init(&d->arch.hvm_domain.vmport_lock); > + d->arch.hvm_domain.vmport_data = vs; > + > + if ( !vs ) > + return -ENOMEM; > + > + /* > + * Any value is fine here. In fact a random number may better. > + * It is used to help validate that a both sides are talking > + * about the same channel. > + */ > + vs->open_cookie = 435; > + > + vs->used_guestinfo = 10; > + for ( i = 0; i < vs->used_guestinfo; i++ ) > + vs->guestinfo[i] = xzalloc(vmport_guestinfo_t); > + > + vs->used_guestinfo_jumbo = 2; > + for ( i = 0; i < vs->used_guestinfo_jumbo; i++ ) > + vs->guestinfo_jumbo[i] = xzalloc(vmport_guestinfo_jumbo_t); > + > + vmport_flush(&d->arch.hvm_domain); > + > + d->arch.hvm_domain.params[HVM_PARAM_VMPORT_RESET_TIME] = 14; > + > + return 0; > +} > + > +void vmport_rpc_deinit(struct domain *d) > +{ > + struct vmport_state *vs = d->arch.hvm_domain.vmport_data; > + int i; > + > + if ( !vs ) > + return; > + > + for ( i = 0; i < vs->used_guestinfo; i++ ) > + xfree(vs->guestinfo[i]); > + for ( i = 0; i < vs->used_guestinfo_jumbo; i++ ) > + xfree(vs->guestinfo_jumbo[i]); > + xfree(vs); > +} > + > +/* > + * 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 93b081b..8fa9090 100644 > --- a/xen/include/asm-x86/hvm/domain.h > +++ b/xen/include/asm-x86/hvm/domain.h > @@ -107,6 +107,10 @@ struct hvm_domain { > /* emulated irq to pirq */ > struct radix_tree_root emuirq_pirq; > > + /* VMware special port RPC */ > + 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 > index 74a3b66..a5c70bb 100644 > --- a/xen/include/asm-x86/hvm/vmport.h > +++ b/xen/include/asm-x86/hvm/vmport.h > @@ -25,6 +25,15 @@ > #define VMPORT_LOG_VGP_UNKNOWN (1 << 3) > #define VMPORT_LOG_REALMODE_GP (1 << 4) > > +#define VMPORT_LOG_RECV (1 << 8) > +#define VMPORT_LOG_SEND (1 << 9) > +#define VMPORT_LOG_SKIP_SEND (1 << 10) > +#define VMPORT_LOG_ERROR (1 << 11) > + > +#define VMPORT_LOG_SWEEP (1 << 12) > +#define VMPORT_LOG_PING (1 << 13) > + > + > extern unsigned int opt_vmport_debug; > #define VMPORT_DBG_LOG(level, _f, _a...) \ > do { \ > @@ -42,6 +51,13 @@ int vmport_ioport(int dir, uint32_t port, uint32_t bytes, uint32_t *val); > int vmport_gp_check(struct cpu_user_regs *regs, struct vcpu *v, > unsigned long inst_len, unsigned long inst_addr, > unsigned long ei1, unsigned long ei2); > +int vmport_rpc_init(struct domain *d); > +void vmport_rpc_deinit(struct domain *d); > +void vmport_rpc(struct hvm_domain *hd, struct cpu_user_regs *ur); > +int vmport_rpc_hvmop_precheck(unsigned long op, > + struct xen_hvm_vmport_guest_info *a); > +int vmport_rpc_hvmop_do(struct domain *d, unsigned long op, > + struct xen_hvm_vmport_guest_info *a); > > #endif /* ASM_X86_HVM_VMPORT_H__ */ > > diff --git a/xen/include/public/arch-x86/hvm/vmporttype.h b/xen/include/public/arch-x86/hvm/vmporttype.h > new file mode 100644 > index 0000000..98875d2 > --- /dev/null > +++ b/xen/include/public/arch-x86/hvm/vmporttype.h > @@ -0,0 +1,118 @@ > +/* > + * vmporttype.h: HVM VMPORT structure definitions > + * > + * > + * 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. . > + */ > + > +#ifndef ASM_X86_HVM_VMPORTTYPE_H__ > +#define ASM_X86_HVM_VMPORTTYPE_H__ > + > +#define VMPORT_MAX_KEY_LEN 30 > +#define VMPORT_MAX_VAL_LEN 128 > +#define VMPORT_MAX_NUM_KEY 64 > +#define VMPORT_MAX_NUM_JUMBO_KEY 4 > +#define VMPORT_MAX_VAL_JUMBO_LEN 4096 > + > +#define VMPORT_MAX_SEND_BUF ((22 + VMPORT_MAX_KEY_LEN + \ > + VMPORT_MAX_VAL_JUMBO_LEN + 3)/4) > +#define VMPORT_MAX_RECV_BUF ((2 + VMPORT_MAX_VAL_LEN + 3)/4) > +#define VMPORT_MAX_RECV_JUMBO_BUF ((2 + VMPORT_MAX_VAL_JUMBO_LEN + 3)/4) > +#define VMPORT_MAX_CHANS 6 > +#define VMPORT_MAX_BKTS 8 > + > +#define VMPORT_SAVE_VERSION 0xabcd0001 > + > +typedef struct > +{ > + 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 > +{ > + uint16_t val_len; > + uint8_t key_len; > + char key_data[VMPORT_MAX_KEY_LEN]; > + char val_data[VMPORT_MAX_VAL_JUMBO_LEN]; > +} vmport_guestinfo_jumbo_t; > + > +typedef struct __attribute__((packed)) > +{ > + uint16_t recv_len; > + uint16_t recv_idx; > +} > +vmport_bucket_control_t; > + > +typedef struct __attribute__((packed)) > +{ > + vmport_bucket_control_t ctl; > + uint32_t recv_buf[VMPORT_MAX_RECV_BUF + 1]; > +} > +vmport_bucket_t; > + > +typedef struct __attribute__((packed)) > +{ > + vmport_bucket_control_t ctl; > + uint32_t recv_buf[VMPORT_MAX_RECV_JUMBO_BUF + 1]; > +} > +vmport_jumbo_bucket_t; > + > +typedef struct __attribute__((packed)) > +{ > + uint64_t active_time; > + uint32_t chan_id; > + uint32_t cookie; > + uint32_t proto_num; > + uint16_t send_len; > + uint16_t send_idx; > + uint8_t jumbo; > + uint8_t recv_read; > + uint8_t recv_write; > + uint8_t recv_chan_pad[1]; > +} > +vmport_channel_control_t; > + > +typedef struct __attribute__((packed)) > +{ > + vmport_channel_control_t ctl; > + vmport_bucket_t recv_bkt[VMPORT_MAX_BKTS]; > + vmport_jumbo_bucket_t jumbo_recv_bkt; > + uint32_t send_buf[VMPORT_MAX_SEND_BUF + 1]; > +} > +vmport_channel_t; > + > +struct vmport_state > +{ > + uint64_t ping_time; > + uint32_t open_cookie; > + uint32_t used_guestinfo; > + uint32_t used_guestinfo_jumbo; > + uint8_t max_chans; > + uint8_t state_pad[3]; > + vmport_channel_t chans[VMPORT_MAX_CHANS]; > + vmport_guestinfo_t *guestinfo[VMPORT_MAX_NUM_KEY]; > + vmport_guestinfo_jumbo_t *guestinfo_jumbo[VMPORT_MAX_NUM_JUMBO_KEY]; > +}; > + > +#endif /* ASM_X86_HVM_VMPORTTYPE_H__ */ > + > +/* > + * Local variables: > + * mode: C > + * c-file-style: "BSD" > + * c-basic-offset: 4 > + * indent-tabs-mode: nil > + * End: > + */ > diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h > index eeb0a60..8e1e072 100644 > --- a/xen/include/public/hvm/hvm_op.h > +++ b/xen/include/public/hvm/hvm_op.h > @@ -369,6 +369,24 @@ DEFINE_XEN_GUEST_HANDLE(xen_hvm_set_ioreq_server_state_t); > > #endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */ > > +/* Get/set vmport subcommands */ > +#define HVMOP_get_vmport_guest_info 23 > +#define HVMOP_set_vmport_guest_info 24 > +#define VMPORT_GUEST_INFO_KEY_MAX 40 > +#define VMPORT_GUEST_INFO_VAL_MAX 4096 > +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__ */ > > /* > diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h > index dee6d68..722e30b 100644 > --- a/xen/include/public/hvm/params.h > +++ b/xen/include/public/hvm/params.h > @@ -153,7 +153,10 @@ > > /* Params for VMware */ > #define HVM_PARAM_VMWARE_HW 35 > +#define HVM_PARAM_VMPORT_BUILD_NUMBER_TIME 36 > +#define HVM_PARAM_VMPORT_BUILD_NUMBER_VALUE 37 > +#define HVM_PARAM_VMPORT_RESET_TIME 38 > > -#define HVM_NR_PARAMS 36 > +#define HVM_NR_PARAMS 39 > > #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */