[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH 07/10] Add new vmport code.
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. + */ diff --git a/xen/arch/x86/hvm/vmport/vmport.c b/xen/arch/x86/hvm/vmport/vmport.c new file mode 100644 index 0000000..43bdf7b --- /dev/null +++ b/xen/arch/x86/hvm/vmport/vmport.c @@ -0,0 +1,719 @@ +/* + * HVM VMPORT emulation + * + * Copyright (C) 2012 Verizon Corporation + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 (GPLv2) + * as published by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. <http://www.gnu.org/licenses/>. + */ + +#include "xen_vmport_def.h" +#include "backdoor_def.h" +#include "guest_msg_def.h" +#include "asm-x86/hvm/support.h" + +#define LOG_RPC 0x0000001 +#define LOG_RECV_STATUS 0x0000002 +#define LOG_SKIP_SEND 0x0000004 +#define LOG_SEND 0x0000008 +#define LOG_SEND_SIZE_ALL 0x0000010 +#define LOG_SEND_SIZE 0x0000020 +#define LOG_RECV_SIZE_ALL 0x0000040 +#define LOG_RECV_SIZE 0x0000080 +#define LOG_CLOSE 0x0000100 +#define LOG_OPEN 0x0000200 +#define LOG_FLUSH 0x0000400 +#define LOG_TRACE 0x0000800 +#define LOG_PING 0x0001000 +#define LOG_SWEEP 0x0002000 +#define LOG_BUILD 0x0004000 +#define LOG_STATUS 0x0008000 + +#define LOG_ERROR 0x0010000 + +#define LOG_INFO_GET 0x0020000 +#define LOG_INFO_SET 0x0040000 + +#define LOG_GP_UNKNOWN 0x0100000 +#define LOG_GP_NOT_VMWARE 0x0200000 +#define LOG_GP_FAIL_RD_INST 0x0400000 +#define LOG_GP_VMWARE_AFTER 0x0800000 + +#define LOG_VGP_UNKNOWN 0x1000000 +#define LOG_REALMODE_GP 0x8000000 + +extern unsigned long get_sec(void); + +/* Note: VMPORT_PORT and VMPORT_MAGIC is also defined as BDOOR_PORT + * and BDOOR_MAGIC in backdoor_def.h Defined in vmport.h also. + */ + +inline uint16_t getLowBits(uint32_t bits) +{ + return bits & 0xffff; +} + +inline uint16_t getHighBits(uint32_t bits) +{ + return bits >> 16; +} + +inline uint32_t setHighBits(uint32_t b, uint32_t val) +{ + return (val << 16) | getLowBits(b); +} + +static inline long getLogMask(struct hvm_domain *hd) +{ + return hd->params[HVM_PARAM_VMPORT_LOGMASK]; +} + +static inline char *getStatus(struct hvm_domain *hd) +{ + return (char*)&hd->params[HVM_PARAM_VMPORT_STATUS]; +} + +void vmport_safe_print(char *prefix, int len, char *msg) +{ + unsigned char c; + int end = len; + int i,k; + char out[4*(VMPORT_MAX_SEND_BUF + 1)*3 + 6]; + + if (end > (sizeof(out)/3 - 6)) + end = sizeof(out)/3 - 6; + out[0] = '<'; + k = 1; + for (i = 0; i < end; i++) { + c = msg[i]; + if ((c == '^') || (c == '\\') || (c == '>')) { + out[k++] = '\\'; + out[k++] = c; + } else if ((c >= ' ') && (c <= '~')) { + out[k++] = c; + } else if (c < ' ') { + out[k++] = '^'; + out[k++] = c ^ 0x40; + } else { + snprintf(&out[k], sizeof(out) - k, "\\%02x", c); + k += 3; + } + } + out[k++] = '>'; + if (len > end) { + out[k++] = '.'; + out[k++] = '.'; + out[k++] = '.'; + } + out[k++] = 0; + gdprintk(XENLOG_DEBUG, "%s%d(%d,%d,%ld)%s\n", prefix, end, len, k, sizeof(out), out); +} + +void vmport_send(struct hvm_domain *hd, vmport_channel_t *c, char *msg, int slot) +{ + unsigned int cur_recv_len = strlen(msg) + 1; + char prefix[30]; + unsigned int my_bkt = c->recv_write; + unsigned int next_bkt = my_bkt + 1; + vmport_bucket_t *b; + + if (next_bkt >= VMPORT_MAX_BKTS) + next_bkt = 0; + + if (next_bkt == c->recv_read) { + if (getLogMask(hd) & LOG_SKIP_SEND) { + snprintf(prefix, sizeof(prefix), + "VMware _send skipped %d (%d, %d) ", c->chan_id, my_bkt, c->recv_read); + prefix[sizeof(prefix)-1] = 0; + vmport_safe_print(prefix, cur_recv_len, msg); + } + getStatus(hd)[slot] = 200; + if (getLogMask(hd) & LOG_STATUS) + gdprintk(XENLOG_DEBUG, "VMware %d getStatus[%d]=200\n", c->chan_id, slot); + return; + } + + c->recv_write = next_bkt; + b = &c->recv_bkt[my_bkt]; + if (getLogMask(hd) & LOG_SEND) { + snprintf(prefix, sizeof(prefix), + "VMware _send %d (%d) ", c->chan_id, my_bkt); + prefix[sizeof(prefix)-1] = 0; + vmport_safe_print(prefix, cur_recv_len, msg); + } + + b->recv_len = cur_recv_len; + b->recv_slot = slot; + b->recv_idx = 0; + memset(b->recv_buf, 0, sizeof(b->recv_buf)); + if (cur_recv_len >= (sizeof(b->recv_buf) - 1)) { + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_DEBUG, "VMware recv_len=%d >= %ld.\n", + cur_recv_len, sizeof(b->recv_buf) - 1); + cur_recv_len = sizeof(b->recv_buf) - 1; + } + memcpy(b->recv_buf, msg, cur_recv_len); + getStatus(hd)[b->recv_slot] = 1; + if (getLogMask(hd) & LOG_STATUS) + gdprintk(XENLOG_DEBUG, "VMware %d,%d getStatus[%d]=1\n", + c->chan_id, c->recv_read, b->recv_slot); +} + +void vmport_ctrl_send(struct hvm_domain *hd, char *msg, int slot) +{ + struct vmport_state *vs = hd->vmport_data; + int i; + + if (slot < 1 || slot > 7) + slot = 7; + hd->vmport_data->ping_time = get_sec(); + spin_lock(&hd->vmport_lock); + for (i = 0; i < VMPORT_MAX_CHANS; i++) { + if (vs->chans[i].proto_num == 0x4f4c4354) { + vmport_send(hd, &vs->chans[i], msg, slot); + } + } + spin_unlock(&hd->vmport_lock); +} + +void vmport_flush(struct hvm_domain *hd) +{ + if (getLogMask(hd) & LOG_FLUSH) + gdprintk(XENLOG_DEBUG, "VMware flush.\n"); + spin_lock(&hd->vmport_lock); + memset(&hd->vmport_data->chans, 0, sizeof(hd->vmport_data->chans)); + spin_unlock(&hd->vmport_lock); +} + +void vmport_sweep(struct hvm_domain *hd, unsigned long now_time) +{ + struct vmport_state *vs = hd->vmport_data; + int i; + + for (i = 0; i < VMPORT_MAX_CHANS; i++) { + if (vs->chans[i].proto_num) { + vmport_channel_t *c = &vs->chans[i]; + long delta = now_time - c->active_time; + + if ( delta >= 80 ) { + if (getLogMask(hd) & LOG_SWEEP) + gdprintk(XENLOG_DEBUG, "VMware flush %d. delta=%ld\n", + c->chan_id, delta); + // Return channel to free pool + c->proto_num = 0; + } + } + } +} + +vmport_channel_t *vmport_new_chan(struct vmport_state *vs, unsigned long now_time) +{ + int i; + + for (i = 0; i < VMPORT_MAX_CHANS; i++) { + if (!vs->chans[i].proto_num) { + vmport_channel_t *c = &vs->chans[i]; + + c->chan_id = i; + c->cookie = vs->open_cookie++; + c->active_time = now_time; + c->send_len = 0; + c->send_idx = 0; + c->recv_read = 0; + c->recv_write = 0; + return c; + } + } + return NULL; +} + +void vmport_process_send_size(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) +{ + // vmware tools often send a 0 byte request size. + c->send_len = ur->ebx; + c->send_idx = 0; + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + if ((getLogMask(hd) & LOG_SEND_SIZE_ALL) || + ((getLogMask(hd) & LOG_SEND_SIZE) && (c->send_len))) + gdprintk(XENLOG_DEBUG, "VMware SENDSIZE %d is %d.\n", + c->chan_id, c->send_len); +} + +void vmport_process_send_payload(struct hvm_domain *hd, vmport_channel_t *c, + struct cpu_user_regs *ur, unsigned long now_time) +{ + char prefix[30]; + + if (c->send_idx < VMPORT_MAX_SEND_BUF) { + c->send_buf[c->send_idx] = ur->ebx; + } + c->send_idx++; + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + if (c->send_idx * 4 >= c->send_len) { + if (c->send_idx < VMPORT_MAX_SEND_BUF) + ((char*)c->send_buf)[c->send_len] = 0; + if (getLogMask(hd) & LOG_RPC) { + snprintf(prefix, sizeof(prefix), + "VMware RPC %d (%d) ", c->chan_id, c->recv_read); + prefix[sizeof(prefix)-1] = 0; + vmport_safe_print(prefix, c->send_len, (char*)c->send_buf); + } + if (c->proto_num == 0x49435052) { +/* log toolbox: Version: build-341836 */ +/* SetGuestInfo 4 build-341836 */ +/* info-get guestinfo.ip */ +/* info-set guestinfo.ip joe */ + char * build = NULL; + char * info_key = NULL; + char * ret_msg = "1 "; + char ret_buffer[2 + VMPORT_MAX_VAL_LEN + 2]; + + if (strncmp((char*)c->send_buf, "log toolbox: Version: build-", + strlen("log toolbox: Version: build-")) == 0) { + build = (char*)c->send_buf + strlen("log toolbox: Version: build-"); + } else if (strncmp((char*)c->send_buf, "SetGuestInfo 4 build-", + strlen("SetGuestInfo 4 build-")) == 0) { + build = (char*)c->send_buf + strlen("SetGuestInfo 4 build-"); + } else if (strncmp((char*)c->send_buf, "info-get guestinfo.", + strlen("info-get guestinfo.")) == 0) { + int keyLen = c->send_len - strlen("info-get guestinfo."); + int idx; + struct vmport_state *vs = hd->vmport_data; + + info_key = (char*)c->send_buf + strlen("info-get guestinfo."); + if (getLogMask(hd) & LOG_INFO_GET) { + snprintf(prefix, sizeof(prefix), + "VMware info-get key:"); + vmport_safe_print(prefix, keyLen, info_key); + } + if (keyLen <= VMPORT_MAX_KEY_LEN) { + for (idx = 0; idx < vs->used_guestinfo; idx++) { + if ((vs->guestinfo[idx]->key_len == keyLen) && + (memcmp(info_key, + vs->guestinfo[idx]->key_data, + vs->guestinfo[idx]->key_len) == 0)) { + if (getLogMask(hd) & LOG_INFO_GET) { + snprintf(prefix, sizeof(prefix), + "VMware info-get val:"); + vmport_safe_print(prefix, + vs->guestinfo[idx]->val_len, + vs->guestinfo[idx]->val_data); + } + snprintf(ret_buffer, sizeof(ret_buffer) - 1, "1 %.*s", + (int)vs->guestinfo[idx]->val_len, + vs->guestinfo[idx]->val_data); + ret_msg = ret_buffer; + break; + } + } + if (idx >= vs->used_guestinfo) { + ret_msg = "0 No value found"; + } + } else { + ret_msg = "0 Key is too long"; + } + } else if (strncmp((char*)c->send_buf, "info-set guestinfo.", + strlen("info-set guestinfo.")) == 0) { + char * val; + int rest_len = c->send_len - strlen("info-set guestinfo."); + + info_key = (char*)c->send_buf + strlen("info-set guestinfo."); + val = strstr(info_key, " "); + if (val) { + int keyLen = val - info_key; + int valLen = rest_len - keyLen - 1; + int free_idx = -1; + int idx; + struct vmport_state *vs = hd->vmport_data; + + val++; + if (getLogMask(hd) & LOG_INFO_SET) { + snprintf(prefix, sizeof(prefix), + "VMware info-set key:"); + vmport_safe_print(prefix, keyLen, info_key); + snprintf(prefix, sizeof(prefix), + "VMware info-set val:"); + vmport_safe_print(prefix, valLen, val); + } + if (keyLen <= VMPORT_MAX_KEY_LEN) { + if (valLen <= VMPORT_MAX_VAL_LEN) { + for (idx = 0; idx < vs->used_guestinfo; idx++) { + if (!vs->guestinfo[idx]) { + gdprintk(XENLOG_WARNING, "idx=%d not allocated, but used_guestinfo=%d\n", + idx, vs->used_guestinfo); + } else if ((vs->guestinfo[idx]->key_len == keyLen) && + (memcmp(info_key, + vs->guestinfo[idx]->key_data, + vs->guestinfo[idx]->key_len) == 0)) { + vs->guestinfo[idx]->val_len = valLen; + memcpy(vs->guestinfo[idx]->val_data, val, valLen); + break; + } else if ((vs->guestinfo[idx]->key_len == 0) && + (free_idx == -1)) { + free_idx = idx; + } + } + if (idx >= vs->used_guestinfo) { + if (free_idx == -1) { + ret_msg = "0 Too many keys"; + } else { + vs->guestinfo[free_idx]->key_len = keyLen; + memcpy(vs->guestinfo[free_idx]->key_data, info_key, keyLen); + vs->guestinfo[free_idx]->val_len = valLen; + memcpy(vs->guestinfo[free_idx]->val_data, val, valLen); + } + } + } else { + ret_msg = "0 Value too long"; + } + } else { + ret_msg = "0 Key is too long"; + } + } else { + if (getLogMask(hd) & LOG_INFO_SET) { + snprintf(prefix, sizeof(prefix), + "VMware info-set missing val; key:"); + vmport_safe_print(prefix, rest_len, info_key); + } + ret_msg = "0 Two and exactly two arguments expected"; + } + } + + vmport_send(hd, c, ret_msg, 5); + if (build) { + long val = 0; + char *p = build; + + while (*p) { + if (*p < '0' || *p > '9') + break; + val = val * 10 + *p - '0'; + p++; + }; + + hd->params[HVM_PARAM_VMPORT_BUILD_NUMBER_VALUE] = val; + hd->params[HVM_PARAM_VMPORT_BUILD_NUMBER_TIME] = now_time; + if (getLogMask(hd) & LOG_BUILD) { + snprintf(prefix, sizeof(prefix), + "VMware build %ld ", val); + vmport_safe_print(prefix, p - build, build); + } + } + } else { + unsigned int my_bkt = c->recv_read - 1; + vmport_bucket_t *b; + int stat = 100; + int slot; + + if (my_bkt >= VMPORT_MAX_BKTS) + my_bkt = VMPORT_MAX_BKTS - 1; + b = &c->recv_bkt[my_bkt]; + b->recv_len = 0; + slot = b->recv_slot; + if (slot < 1 || slot > 7) + slot = 7; + if ((c->send_len > 2) && ((c->send_buf[0] & 0xffff) == 0x4b4f)) + stat = 3; + if (getLogMask(hd) & LOG_STATUS) + gdprintk(XENLOG_DEBUG, "VMware %d,%d(%d) getStatus[%d(%d)]=%d <== %d hex=0x%x\n", + c->chan_id, my_bkt, c->recv_read, slot, b->recv_slot, + getStatus(hd)[slot], stat, c->send_buf[0] & 0xffff); + getStatus(hd)[slot] = stat; + } + } +} + +void vmport_process_recv_size(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) +{ + vmport_bucket_t *b = &c->recv_bkt[c->recv_read]; + + if ((getLogMask(hd) & LOG_RECV_SIZE_ALL) || + ((getLogMask(hd) & LOG_RECV_SIZE) && (b->recv_len))) + gdprintk(XENLOG_DEBUG, "VMware RECVSIZE %d is %d.\n", + c->chan_id, b->recv_len); + + if (b->recv_len) { + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_DORECV | MESSAGE_STATUS_SUCCESS); + ur->edx = setHighBits(ur->edx, MESSAGE_TYPE_SENDSIZE); + ur->ebx = b->recv_len; + } else { + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + } +} + +void vmport_process_recv_payload(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) +{ + vmport_bucket_t *b = &c->recv_bkt[c->recv_read]; + + if (b->recv_idx < VMPORT_MAX_RECV_BUF) { + ur->ebx = b->recv_buf[b->recv_idx++]; + } else { + ur->ebx = 0; + } + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + ur->edx = setHighBits(ur->edx, MESSAGE_TYPE_SENDPAYLOAD); +} + +void vmport_process_recv_status(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) +{ + vmport_bucket_t *b = &c->recv_bkt[c->recv_read]; + char prefix[30]; + + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + if (getLogMask(hd) & LOG_RECV_STATUS) { + snprintf(prefix, sizeof(prefix), + "VMware RECVSTATUS %d (%d) ", c->chan_id, c->recv_read); + prefix[sizeof(prefix)-1] = 0; + vmport_safe_print(prefix, b->recv_len, (char*)b->recv_buf); + } + getStatus(hd)[b->recv_slot] = 2; + if (getLogMask(hd) & LOG_STATUS) + gdprintk(XENLOG_DEBUG, "VMware %d,%d getStatus[%d]=2\n", + c->chan_id, c->recv_read, b->recv_slot); + c->recv_read++; + if (c->recv_read >= VMPORT_MAX_BKTS) + c->recv_read = 0; +} + +void vmport_process_close(struct hvm_domain *hd, vmport_channel_t *c, struct cpu_user_regs *ur) +{ + // Return channel to free pool + c->proto_num = 0; + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + if (getLogMask(hd) & LOG_CLOSE) + gdprintk(XENLOG_DEBUG, "VMware CLOSE %d.\n", + c->chan_id); + if (getLogMask(hd) & LOG_STATUS) + gdprintk(XENLOG_DEBUG, "VMware %d getStatus[0]=0x%x & ~0x%x=0x%x\n", + c->chan_id, getStatus(hd)[0], 1 << c->chan_id, ~(1 << c->chan_id)); + getStatus(hd)[0] &= ~(1 << c->chan_id); +} + +void vmport_process_packet(struct hvm_domain *hd, vmport_channel_t *c, + struct cpu_user_regs *ur, int sub_cmd, + unsigned long now_time) +{ + c->active_time = now_time; + switch (sub_cmd) { + case MESSAGE_TYPE_SENDSIZE: + vmport_process_send_size(hd, c, ur); + break; + case MESSAGE_TYPE_SENDPAYLOAD: + vmport_process_send_payload(hd, c, ur, now_time); + break; + + case MESSAGE_TYPE_RECVSIZE: + vmport_process_recv_size(hd, c, ur); + break; + case MESSAGE_TYPE_RECVPAYLOAD: + vmport_process_recv_payload(hd, c, ur); + break; + case MESSAGE_TYPE_RECVSTATUS: + vmport_process_recv_status(hd, c, ur); + break; + + case MESSAGE_TYPE_CLOSE: + vmport_process_close(hd, c, ur); + break; + + default: + ur->ecx = 0; + break; + } +} + +void vmport_rpc(struct hvm_domain *hd, struct cpu_user_regs *ur) +{ + int sub_cmd = (ur->ecx >> 16) & 0xffff; + vmport_channel_t *c = NULL; + uint16_t msg_id; + uint32_t msg_cookie; + unsigned long now_time = get_sec(); + long delta = now_time - hd->vmport_data->ping_time; + + if ( delta >= hd->params[HVM_PARAM_VMPORT_RESET_TIME] ) { + if (getLogMask(hd) & LOG_PING) + gdprintk(XENLOG_DEBUG, "VMware ping. delta=%ld\n", + delta); + vmport_ctrl_send(hd, "reset", 7); + } + spin_lock(&hd->vmport_lock); + vmport_sweep(hd, now_time); + do { + // Check to see if a new open request is happening... + if (MESSAGE_TYPE_OPEN == sub_cmd) { + c = vmport_new_chan(hd->vmport_data, now_time); + if (NULL == c) { + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_ERR, "VMware failed to find a free channel.\n"); + break; + } + + // Attach the apropriate protocol the the channel + c->proto_num = ur->ebx & ~GUESTMSG_FLAG_COOKIE; + ur->ecx = setHighBits(ur->ecx, MESSAGE_STATUS_SUCCESS); + ur->edx = setHighBits(ur->edx, c->chan_id); + ur->edi = getLowBits(c->cookie); + ur->esi = getHighBits(c->cookie); + if (getLogMask(hd) & LOG_OPEN) + gdprintk(XENLOG_DEBUG, "VMware OPEN %d p=%x.\n", + c->chan_id, c->proto_num); + if (getLogMask(hd) & LOG_STATUS) + gdprintk(XENLOG_DEBUG, "VMware %d getStatus[0]=0x%x | 0x%x\n", + c->chan_id, getStatus(hd)[0], 1 << c->chan_id); + getStatus(hd)[0] |= 1 << c->chan_id; + if (c->proto_num == 0x4f4c4354) { + vmport_send(hd, c, "reset", 6); + } + break; + } + + msg_id = getHighBits(ur->edx); + msg_cookie = getLowBits(ur->edi) | (ur->esi << 16); + if (msg_id >= VMPORT_MAX_CHANS) { + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_ERR, "VMware chan id err %d >= %d.\n", + msg_id, VMPORT_MAX_CHANS); + break; + } + c = &hd->vmport_data->chans[msg_id]; + if (!c->proto_num) { + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_ERR, "VMware chan %d not open.\n", + msg_id); + break; + } + + // We check the cookie here since it's possible that the + // connection timed out on us and another channel was opened + // if this happens, return error and the um tool will + // need to reopen the connection + if (msg_cookie != c->cookie) { + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_ERR, "VMware cookie err %x vs %x.\n", + msg_cookie, c->cookie); + break; + } + vmport_process_packet(hd, c, ur, sub_cmd, now_time); + } while( 0 ); + + if( NULL == c ) + ur->ecx = setHighBits(ur->ecx, 0); + + spin_unlock(&hd->vmport_lock); +} + +int vmport_ioport(int dir, int size, unsigned long data, struct cpu_user_regs *regs) +{ + uint32_t cmd = getLowBits(regs->ecx); + uint32_t magic = regs->eax; + struct hvm_domain *hd = ¤t->domain->arch.hvm_domain; + + if ( dir != IOREQ_WRITE ) + data = 0; + + if (magic == BDOOR_MAGIC) { + const uint32_t apicHz = 1000000000L; + uint64_t value; + + switch (cmd) { + case BDOOR_CMD_GETMHZ: + /* ... */ + regs->ebx = BDOOR_MAGIC; + regs->eax = (uint32_t)(current->domain->arch.tsc_khz / 1000); + break; + case BDOOR_CMD_GETVERSION: + /* ... */ + regs->ebx = BDOOR_MAGIC; + /* VERSION_MAGIC */ + regs->eax = 6; + /* Claim we are an ESX. VMX_TYPE_SCALABLE_SERVER */ + regs->ecx = 2; + break; + case BDOOR_CMD_GETHWVERSION: + /* ... */ + regs->ebx = BDOOR_MAGIC; + /* ?? */ + regs->eax = 0x4; + break; + case BDOOR_CMD_GETHZ: + value = current->domain->arch.tsc_khz * 1000; + /* apic-frequency (bus speed) */ + regs->ecx = apicHz; + /* High part of tsc-frequency */ + regs->ebx = (uint32_t)(value >> 32); + /* Low part of tsc-frequency */ + regs->eax = (uint32_t)value; + break; + case BDOOR_CMD_GETTIME: + value = get_localtime_us(current->domain); + /* hostUsecs */ + regs->ebx = (uint32_t)(value % 1000000UL); + /* hostSecs */ + regs->eax = (uint32_t)(value / 1000000ULL); + /* maxTimeLag */ + regs->ecx = 0; + break; + case BDOOR_CMD_GETTIMEFULL: + value = get_localtime_us(current->domain); + /* ... */ + regs->eax = BDOOR_MAGIC; + /* hostUsecs */ + regs->ebx = (uint32_t)(value % 1000000UL); + /* High part of hostSecs */ + regs->esi = (uint32_t)((value / 1000000ULL) >> 32); + /* Low part of hostSecs */ + regs->edx = (uint32_t)(value / 1000000ULL); + /* maxTimeLag */ + regs->ecx = 0; + break; + case BDOOR_CMD_MESSAGE: + vmport_rpc(hd, regs); + break; + + default: + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_DEBUG, "VMware size=%d dir=%d data=%lx cmd=%d.\n", + size, dir, data, cmd); + break; + } + if (getLogMask(hd) & LOG_TRACE) + gdprintk(XENLOG_DEBUG, "VMware ip=%lx cmd=%d ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx\n", + (unsigned long)regs->eip, cmd, + (unsigned long)regs->eax, (unsigned long)regs->ebx, + (unsigned long)regs->ecx, (unsigned long)regs->edx, + (unsigned long)regs->esi, (unsigned long)regs->edi); + } else + if (getLogMask(hd) & LOG_ERROR) + gdprintk(XENLOG_ERR, "Not VMware %x vs %x vs %x; ip=%lx ax=%lx bx=%lx cx=%lx dx=%lx si=%lx di=%lx\n", + magic, BDOOR_MAGIC, VMPORT_MAGIC, + (unsigned long)regs->eip, + (unsigned long)regs->eax, (unsigned long)regs->ebx, + (unsigned long)regs->ecx, (unsigned long)regs->edx, + (unsigned long)regs->esi, (unsigned long)regs->edi); + + if (dir == IOREQ_READ) + HVMTRACE_ND(IOPORT_READ, 0, 1/*cycles*/, 5, VMPORT_PORT, cmd, + regs->eax, regs->ebx, regs->ecx, 0); + else + HVMTRACE_ND(IOPORT_WRITE, 0, 1/*cycles*/, 5, VMPORT_PORT, cmd, + regs->eax, regs->ebx, regs->ecx, 0); + + return 1; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/x86/hvm/vmport/xen_vmport_def.h b/xen/arch/x86/hvm/vmport/xen_vmport_def.h new file mode 100644 index 0000000..e87845b --- /dev/null +++ b/xen/arch/x86/hvm/vmport/xen_vmport_def.h @@ -0,0 +1,36 @@ +/* + * xen_vmport_def.h: HVM VMPORT emulation + * + * + * Copyright (C) 2012 Verizon Corporation + * + * This file is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License Version 2 (GPLv2) + * as published by the Free Software Foundation. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. <http://www.gnu.org/licenses/>. + */ + +#ifndef __XEN_VMPORT_DEF_H__ +#define __XEN_VMPORT_DEF_H__ + +#include <xen/config.h> +#include <xen/init.h> +#include <xen/mm.h> +#include <xen/lib.h> +#include <xen/errno.h> +#include <xen/trace.h> +#include <xen/event.h> +#include <xen/hypercall.h> +#include <asm/current.h> +#include <asm/cpufeature.h> +#include <asm/processor.h> +#include <asm/hvm/hvm.h> +#include <asm/hvm/support.h> +#include <asm/hvm/trace.h> +#include <asm/hvm/vmport.h> + +#endif diff --git a/xen/include/asm-x86/hvm/trace.h b/xen/include/asm-x86/hvm/trace.h index 9d7e00b..d5c3a3e 100644 --- a/xen/include/asm-x86/hvm/trace.h +++ b/xen/include/asm-x86/hvm/trace.h @@ -52,8 +52,11 @@ #define DO_TRC_HVM_LMSW64 DEFAULT_HVM_MISC #define DO_TRC_HVM_REALMODE_EMULATE DEFAULT_HVM_MISC #define DO_TRC_HVM_TRAP DEFAULT_HVM_MISC +#define DO_TRC_HVM_TRAP64 DEFAULT_HVM_MISC #define DO_TRC_HVM_TRAP_DEBUG DEFAULT_HVM_MISC #define DO_TRC_HVM_VLAPIC DEFAULT_HVM_MISC +#define DO_TRC_HVM_IOPORT_READ DEFAULT_HVM_IO +#define DO_TRC_HVM_IOPORT_WRITE DEFAULT_HVM_IO #define TRC_PAR_LONG(par) ((par)&0xFFFFFFFF),((par)>>32) -- 1.8.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |