xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Boris Ostrovsky <boris.ostrovsky@oracle.com>
To: Don Slutz <dslutz@verizon.com>, xen-devel@lists.xen.org
Cc: Kevin Tian <kevin.tian@intel.com>, Keir Fraser <keir@xen.org>,
	Ian Campbell <ian.campbell@citrix.com>,
	Stefano Stabellini <stefano.stabellini@eu.citrix.com>,
	Jun Nakajima <jun.nakajima@intel.com>,
	Eddie Dong <eddie.dong@intel.com>,
	Ian Jackson <ian.jackson@eu.citrix.com>, Tim Deegan <tim@xen.org>,
	George Dunlap <George.Dunlap@eu.citrix.com>,
	Aravind Gopalakrishnan <Aravind.Gopalakrishnan@amd.com>,
	Jan Beulich <jbeulich@suse.com>,
	Andrew Cooper <andrew.cooper3@citrix.com>,
	Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
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	[thread overview]
Message-ID: <5412F701.4030505@oracle.com> (raw)
In-Reply-To: <1410460610-14759-9-git-send-email-dslutz@verizon.com>

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(&current->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. <http://www.gnu.org/licenses/>.
> + */
> +
> +/*
> + * 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 <xen/config.h>
> +#include <xen/lib.h>
> +#include <xen/cper.h>
> +#include <asm/hvm/hvm.h>
> +#include <asm/hvm/support.h>
> +#include <asm/hvm/vmport.h>
> +#include <asm/hvm/trace.h>
> +
> +#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. <http://www.gnu.org/licenses/>.
> + */
> +
> +#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__ */

  reply	other threads:[~2014-09-12 13:37 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-09-11 18:36 [PATCH v4 00/16] Xen VMware tools support Don Slutz
2014-09-11 18:36 ` [PATCH v4 01/16] xen: Add support for VMware cpuid leaves Don Slutz
2014-09-11 19:49   ` Andrew Cooper
2014-09-12  9:49     ` Jan Beulich
2014-09-12 17:46       ` Don Slutz
2014-09-15  7:42         ` Jan Beulich
2014-09-17 15:41           ` Don Slutz
2014-09-12 21:26     ` Don Slutz
2014-09-12 12:37   ` Boris Ostrovsky
2014-09-12 17:50     ` Don Slutz
2014-09-11 18:36 ` [PATCH v4 02/16] tools: Add vmware_hw support Don Slutz
2014-09-11 21:09   ` Andrew Cooper
2014-09-16 16:20     ` Don Slutz
2014-09-11 18:36 ` [PATCH v4 03/16] vmware: Add VMware provided include files Don Slutz
2014-09-11 18:36 ` [PATCH v4 04/16] xen: Add is_vmware_port_enabled Don Slutz
2014-09-11 21:22   ` Andrew Cooper
2014-09-16 16:20     ` Don Slutz
2014-09-12 13:08   ` Boris Ostrovsky
2014-09-16 12:08     ` Slutz, Donald Christopher
2014-09-17 15:56       ` Boris Ostrovsky
2014-09-17 18:23         ` Slutz, Donald Christopher
2014-09-18  9:14           ` Jan Beulich
2014-09-19 12:48             ` Slutz, Donald Christopher
2014-09-18 22:53           ` Boris Ostrovsky
2014-09-19 13:24             ` Slutz, Donald Christopher
2014-09-19 15:50               ` Boris Ostrovsky
2014-09-19 17:00                 ` Slutz, Donald Christopher
2014-09-11 18:36 ` [PATCH v4 05/16] tools: Add vmware_port support Don Slutz
2014-09-11 18:36 ` [PATCH v4 06/16] xen: Convert vmware_port to xentrace usage Don Slutz
2014-09-12 13:10   ` Boris Ostrovsky
2014-09-12 23:57     ` Don Slutz
2014-09-11 18:36 ` [PATCH v4 07/16] tools: " Don Slutz
2014-09-12 13:15   ` Boris Ostrovsky
2014-09-13  0:01     ` Don Slutz
2014-09-11 18:36 ` [PATCH v4 08/16] xen: Add limited support of VMware's hyper-call rpc Don Slutz
2014-09-12 13:37   ` Boris Ostrovsky [this message]
2014-09-12 14:27     ` Jan Beulich
2014-09-16 12:38       ` Slutz, Donald Christopher
2014-09-16 12:46         ` Jan Beulich
2014-09-16 13:47           ` Slutz, Donald Christopher
2014-09-16 13:17     ` Slutz, Donald Christopher
2014-09-11 18:36 ` [PATCH v4 09/16] tools: " Don Slutz
2014-09-11 18:36 ` [PATCH v4 10/16] Add VMware tool's triggers Don Slutz
2014-09-11 18:36 ` [PATCH v4 11/16] Add live migration of VMware's hyper-call RPC Don Slutz
2014-09-12 13:54   ` Boris Ostrovsky
2014-09-16 15:48     ` Don Slutz
2014-09-11 18:36 ` [PATCH v4 12/16] Add dump of HVM_SAVE_CODE(VMPORT) to xen-hvmctx Don Slutz
2014-09-11 18:36 ` [PATCH v4 13/16] Add xen-hvm-param Don Slutz
2014-09-11 18:36 ` [PATCH v4 14/16] Add xen-vmware-guestinfo Don Slutz
2014-09-11 18:36 ` [PATCH v4 15/16] Add xen-list-vmware-guestinfo Don Slutz
2014-09-11 18:36 ` [PATCH v4 16/16] Add xen-hvm-send-trigger Don Slutz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5412F701.4030505@oracle.com \
    --to=boris.ostrovsky@oracle.com \
    --cc=Aravind.Gopalakrishnan@amd.com \
    --cc=George.Dunlap@eu.citrix.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=dslutz@verizon.com \
    --cc=eddie.dong@intel.com \
    --cc=ian.campbell@citrix.com \
    --cc=ian.jackson@eu.citrix.com \
    --cc=jbeulich@suse.com \
    --cc=jun.nakajima@intel.com \
    --cc=keir@xen.org \
    --cc=kevin.tian@intel.com \
    --cc=stefano.stabellini@eu.citrix.com \
    --cc=suravee.suthikulpanit@amd.com \
    --cc=tim@xen.org \
    --cc=xen-devel@lists.xen.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).