[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [RFC PATCH 07/10] Add new vmport code.



On 12/12/2013 19:15, Don Slutz wrote:
> From: Don Slutz <dslutz@xxxxxxxxxxx>
>
> enable vmport_flush call.
>
> Signed-off-by: Don Slutz <dslutz@xxxxxxxxxxx>
> ---
>  xen/arch/x86/hvm/Makefile                |   1 +
>  xen/arch/x86/hvm/hvm.c                   |   2 -
>  xen/arch/x86/hvm/vmport/Makefile         |   1 +
>  xen/arch/x86/hvm/vmport/includeCheck.h   |  17 +
>  xen/arch/x86/hvm/vmport/vmport.c         | 719 
> +++++++++++++++++++++++++++++++
>  xen/arch/x86/hvm/vmport/xen_vmport_def.h |  36 ++
>  xen/include/asm-x86/hvm/trace.h          |   3 +
>  7 files changed, 777 insertions(+), 2 deletions(-)
>  create mode 100644 xen/arch/x86/hvm/vmport/Makefile
>  create mode 100644 xen/arch/x86/hvm/vmport/includeCheck.h
>  create mode 100644 xen/arch/x86/hvm/vmport/vmport.c
>  create mode 100644 xen/arch/x86/hvm/vmport/xen_vmport_def.h
>
> diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile
> index eea5555..954a81c 100644
> --- a/xen/arch/x86/hvm/Makefile
> +++ b/xen/arch/x86/hvm/Makefile
> @@ -1,5 +1,6 @@
>  subdir-y += svm
>  subdir-y += vmx
> +subdir-y += vmport
>  
>  obj-y += asid.o
>  obj-y += emulate.o
> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index fa5d382..a557272 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -614,9 +614,7 @@ int hvm_domain_initialise(struct domain *d)
>               (d->max_pages + (1 << 10) - 1) >> 10,
>               (d->max_pages + (1 << 20) - 1) >> 20);
>  
> -#if 0
>      vmport_flush(&d->arch.hvm_domain);
> -#endif
>  
>      if ( is_pvh_domain(d) )
>      {
> diff --git a/xen/arch/x86/hvm/vmport/Makefile 
> b/xen/arch/x86/hvm/vmport/Makefile
> new file mode 100644
> index 0000000..2648fae
> --- /dev/null
> +++ b/xen/arch/x86/hvm/vmport/Makefile
> @@ -0,0 +1 @@
> +obj-y += vmport.o
> diff --git a/xen/arch/x86/hvm/vmport/includeCheck.h 
> b/xen/arch/x86/hvm/vmport/includeCheck.h
> new file mode 100644
> index 0000000..26e0d59
> --- /dev/null
> +++ b/xen/arch/x86/hvm/vmport/includeCheck.h
> @@ -0,0 +1,17 @@
> +/*
> + * includeCheck.h
> + *
> + * Copyright (C) 2012 Verizon Corporation
> + *
> + * This file is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License Version 2 (GPLv2)
> + * as published by the Free Software Foundation.
> + *
> + * This file is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details. <http://www.gnu.org/licenses/>.
> + */
> +/*
> + * Nothing here.  Just to use backdoor_def.h without change.

What do you mean by this?

> + */
> diff --git a/xen/arch/x86/hvm/vmport/vmport.c 
> b/xen/arch/x86/hvm/vmport/vmport.c
> new file mode 100644
> index 0000000..43bdf7b
> --- /dev/null
> +++ b/xen/arch/x86/hvm/vmport/vmport.c
> @@ -0,0 +1,719 @@
> +/*
> + * HVM VMPORT emulation
> + *
> + * Copyright (C) 2012 Verizon Corporation
> + *
> + * This file is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License Version 2 (GPLv2)
> + * as published by the Free Software Foundation.
> + *
> + * This file is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details. <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "xen_vmport_def.h"
> +#include "backdoor_def.h"
> +#include "guest_msg_def.h"
> +#include "asm-x86/hvm/support.h"

#include <asm/hvm/support.h>

> +
> +#define LOG_RPC             0x0000001
> +#define LOG_RECV_STATUS     0x0000002
> +#define LOG_SKIP_SEND       0x0000004
> +#define LOG_SEND            0x0000008
> +#define LOG_SEND_SIZE_ALL   0x0000010
> +#define LOG_SEND_SIZE       0x0000020
> +#define LOG_RECV_SIZE_ALL   0x0000040
> +#define LOG_RECV_SIZE       0x0000080
> +#define LOG_CLOSE           0x0000100
> +#define LOG_OPEN            0x0000200
> +#define LOG_FLUSH           0x0000400
> +#define LOG_TRACE           0x0000800
> +#define LOG_PING            0x0001000
> +#define LOG_SWEEP           0x0002000
> +#define LOG_BUILD           0x0004000
> +#define LOG_STATUS          0x0008000
> +
> +#define LOG_ERROR           0x0010000
> +
> +#define LOG_INFO_GET        0x0020000
> +#define LOG_INFO_SET        0x0040000
> +
> +#define LOG_GP_UNKNOWN      0x0100000
> +#define LOG_GP_NOT_VMWARE   0x0200000
> +#define LOG_GP_FAIL_RD_INST 0x0400000
> +#define LOG_GP_VMWARE_AFTER 0x0800000
> +
> +#define LOG_VGP_UNKNOWN     0x1000000
> +#define LOG_REALMODE_GP     0x8000000
> +
> +extern unsigned long get_sec(void);

Please include the appropriate header files.

> +
> +/* Note: VMPORT_PORT and VMPORT_MAGIC is also defined as BDOOR_PORT
> + * and BDOOR_MAGIC in backdoor_def.h Defined in vmport.h also.
> + */
> +
> +inline uint16_t getLowBits(uint32_t bits)
> +{
> +    return bits & 0xffff;
> +}
> +
> +inline uint16_t getHighBits(uint32_t bits)
> +{
> +    return bits >> 16;
> +}
> +
> +inline uint32_t setHighBits(uint32_t b, uint32_t val)
> +{
> +    return (val << 16) | getLowBits(b);
> +}

What is the point of these functions being separated out?

setHighBits only seems to be used with regs->ecx (which is actually a
64bit value not a 32bit value) to set a status value.

Why not set_status(cpu_user_regs *, uint16_t val) ?

> +
> +static inline long getLogMask(struct hvm_domain *hd)
> +{
> +    return hd->params[HVM_PARAM_VMPORT_LOGMASK];

A param is unsigned long, not long...

> +}
> +
> +static inline char *getStatus(struct hvm_domain *hd)
> +{
> +    return (char*)&hd->params[HVM_PARAM_VMPORT_STATUS];

... And most certainly not a string.

> +}
> +
> +void vmport_safe_print(char *prefix, int len, char *msg)
> +{
> +    unsigned char c;
> +    int end = len;
> +    int i,k;
> +    char out[4*(VMPORT_MAX_SEND_BUF + 1)*3 + 6];
> +
> +    if (end > (sizeof(out)/3 - 6))
> +        end = sizeof(out)/3 - 6;
> +    out[0] = '<';
> +    k = 1;
> +    for (i = 0; i < end; i++) {
> +        c = msg[i];
> +        if ((c == '^') || (c == '\\') || (c == '>')) {
> +            out[k++] = '\\';
> +            out[k++] = c;
> +        } else if ((c >= ' ') && (c <= '~')) {
> +            out[k++] = c;
> +        } else if (c < ' ') {
> +            out[k++] = '^';
> +            out[k++] = c ^ 0x40;
> +        } else {
> +            snprintf(&out[k], sizeof(out) - k, "\\%02x", c);
> +            k += 3;
> +        }
> +    }
> +    out[k++] = '>';
> +    if (len > end) {
> +        out[k++] = '.';
> +        out[k++] = '.';
> +        out[k++] = '.';
> +    }
> +    out[k++] = 0;
> +    gdprintk(XENLOG_DEBUG, "%s%d(%d,%d,%ld)%s\n", prefix, end, len, k, 
> sizeof(out), out);

the correct format for any sizeof is %zu or %zx depending on decimal/hex.

> +}
> +
> +void vmport_send(struct hvm_domain *hd, vmport_channel_t *c, char *msg, int 
> slot)
> +{
> +    unsigned int cur_recv_len = strlen(msg) + 1;
> +    char prefix[30];
> +    unsigned int my_bkt = c->recv_write;
> +    unsigned int next_bkt = my_bkt + 1;
> +    vmport_bucket_t *b;
> +
> +    if (next_bkt >= VMPORT_MAX_BKTS)
> +        next_bkt = 0;
> +
> +    if (next_bkt == c->recv_read) {
> +        if (getLogMask(hd) & LOG_SKIP_SEND) {
> +            snprintf(prefix, sizeof(prefix),
> +                     "VMware _send skipped %d (%d, %d) ", c->chan_id, 
> my_bkt, c->recv_read);
> +            prefix[sizeof(prefix)-1] = 0;
> +            vmport_safe_print(prefix, cur_recv_len, msg);
> +        }
> +        getStatus(hd)[slot] = 200;

This (and every use of getStatus() below) most certainly needs to
guarentee that slot is strictly in the bound 0 to 7, and writing the
integer 200 to a char is undefined I believe.

> +        if (getLogMask(hd) & LOG_STATUS)
> +            gdprintk(XENLOG_DEBUG, "VMware %d getStatus[%d]=200\n", 
> c->chan_id, slot);
> +        return;
> +    }
> +
> +    c->recv_write = next_bkt;
> +    b = &c->recv_bkt[my_bkt];
> +    if (getLogMask(hd) & LOG_SEND) {
> +        snprintf(prefix, sizeof(prefix),
> +                 "VMware _send %d (%d) ", c->chan_id, my_bkt);
> +        prefix[sizeof(prefix)-1] = 0;
> +        vmport_safe_print(prefix, cur_recv_len, msg);
> +    }
> +
> +    b->recv_len = cur_recv_len;
> +    b->recv_slot = slot;
> +    b->recv_idx = 0;
> +    memset(b->recv_buf, 0, sizeof(b->recv_buf));
> +    if (cur_recv_len >= (sizeof(b->recv_buf) - 1)) {
> +        if (getLogMask(hd) & LOG_ERROR)
> +            gdprintk(XENLOG_DEBUG, "VMware recv_len=%d >= %ld.\n",
> +                     cur_recv_len, sizeof(b->recv_buf) - 1);
> +        cur_recv_len = sizeof(b->recv_buf) - 1;
> +    }
> +    memcpy(b->recv_buf, msg, cur_recv_len);
> +    getStatus(hd)[b->recv_slot] = 1;
> +    if (getLogMask(hd) & LOG_STATUS)
> +        gdprintk(XENLOG_DEBUG, "VMware %d,%d getStatus[%d]=1\n",
> +                 c->chan_id, c->recv_read, b->recv_slot);
> +}
> +
> +void vmport_ctrl_send(struct hvm_domain *hd, char *msg, int slot)
> +{
> +    struct vmport_state *vs = hd->vmport_data;
> +    int i;
> +
> +    if (slot < 1 || slot > 7)
> +        slot = 7;
> +    hd->vmport_data->ping_time = get_sec();
> +    spin_lock(&hd->vmport_lock);
> +    for (i = 0; i < VMPORT_MAX_CHANS; i++) {
> +        if (vs->chans[i].proto_num == 0x4f4c4354) {
> +            vmport_send(hd, &vs->chans[i], msg, slot);
> +        }
> +    }
> +    spin_unlock(&hd->vmport_lock);
> +}
> +
> +void vmport_flush(struct hvm_domain *hd)
> +{
> +    if (getLogMask(hd) & LOG_FLUSH)
> +        gdprintk(XENLOG_DEBUG, "VMware flush.\n");
> +    spin_lock(&hd->vmport_lock);
> +    memset(&hd->vmport_data->chans, 0, sizeof(hd->vmport_data->chans));
> +    spin_unlock(&hd->vmport_lock);
> +}
> +
> +void vmport_sweep(struct hvm_domain *hd, unsigned long now_time)
> +{
> +    struct vmport_state *vs = hd->vmport_data;
> +    int i;
> +
> +    for (i = 0; i < VMPORT_MAX_CHANS; i++) {
> +        if (vs->chans[i].proto_num) {
> +            vmport_channel_t *c = &vs->chans[i];
> +            long delta = now_time - c->active_time;
> +
> +            if ( delta >= 80 ) {
> +                if (getLogMask(hd) & LOG_SWEEP)
> +                    gdprintk(XENLOG_DEBUG, "VMware flush %d. delta=%ld\n",
> +                             c->chan_id, delta);
> +                // Return channel to free pool
> +                c->proto_num = 0;
> +            }
> +        }
> +    }
> +}
> +
> +vmport_channel_t *vmport_new_chan(struct vmport_state *vs, unsigned long 
> now_time)
> +{
> +    int i;
> +
> +    for (i = 0; i < VMPORT_MAX_CHANS; i++) {
> +        if (!vs->chans[i].proto_num) {
> +            vmport_channel_t *c = &vs->chans[i];
> +
> +            c->chan_id = i;
> +            c->cookie = vs->open_cookie++;
> +            c->active_time = now_time;
> +            c->send_len = 0;
> +            c->send_idx = 0;
> +            c->recv_read = 0;
> +            c->recv_write = 0;
> +            return c;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +void vmport_process_send_size(struct hvm_domain *hd, vmport_channel_t *c, 
> struct cpu_user_regs *ur)
> +{
> +    // vmware tools often send a 0 byte request size.
> +    c->send_len = ur->ebx;
> +    c->send_idx = 0;
> +    ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS);
> +    if ((getLogMask(hd) & LOG_SEND_SIZE_ALL) ||
> +        ((getLogMask(hd) & LOG_SEND_SIZE) && (c->send_len)))
> +        gdprintk(XENLOG_DEBUG, "VMware SENDSIZE %d is %d.\n",
> +                 c->chan_id, c->send_len);
> +}
> +
> +void vmport_process_send_payload(struct hvm_domain *hd, vmport_channel_t *c,
> +                                 struct cpu_user_regs *ur, unsigned long 
> now_time)
> +{
> +    char prefix[30];
> +
> +    if (c->send_idx < VMPORT_MAX_SEND_BUF) {
> +        c->send_buf[c->send_idx] = ur->ebx;
> +    }
> +    c->send_idx++;
> +    ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS);
> +    if (c->send_idx * 4 >= c->send_len) {
> +        if (c->send_idx < VMPORT_MAX_SEND_BUF)
> +            ((char*)c->send_buf)[c->send_len] = 0;
> +        if (getLogMask(hd) & LOG_RPC) {
> +            snprintf(prefix, sizeof(prefix),
> +                     "VMware RPC %d (%d) ", c->chan_id, c->recv_read);
> +            prefix[sizeof(prefix)-1] = 0;
> +            vmport_safe_print(prefix, c->send_len, (char*)c->send_buf);
> +        }
> +        if (c->proto_num == 0x49435052) {
> +/* log toolbox: Version: build-341836 */
> +/* SetGuestInfo  4 build-341836 */
> +/* info-get guestinfo.ip */
> +/* info-set guestinfo.ip joe */
> +            char * build = NULL;
> +            char * info_key = NULL;
> +            char * ret_msg = "1 ";

I cant remember offhand whether Xen is compiled with or without
read-only strings,

> +            char ret_buffer[2 + VMPORT_MAX_VAL_LEN + 2];
> +
> +            if (strncmp((char*)c->send_buf, "log toolbox: Version: build-",
> +                        strlen("log toolbox: Version: build-")) == 0) {
> +                build = (char*)c->send_buf + strlen("log toolbox: Version: 
> build-");
> +            } else if (strncmp((char*)c->send_buf, "SetGuestInfo  4 build-",
> +                               strlen("SetGuestInfo  4 build-")) == 0) {
> +                build = (char*)c->send_buf + strlen("SetGuestInfo  4 
> build-");
> +            } else if (strncmp((char*)c->send_buf, "info-get guestinfo.",
> +                               strlen("info-get guestinfo.")) == 0) {
> +                int keyLen = c->send_len - strlen("info-get guestinfo.");
> +                int idx;
> +                struct vmport_state *vs = hd->vmport_data;
> +
> +                info_key = (char*)c->send_buf + strlen("info-get 
> guestinfo.");
> +                if (getLogMask(hd) & LOG_INFO_GET) {
> +                    snprintf(prefix, sizeof(prefix),
> +                             "VMware info-get key:");
> +                    vmport_safe_print(prefix, keyLen, info_key);
> +                }
> +                if (keyLen <= VMPORT_MAX_KEY_LEN) {
> +                    for (idx = 0; idx < vs->used_guestinfo; idx++) {
> +                        if ((vs->guestinfo[idx]->key_len == keyLen) &&
> +                            (memcmp(info_key,
> +                                    vs->guestinfo[idx]->key_data,
> +                                    vs->guestinfo[idx]->key_len) == 0)) {
> +                            if (getLogMask(hd) & LOG_INFO_GET) {
> +                                snprintf(prefix, sizeof(prefix),
> +                                         "VMware info-get val:");
> +                                vmport_safe_print(prefix,
> +                                                  
> vs->guestinfo[idx]->val_len,
> +                                                  
> vs->guestinfo[idx]->val_data);
> +                            }
> +                            snprintf(ret_buffer, sizeof(ret_buffer) - 1, "1 
> %.*s",
> +                                     (int)vs->guestinfo[idx]->val_len,
> +                                     vs->guestinfo[idx]->val_data);
> +                            ret_msg = ret_buffer;
> +                            break;
> +                        }
> +                    }
> +                    if (idx >= vs->used_guestinfo) {
> +                        ret_msg = "0 No value found";
> +                    }
> +                } else {
> +                    ret_msg = "0 Key is too long";
> +                }
> +            } else if (strncmp((char*)c->send_buf, "info-set guestinfo.",
> +                               strlen("info-set guestinfo.")) == 0) {
> +                char * val;
> +                int rest_len = c->send_len - strlen("info-set guestinfo.");
> +
> +                info_key = (char*)c->send_buf + strlen("info-set 
> guestinfo.");
> +                val = strstr(info_key, " ");
> +                if (val) {
> +                    int keyLen = val - info_key;
> +                    int valLen = rest_len - keyLen - 1;
> +                    int free_idx = -1;
> +                    int idx;
> +                    struct vmport_state *vs = hd->vmport_data;
> +
> +                    val++;
> +                    if (getLogMask(hd) & LOG_INFO_SET) {
> +                        snprintf(prefix, sizeof(prefix),
> +                                 "VMware info-set key:");
> +                        vmport_safe_print(prefix, keyLen, info_key);
> +                        snprintf(prefix, sizeof(prefix),
> +                                 "VMware info-set val:");
> +                        vmport_safe_print(prefix, valLen, val);
> +                    }
> +                    if (keyLen <= VMPORT_MAX_KEY_LEN) {
> +                        if (valLen <= VMPORT_MAX_VAL_LEN) {
> +                            for (idx = 0; idx < vs->used_guestinfo; idx++) {
> +                                if (!vs->guestinfo[idx]) {
> +                                    gdprintk(XENLOG_WARNING, "idx=%d not 
> allocated, but used_guestinfo=%d\n",
> +                                             idx, vs->used_guestinfo);
> +                                } else if ((vs->guestinfo[idx]->key_len == 
> keyLen) &&
> +                                           (memcmp(info_key,
> +                                                   
> vs->guestinfo[idx]->key_data,
> +                                                   
> vs->guestinfo[idx]->key_len) == 0)) {
> +                                    vs->guestinfo[idx]->val_len = valLen;
> +                                    memcpy(vs->guestinfo[idx]->val_data, 
> val, valLen);
> +                                    break;
> +                                } else if ((vs->guestinfo[idx]->key_len == 
> 0) &&
> +                                           (free_idx == -1)) {
> +                                    free_idx = idx;
> +                                }
> +                            }
> +                            if (idx >= vs->used_guestinfo) {
> +                                if (free_idx == -1) {
> +                                    ret_msg = "0 Too many keys";
> +                                } else {
> +                                    vs->guestinfo[free_idx]->key_len = 
> keyLen;
> +                                    
> memcpy(vs->guestinfo[free_idx]->key_data, info_key, keyLen);
> +                                    vs->guestinfo[free_idx]->val_len = 
> valLen;
> +                                    
> memcpy(vs->guestinfo[free_idx]->val_data, val, valLen);
> +                                }
> +                            }
> +                        } else {
> +                            ret_msg = "0 Value too long";
> +                        }
> +                    } else {
> +                        ret_msg = "0 Key is too long";
> +                    }
> +                } else {
> +                    if (getLogMask(hd) & LOG_INFO_SET) {
> +                        snprintf(prefix, sizeof(prefix),
> +                                 "VMware info-set missing val; key:");
> +                        vmport_safe_print(prefix, rest_len, info_key);
> +                    }
> +                    ret_msg = "0 Two and exactly two arguments expected";
> +                }
> +            }
> +
> +            vmport_send(hd, c, ret_msg, 5);
> +            if (build) {
> +                long val = 0;
> +                char *p = build;
> +
> +                while (*p) {
> +                    if (*p < '0' || *p > '9')
> +                        break;
> +                    val = val * 10 + *p - '0';
> +                    p++;
> +                };
> +
> +                hd->params[HVM_PARAM_VMPORT_BUILD_NUMBER_VALUE] = val;
> +                hd->params[HVM_PARAM_VMPORT_BUILD_NUMBER_TIME] = now_time;
> +                if (getLogMask(hd) & LOG_BUILD) {
> +                    snprintf(prefix, sizeof(prefix),
> +                             "VMware build %ld ", val);
> +                    vmport_safe_print(prefix, p - build, build);
> +                }
> +            }
> +        } else {
> +            unsigned int my_bkt = c->recv_read - 1;
> +            vmport_bucket_t *b;
> +            int stat = 100;
> +            int slot;
> +
> +            if (my_bkt >= VMPORT_MAX_BKTS)
> +                my_bkt = VMPORT_MAX_BKTS - 1;
> +            b = &c->recv_bkt[my_bkt];
> +            b->recv_len = 0;
> +            slot = b->recv_slot;
> +            if (slot < 1 || slot > 7)
> +                slot = 7;
> +            if ((c->send_len > 2) && ((c->send_buf[0] & 0xffff) == 0x4b4f))
> +                stat = 3;
> +            if (getLogMask(hd) & LOG_STATUS)
> +                gdprintk(XENLOG_DEBUG, "VMware %d,%d(%d) 
> getStatus[%d(%d)]=%d <== %d hex=0x%x\n",
> +                         c->chan_id, my_bkt, c->recv_read, slot, 
> b->recv_slot,
> +                         getStatus(hd)[slot], stat, c->send_buf[0] & 0xffff);
> +            getStatus(hd)[slot] = stat;
> +        }
> +    }
> +}
> +
> +void vmport_process_recv_size(struct hvm_domain *hd, vmport_channel_t *c, 
> struct cpu_user_regs *ur)
> +{
> +    vmport_bucket_t *b = &c->recv_bkt[c->recv_read];
> +
> +    if ((getLogMask(hd) & LOG_RECV_SIZE_ALL) ||
> +        ((getLogMask(hd) & LOG_RECV_SIZE) && (b->recv_len)))
> +        gdprintk(XENLOG_DEBUG, "VMware RECVSIZE %d is %d.\n",
> +                 c->chan_id, b->recv_len);
> +
> +    if (b->recv_len) {
> +        ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_DORECV | 
> MESSAGE_STATUS_SUCCESS);
> +        ur->edx = setHighBits(ur->edx, MESSAGE_TYPE_SENDSIZE);
> +        ur->ebx = b->recv_len;
> +    } else {
> +        ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS);
> +    }
> +}
> +
> +void vmport_process_recv_payload(struct hvm_domain *hd, vmport_channel_t *c, 
> struct cpu_user_regs *ur)
> +{
> +    vmport_bucket_t *b = &c->recv_bkt[c->recv_read];
> +
> +    if (b->recv_idx < VMPORT_MAX_RECV_BUF) {
> +        ur->ebx = b->recv_buf[b->recv_idx++];
> +    } else {
> +        ur->ebx = 0;
> +    }
> +    ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS);
> +    ur->edx = setHighBits(ur->edx, MESSAGE_TYPE_SENDPAYLOAD);
> +}
> +
> +void vmport_process_recv_status(struct hvm_domain *hd, vmport_channel_t *c, 
> struct cpu_user_regs *ur)
> +{
> +    vmport_bucket_t *b = &c->recv_bkt[c->recv_read];
> +    char prefix[30];
> +
> +    ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS);
> +    if (getLogMask(hd) & LOG_RECV_STATUS) {
> +        snprintf(prefix, sizeof(prefix),
> +                 "VMware RECVSTATUS %d (%d) ", c->chan_id, c->recv_read);
> +        prefix[sizeof(prefix)-1] = 0;
> +        vmport_safe_print(prefix, b->recv_len, (char*)b->recv_buf);
> +    }
> +    getStatus(hd)[b->recv_slot] = 2;
> +    if (getLogMask(hd) & LOG_STATUS)
> +        gdprintk(XENLOG_DEBUG, "VMware %d,%d getStatus[%d]=2\n",
> +                 c->chan_id, c->recv_read, b->recv_slot);
> +    c->recv_read++;
> +    if (c->recv_read >= VMPORT_MAX_BKTS)
> +        c->recv_read = 0;
> +}
> +
> +void vmport_process_close(struct hvm_domain *hd, vmport_channel_t *c, struct 
> cpu_user_regs *ur)
> +{
> +    // Return channel to free pool
> +    c->proto_num = 0;
> +    ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS);
> +    if (getLogMask(hd) & LOG_CLOSE)
> +        gdprintk(XENLOG_DEBUG, "VMware CLOSE %d.\n",
> +                 c->chan_id);
> +    if (getLogMask(hd) & LOG_STATUS)
> +        gdprintk(XENLOG_DEBUG, "VMware %d getStatus[0]=0x%x & ~0x%x=0x%x\n",
> +                 c->chan_id, getStatus(hd)[0], 1 << c->chan_id, ~(1 << 
> c->chan_id));
> +    getStatus(hd)[0] &= ~(1 << c->chan_id);
> +}
> +
> +void vmport_process_packet(struct hvm_domain *hd, vmport_channel_t *c,
> +                           struct cpu_user_regs *ur, int sub_cmd,
> +                           unsigned long now_time)
> +{
> +    c->active_time = now_time;
> +    switch (sub_cmd) {
> +    case MESSAGE_TYPE_SENDSIZE:
> +        vmport_process_send_size(hd, c, ur);
> +        break;
> +    case MESSAGE_TYPE_SENDPAYLOAD:
> +        vmport_process_send_payload(hd, c, ur, now_time);
> +        break;
> +
> +    case MESSAGE_TYPE_RECVSIZE:
> +        vmport_process_recv_size(hd, c, ur);
> +        break;
> +    case MESSAGE_TYPE_RECVPAYLOAD:
> +        vmport_process_recv_payload(hd, c, ur);
> +        break;
> +    case MESSAGE_TYPE_RECVSTATUS:
> +        vmport_process_recv_status(hd, c, ur);
> +        break;
> +
> +    case MESSAGE_TYPE_CLOSE:
> +        vmport_process_close(hd, c, ur);
> +        break;
> +
> +    default:
> +        ur->ecx = 0;
> +        break;
> +    }
> +}
> +
> +void vmport_rpc(struct hvm_domain *hd, struct cpu_user_regs *ur)
> +{
> +    int sub_cmd = (ur->ecx >> 16) & 0xffff;
> +    vmport_channel_t *c = NULL;
> +    uint16_t msg_id;
> +    uint32_t msg_cookie;
> +    unsigned long now_time = get_sec();
> +    long delta = now_time - hd->vmport_data->ping_time;
> +
> +    if ( delta >= hd->params[HVM_PARAM_VMPORT_RESET_TIME] ) {
> +        if (getLogMask(hd) & LOG_PING)
> +            gdprintk(XENLOG_DEBUG, "VMware ping. delta=%ld\n",
> +                     delta);
> +        vmport_ctrl_send(hd, "reset", 7);
> +    }
> +    spin_lock(&hd->vmport_lock);
> +    vmport_sweep(hd, now_time);
> +    do {
> +        // Check to see if a new open request is happening...
> +        if (MESSAGE_TYPE_OPEN == sub_cmd) {
> +            c = vmport_new_chan(hd->vmport_data, now_time);
> +            if (NULL == c) {
> +                if (getLogMask(hd) & LOG_ERROR)
> +                    gdprintk(XENLOG_ERR, "VMware failed to find a free 
> channel.\n");
> +                break;
> +            }
> +
> +            // Attach the apropriate protocol the the channel
> +            c->proto_num = ur->ebx & ~GUESTMSG_FLAG_COOKIE;
> +            ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS);
> +            ur->edx = setHighBits(ur->edx, c->chan_id);
> +            ur->edi = getLowBits(c->cookie);
> +            ur->esi = getHighBits(c->cookie);
> +            if (getLogMask(hd) & LOG_OPEN)
> +                gdprintk(XENLOG_DEBUG, "VMware OPEN %d p=%x.\n",
> +                         c->chan_id, c->proto_num);
> +            if (getLogMask(hd) & LOG_STATUS)
> +                gdprintk(XENLOG_DEBUG, "VMware %d getStatus[0]=0x%x | 
> 0x%x\n",
> +                         c->chan_id, getStatus(hd)[0], 1 << c->chan_id);
> +            getStatus(hd)[0] |= 1 << c->chan_id;
> +            if (c->proto_num == 0x4f4c4354) {
> +                vmport_send(hd, c, "reset", 6);
> +            }
> +            break;
> +        }
> +
> +        msg_id = getHighBits(ur->edx);
> +        msg_cookie = getLowBits(ur->edi) | (ur->esi << 16);
> +        if (msg_id >= VMPORT_MAX_CHANS) {
> +            if (getLogMask(hd) & LOG_ERROR)
> +                gdprintk(XENLOG_ERR, "VMware chan id err %d >= %d.\n",
> +                         msg_id, VMPORT_MAX_CHANS);
> +            break;
> +        }
> +        c = &hd->vmport_data->chans[msg_id];
> +        if (!c->proto_num) {
> +            if (getLogMask(hd) & LOG_ERROR)
> +                gdprintk(XENLOG_ERR, "VMware chan %d not open.\n",
> +                         msg_id);
> +            break;
> +        }
> +
> +        // We check the cookie here since it's possible that the
> +        // connection timed out on us and another channel was opened
> +        // if this happens, return error and the um tool will
> +        // need to reopen the connection
> +        if (msg_cookie != c->cookie) {
> +            if (getLogMask(hd) & LOG_ERROR)
> +                gdprintk(XENLOG_ERR, "VMware cookie err %x vs %x.\n",
> +                         msg_cookie, c->cookie);
> +            break;
> +        }
> +        vmport_process_packet(hd, c, ur, sub_cmd, now_time);
> +    } while( 0 );
> +
> +    if( NULL == c )
> +        ur->ecx = setHighBits(ur->ecx, 0);
> +
> +    spin_unlock(&hd->vmport_lock);
> +}
> +
> +int vmport_ioport(int dir, int size, unsigned long data, struct 
> cpu_user_regs *regs)
> +{
> +    uint32_t cmd = getLowBits(regs->ecx);
> +    uint32_t magic = regs->eax;
> +    struct hvm_domain *hd = &current->domain->arch.hvm_domain;
> +
> +    if ( dir != IOREQ_WRITE )
> +        data = 0;
> +
> +    if (magic == BDOOR_MAGIC) {
> +        const uint32_t apicHz = 1000000000L;

Again this hard coded constant.

> +        uint64_t value;
> +
> +        switch (cmd) {
> +        case BDOOR_CMD_GETMHZ:
> +            /* ... */
> +            regs->ebx = BDOOR_MAGIC;
> +            regs->eax = (uint32_t)(current->domain->arch.tsc_khz / 1000);
> +            break;
> +        case BDOOR_CMD_GETVERSION:
> +            /* ... */
> +            regs->ebx = BDOOR_MAGIC;
> +            /* VERSION_MAGIC */
> +            regs->eax = 6;
> +            /* Claim we are an ESX. VMX_TYPE_SCALABLE_SERVER */
> +            regs->ecx = 2;
> +            break;
> +        case BDOOR_CMD_GETHWVERSION:
> +            /* ... */
> +            regs->ebx = BDOOR_MAGIC;
> +            /* ?? */
> +            regs->eax = 0x4;
> +            break;
> +        case BDOOR_CMD_GETHZ:
> +            value = current->domain->arch.tsc_khz * 1000;
> +            /* apic-frequency (bus speed) */
> +            regs->ecx = apicHz;
> +            /* High part of tsc-frequency */
> +            regs->ebx = (uint32_t)(value >> 32);
> +            /* Low part of tsc-frequency */
> +            regs->eax = (uint32_t)value;
> +            break;
> +        case BDOOR_CMD_GETTIME:
> +            value = get_localtime_us(current->domain);
> +            /* hostUsecs */
> +            regs->ebx = (uint32_t)(value % 1000000UL);
> +            /* hostSecs */
> +            regs->eax = (uint32_t)(value / 1000000ULL);
> +            /* maxTimeLag */
> +            regs->ecx = 0;
> +            break;
> +        case BDOOR_CMD_GETTIMEFULL:
> +            value = get_localtime_us(current->domain);
> +            /* ... */
> +            regs->eax = BDOOR_MAGIC;
> +            /* hostUsecs */
> +            regs->ebx = (uint32_t)(value % 1000000UL);
> +            /* High part of hostSecs */
> +            regs->esi = (uint32_t)((value / 1000000ULL) >> 32);
> +            /* Low part of hostSecs */
> +            regs->edx = (uint32_t)(value / 1000000ULL);
> +            /* maxTimeLag */
> +            regs->ecx = 0;
> +            break;
> +        case BDOOR_CMD_MESSAGE:
> +            vmport_rpc(hd, regs);
> +            break;
> +
> +        default:
> +            if (getLogMask(hd) & LOG_ERROR)
> +                gdprintk(XENLOG_DEBUG, "VMware size=%d dir=%d data=%lx 
> cmd=%d.\n",
> +                         size, dir, data, cmd);
> +            break;
> +        }
> +        if (getLogMask(hd) & LOG_TRACE)
> +            gdprintk(XENLOG_DEBUG, "VMware ip=%lx cmd=%d ax=%lx bx=%lx 
> cx=%lx dx=%lx si=%lx di=%lx\n",
> +                     (unsigned long)regs->eip, cmd,
> +                     (unsigned long)regs->eax, (unsigned long)regs->ebx,
> +                     (unsigned long)regs->ecx, (unsigned long)regs->edx,
> +                     (unsigned long)regs->esi, (unsigned long)regs->edi);
> +    } else
> +        if (getLogMask(hd) & LOG_ERROR)
> +            gdprintk(XENLOG_ERR, "Not VMware %x vs %x vs %x; ip=%lx ax=%lx 
> bx=%lx cx=%lx dx=%lx si=%lx di=%lx\n",
> +                     magic, BDOOR_MAGIC, VMPORT_MAGIC,
> +                     (unsigned long)regs->eip,
> +                     (unsigned long)regs->eax, (unsigned long)regs->ebx,
> +                     (unsigned long)regs->ecx, (unsigned long)regs->edx,
> +                     (unsigned long)regs->esi, (unsigned long)regs->edi);
> +
> +    if (dir == IOREQ_READ)
> +        HVMTRACE_ND(IOPORT_READ, 0, 1/*cycles*/, 5, VMPORT_PORT, cmd,
> +                    regs->eax, regs->ebx, regs->ecx, 0);
> +    else
> +        HVMTRACE_ND(IOPORT_WRITE, 0, 1/*cycles*/, 5, VMPORT_PORT, cmd,
> +                    regs->eax, regs->ebx, regs->ecx, 0);
> +
> +    return 1;
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-set-style: "BSD"
> + * c-basic-offset: 4
> + * tab-width: 4
> + * indent-tabs-mode: nil
> + * End:
> + */

Frankly, this while file is quite nasty.  There is a huge amount of
pointer arithmetic and array indexing with guest data, which doesn't
appear at a glance to have sufficient validation.

The vast majority of the ints should be unsigned as they are used as
indices.  All the times should probably be s_time_t's

The idiom

if ( getLogMask(hd) & LOG_$SOMETHING )
    gdprintk(XENLOG_$SOMETHING, ...);

Can probably be moved into a single macro, which will simply the reading
of the code quite a bit.

Is there a spec for what this code is trying to accomplish?  Some of the
comments suggest that it has been reverse engineered?

I think I have counted 4 coding styles in there.  Given the Xen block on
the bottom, can it settle on a single style.

> diff --git a/xen/arch/x86/hvm/vmport/xen_vmport_def.h 
> b/xen/arch/x86/hvm/vmport/xen_vmport_def.h
> new file mode 100644
> index 0000000..e87845b
> --- /dev/null
> +++ b/xen/arch/x86/hvm/vmport/xen_vmport_def.h
> @@ -0,0 +1,36 @@
> +/*
> + * xen_vmport_def.h: HVM VMPORT emulation
> + *
> + *
> + * Copyright (C) 2012 Verizon Corporation
> + *
> + * This file is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License Version 2 (GPLv2)
> + * as published by the Free Software Foundation.
> + *
> + * This file is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * General Public License for more details. <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef __XEN_VMPORT_DEF_H__
> +#define __XEN_VMPORT_DEF_H__
> +
> +#include <xen/config.h>
> +#include <xen/init.h>
> +#include <xen/mm.h>
> +#include <xen/lib.h>
> +#include <xen/errno.h>
> +#include <xen/trace.h>
> +#include <xen/event.h>
> +#include <xen/hypercall.h>
> +#include <asm/current.h>
> +#include <asm/cpufeature.h>
> +#include <asm/processor.h>
> +#include <asm/hvm/hvm.h>
> +#include <asm/hvm/support.h>
> +#include <asm/hvm/trace.h>
> +#include <asm/hvm/vmport.h>

What is the point of this header file?

> +
> +#endif
> diff --git a/xen/include/asm-x86/hvm/trace.h b/xen/include/asm-x86/hvm/trace.h
> index 9d7e00b..d5c3a3e 100644
> --- a/xen/include/asm-x86/hvm/trace.h
> +++ b/xen/include/asm-x86/hvm/trace.h
> @@ -52,8 +52,11 @@
>  #define DO_TRC_HVM_LMSW64      DEFAULT_HVM_MISC
>  #define DO_TRC_HVM_REALMODE_EMULATE DEFAULT_HVM_MISC 
>  #define DO_TRC_HVM_TRAP             DEFAULT_HVM_MISC
> +#define DO_TRC_HVM_TRAP64           DEFAULT_HVM_MISC
>  #define DO_TRC_HVM_TRAP_DEBUG       DEFAULT_HVM_MISC
>  #define DO_TRC_HVM_VLAPIC           DEFAULT_HVM_MISC
> +#define DO_TRC_HVM_IOPORT_READ      DEFAULT_HVM_IO
> +#define DO_TRC_HVM_IOPORT_WRITE     DEFAULT_HVM_IO

There are already traps for io ports, which I believe are part of the
generic vmexit traps.

~Andrew

>  
>  
>  #define TRC_PAR_LONG(par) ((par)&0xFFFFFFFF),((par)>>32)


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.