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

[Xen-devel] [PATCH v2 3/3] Add limited support of VMware's hyper-call



This is both a more complete support then in currently provided by
QEMU and/or KVM and less.  The missing part requires QEMU changes
and has been left out until the QEMU patches are accepted upstream.

VMware's hyper-call is also known as VMware Backdoor I/O Port.

Note: this support does not depend on vmware_hw being non-zero.

Summary is that VMware treats "IN EAX, DX" (or "OUT DX, EAX"; or
"inl %dx, %eax" in AT&T syntax ) to port 0x5658 specially.  Note:
since many operations return data in EAX, "OUT DX, EAX" does not
work for them on VMware, I did not support the "OUT DX, EAX", but it
would not be hard to add.

Also this instruction is allowed to be used from ring 3.  To
support this the vmexit for GP needs to be enabled.  I have not
fully tested that nested HVM is doing the right thing for this.

An open source example of using this is:

http://open-vm-tools.sourceforge.net/

Which only uses "IN EAX, DX".  Also

http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458

Lists just "inl (%%dx)" (I assume this is AT&T syntax and is the
same as "inl %dx, %eax").

The support included is enough to allow VMware tools to install in a
HVM domU and provide guestinfo support.  guestinfo support is
provide by what is known as VMware RPC support.  This guestinfo
support is provided via libxc.  libxl support has not be written.

Note: VMware RPC support is only available on HVM domU.

This interface is an extension of __HYPERVISOR_HVM_op.  It was
picked because xc_get_hvm_param() also uses it and VMware guest
info is a lot like a hvm param.

The HVMOP_get_vmport_guest_info is used by two libxc functions,
xc_get_vmport_guest_info and xc_fetch_vmport_guest_info.
xc_fetch_vmport_guest_info is designed to be used to fetch all
currently set guestinfo values.

To save on hypervisor heap memory, the guestinfo support in done in
two sizes, normal and jumbo.  Normal is used to handle up to 128
byte values and jumbo is used to handle up to 4096 byte values.

Since all this is work is done when the guest is doing a single
instruction; it was designed to not use the hypervisor heap to
allocate the memory at this time.  Instead a few are allocated at
the create domain time and during the xen's hyper-call to get or set
them.  This was picked in that if a tool stack is using the VMware
guest info support, it should be using either of both of the get and
set.  And so in this case the guest should only see an out of memory
error when the compile max amount of hypervisor heap memory is in
use.

Doing it this way does lead to a lot of pointer use and many
sub structures.

If the domU is running VMware tools, then the "build version" of
the tools is also available via xc_get_HVM_param().  This also
enables the use of new triggers that will use the VMware hyper-call
to do some limited control of the domU.  The most useful are
poweroff and reboot.  Since a guest process needs to be running
for these to work, a tool stack should check that the build version
is non zero before assuming these will work.

The 2 hvm param's HVM_PARAM_VMPORT_BUILD_NUMBER_TIME and
HVM_PARAM_VMPORT_BUILD_NUMBER_VALUE are how "build version" is
accessed.  These 2 params are only allowed to be set to zero.  The
HVM_PARAM_VMPORT_BUILD_NUMBER_TIME can be used to track the last
time the VMware tools in the guest responded.  One such use would
be the health of the tools in the guest.  The hvm param
HVM_PARAM_VMPORT_RESET_TIME controls how often to request them in
seconds minus 1.  The minus 1 is to handle to 0 case.  I.E. the
fastest that can be selected is every second.  The default is 4
times a minute.

The VMware RPC support includes the notion of channels that are
opened, active and closed.  All RPC messages sent via a channel
starts with normal ASCII text.  The message some times does include
binary data.

Currently there are 2 protocols defined for VMware RPC.  They
determine the direction for data flow, domU to tool stack or
tool stack to domU.

There is no provided interrupt for VMware RPC.

The VMware's hyper-call state is included in live migration and
save/restore.  Because the max size of the VMware guestinfo is
large, then data is compressed and expanded in the
vmport_save_domain_ctxt and vmport_load_domain_ctxt.

For a debug=y build there is a new command line option
vmport_debug=.  It enabled output to the console of various
stages of handling the "IN EAX, DX" instruction.  Most uses
are the summary ones that show complete RPC actions.

Signed-off-by: Don Slutz <dslutz@xxxxxxxxxxx>
---
 tools/libxc/xc_domain.c                      |  115 +++
 tools/libxc/xenctrl.h                        |   24 +
 tools/misc/xen-hvmctx.c                      |  229 ++++
 tools/xentrace/formats                       |    8 +
 xen/arch/x86/domctl.c                        |   34 +
 xen/arch/x86/hvm/Makefile                    |    1 +
 xen/arch/x86/hvm/hvm.c                       |  480 ++++++++-
 xen/arch/x86/hvm/io.c                        |    1 +
 xen/arch/x86/hvm/svm/emulate.c               |    3 +
 xen/arch/x86/hvm/svm/svm.c                   |   79 ++
 xen/arch/x86/hvm/svm/vmcb.c                  |    1 +
 xen/arch/x86/hvm/vmport/Makefile             |    1 +
 xen/arch/x86/hvm/vmport/includeCheck.h       |   17 +
 xen/arch/x86/hvm/vmport/vmport.c             | 1436 ++++++++++++++++++++++++++
 xen/arch/x86/hvm/vmx/vmcs.c                  |    1 +
 xen/arch/x86/hvm/vmx/vmx.c                   |   90 ++
 xen/arch/x86/hvm/vmx/vvmx.c                  |   14 +
 xen/include/asm-x86/hvm/domain.h             |    4 +
 xen/include/asm-x86/hvm/svm/emulate.h        |    1 +
 xen/include/asm-x86/hvm/trace.h              |   31 +
 xen/include/asm-x86/hvm/vmport.h             |   90 ++
 xen/include/public/arch-x86/hvm/save.h       |   39 +-
 xen/include/public/arch-x86/hvm/vmporttype.h |  105 ++
 xen/include/public/domctl.h                  |    3 +
 xen/include/public/hvm/hvm_op.h              |   18 +
 xen/include/public/hvm/params.h              |    5 +-
 xen/include/public/trace.h                   |    7 +
 27 files changed, 2834 insertions(+), 3 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/include/asm-x86/hvm/vmport.h
 create mode 100644 xen/include/public/arch-x86/hvm/vmporttype.h

diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index c67ac9a..24a72e9 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -1577,6 +1577,121 @@ int xc_hvm_set_ioreq_server_state(xc_interface *xch,
     return rc;
 }
 
+int xc_set_vmport_guest_info(xc_interface *handle,
+                             domid_t dom,
+                             unsigned int key_len,
+                             char *key,
+                             unsigned int val_len,
+                             char *val)
+{
+    DECLARE_HYPERCALL;
+    DECLARE_HYPERCALL_BUFFER(xen_hvm_vmport_guest_info_t, arg);
+    int rc;
+
+    if ( (key_len < 1) ||
+        (key_len > VMPORT_GUEST_INFO_KEY_MAX) ||
+        (val_len > VMPORT_GUEST_INFO_VAL_MAX) )
+        return -1;
+
+    arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
+    if ( arg == NULL )
+        return -1;
+
+    hypercall.op     = __HYPERVISOR_hvm_op;
+    hypercall.arg[0] = HVMOP_set_vmport_guest_info;
+    hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg);
+    arg->domid = dom;
+    arg->key_length = key_len;
+    arg->value_length = val_len;
+    memcpy(arg->data, key, key_len);
+    memcpy(&arg->data[key_len], val, val_len);
+    rc = do_xen_hypercall(handle, &hypercall);
+    xc_hypercall_buffer_free(handle, arg);
+    return rc;
+}
+
+int xc_get_vmport_guest_info(xc_interface *handle,
+                             domid_t dom,
+                             unsigned int key_len,
+                             char *key,
+                             unsigned int val_max,
+                             unsigned int *val_len,
+                             char *val)
+{
+    DECLARE_HYPERCALL;
+    DECLARE_HYPERCALL_BUFFER(xen_hvm_vmport_guest_info_t, arg);
+    int rc;
+
+    if ( (key_len < 1) ||
+        (key_len > VMPORT_GUEST_INFO_KEY_MAX) )
+        return -1;
+
+    arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
+
+    hypercall.op     = __HYPERVISOR_hvm_op;
+    hypercall.arg[0] = HVMOP_get_vmport_guest_info;
+    hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg);
+    arg->domid = dom;
+    arg->key_length = key_len;
+    arg->value_length = 0;
+    *val_len = 0;
+    memcpy(arg->data, key, key_len);
+    rc = do_xen_hypercall(handle, &hypercall);
+    if ( rc == 0 )
+    {
+        *val_len = arg->value_length;
+        if ( arg->value_length > val_max )
+            arg->value_length = val_max;
+        memcpy(val, &arg->data[key_len], arg->value_length);
+    }
+    xc_hypercall_buffer_free(handle, arg);
+    return rc;
+}
+
+int xc_fetch_vmport_guest_info(xc_interface *handle,
+                               domid_t dom,
+                               unsigned int idx,
+                               unsigned int key_max,
+                               unsigned int *key_len,
+                               char *key,
+                               unsigned int val_max,
+                               unsigned int *val_len,
+                               char *val)
+{
+    DECLARE_HYPERCALL;
+    DECLARE_HYPERCALL_BUFFER(xen_hvm_vmport_guest_info_t, arg);
+    int rc;
+
+    arg = xc_hypercall_buffer_alloc(handle, arg, sizeof(*arg));
+
+    hypercall.op     = __HYPERVISOR_hvm_op;
+    hypercall.arg[0] = HVMOP_get_vmport_guest_info;
+    hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(arg);
+    arg->domid = dom;
+    arg->key_length = 0;
+    arg->value_length = idx;
+    *key_len = 0;
+    *val_len = 0;
+    rc = do_xen_hypercall(handle, &hypercall);
+    if ( rc == 0 )
+    {
+        uint16_t val_off = arg->key_length;
+
+        *key_len = arg->key_length;
+        if ( arg->key_length > key_max )
+            arg->key_length = key_max;
+        memcpy(key, arg->data, arg->key_length);
+        *val_len = arg->value_length;
+        if ( arg->value_length > val_max )
+            arg->value_length = val_max;
+        memcpy(val,
+               &arg->data[val_off],
+               arg->value_length);
+    }
+    xc_hypercall_buffer_free(handle, arg);
+    return rc;
+}
+
 int xc_domain_setdebugging(xc_interface *xch,
                            uint32_t domid,
                            unsigned int enable)
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index 1c5d0db..6af3fd2 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -2009,6 +2009,30 @@ int xc_hvm_destroy_ioreq_server(xc_interface *xch,
                                 domid_t domid,
                                 ioservid_t id);
 
+int xc_set_vmport_guest_info(xc_interface *handle,
+                             domid_t dom,
+                             unsigned int key_len,
+                             char *key,
+                             unsigned int val_len,
+                             char *val);
+int xc_get_vmport_guest_info(xc_interface *handle,
+                             domid_t dom,
+                             unsigned int key_len,
+                             char *key,
+                             unsigned int val_max,
+                             unsigned int *val_len,
+                             char *val);
+int xc_fetch_vmport_guest_info(xc_interface *handle,
+                               domid_t dom,
+                               unsigned int idx,
+                               unsigned int key_max,
+                               unsigned int *key_len,
+                               char *key,
+                               unsigned int val_max,
+                               unsigned int *val_len,
+                               char *val);
+
+
 /* HVM guest pass-through */
 int xc_assign_device(xc_interface *xch,
                      uint32_t domid,
diff --git a/tools/misc/xen-hvmctx.c b/tools/misc/xen-hvmctx.c
index 5a69245..1abd2be 100644
--- a/tools/misc/xen-hvmctx.c
+++ b/tools/misc/xen-hvmctx.c
@@ -399,6 +399,225 @@ static void dump_tsc_adjust(void)
     printf("    TSC_ADJUST: tsc_adjust %" PRIx64 "\n", p.tsc_adjust);
 }
 
+static void dump_vmport(int vmport_size)
+{
+    int i;
+    HVM_SAVE_TYPE(VMPORT) *vp;
+    int64_t vmport_guestsize;
+    uint32_t vmport_used_guestinfo;
+    uint32_t vmport_used_guestinfo_jumbo;
+    uint8_t pb[vmport_size];
+    char *p;
+    int chans_size;
+
+    READ(pb);
+    vp = (void *)&pb;
+
+    p = vp->u.packed.packed_data;
+
+    vmport_guestsize = vp->used_guestsize;
+    chans_size = vmport_size - vmport_guestsize - (p - (char *)pb);
+    if ( chans_size < 0 )
+    {
+        fprintf(stderr, "*** VMPORT: bogus chans_size=%d should be >= 0\n"
+                "   vmport_size=%d vmport_guestsize=%d fixed_size=%ld\n",
+                chans_size, vmport_size, (int)vmport_guestsize,
+                p - (char *)pb);
+        chans_size = 0;
+    }
+
+    printf("    VMPORT: ping_time %" PRIu64 "\n", vp->ping_time);
+    printf("    VMPORT: open_cookie %" PRIx32 "\n", vp->open_cookie);
+    for (i = 0; i < VMPORT_MAX_CHANS; i++)
+    {
+        int j;
+        vmport_channel_control_t *vc = &vp->u.packed.chan_ctl[i].chan;
+        vmport_bucket_control_t *jb =  &vp->u.packed.chan_ctl[i].jumbo;
+
+        printf("    VMPORT: chan[%d] chan_id %d\n", i, vc->chan_id);
+        printf("    VMPORT: chan[%d] active_time %" PRIx64 "\n",
+               i, vc->active_time);
+        printf("    VMPORT: chan[%d] proto_num %" PRIx32 "\n",
+               i, vc->proto_num);
+        printf("    VMPORT: chan[%d] recv_read %d\n", i, vc->recv_read);
+        printf("    VMPORT: chan[%d] recv_write %d\n", i, vc->recv_write);
+        printf("    VMPORT: chan[%d] jumbo %d\n", i, vc->jumbo);
+        printf("    VMPORT: chan[%d] send_len %d\n", i, vc->send_len);
+        if ( vc->send_len > VMPORT_MAX_SEND_BUF * 4 )
+        {
+            printf("--- VMPORT: trucated send_len=%d > %d\n",
+                   vc->send_len, VMPORT_MAX_SEND_BUF * 4);
+            vc->send_len = VMPORT_MAX_SEND_BUF * 4;
+        }
+        if ( vc->send_len > chans_size )
+        {
+            fprintf(stderr, "*** VMPORT: bogus send_len=%d > %d\n",
+                    vc->send_len, chans_size);
+            if ( chans_size >= 0 )
+                vc->send_len = chans_size;
+            else
+                vc->send_len = 0;
+        }
+        p += vc->send_len;
+        chans_size -= vc->send_len;
+        for (j = 0; j < VMPORT_MAX_BKTS; j++)
+        {
+            vmport_bucket_control_t *b = &vp->u.packed.chan_ctl[i].recv[j];
+
+            printf("    VMPORT: chan[%d] bucket[%d] recv_len %d\n",
+                   i, j, b->recv_len);
+            if ( b->recv_len > VMPORT_MAX_RECV_BUF * 4 )
+            {
+                printf("--- VMPORT: trucated recv_len=%d > %d\n",
+                       b->recv_len, VMPORT_MAX_RECV_BUF * 4);
+                b->recv_len = VMPORT_MAX_RECV_BUF * 4;
+            }
+            if ( b->recv_len > chans_size )
+            {
+                fprintf(stderr, "*** VMPORT: bogus recv_len=%d > %d\n",
+                        b->recv_len, chans_size);
+                if ( chans_size >= 0 )
+                    b->recv_len = chans_size;
+                else
+                    b->recv_len = 0;
+            }
+            p += b->recv_len;
+            chans_size -= b->recv_len;
+        }
+        printf("    VMPORT: chan[%d] jumbo_bkt recv_len %d\n", i, 
jb->recv_len);
+        if ( jb->recv_len > VMPORT_MAX_RECV_JUMBO_BUF * 4 )
+        {
+            printf("--- VMPORT: trucated recv_len=%d > %d\n",
+                   jb->recv_len, VMPORT_MAX_RECV_JUMBO_BUF * 4);
+            jb->recv_len = VMPORT_MAX_RECV_JUMBO_BUF * 4;
+        }
+        if ( jb->recv_len > chans_size )
+        {
+            fprintf(stderr, "*** VMPORT: bogus recv_len=%d > %d\n",
+                    jb->recv_len, chans_size);
+            if ( chans_size >= 0 )
+                jb->recv_len = chans_size;
+            else
+                jb->recv_len = 0;
+        }
+        p += jb->recv_len;
+        chans_size -= jb->recv_len;
+    }
+
+    if ( chans_size != 0 )
+        fprintf(stderr, "*** VMPORT: bogus chans_size=%d should be 0\n",
+                chans_size);
+
+    vmport_used_guestinfo = vp->used_guestinfo;
+    vmport_used_guestinfo_jumbo = vp->used_guestinfo_jumbo;
+
+    if ( vmport_used_guestinfo == 0 )
+        printf("    VMPORT: no small data\n");
+    for (i = 0; i < vmport_used_guestinfo; i++)
+    {
+        if ( vmport_guestsize > 0 )
+        {
+            uint8_t key_len = (uint8_t)(*p++);
+            uint8_t val_len = (uint8_t)(*p++);
+            if ( key_len )
+            {
+                char key[VMPORT_MAX_KEY_LEN + 1];
+                char val[VMPORT_MAX_VAL_LEN + 1];
+
+                if ( key_len > VMPORT_MAX_KEY_LEN )
+                {
+                    fprintf(stderr,
+                            "*** VMPORT: bogus key_len=%d > %d for 
guestinfo[%d]\n",
+                            key_len, VMPORT_MAX_KEY_LEN, i);
+                    key_len = VMPORT_MAX_KEY_LEN;
+                }
+                memcpy(key, p, key_len);
+                p += key_len;
+                key[key_len] = '\0';
+                if ( val_len > VMPORT_MAX_VAL_LEN )
+                {
+                    fprintf(stderr,
+                            "*** VMPORT: bogus val_len=%d > %d for 
guestinfo[%d]\n",
+                            val_len, VMPORT_MAX_VAL_LEN, i);
+                    val_len = VMPORT_MAX_VAL_LEN;
+                }
+                memcpy(val, p, val_len);
+                p += val_len;
+                val[val_len] = '\0';
+                vmport_guestsize -= 2 + key_len + val_len;
+                printf("    VMPORT: guestinfo[%d](%s) = \"%s\"\n",
+                       i, key, val);
+            }
+            else
+            {
+                fprintf(stderr,
+                        "*** VMPORT: bogus len for guestinfo[%d]\n",
+                        i);
+                vmport_guestsize -= 2;
+            }
+            if ( vmport_guestsize < 0 )
+                printf("    VMPORT: data length skew at guestinfo[%d]\n"
+                       "         remaining datasize=%ld\n",
+                       i, vmport_guestsize);
+        }
+    }
+
+    if ( vmport_guestsize == 0 )
+        printf("    VMPORT: no jumbo data\n");
+    for (i = 0; i < vmport_used_guestinfo_jumbo; i++)
+    {
+        if ( vmport_guestsize > 0 )
+        {
+            uint8_t key_len = (uint8_t)(*p++);
+            uint16_t val_len;
+
+            memcpy(&val_len, p, 2);
+            p += 2;
+            if ( key_len )
+            {
+                char key[VMPORT_MAX_KEY_LEN + 1];
+                char val[VMPORT_MAX_VAL_JUMBO_LEN + 1];
+
+                if ( key_len > VMPORT_MAX_KEY_LEN )
+                {
+                    fprintf(stderr,
+                            "*** VMPORT: bogus key_len=%d > %d for 
guestinfo[%d]\n",
+                            key_len, VMPORT_MAX_KEY_LEN, i);
+                    key_len = VMPORT_MAX_KEY_LEN;
+                }
+                memcpy(key, p, key_len);
+                p += key_len;
+                key[key_len] = '\0';
+                if ( val_len > VMPORT_MAX_VAL_JUMBO_LEN )
+                {
+                    fprintf(stderr,
+                            "*** VMPORT: bogus val_len=%d > %d for 
guestinfo[%d]\n",
+                            val_len, VMPORT_MAX_VAL_JUMBO_LEN, i);
+                    val_len = VMPORT_MAX_VAL_JUMBO_LEN;
+                }
+                memcpy(val, p, val_len);
+                p += val_len;
+                val[val_len] = '\0';
+                vmport_guestsize -= 2 + key_len + val_len;
+                printf("    VMPORT: guestinfo_jumbo[%d](%s) = \"%s\"\n",
+                       i, key, val);
+            }
+            else
+            {
+                printf("    VMPORT: bogus len for guestinfo_jumbo[%d]\n", i);
+                vmport_guestsize -= 2;
+            }
+            if ( vmport_guestsize < 0 )
+                printf("    VMPORT: data length skew at guestinfo_jumbo[%d]\n"
+                       "         remaining datasize=%ld\n", i,
+                       vmport_guestsize);
+        }
+    }
+
+    if ( !vmport_guestsize )
+        printf("    VMPORT: %ld bytes leftover data\n", vmport_guestsize);
+}
+
 int main(int argc, char **argv)
 {
     int entry, domid;
@@ -467,6 +686,7 @@ int main(int argc, char **argv)
         case HVM_SAVE_CODE(VIRIDIAN_VCPU): dump_viridian_vcpu(); break;
         case HVM_SAVE_CODE(VMCE_VCPU): dump_vmce_vcpu(); break;
         case HVM_SAVE_CODE(TSC_ADJUST): dump_tsc_adjust(); break;
+        case HVM_SAVE_CODE(VMPORT): dump_vmport(desc.length); break;
         case HVM_SAVE_CODE(END): break;
         default:
             printf(" ** Don't understand type %u: skipping\n",
@@ -477,3 +697,12 @@ int main(int argc, char **argv)
 
     return 0;
 } 
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/tools/xentrace/formats b/tools/xentrace/formats
index da658bf..75a5d34 100644
--- a/tools/xentrace/formats
+++ b/tools/xentrace/formats
@@ -79,6 +79,14 @@
 0x00082020  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  INTR_WINDOW [ value = 
0x%(1)08x ]
 0x00082021  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  NPF         [ gpa = 
0x%(2)08x%(1)08x mfn = 0x%(4)08x%(3)08x qual = 0x%(5)04x p2mt = 0x%(6)04x ]
 0x00082023  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  TRAP        [ vector = 
0x%(1)02x ]
+0x00082024  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  TRAP_DEBUG  [ 
exit_qualification = 0x%(1)08x ]
+0x00082025  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  VLAPIC
+0x00082026  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  TRAP_GP     [ vector = 
0x%(1)02x inst_len = %(2)d exitinfo1 = %(3)d exitinfo2 = 0x%(4)08x ]
+0x00082126  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  TRAP_GP     [ vector = 
0x%(1)02x inst_len = %(2)d exitinfo1 = %(3)d exitinfo2 = 0x%(5)08x%(4)08x ]
+0x00082027  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  VMPORT_READ1  [ eax = 
0x%(1)08x ebx = 0x%(2)08x ecx = 0x%(3)08x edx = 0x%(4)08x esi = 0x%(5)08x edi = 
0x%(6)08x ]
+0x00082227  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  VMPORT_WRITE1 [ eax = 
0x%(1)08x ebx = 0x%(2)08x ecx = 0x%(3)08x edx = 0x%(4)08x esi = 0x%(5)08x edi = 
0x%(6)08x ]
+0x00082028  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  VMPORT_READ2  [ eax = 
0x%(1)08x ebx = 0x%(2)08x ecx = 0x%(3)08x edx = 0x%(4)08x esi = 0x%(5)08x edi = 
0x%(6)08x ]
+0x00082228  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  VMPORT_WRITE2 [ eax = 
0x%(1)08x ebx = 0x%(2)08x ecx = 0x%(3)08x edx = 0x%(4)08x esi = 0x%(5)08x edi = 
0x%(6)08x ]
 
 0x0010f001  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  page_grant_map      [ domid = 
%(1)d ]
 0x0010f002  CPU%(cpu)d  %(tsc)d (+%(reltsc)8d)  page_grant_unmap    [ domid = 
%(1)d ]
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index d1517c4..bee2b30 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -23,6 +23,7 @@
 #include <xen/paging.h>
 #include <asm/irq.h>
 #include <asm/hvm/hvm.h>
+#include <asm/hvm/vmport.h>
 #include <asm/hvm/support.h>
 #include <asm/hvm/cacheattr.h>
 #include <asm/processor.h>
@@ -579,6 +580,39 @@ long arch_do_domctl(
         }
         break;
 
+        case XEN_DOMCTL_SENDTRIGGER_VTPOWER:
+        {
+            ret = -EINVAL;
+            if ( is_hvm_domain(d) )
+            {
+                ret = 0;
+                vmport_ctrl_send(&d->arch.hvm_domain, "OS_Halt");
+            }
+        }
+        break;
+
+        case XEN_DOMCTL_SENDTRIGGER_VTREBOOT:
+        {
+            ret = -EINVAL;
+            if ( is_hvm_domain(d) )
+            {
+                ret = 0;
+                vmport_ctrl_send(&d->arch.hvm_domain, "OS_Reboot");
+            }
+        }
+        break;
+
+        case XEN_DOMCTL_SENDTRIGGER_VTPING:
+        {
+            ret = -EINVAL;
+            if ( is_hvm_domain(d) )
+            {
+                ret = 0;
+                vmport_ctrl_send(&d->arch.hvm_domain, "ping");
+            }
+        }
+        break;
+
         default:
             ret = -ENOSYS;
         }
diff --git a/xen/arch/x86/hvm/Makefile b/xen/arch/x86/hvm/Makefile
index 3474a65..8e630db 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 eded446..3e5ac67 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -57,6 +57,7 @@
 #include <asm/hvm/cacheattr.h>
 #include <asm/hvm/trace.h>
 #include <asm/hvm/nestedhvm.h>
+#include <asm/hvm/vmport.h>
 #include <asm/mtrr.h>
 #include <asm/apic.h>
 #include <public/sched.h>
@@ -1480,6 +1481,7 @@ int hvm_domain_initialise(struct domain *d)
     INIT_LIST_HEAD(&d->arch.hvm_domain.ioreq_server.list);
     spin_lock_init(&d->arch.hvm_domain.irq_lock);
     spin_lock_init(&d->arch.hvm_domain.uc_lock);
+    spin_lock_init(&d->arch.hvm_domain.vmport_lock);
 
     INIT_LIST_HEAD(&d->arch.hvm_domain.msixtbl_list);
     spin_lock_init(&d->arch.hvm_domain.msixtbl_list_lock);
@@ -1492,11 +1494,36 @@ int hvm_domain_initialise(struct domain *d)
 
     d->arch.hvm_domain.params = xzalloc_array(uint64_t, HVM_NR_PARAMS);
     d->arch.hvm_domain.io_handler = xmalloc(struct hvm_io_handler);
+    d->arch.hvm_domain.vmport_data = xzalloc(struct vmport_state);
     rc = -ENOMEM;
-    if ( !d->arch.hvm_domain.params || !d->arch.hvm_domain.io_handler )
+    if ( !d->arch.hvm_domain.params || !d->arch.hvm_domain.io_handler ||
+         !d->arch.hvm_domain.vmport_data )
         goto fail1;
     d->arch.hvm_domain.io_handler->num_slot = 0;
 
+    /*
+     * 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.
+     */
+    d->arch.hvm_domain.vmport_data->open_cookie = 435;
+
+    d->arch.hvm_domain.vmport_data->used_guestinfo = 10;
+    for (rc = 0;
+         rc < d->arch.hvm_domain.vmport_data->used_guestinfo;
+         rc++)
+        d->arch.hvm_domain.vmport_data->guestinfo[rc] =
+            xzalloc(vmport_guestinfo_t);
+
+    d->arch.hvm_domain.vmport_data->used_guestinfo_jumbo = 2;
+    for (rc = 0;
+         rc < d->arch.hvm_domain.vmport_data->used_guestinfo_jumbo;
+         rc++)
+        d->arch.hvm_domain.vmport_data->guestinfo_jumbo[rc] =
+            xzalloc(vmport_guestinfo_jumbo_t);
+
+    vmport_flush(&d->arch.hvm_domain);
+
     if ( is_pvh_domain(d) )
     {
         register_portio_handler(d, 0, 0x10003, handle_pvh_io);
@@ -1507,6 +1534,7 @@ int hvm_domain_initialise(struct domain *d)
 
     d->arch.hvm_domain.params[HVM_PARAM_HPET_ENABLED] = 1;
     d->arch.hvm_domain.params[HVM_PARAM_TRIPLE_FAULT_REASON] = SHUTDOWN_reboot;
+    d->arch.hvm_domain.params[HVM_PARAM_VMPORT_RESET_TIME] = 14;
 
     vpic_init(d);
 
@@ -1520,6 +1548,7 @@ int hvm_domain_initialise(struct domain *d)
 
     register_portio_handler(d, 0xe9, 1, hvm_print_line);
     register_portio_handler(d, 0xcf8, 4, hvm_access_cf8);
+    register_portio_handler(d, VMPORT_PORT, 4, vmport_ioport);
 
     rc = hvm_funcs.domain_initialise(d);
     if ( rc != 0 )
@@ -1532,6 +1561,17 @@ int hvm_domain_initialise(struct domain *d)
     stdvga_deinit(d);
     vioapic_deinit(d);
  fail1:
+    if ( d->arch.hvm_domain.vmport_data )
+    {
+        struct vmport_state *vs = d->arch.hvm_domain.vmport_data;
+        int idx;
+
+        for (idx = 0; idx < vs->used_guestinfo; idx++)
+            xfree(vs->guestinfo[idx]);
+        for (idx = 0; idx < vs->used_guestinfo_jumbo; idx++)
+            xfree(vs->guestinfo_jumbo[idx]);
+    }
+    xfree(d->arch.hvm_domain.vmport_data);
     xfree(d->arch.hvm_domain.io_handler);
     xfree(d->arch.hvm_domain.params);
  fail0:
@@ -1541,6 +1581,15 @@ int hvm_domain_initialise(struct domain *d)
 
 void hvm_domain_relinquish_resources(struct domain *d)
 {
+    if ( d->arch.hvm_domain.vmport_data )
+    {
+        struct vmport_state *vs = d->arch.hvm_domain.vmport_data;
+        int idx;
+
+        for (idx = 0; idx < vs->used_guestinfo; idx++)
+            xfree(vs->guestinfo[idx]);
+        xfree(d->arch.hvm_domain.vmport_data);
+    }
     xfree(d->arch.hvm_domain.io_handler);
     xfree(d->arch.hvm_domain.params);
 
@@ -5473,6 +5522,257 @@ static int hvmop_destroy_ioreq_server(
     return rc;
 }
 
+static void hvm_del_guestinfo_jumbo(struct vmport_state *vs, char *key,
+                                    uint8_t len)
+{
+    int idx;
+
+    for (idx = 0; idx < vs->used_guestinfo_jumbo; idx++)
+    {
+        if ( vs->guestinfo[idx] &&
+             (vs->guestinfo_jumbo[idx]->key_len == len) &&
+             (memcmp(key, vs->guestinfo_jumbo[idx]->key_data, len) == 0) )
+        {
+            vs->guestinfo_jumbo[idx]->val_data[0] = '\0';
+            vs->guestinfo_jumbo[idx]->key_len = 0;
+            break;
+        }
+    }
+}
+
+static void hvm_del_guestinfo(struct vmport_state *vs, char *key, uint8_t len)
+{
+    int idx;
+
+    for (idx = 0; idx < vs->used_guestinfo; idx++)
+    {
+        if ( vs->guestinfo[idx] &&
+             (vs->guestinfo[idx]->key_len == len) &&
+             (memcmp(key, vs->guestinfo[idx]->key_data, len) == 0) )
+        {
+            vs->guestinfo[idx]->val_data[0] = '\0';
+            vs->guestinfo[idx]->key_len = 0;
+            break;
+        }
+    }
+}
+
+static long hvm_set_guestinfo(struct vmport_state *vs,
+                              struct xen_hvm_vmport_guest_info *a,
+                              char *key, char *value)
+{
+    int idx;
+    int free_idx = -1;
+    long 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 long 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;
+    long 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 long hvm_get_guestinfo(struct vmport_state *vs,
+                              struct xen_hvm_vmport_guest_info *a,
+                              char *key, char *value,
+                              XEN_GUEST_HANDLE_PARAM(void) arg)
+{
+    int idx;
+    long 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 = copy_to_guest(arg, a, 1) ? -EFAULT : 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 = copy_to_guest(arg, a, 1) ? -EFAULT : 0;
+                break;
+            }
+        }
+        if ( idx >= vs->used_guestinfo )
+            rc = -ENOENT;
+    }
+    return rc;
+}
+
+static long hvm_get_guestinfo_jumbo(struct vmport_state *vs,
+                                    struct xen_hvm_vmport_guest_info *a,
+                                    char *key, char *value,
+                                    XEN_GUEST_HANDLE_PARAM(void) arg)
+{
+    int idx, total_entries;
+    long 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 < 0) || (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 = copy_to_guest(arg, a, 1) ? -EFAULT : 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 = copy_to_guest(arg, a, 1) ? -EFAULT : 0;
+                break;
+            }
+        }
+        if ( idx >= vs->used_guestinfo_jumbo )
+            rc = -ENOENT;
+    }
+    return rc;
+}
+
 #define HVMOP_op_mask 0xff
 
 long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
@@ -5711,6 +6011,18 @@ long do_hvm_op(unsigned long op, 
XEN_GUEST_HANDLE_PARAM(void) arg)
                     break;
                 }
                 break;
+            case HVM_PARAM_VMPORT_BUILD_NUMBER_TIME:
+            case HVM_PARAM_VMPORT_BUILD_NUMBER_VALUE:
+                /*
+                 * These should only ever be set to zero by tools.
+                 * So disallow anything else.
+                 */
+                if ( a.value )
+                {
+                    rc = -EINVAL;
+                    break;
+                }
+                break;
             }
 
             if ( rc == 0 ) 
@@ -6125,6 +6437,172 @@ 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;
+        char *key = NULL;
+        char *value = NULL;
+        struct vmport_state *vs;
+        int idx, 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;
+
+        if ( copy_from_guest(&a, arg, 1) )
+            return -EFAULT;
+
+        ASSERT(strlen("guestinfo.") == 10);
+
+#if VMPORT_MAX_KEY_LEN + 10 != VMPORT_GUEST_INFO_KEY_MAX
+#error Need to adjust VMPORT_MAX_KEY_LEN & VMPORT_GUEST_INFO_KEY_MAX
+#endif
+
+#if VMPORT_MAX_VAL_JUMBO_LEN != VMPORT_GUEST_INFO_VAL_MAX
+#error Need to adjust VMPORT_MAX_VAL_JUMBO_LEN & VMPORT_GUEST_INFO_VAL_MAX
+#endif
+
+        if ( a.key_length > strlen("guestinfo.") )
+        {
+            if ( (size_t)a.key_length + (size_t)a.value_length >
+                 sizeof(a.data) )
+                return -EINVAL;
+
+            if ( memcmp(a.data, "guestinfo.", strlen("guestinfo.")) == 0 )
+            {
+                key = &a.data[strlen("guestinfo.")];
+                a.key_length -= strlen("guestinfo.");
+            }
+            else
+                key = &a.data[0];
+            if ( a.key_length > VMPORT_MAX_KEY_LEN )
+            {
+                gdprintk(XENLOG_ERR, "bad key len %d\n", a.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;
+            }
+            value = key + a.key_length;
+
+        }
+        else if (a.key_length > 0)
+        {
+            if ( (size_t)a.key_length + (size_t)a.value_length >
+                 sizeof(a.data) )
+                return -EINVAL;
+            key = &a.data[0];
+            if ( a.key_length > VMPORT_MAX_KEY_LEN )
+            {
+                gdprintk(XENLOG_ERR, "bad key len %d", a.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;
+            }
+            value = key + a.key_length;
+
+        }
+        else if ( (a.key_length == 0) && (op == HVMOP_set_vmport_guest_info) )
+            return -EINVAL;
+
+        d = rcu_lock_domain_by_any_id(a.domid);
+        if ( d == NULL )
+            return rc;
+
+        rc = -EINVAL;
+        if ( !is_hvm_domain(d) )
+            goto param_fail9;
+
+        rc = xsm_hvm_param(XSM_TARGET, d, op);
+        if ( rc )
+            goto param_fail9;
+
+        vs = d->arch.hvm_domain.vmport_data;
+        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
+             */
+            rc = -E2BIG;
+            goto param_fail9;
+        }
+
+        num_free_slots = 0;
+        for (idx = 0; idx < vs->used_guestinfo; idx++)
+        {
+            if ( vs->guestinfo[idx] &&
+                (vs->guestinfo[idx]->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 (idx = 0; idx < num_slots; idx++)
+                add_slots[idx] = xzalloc(vmport_guestinfo_t);
+        }
+
+        num_free_slots = 0;
+        for (idx = 0; idx < vs->used_guestinfo_jumbo; idx++)
+        {
+            if ( vs->guestinfo_jumbo[idx] &&
+                 (vs->guestinfo_jumbo[idx]->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 (idx = 0; idx < num_slots_jumbo; idx++)
+                add_slots_jumbo[idx] = xzalloc(vmport_guestinfo_jumbo_t);
+        }
+
+        spin_lock(&d->arch.hvm_domain.vmport_lock);
+
+        for (idx = 0; idx < num_slots; idx++)
+            vs->guestinfo[vs->used_guestinfo + idx] = add_slots[idx];
+        vs->used_guestinfo += num_slots;
+
+        for (idx = 0; idx < num_slots_jumbo; idx++)
+            vs->guestinfo_jumbo[vs->used_guestinfo_jumbo + idx] =
+                add_slots_jumbo[idx];
+        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, arg);
+            if ( rc != 0 )
+                rc = hvm_get_guestinfo_jumbo(vs, &a, key, value, arg);
+        }
+        spin_unlock(&d->arch.hvm_domain.vmport_lock);
+
+    param_fail9:
+        rcu_unlock_domain(d);
+        break;
+    }
+
     default:
     {
         gdprintk(XENLOG_DEBUG, "Bad HVM op %ld.\n", op);
diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c
index 9f565d6..94e08eb 100644
--- a/xen/arch/x86/hvm/io.c
+++ b/xen/arch/x86/hvm/io.c
@@ -42,6 +42,7 @@
 #include <asm/hvm/vlapic.h>
 #include <asm/hvm/trace.h>
 #include <asm/hvm/emulate.h>
+#include <asm/hvm/vmport.h>
 #include <public/sched.h>
 #include <xen/iocap.h>
 #include <public/hvm/ioreq.h>
diff --git a/xen/arch/x86/hvm/svm/emulate.c b/xen/arch/x86/hvm/svm/emulate.c
index 37a1ece..61002fb 100644
--- a/xen/arch/x86/hvm/svm/emulate.c
+++ b/xen/arch/x86/hvm/svm/emulate.c
@@ -78,6 +78,7 @@ static unsigned long svm_nextrip_insn_length(struct vcpu *v)
         /* ...and the rest of the #VMEXITs */
     case VMEXIT_CR0_SEL_WRITE:
     case VMEXIT_EXCEPTION_BP:
+    case VMEXIT_EXCEPTION_GP:
         break;
     default:
         BUG();
@@ -106,6 +107,7 @@ MAKE_INSTR(VMSAVE, 3, 0x0f, 0x01, 0xdb);
 MAKE_INSTR(STGI,   3, 0x0f, 0x01, 0xdc);
 MAKE_INSTR(CLGI,   3, 0x0f, 0x01, 0xdd);
 MAKE_INSTR(INVLPGA,3, 0x0f, 0x01, 0xdf);
+MAKE_INSTR(IN,     1, 0xed);
 
 static const u8 *const opc_bytes[INSTR_MAX_COUNT] =
 {
@@ -126,6 +128,7 @@ static const u8 *const opc_bytes[INSTR_MAX_COUNT] =
     [INSTR_STGI]   = OPCODE_STGI,
     [INSTR_CLGI]   = OPCODE_CLGI,
     [INSTR_INVLPGA] = OPCODE_INVLPGA,
+    [INSTR_IN] = OPCODE_IN,
 };
 
 static int fetch(struct vcpu *v, u8 *buf, unsigned long addr, int len)
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index b5188e6..f61bd02 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -56,6 +56,7 @@
 #include <asm/hvm/svm/nestedsvm.h>
 #include <asm/hvm/nestedhvm.h>
 #include <asm/x86_emulate.h>
+#include <asm/hvm/vmport.h>
 #include <public/sched.h>
 #include <asm/hvm/vpt.h>
 #include <asm/hvm/trace.h>
@@ -2065,6 +2066,80 @@ svm_vmexit_do_vmsave(struct vmcb_struct *vmcb,
     return;
 }
 
+static void svm_vmexit_gp_intercept(struct cpu_user_regs *regs, struct vcpu *v)
+{
+    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+    unsigned long inst_len = __get_instruction_length(v, INSTR_IN);
+
+    regs->error_code = vmcb->exitinfo1;
+    if ( hvm_long_mode_enabled(v) )
+        HVMTRACE_LONG_C4D(TRAP_GP, TRAP_gp_fault, inst_len,
+                          regs->error_code,
+                          TRC_PAR_LONG(vmcb->exitinfo2));
+    else
+        HVMTRACE_C4D(TRAP_GP, TRAP_gp_fault, inst_len,
+                     regs->error_code, vmcb->exitinfo2);
+
+    if ( inst_len <= 1 && (regs->rdx & 0xffff) == VMPORT_PORT &&
+         vmcb->exitinfo2 == 0 && regs->error_code == 0 )
+    {
+        uint32_t magic = regs->rax;
+
+        if ( magic == VMPORT_MAGIC )
+        {
+            unsigned char bytes[1] = { 0 };
+            int frc = hvm_fetch_from_guest_virt_nofault(bytes, regs->rip,
+                                                        1, PFEC_page_present);
+
+            if ( !frc && bytes[0] == 0xed ) /* in (%dx),%eax */
+            {
+                uint32_t val;
+
+                __update_guest_eip(regs, 1);
+                vmport_ioport(IOREQ_READ, VMPORT_PORT, 4, &val);
+                VMPORT_DBG_LOG(VMPORT_LOG_VMWARE_AFTER,
+                               "gp: VMware ip=%"PRIx64" ax=%"PRIx64
+                               " bx=%"PRIx64" cx=%"PRIx64" dx=%"PRIx64
+                               " si=%"PRIx64" di=%"PRIx64,
+                               regs->rip, regs->rax, regs->rbx, regs->rcx,
+                               regs->rdx, regs->rsi, regs->rdi);
+                return;
+            }
+            else
+            {
+                VMPORT_DBG_LOG(VMPORT_LOG_GP_FAIL_RD_INST,
+                               "gp: VMware? ip=%"PRIx64"=>0x%x(%ld,%d) 
ax=%"PRIx64
+                               " bx=%"PRIx64" cx=%"PRIx64" dx=%"PRIx64
+                               " si=%"PRIx64" di=%"PRIx64,
+                               regs->rip, bytes[0], inst_len, frc, regs->rax, 
regs->rbx,
+                               regs->rcx, regs->rdx, regs->rsi, regs->rdi);
+            }
+        }
+        else
+        {
+            VMPORT_DBG_LOG(VMPORT_LOG_GP_NOT_VMWARE,
+                           "gp: ip=%"PRIx64" ax=%"PRIx64" bx=%"PRIx64
+                           " cx=%"PRIx64 " dx=%"PRIx64" si=%"PRIx64
+                           " di=%"PRIx64,
+                           regs->rip, regs->rax, regs->rbx, regs->rcx,
+                           regs->rdx, regs->rsi, regs->rdi);
+            hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code);
+        }
+    }
+    else
+    {
+        VMPORT_DBG_LOG(VMPORT_LOG_GP_UNKNOWN,
+                       "gp: e2=%lx ec=%lx ip=%"PRIx64" (%ld) ax=%"PRIx64
+                       " bx=%"PRIx64" cx=%"PRIx64" dx=%"PRIx64" si=%"PRIx64
+                       " di=%"PRIx64,
+                       (unsigned long)vmcb->exitinfo2,
+                       (unsigned long)regs->error_code,
+                       regs->rip, inst_len, regs->rax, regs->rbx, regs->rcx,
+                       regs->rdx, regs->rsi, regs->rdi);
+        hvm_inject_hw_exception(TRAP_gp_fault, regs->error_code);
+    }
+}
+
 static void svm_vmexit_ud_intercept(struct cpu_user_regs *regs)
 {
     struct hvm_emulate_ctxt ctxt;
@@ -2412,6 +2487,10 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
         break;
     }
 
+    case VMEXIT_EXCEPTION_GP:
+        svm_vmexit_gp_intercept(regs, v);
+        break;
+
     case VMEXIT_EXCEPTION_UD:
         svm_vmexit_ud_intercept(regs);
         break;
diff --git a/xen/arch/x86/hvm/svm/vmcb.c b/xen/arch/x86/hvm/svm/vmcb.c
index 21292bb..791c045 100644
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -193,6 +193,7 @@ static int construct_vmcb(struct vcpu *v)
 
     vmcb->_exception_intercepts =
         HVM_TRAP_MASK
+        | (1U << TRAP_gp_fault)
         | (1U << TRAP_no_device);
 
     if ( paging_mode_hap(v->domain) )
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..64609f2
--- /dev/null
+++ b/xen/arch/x86/hvm/vmport/vmport.c
@@ -0,0 +1,1436 @@
+/*
+ * 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/>.
+ */
+
+/*
+ * 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/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>
+
+#include "backdoor_def.h"
+#include "guest_msg_def.h"
+#include <asm/hvm/support.h>
+#include <asm/hvm/vlapic.h>
+#include <public/hvm/save.h>
+#include <public/arch-x86/hvm/save.h>
+#include <xen/cper.h>
+
+#define VMWARE_PROTO_TO_GUEST        0x4f4c4354
+#define VMWARE_PROTO_FROM_GUEST      0x49435052
+
+/* Some more VMware defines */
+#define VMWARE_GUI_AUTO_GRAB              0x001
+#define VMWARE_GUI_AUTO_UNGRAB            0x002
+#define VMWARE_GUI_AUTO_SCROLL            0x004
+#define VMWARE_GUI_AUTO_RAISE             0x008
+#define VMWARE_GUI_EXCHANGE_SELECTIONS    0x010
+#define VMWARE_GUI_WARP_CURSOR_ON_UNGRAB  0x020
+#define VMWARE_GUI_FULL_SCREEN            0x040
+
+#define VMWARE_GUI_TO_FULL_SCREEN         0x080
+#define VMWARE_GUI_TO_WINDOW              0x100
+
+#define VMWARE_GUI_AUTO_RAISE_DISABLED    0x200
+
+#define VMWARE_GUI_SYNC_TIME              0x400
+
+/* When set, toolboxes should not show the cursor options page. */
+#define VMWARE_DISABLE_CURSOR_OPTIONS     0x800
+
+/* End of more VMware defines */
+
+#define GUESTINFO_NOTFOUND      500
+#define GUESTINFO_VALTOOLONG    1
+#define GUESTINFO_KEYTOOLONG    2
+#define GUESTINFO_TOOMANYKEYS   3
+
+
+#ifndef NDEBUG
+unsigned int opt_vmport_debug __read_mostly;
+integer_param("vmport_debug", opt_vmport_debug);
+#endif
+
+/* 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 get_low_bits(uint32_t bits)
+{
+    return bits & 0xffff;
+}
+
+inline uint16_t get_high_bits(uint32_t bits)
+{
+    return bits >> 16;
+}
+
+inline uint32_t set_high_bits(uint32_t b, uint32_t val)
+{
+    return (val << 16) | get_low_bits(b);
+}
+
+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);
+}
+
+#ifndef NDEBUG
+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
+ */
+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
+ */
+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);
+}
+
+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);
+}
+
+void vmport_flush(struct hvm_domain *hd)
+{
+    VMPORT_DBG_LOG(VMPORT_LOG_FLUSH, "VMware flush");
+    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;
+    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;
+            }
+        }
+    }
+}
+
+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;
+}
+
+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);
+#ifndef NDEBUG
+    if ( (opt_vmport_debug & VMPORT_LOG_SEND_SIZE_ALL) ||
+         ((opt_vmport_debug & VMPORT_LOG_SEND_SIZE) && (c->ctl.send_len)) )
+        gdprintk(XENLOG_DEBUG, "VMware SENDSIZE %d is %d\n",
+                 c->ctl.chan_id, c->ctl.send_len);
+#endif
+}
+
+/* ret_buffer is in/out param */
+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 idx;
+
+    for (idx = 0; idx < vs->used_guestinfo; idx++)
+    {
+        if ( vs->guestinfo[idx] &&
+             (vs->guestinfo[idx]->key_len == a_key_len) &&
+             (memcmp(a_info_key, vs->guestinfo[idx]->key_data,
+                     vs->guestinfo[idx]->key_len) == 0) )
+        {
+#ifndef NDEBUG
+            if ( opt_vmport_debug & VMPORT_LOG_INFO_GET )
+            {
+                char prefix[30];
+
+                snprintf(prefix, sizeof(prefix),
+                         "VMware info-get val:");
+                vmport_safe_print(prefix, vs->guestinfo[idx]->val_len,
+                                  vs->guestinfo[idx]->val_data);
+            }
+#endif
+            snprintf(ret_buffer, ret_buffer_len - 1, "1 %.*s",
+                     (int)vs->guestinfo[idx]->val_len,
+                     vs->guestinfo[idx]->val_data);
+            return idx;
+        }
+    }
+
+    for (idx = 0; idx < vs->used_guestinfo_jumbo; idx++)
+    {
+        if ( vs->guestinfo_jumbo[idx] &&
+             (vs->guestinfo_jumbo[idx]->key_len == a_key_len) &&
+             (memcmp(a_info_key, vs->guestinfo_jumbo[idx]->key_data,
+                     vs->guestinfo_jumbo[idx]->key_len) == 0) )
+        {
+#ifndef NDEBUG
+            if ( opt_vmport_debug & VMPORT_LOG_INFO_GET )
+            {
+                char prefix[30];
+
+                snprintf(prefix, sizeof(prefix),
+                         "VMware info-get val:");
+                vmport_safe_print(prefix, vs->guestinfo_jumbo[idx]->val_len,
+                                  vs->guestinfo_jumbo[idx]->val_data);
+            }
+#endif
+            snprintf(ret_buffer, ret_buffer_len - 1, "1 %.*s",
+                     (int)vs->guestinfo_jumbo[idx]->val_len,
+                     vs->guestinfo_jumbo[idx]->val_data);
+            return idx;
+        }
+    }
+    return GUESTINFO_NOTFOUND;
+}
+
+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 idx;
+    int free_idx = -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 (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_len) &&
+                          (memcmp(a_info_key, vs->guestinfo[idx]->key_data,
+                                  vs->guestinfo[idx]->key_len) == 0) )
+                {
+                    vs->guestinfo[idx]->val_len = a_val_len;
+                    memcpy(vs->guestinfo[idx]->val_data, val, a_val_len);
+                    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 = GUESTINFO_TOOMANYKEYS;
+                else
+                {
+                    vs->guestinfo[free_idx]->key_len = a_key_len;
+                    memcpy(vs->guestinfo[free_idx]->key_data,
+                           a_info_key, a_key_len);
+                    vs->guestinfo[free_idx]->val_len = a_val_len;
+                    memcpy(vs->guestinfo[free_idx]->val_data,
+                           val, a_val_len);
+                }
+            }
+        }
+        else
+            rc = GUESTINFO_VALTOOLONG;
+    }
+    else
+        rc = GUESTINFO_KEYTOOLONG;
+    if ( !rc )
+    {
+        for (idx = 0; idx < vs->used_guestinfo_jumbo; idx++)
+        {
+            if ( !vs->guestinfo_jumbo[idx] )
+            {
+#ifndef NDEBUG
+                gdprintk(XENLOG_WARNING,
+                         "idx=%d not allocated used_guestinfo_jumbo=%d\n",
+                         idx, vs->used_guestinfo_jumbo);
+#endif
+            }
+            else if ( (vs->guestinfo_jumbo[idx]->key_len == a_key_len) &&
+                      (memcmp(a_info_key,
+                              vs->guestinfo_jumbo[idx]->key_data,
+                              vs->guestinfo_jumbo[idx]->key_len) == 0) )
+            {
+                vs->guestinfo_jumbo[idx]->key_len = 0;
+                vs->guestinfo_jumbo[idx]->val_len = 0;
+                break;
+            }
+        }
+    }
+    return rc;
+}
+
+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 idx;
+    int free_idx = -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 (idx = 0; idx < vs->used_guestinfo_jumbo; idx++)
+            {
+                if ( !vs->guestinfo_jumbo[idx] )
+                {
+#ifndef NDEBUG
+                    gdprintk(XENLOG_WARNING,
+                             "idx=%d not allocated; used_guestinfo_jumbo=%d\n",
+                             idx, vs->used_guestinfo_jumbo);
+#endif
+                }
+                else if ( (vs->guestinfo_jumbo[idx]->key_len == a_key_len) &&
+                          (memcmp(a_info_key,
+                                  vs->guestinfo_jumbo[idx]->key_data,
+                                  vs->guestinfo_jumbo[idx]->key_len) == 0) )
+                {
+
+                    vs->guestinfo_jumbo[idx]->val_len = a_val_len;
+                    memcpy(vs->guestinfo_jumbo[idx]->val_data, val, a_val_len);
+                    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 = GUESTINFO_TOOMANYKEYS;
+                else
+                {
+                    vs->guestinfo_jumbo[free_idx]->key_len = a_key_len;
+                    memcpy(vs->guestinfo_jumbo[free_idx]->key_data,
+                           a_info_key, a_key_len);
+                    vs->guestinfo_jumbo[free_idx]->val_len = a_val_len;
+                    memcpy(vs->guestinfo_jumbo[free_idx]->val_data,
+                           val, a_val_len);
+                }
+            }
+        }
+        else
+            rc = GUESTINFO_VALTOOLONG;
+    }
+    else
+        rc = GUESTINFO_KEYTOOLONG;
+    if ( !rc )
+    {
+        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_len) &&
+                      (memcmp(a_info_key,
+                              vs->guestinfo[idx]->key_data,
+                              vs->guestinfo[idx]->key_len) == 0) )
+            {
+                vs->guestinfo[idx]->key_len = 0;
+                vs->guestinfo[idx]->val_len = 0;
+                break;
+            }
+        }
+    }
+    return rc;
+}
+
+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_RPC )
+        {
+            char prefix[30];
+
+            snprintf(prefix, sizeof(prefix),
+                     "VMware RPC %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.");
+#ifndef NDEBUG
+                if ( opt_vmport_debug & VMPORT_LOG_INFO_GET )
+                {
+                    char prefix[30];
+
+                    snprintf(prefix, sizeof(prefix),
+                             "VMware info-get key:");
+                    vmport_safe_print(prefix, a_key_len, info_key);
+                }
+#endif
+                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++;
+#ifndef NDEBUG
+                    if ( opt_vmport_debug & VMPORT_LOG_INFO_SET )
+                    {
+                        char prefix[30];
+
+                        snprintf(prefix, sizeof(prefix),
+                                 "VMware info-set key:");
+                        vmport_safe_print(prefix, a_key_len, info_key);
+                        snprintf(prefix, sizeof(prefix),
+                                 "VMware info-set val:");
+                        vmport_safe_print(prefix, a_val_len, val);
+                    }
+#endif
+                    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
+                {
+#ifndef NDEBUG
+                    if ( opt_vmport_debug & VMPORT_LOG_INFO_SET )
+                    {
+                        char prefix[30];
+
+                        snprintf(prefix, sizeof(prefix),
+                                 "VMware info-set missing val; key:");
+                        vmport_safe_print(prefix, rest_len, info_key);
+                    }
+#endif
+                    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;
+#ifndef NDEBUG
+                if ( opt_vmport_debug & VMPORT_LOG_BUILD )
+                {
+                    char prefix[30];
+
+                    snprintf(prefix, sizeof(prefix),
+                             "VMware build %ld ", val);
+                    vmport_safe_print(prefix, p - build, build);
+                }
+#endif
+            }
+        }
+        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;
+        }
+    }
+}
+
+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);
+#ifndef NDEBUG
+    if ( (opt_vmport_debug & VMPORT_LOG_RECV_SIZE_ALL) ||
+         ((opt_vmport_debug & VMPORT_LOG_RECV_SIZE) && (recv_len)) )
+        gdprintk(XENLOG_DEBUG, "VMware RECVSIZE %d is %d.\n",
+                 c->ctl.chan_id, recv_len);
+#endif
+}
+
+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);
+}
+
+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];
+
+#ifndef NDEBUG
+    if ( unlikely(opt_vmport_debug & VMPORT_LOG_RECV_STATUS) )
+    {
+        char prefix[30];
+
+        snprintf(prefix, sizeof(prefix),
+                 "VMware RECVSTATUS %d (%d) ",
+                 c->ctl.chan_id, c->ctl.recv_read);
+        prefix[sizeof(prefix) - 1] = 0;
+        vmport_safe_print(prefix, b->ctl.recv_len, (char *)b->recv_buf);
+    }
+#endif
+    c->ctl.recv_read++;
+    if ( c->ctl.recv_read >= VMPORT_MAX_BKTS )
+        c->ctl.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->ctl.proto_num = 0;
+    set_status(ur, MESSAGE_STATUS_SUCCESS);
+    VMPORT_DBG_LOG(VMPORT_LOG_CLOSE, "VMware CLOSE %d",
+                   c->ctl.chan_id);
+}
+
+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);
+            VMPORT_DBG_LOG(VMPORT_LOG_OPEN, "VMware OPEN %d p=%x",
+                           c->ctl.chan_id, c->ctl.proto_num);
+            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);
+}
+
+int vmport_ioport(int dir, uint32_t port, uint32_t bytes, uint32_t *val)
+{
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    uint32_t cmd = get_low_bits(regs->rcx);
+    uint32_t magic = regs->rax;
+    int rc = X86EMUL_OKAY;
+
+    if ( magic == BDOOR_MAGIC )
+    {
+        uint64_t value;
+
+        if (dir == IOREQ_READ)
+            HVMTRACE_ND(VMPORT_READ1, 0, 1/*cycles*/, 6,
+                        regs->rax, regs->rbx, regs->rcx,
+                        regs->rdx, regs->rsi, regs->rdi);
+        else
+            HVMTRACE_ND(VMPORT_WRITE1, 0, 1/*cycles*/, 6,
+                        regs->rax, regs->rbx, regs->rcx,
+                        regs->rdx, regs->rsi, regs->rdi);
+
+#ifndef NDEBUG
+        if ( opt_vmport_debug & VMPORT_LOG_TRACE &&
+             (!(opt_vmport_debug & VMPORT_LOG_SKIP_MESSAGE) ||
+              (opt_vmport_debug & VMPORT_LOG_SKIP_MESSAGE &&
+               cmd != BDOOR_CMD_MESSAGE)) )
+            gdprintk(XENLOG_DEBUG,
+                     "VMware trace ip=%"PRIx64" cmd=%d ax=%"PRIx64" bx=%"PRIx64
+                     " cx=%"PRIx64" dx=%"PRIx64" si=%"PRIx64" di=%"PRIx64"\n",
+                     regs->rip, cmd, regs->rax, regs->rbx, regs->rcx, 
regs->rdx,
+                     regs->rsi, regs->rdi);
+#endif
+        switch (cmd)
+        {
+        case BDOOR_CMD_GETMHZ:
+            /* ... */
+            regs->rbx = BDOOR_MAGIC;
+            regs->rax = (uint32_t)(current->domain->arch.tsc_khz / 1000);
+            break;
+        case BDOOR_CMD_GETVERSION:
+            /* ... */
+            regs->rbx = BDOOR_MAGIC;
+            /* VERSION_MAGIC */
+            regs->rax = 6;
+            /* Claim we are an ESX. VMX_TYPE_SCALABLE_SERVER */
+            regs->rcx = 2;
+            break;
+        case BDOOR_CMD_GETHWVERSION:
+            /* ... */
+            regs->rbx = BDOOR_MAGIC;
+            /* ?? */
+            regs->rax = 0x4;
+            break;
+        case BDOOR_CMD_GETHZ:
+            value = current->domain->arch.tsc_khz * 1000;
+            /* apic-frequency (bus speed) */
+            regs->rcx = (uint32_t)(1000000000ULL / APIC_BUS_CYCLE_NS);
+            /* High part of tsc-frequency */
+            regs->rbx = (uint32_t)(value >> 32);
+            /* Low part of tsc-frequency */
+            regs->rax = (uint32_t)value;
+            break;
+        case BDOOR_CMD_GETTIME:
+            value = get_localtime_us(current->domain);
+            /* hostUsecs */
+            regs->rbx = (uint32_t)(value % 1000000UL);
+            /* hostSecs */
+            regs->rax = (uint32_t)(value / 1000000ULL);
+            /* maxTimeLag */
+            regs->rcx = 0;
+            break;
+        case BDOOR_CMD_GETTIMEFULL:
+            value = get_localtime_us(current->domain);
+            /* ... */
+            regs->rax = BDOOR_MAGIC;
+            /* hostUsecs */
+            regs->rbx = (uint32_t)(value % 1000000UL);
+            /* High part of hostSecs */
+            regs->rsi = (uint32_t)((value / 1000000ULL) >> 32);
+            /* Low part of hostSecs */
+            regs->rdx = (uint32_t)(value / 1000000ULL);
+            /* maxTimeLag */
+            regs->rcx = 0;
+            break;
+        case BDOOR_CMD_MESSAGE:
+            if ( !is_pv_vcpu(current) )
+            {
+                /* Only supported for non pv domains */
+                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 |
+                VMWARE_DISABLE_CURSOR_OPTIONS;
+            break;
+        case BDOOR_CMD_SETGUIOPTIONS:
+            regs->rax = 0x0;
+            break;
+        default:
+            VMPORT_DBG_LOG(VMPORT_LOG_ERROR,
+                           "VMware bytes=%d dir=%d cmd=%d",
+                           bytes, dir, cmd);
+            break;
+        }
+#ifndef NDEBUG
+        if ( opt_vmport_debug & VMPORT_LOG_VMWARE_AFTER &&
+             (!(opt_vmport_debug & VMPORT_LOG_SKIP_MESSAGE) ||
+              (opt_vmport_debug & VMPORT_LOG_SKIP_MESSAGE &&
+               cmd != BDOOR_CMD_MESSAGE)) )
+            gdprintk(XENLOG_DEBUG,
+                     "VMware after ip=%"PRIx64" cmd=%d ax=%"PRIx64" bx=%"PRIx64
+                     " cx=%"PRIx64" dx=%"PRIx64" si=%"PRIx64" di=%"PRIx64"\n",
+                     regs->rip, cmd, regs->rax, regs->rbx, regs->rcx, 
regs->rdx,
+                     regs->rsi, regs->rdi);
+#endif
+        if (dir == IOREQ_READ)
+            *val = regs->rax;
+    }
+    else
+    {
+        rc = X86EMUL_UNHANDLEABLE;
+        VMPORT_DBG_LOG(VMPORT_LOG_ERROR,
+                       "Not VMware %x vs %x vs %x; ip=%"PRIx64" ax=%"PRIx64
+                       " bx=%"PRIx64" cx=%"PRIx64" dx=%"PRIx64" si=%"PRIx64
+                       " di=%"PRIx64"",
+                       magic, BDOOR_MAGIC, VMPORT_MAGIC,
+                       regs->rip, regs->rax, regs->rbx, regs->rcx, regs->rdx,
+                       regs->rsi, regs->rdi);
+    }
+
+    if (dir == IOREQ_READ)
+        HVMTRACE_ND(VMPORT_READ2, 0, 1/*cycles*/, 6,
+                    regs->rax, regs->rbx, regs->rcx,
+                    regs->rdx, regs->rsi, regs->rdi);
+    else
+        HVMTRACE_ND(VMPORT_WRITE2, 0, 1/*cycles*/, 6,
+                    regs->rax, regs->rbx, regs->rcx,
+                    regs->rdx, regs->rsi, regs->rdi);
+
+    return rc;
+}
+
+/* save and restore functions */
+
+static int vmport_save_domain_ctxt(struct domain *d, hvm_domain_context_t *h)
+{
+    struct hvm_vmport_context *ctxt;
+    struct hvm_save_descriptor *desc;
+    struct hvm_domain *hd = &d->arch.hvm_domain;
+    struct vmport_state *vs = hd->vmport_data;
+    char *p;
+    unsigned int guestinfo_size = 0;
+    unsigned int used_guestinfo = 0;
+    unsigned int used_guestinfo_jumbo = 0;
+    unsigned int chans_size;
+    unsigned int i;
+
+    /* Customized handling for entry since our entry is of variable length */
+    desc = (struct hvm_save_descriptor *)&h->data[h->cur];
+    if ( _hvm_init_entry(h, HVM_SAVE_CODE(VMPORT), 0,
+                         HVM_SAVE_LENGTH(VMPORT)) )
+        return 1;
+    ctxt = (struct hvm_vmport_context *)&h->data[h->cur];
+
+    spin_lock(&hd->vmport_lock);
+
+    ctxt->version = VMPORT_SAVE_VERSION;
+    ctxt->ping_time = vs->ping_time;
+    ctxt->open_cookie = vs->open_cookie;
+    ctxt->used_guestinfo = vs->used_guestinfo;
+    ctxt->used_guestinfo_jumbo = vs->used_guestinfo_jumbo;
+
+    p = ctxt->u.packed.packed_data;
+
+    for (i = 0; i < VMPORT_MAX_CHANS; i++)
+    {
+        unsigned int j;
+        unsigned int buf_max;
+
+        ctxt->u.packed.chan_ctl[i].chan = vs->chans[i].ctl;
+        buf_max = vs->chans[i].ctl.send_len;
+        if ( buf_max > VMPORT_MAX_SEND_BUF * 4 )
+            buf_max = VMPORT_MAX_SEND_BUF * 4;
+        memcpy(p, vs->chans[i].send_buf, buf_max);
+        p += buf_max;
+        for (j = 0; j < VMPORT_MAX_BKTS; j++)
+        {
+            ctxt->u.packed.chan_ctl[i].recv[j] = vs->chans[i].recv_bkt[j].ctl;
+            buf_max = vs->chans[i].recv_bkt[j].ctl.recv_len;
+            if ( buf_max > VMPORT_MAX_RECV_BUF * 4 )
+                buf_max = VMPORT_MAX_RECV_BUF * 4;
+            memcpy(p, vs->chans[i].recv_bkt[j].recv_buf, buf_max);
+            p += buf_max;
+        }
+        ctxt->u.packed.chan_ctl[i].jumbo = vs->chans[i].jumbo_recv_bkt.ctl;
+        buf_max = vs->chans[i].jumbo_recv_bkt.ctl.recv_len;
+        if ( buf_max > VMPORT_MAX_RECV_JUMBO_BUF * 4 )
+            buf_max = VMPORT_MAX_RECV_JUMBO_BUF * 4;
+        memcpy(p, vs->chans[i].jumbo_recv_bkt.recv_buf, buf_max);
+        p += buf_max;
+    }
+
+    chans_size = p - ctxt->u.packed.packed_data;
+
+    for (i = 0; i < ctxt->used_guestinfo; i++)
+    {
+        vmport_guestinfo_t *vg = vs->guestinfo[i];
+
+        if ( vg && vg->key_len )
+        {
+            guestinfo_size += sizeof(vg->key_len) + sizeof(vg->val_len) +
+                vg->key_len + vg->val_len;
+            used_guestinfo++;
+            ASSERT(sizeof(vg->key_len) == 1);
+            *p++ = (char) vg->key_len;
+            ASSERT(sizeof(vg->val_len) == 1);
+            *p++ = (char) vg->val_len;
+            if ( vg->key_len )
+            {
+                memcpy(p, vg->key_data, vg->key_len);
+                p += vg->key_len;
+                if ( vg->val_len )
+                {
+                    memcpy(p, vg->val_data, vg->val_len);
+                    p += vg->val_len;
+                }
+            }
+        }
+    }
+    ctxt->used_guestinfo = used_guestinfo;
+
+    for (i = 0; i < ctxt->used_guestinfo_jumbo; i++)
+    {
+        vmport_guestinfo_jumbo_t *vgj =
+            vs->guestinfo_jumbo[i];
+        if ( vgj && vgj->key_len )
+        {
+            guestinfo_size += sizeof(vgj->key_len) + sizeof(vgj->val_len) +
+                vgj->key_len + vgj->val_len;
+            used_guestinfo_jumbo++;
+            ASSERT(sizeof(vgj->key_len) == 1);
+            *p++ = (char) vgj->key_len;
+            memcpy(p, &vgj->val_len, sizeof(vgj->val_len));
+            p += sizeof(vgj->val_len);
+            if ( vgj->key_len )
+            {
+                memcpy(p, vgj->key_data, vgj->key_len);
+                p += vgj->key_len;
+                if ( vgj->val_len )
+                {
+                    memcpy(p, vgj->val_data, vgj->val_len);
+                    p += vgj->val_len;
+                }
+            }
+        }
+    }
+    ctxt->used_guestinfo_jumbo = used_guestinfo_jumbo;
+
+    ctxt->used_guestsize = guestinfo_size;
+
+    spin_unlock(&hd->vmport_lock);
+
+#ifndef NDEBUG
+    gdprintk(XENLOG_WARNING, "chans_size=%d guestinfo_size=%d, used=%ld\n",
+             chans_size, guestinfo_size,
+             p - ctxt->u.packed.packed_data);
+#endif
+    ASSERT(p - ctxt->u.packed.packed_data == chans_size + guestinfo_size);
+    ASSERT(desc->length >= p - (char *)ctxt);
+    desc->length = p - (char *)ctxt; /* Fixup length to be right */
+    h->cur += desc->length; /* Do _hvm_write_entry */
+    ASSERT(guestinfo_size < desc->length);
+
+    return 0;
+}
+
+static int vmport_load_domain_ctxt(struct domain *d, hvm_domain_context_t *h)
+{
+    struct hvm_vmport_context *ctxt;
+    struct hvm_save_descriptor *desc;
+    struct hvm_domain *hd = &d->arch.hvm_domain;
+    struct vmport_state *vs = hd->vmport_data;
+    unsigned int i;
+    uint8_t key_len;
+    uint16_t val_len;
+    char *p;
+    vmport_guestinfo_t *vg;
+    vmport_guestinfo_jumbo_t *vgj;
+    unsigned int loop_cnt;
+    unsigned int guestinfo_size;
+    unsigned int used_guestinfo;
+    unsigned int used_guestinfo_jumbo;
+
+    if ( !vs )
+        return -ENOMEM;
+
+    /* Customized checking for entry since our entry is of variable length */
+    desc = (struct hvm_save_descriptor *)&h->data[h->cur];
+    if ( sizeof(*desc) > h->size - h->cur )
+    {
+        printk(XENLOG_G_WARNING
+               "HVM%d restore: not enough data left to read descriptor"
+               "for type %lu\n", d->domain_id,
+               HVM_SAVE_CODE(VMPORT));
+        return -1;
+    }
+    if ( desc->length + sizeof(*desc) > h->size - h->cur )
+    {
+        printk(XENLOG_G_WARNING
+               "HVM%d restore: not enough data left to read %u bytes "
+               "for type %lu\n", d->domain_id, desc->length,
+               HVM_SAVE_CODE(VMPORT));
+        return -1;
+    }
+    if ( HVM_SAVE_CODE(VMPORT) != desc->typecode ||
+         (desc->length > HVM_SAVE_LENGTH(VMPORT)) )
+    {
+        printk(XENLOG_G_WARNING
+               "HVM%d restore mismatch: expected type %lu with max length %lu, 
"
+               "saw type %u length %u\n", d->domain_id, HVM_SAVE_CODE(VMPORT),
+               HVM_SAVE_LENGTH(VMPORT),
+               desc->typecode, desc->length);
+        return -1;
+    }
+    h->cur += sizeof(*desc);
+    /* Checking finished */
+
+    ctxt = (struct hvm_vmport_context *)&h->data[h->cur];
+    h->cur += desc->length;
+
+    if ( ctxt->version != VMPORT_SAVE_VERSION )
+        return -EINVAL;
+
+    spin_lock(&hd->vmport_lock);
+
+    vs->ping_time = ctxt->ping_time;
+    vs->open_cookie = ctxt->open_cookie;
+    vs->used_guestinfo = ctxt->used_guestinfo;
+    vs->used_guestinfo_jumbo = ctxt->used_guestinfo_jumbo;
+    guestinfo_size = ctxt->used_guestsize;
+    used_guestinfo = ctxt->used_guestinfo;
+    used_guestinfo_jumbo = ctxt->used_guestinfo_jumbo;
+
+    p = ctxt->u.packed.packed_data;
+
+    for (i = 0; i < VMPORT_MAX_CHANS; i++)
+    {
+        unsigned int j;
+
+        vs->chans[i].ctl = ctxt->u.packed.chan_ctl[i].chan;
+        memcpy(vs->chans[i].send_buf, p, vs->chans[i].ctl.send_len);
+        p += vs->chans[i].ctl.send_len;
+        for (j = 0; j < VMPORT_MAX_BKTS; j++)
+        {
+            vs->chans[i].recv_bkt[j].ctl = ctxt->u.packed.chan_ctl[i].recv[j];
+            memcpy(vs->chans[i].recv_bkt[j].recv_buf, p,
+                   vs->chans[i].recv_bkt[j].ctl.recv_len);
+            p += vs->chans[i].recv_bkt[j].ctl.recv_len;
+        }
+        vs->chans[i].jumbo_recv_bkt.ctl = ctxt->u.packed.chan_ctl[i].jumbo;
+        memcpy(vs->chans[i].jumbo_recv_bkt.recv_buf, p,
+               vs->chans[i].jumbo_recv_bkt.ctl.recv_len);
+        p += vs->chans[i].jumbo_recv_bkt.ctl.recv_len;
+    }
+
+
+    /* keep at least 10 total and 5 empty entries */
+    loop_cnt = (vs->used_guestinfo + 5) > 10 ?
+        (vs->used_guestinfo + 5) : 10;
+    for (i = 0; i < loop_cnt; i++)
+    {
+        if ( !vs->guestinfo[i] )
+        {
+            vs->guestinfo[i] = xzalloc(vmport_guestinfo_t);
+        }
+        if ( i < vs->used_guestinfo
+             && guestinfo_size > 0 )
+        {
+            key_len = (uint8_t)*p++;
+            val_len = (uint8_t)*p++;
+            guestinfo_size -= 2;
+            if ( guestinfo_size >= key_len + val_len )
+            {
+                vg = vs->guestinfo[i];
+                if ( key_len )
+                {
+                    vg->key_len = key_len;
+                    vg->val_len = val_len;
+                    memcpy(vg->key_data, p, key_len);
+                    p += key_len;
+                    memcpy(vg->val_data, p, val_len);
+                    p += val_len;
+                    guestinfo_size -= key_len + val_len;
+                }
+            }
+        }
+    }
+    vs->used_guestinfo = loop_cnt;
+
+    /* keep at least 2 total and 1 empty entries */
+    loop_cnt = (vs->used_guestinfo_jumbo + 1) > 2 ?
+        (vs->used_guestinfo_jumbo + 1) : 2;
+    for (i = 0; i < loop_cnt; i++)
+    {
+        if ( !vs->guestinfo_jumbo[i] )
+        {
+            vs->guestinfo_jumbo[i] = xzalloc(vmport_guestinfo_jumbo_t);
+        }
+        if ( i < vs->used_guestinfo_jumbo
+             && guestinfo_size > 0 )
+        {
+            key_len = (uint8_t)*p++;
+            memcpy(&val_len, p, 2);
+            p += 2;
+            guestinfo_size -= 3;
+            if ( guestinfo_size >= key_len + val_len )
+            {
+                vgj = vs->guestinfo_jumbo[i];
+                if ( key_len )
+                {
+                    vgj->key_len = key_len;
+                    vgj->val_len = val_len;
+                    memcpy(vgj->key_data, p, key_len);
+                    p += key_len;
+                    memcpy(vgj->val_data, p, val_len);
+                    p += val_len;
+                    guestinfo_size -= key_len + val_len;
+                }
+            }
+        }
+    }
+    vs->used_guestinfo_jumbo = loop_cnt;
+
+    spin_unlock(&hd->vmport_lock);
+
+    return 0;
+}
+
+HVM_REGISTER_SAVE_RESTORE(VMPORT, vmport_save_domain_ctxt,
+                          vmport_load_domain_ctxt, 1, HVMSR_PER_DOM);
+
+/*
+ * 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/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index 4a4f4e1..fa1f69a 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -1077,6 +1077,7 @@ static int construct_vmcs(struct vcpu *v)
 
     v->arch.hvm_vmx.exception_bitmap = HVM_TRAP_MASK
               | (paging_mode_hap(d) ? 0 : (1U << TRAP_page_fault))
+              | (1U << TRAP_gp_fault)
               | (1U << TRAP_no_device);
     vmx_update_exception_bitmap(v);
 
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 26b1ad5..f807d36 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -44,6 +44,7 @@
 #include <asm/hvm/support.h>
 #include <asm/hvm/vmx/vmx.h>
 #include <asm/hvm/vmx/vmcs.h>
+#include <asm/hvm/vmport.h>
 #include <public/sched.h>
 #include <public/hvm/ioreq.h>
 #include <asm/hvm/vpic.h>
@@ -1279,6 +1280,7 @@ static void vmx_update_guest_cr(struct vcpu *v, unsigned 
int cr)
                 v->arch.hvm_vmx.exception_bitmap = HVM_TRAP_MASK
                           | (paging_mode_hap(v->domain) ?
                              0 : (1U << TRAP_page_fault))
+                          | (1U << TRAP_gp_fault)
                           | (1U << TRAP_no_device);
                 vmx_update_exception_bitmap(v);
                 vmx_update_debug_state(v);
@@ -2565,6 +2567,82 @@ static void vmx_idtv_reinject(unsigned long idtv_info)
     }
 }
 
+void do_gp_fault(struct cpu_user_regs *regs, struct vcpu *v)
+{
+    unsigned long exit_qualification;
+    unsigned long inst_len;
+    unsigned long ecode;
+
+    __vmread(EXIT_QUALIFICATION, &exit_qualification);
+    __vmread(VM_EXIT_INSTRUCTION_LEN, &inst_len);
+    __vmread(VM_EXIT_INTR_ERROR_CODE, &ecode);
+    regs->error_code = ecode;
+    if ( hvm_long_mode_enabled(v) )
+        HVMTRACE_LONG_C4D(TRAP_GP, TRAP_gp_fault, inst_len, ecode,
+                          TRC_PAR_LONG(exit_qualification));
+    else
+        HVMTRACE_C4D(TRAP_GP, TRAP_gp_fault, inst_len, ecode,
+                     exit_qualification);
+
+    if ( inst_len == 1 && (regs->rdx & 0xffff) == VMPORT_PORT &&
+         exit_qualification == 0 && ecode == 0 )
+    {
+        uint32_t magic = regs->rax;
+
+        if ( magic == VMPORT_MAGIC )
+        {
+            unsigned char bytes[1] = { 0 };
+            int frc = hvm_fetch_from_guest_virt_nofault(bytes, regs->rip,
+                                                        1, PFEC_page_present);
+
+            if ( !frc && bytes[0] == 0xed ) /* in (%dx),%eax */
+            {
+                uint32_t val;
+
+                update_guest_eip();
+                vmport_ioport(IOREQ_READ, VMPORT_PORT, 4, &val);
+                VMPORT_DBG_LOG(VMPORT_LOG_VMWARE_AFTER,
+                               "gp: VMware ip=%"PRIx64" ax=%"PRIx64
+                               " bx=%"PRIx64" cx=%"PRIx64" dx=%"PRIx64
+                               " si=%"PRIx64" di=%"PRIx64,
+                               regs->rip, regs->rax, regs->rbx, regs->rcx,
+                               regs->rdx, regs->rsi, regs->rdi);
+                return;
+            }
+            else
+            {
+                VMPORT_DBG_LOG(VMPORT_LOG_GP_FAIL_RD_INST,
+                               "gp: VMware? ip=%"PRIx64"=>0x%x(%d) ax=%"PRIx64
+                               " bx=%"PRIx64" cx=%"PRIx64" dx=%"PRIx64
+                               " si=%"PRIx64" di=%"PRIx64,
+                               regs->rip, bytes[0], frc, regs->rax, regs->rbx,
+                               regs->rcx, regs->rdx, regs->rsi, regs->rdi);
+            }
+        }
+        else
+        {
+            VMPORT_DBG_LOG(VMPORT_LOG_GP_NOT_VMWARE,
+                           "gp: ip=%"PRIx64" ax=%"PRIx64" bx=%"PRIx64
+                           " cx=%"PRIx64" dx=%"PRIx64" si=%"PRIx64
+                           " di=%"PRIx64,
+                           regs->rip, regs->rax, regs->rbx, regs->rcx,
+                           regs->rdx, regs->rsi, regs->rdi);
+            hvm_inject_hw_exception(TRAP_gp_fault, ecode);
+        }
+    }
+    else
+    {
+        VMPORT_DBG_LOG(VMPORT_LOG_GP_UNKNOWN,
+                       "gp: eq=%lx ec=%lx ip=%"PRIx64" (%ld) ax=%"PRIx64
+                       " bx=%"PRIx64" cx=%"PRIx64" dx=%"PRIx64
+                       " si=%"PRIx64" di=%"PRIx64,
+                       exit_qualification, ecode,
+                       regs->rip, inst_len, regs->rax, regs->rbx, regs->rcx,
+                       regs->rdx, regs->rsi, regs->rdi);
+        hvm_inject_hw_exception(TRAP_gp_fault, ecode);
+    }
+}
+
 static int vmx_handle_apic_write(void)
 {
     unsigned long exit_qualification;
@@ -2675,6 +2753,15 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
                  && vector != TRAP_nmi 
                  && vector != TRAP_machine_check ) 
             {
+                if ( vector == TRAP_gp_fault )
+                {
+                    VMPORT_DBG_LOG(VMPORT_LOG_REALMODE_GP,
+                                   "realmode gp: ip=%"PRIx64" ax=%"PRIx64
+                                   " bx=%"PRIx64" cx=%"PRIx64" dx=%"PRIx64
+                                   " si=%"PRIx64" di=%"PRIx64,
+                                   regs->rip, regs->rax, regs->rbx, regs->rcx,
+                                   regs->rdx, regs->rsi, regs->rdi);
+                }
                 perfc_incr(realmode_exits);
                 v->arch.hvm_vmx.vmx_emulate = 1;
                 HVMTRACE_0D(REALMODE_EMULATE);
@@ -2790,6 +2877,9 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
             HVMTRACE_1D(TRAP, vector);
             vmx_fpu_dirty_intercept();
             break;
+        case TRAP_gp_fault:
+            do_gp_fault(regs, v);
+            break;
         case TRAP_page_fault:
             __vmread(EXIT_QUALIFICATION, &exit_qualification);
             __vmread(VM_EXIT_INTR_ERROR_CODE, &ecode);
diff --git a/xen/arch/x86/hvm/vmx/vvmx.c b/xen/arch/x86/hvm/vmx/vvmx.c
index 9ccc03f..734d88e 100644
--- a/xen/arch/x86/hvm/vmx/vvmx.c
+++ b/xen/arch/x86/hvm/vmx/vvmx.c
@@ -24,6 +24,7 @@
 #include <asm/types.h>
 #include <asm/mtrr.h>
 #include <asm/p2m.h>
+#include <asm/hvm/vmport.h>
 #include <asm/hvm/vmx/vmx.h>
 #include <asm/hvm/vmx/vvmx.h>
 #include <asm/hvm/nestedhvm.h>
@@ -2182,6 +2183,19 @@ int nvmx_n2_vmexit_handler(struct cpu_user_regs *regs,
             if ( v->fpu_dirtied )
                 nvcpu->nv_vmexit_pending = 1;
         }
+        else if ( vector == TRAP_gp_fault )
+        {
+#ifndef NDEBUG
+            struct cpu_user_regs *ur = guest_cpu_user_regs();
+#endif
+            VMPORT_DBG_LOG(VMPORT_LOG_VGP_UNKNOWN,
+                           "Unexpected gp: ip=%"PRIx64" ax=%"PRIx64
+                           " bx=%"PRIx64" cx=%"PRIx64" dx=%"PRIx64
+                           " si=%"PRIx64" di=%"PRIx64,
+                           ur->rip, ur->rax, ur->rbx, ur->rcx, ur->rdx,
+                           ur->rsi, ur->rdi);
+                nvcpu->nv_vmexit_pending = 1;
+        }
         else if ( (intr_info & valid_mask) == valid_mask )
         {
             exec_bitmap =__get_vvmcs(nvcpu->nv_vvmcx, EXCEPTION_BITMAP);
diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h
index 526b5da..7bbf1de 100644
--- a/xen/include/asm-x86/hvm/domain.h
+++ b/xen/include/asm-x86/hvm/domain.h
@@ -108,6 +108,10 @@ struct hvm_domain {
     /* emulated irq to pirq */
     struct radix_tree_root emuirq_pirq;
 
+    /* VMware special port */
+    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/svm/emulate.h 
b/xen/include/asm-x86/hvm/svm/emulate.h
index ccc2d3c..4ff1aea 100644
--- a/xen/include/asm-x86/hvm/svm/emulate.h
+++ b/xen/include/asm-x86/hvm/svm/emulate.h
@@ -39,6 +39,7 @@ enum instruction_index {
     INSTR_STGI,
     INSTR_CLGI,
     INSTR_INVLPGA,
+    INSTR_IN,
     INSTR_MAX_COUNT /* Must be last - Number of instructions supported */
 };
 
diff --git a/xen/include/asm-x86/hvm/trace.h b/xen/include/asm-x86/hvm/trace.h
index de802a6..2cd60c2 100644
--- a/xen/include/asm-x86/hvm/trace.h
+++ b/xen/include/asm-x86/hvm/trace.h
@@ -52,8 +52,15 @@
 #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_TRAP_GP          DEFAULT_HVM_MISC
+#define DO_TRC_HVM_TRAP_GP64        DEFAULT_HVM_MISC
+#define DO_TRC_HVM_VMPORT_READ1     DEFAULT_HVM_IO
+#define DO_TRC_HVM_VMPORT_WRITE1    DEFAULT_HVM_IO
+#define DO_TRC_HVM_VMPORT_READ2     DEFAULT_HVM_IO
+#define DO_TRC_HVM_VMPORT_WRITE2    DEFAULT_HVM_IO
 
 
 #define TRC_PAR_LONG(par) ((par)&0xFFFFFFFF),((par)>>32)
@@ -98,6 +105,21 @@
 #define HVMTRACE_0D(evt)                            \
     HVMTRACE_ND(evt, 0, 0, 0,  0,  0,  0,  0,  0,  0)
 
+#define HVMTRACE_C6D(evt, d1, d2, d3, d4, d5, d6)    \
+    HVMTRACE_ND(evt, 0, 1, 6, d1, d2, d3, d4, d5, d6)
+#define HVMTRACE_C5D(evt, d1, d2, d3, d4, d5)        \
+    HVMTRACE_ND(evt, 0, 1, 5, d1, d2, d3, d4, d5,  0)
+#define HVMTRACE_C4D(evt, d1, d2, d3, d4)            \
+    HVMTRACE_ND(evt, 0, 1, 4, d1, d2, d3, d4,  0,  0)
+#define HVMTRACE_C3D(evt, d1, d2, d3)                \
+    HVMTRACE_ND(evt, 0, 1, 3, d1, d2, d3,  0,  0,  0)
+#define HVMTRACE_C2D(evt, d1, d2)                    \
+    HVMTRACE_ND(evt, 0, 1, 2, d1, d2,  0,  0,  0,  0)
+#define HVMTRACE_C1D(evt, d1)                        \
+    HVMTRACE_ND(evt, 0, 1, 1, d1,  0,  0,  0,  0,  0)
+#define HVMTRACE_C0D(evt)                            \
+    HVMTRACE_ND(evt, 0, 1, 0,  0,  0,  0,  0,  0,  0)
+
 #define HVMTRACE_LONG_1D(evt, d1)                  \
                    HVMTRACE_2D(evt ## 64, (d1) & 0xFFFFFFFF, (d1) >> 32)
 #define HVMTRACE_LONG_2D(evt, d1, d2, ...)              \
@@ -107,6 +129,15 @@
 #define HVMTRACE_LONG_4D(evt, d1, d2, d3, d4, ...)  \
                    HVMTRACE_5D(evt ## 64, d1, d2, d3, d4)
 
+#define HVMTRACE_LONG_C1D(evt, d1)                  \
+                   HVMTRACE_C2D(evt ## 64, (d1) & 0xFFFFFFFF, (d1) >> 32)
+#define HVMTRACE_LONG_C2D(evt, d1, d2, ...)              \
+                   HVMTRACE_C3D(evt ## 64, d1, d2)
+#define HVMTRACE_LONG_C3D(evt, d1, d2, d3, ...)      \
+                   HVMTRACE_C4D(evt ## 64, d1, d2, d3)
+#define HVMTRACE_LONG_C4D(evt, d1, d2, d3, d4, ...)  \
+                   HVMTRACE_C5D(evt ## 64, d1, d2, d3, d4)
+
 #endif /* __ASM_X86_HVM_TRACE_H__ */
 
 /*
diff --git a/xen/include/asm-x86/hvm/vmport.h b/xen/include/asm-x86/hvm/vmport.h
new file mode 100644
index 0000000..e72e422
--- /dev/null
+++ b/xen/include/asm-x86/hvm/vmport.h
@@ -0,0 +1,90 @@
+/*
+ * vmport.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 __ASM_X86_HVM_VMPORT_H__
+#define __ASM_X86_HVM_VMPORT_H__
+
+#ifndef NDEBUG
+#define VMPORT_LOG_RPC             (1 << 0)
+#define VMPORT_LOG_RECV_STATUS     (1 << 1)
+#define VMPORT_LOG_SKIP_SEND       (1 << 2)
+#define VMPORT_LOG_SEND            (1 << 3)
+#define VMPORT_LOG_SEND_SIZE_ALL   (1 << 4)
+#define VMPORT_LOG_SEND_SIZE       (1 << 5)
+#define VMPORT_LOG_RECV_SIZE_ALL   (1 << 6)
+#define VMPORT_LOG_RECV_SIZE       (1 << 7)
+#define VMPORT_LOG_CLOSE           (1 << 8)
+#define VMPORT_LOG_OPEN            (1 << 9)
+#define VMPORT_LOG_FLUSH           (1 << 10)
+#define VMPORT_LOG_TRACE           (1 << 11)
+#define VMPORT_LOG_PING            (1 << 12)
+#define VMPORT_LOG_SWEEP           (1 << 13)
+#define VMPORT_LOG_BUILD           (1 << 14)
+
+#define VMPORT_LOG_ERROR           (1 << 16)
+
+#define VMPORT_LOG_INFO_GET        (1 << 17)
+#define VMPORT_LOG_INFO_SET        (1 << 18)
+
+#define VMPORT_LOG_SKIP_MESSAGE    (1 << 19)
+
+#define VMPORT_LOG_GP_UNKNOWN      (1 << 20)
+#define VMPORT_LOG_GP_NOT_VMWARE   (1 << 21)
+#define VMPORT_LOG_GP_FAIL_RD_INST (1 << 22)
+
+#define VMPORT_LOG_GP_VMWARE_AFTER (1 << 23)
+
+#define VMPORT_LOG_VGP_UNKNOWN     (1 << 24)
+#define VMPORT_LOG_REALMODE_GP     (1 << 27)
+
+#define VMPORT_LOG_VMWARE_AFTER    (1 << 28)
+
+extern unsigned int opt_vmport_debug;
+#define VMPORT_DBG_LOG(level, _f, _a...)                                \
+    do {                                                                \
+        if ( unlikely((level) & opt_vmport_debug) )                     \
+            printk("[HVM:%d.%d] <%s> " _f "\n",                         \
+                   current->domain->domain_id, current->vcpu_id, __func__, \
+                   ## _a);                                              \
+    } while (0)
+#else
+#define VMPORT_DBG_LOG(level, _f, _a...) do {} while (0)
+#endif
+
+/* Note: VMPORT_PORT and VMPORT_MAGIC is also defined as BDOOR_PORT
+ * and BDOOR_MAGIC in backdoor_def.h Defined here so that other
+ * parts of XEN can use it.
+ */
+
+#define VMPORT_PORT 0x5658
+#define VMPORT_MAGIC 0x564D5868
+
+#include "public/arch-x86/hvm/vmporttype.h"
+
+int vmport_ioport(int dir, uint32_t port, uint32_t bytes, uint32_t *val);
+void vmport_ctrl_send(struct hvm_domain *hd, char *msg);
+void vmport_flush(struct hvm_domain *hd);
+
+#endif /* __ASM_X86_HVM_VMPORT_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/include/public/arch-x86/hvm/save.h 
b/xen/include/public/arch-x86/hvm/save.h
index 16d85a3..7cdcb8f 100644
--- a/xen/include/public/arch-x86/hvm/save.h
+++ b/xen/include/public/arch-x86/hvm/save.h
@@ -26,6 +26,8 @@
 #ifndef __XEN_PUBLIC_HVM_SAVE_X86_H__
 #define __XEN_PUBLIC_HVM_SAVE_X86_H__
 
+#include "vmporttype.h"
+
 /* 
  * Save/restore header: general info about the save file. 
  */
@@ -610,9 +612,44 @@ struct hvm_msr {
 
 #define CPU_MSR_CODE  20
 
+/*
+ * VMware context.
+ */
+struct hvm_vmport_context {
+    uint32_t version;
+    uint32_t used_guestsize;
+    uint64_t ping_time;
+    uint32_t open_cookie;
+    uint32_t used_guestinfo;
+    uint32_t used_guestinfo_jumbo;
+    union {
+        struct {
+            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];
+        } full;
+        struct {
+            struct {
+                vmport_channel_control_t chan;
+                vmport_bucket_control_t recv[VMPORT_MAX_BKTS];
+                vmport_bucket_control_t jumbo;
+            } chan_ctl[VMPORT_MAX_CHANS];
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+            char packed_data[];
+#elif defined(__GNUC__)
+            char packed_data[0];
+#else
+            char packed_data[1 /* Variable length */];
+#endif
+        } packed;
+    } u;
+};
+
+DECLARE_HVM_SAVE_TYPE(VMPORT, 21, struct hvm_vmport_context);
+
 /* 
  * Largest type-code in use
  */
-#define HVM_SAVE_CODE_MAX 20
+#define HVM_SAVE_CODE_MAX 21
 
 #endif /* __XEN_PUBLIC_HVM_SAVE_X86_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..3ecbe25
--- /dev/null
+++ b/xen/include/public/arch-x86/hvm/vmporttype.h
@@ -0,0 +1,105 @@
+/*
+ * 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/domctl.h b/xen/include/public/domctl.h
index 5b11bbf..fd4cc8a 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -458,6 +458,9 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_address_size_t);
 #define XEN_DOMCTL_SENDTRIGGER_INIT   2
 #define XEN_DOMCTL_SENDTRIGGER_POWER  3
 #define XEN_DOMCTL_SENDTRIGGER_SLEEP  4
+#define XEN_DOMCTL_SENDTRIGGER_VTPOWER  5
+#define XEN_DOMCTL_SENDTRIGGER_VTREBOOT 6
+#define XEN_DOMCTL_SENDTRIGGER_VTPING   7
 struct xen_domctl_sendtrigger {
     uint32_t  trigger;  /* IN */
     uint32_t  vcpu;     /* IN */
diff --git a/xen/include/public/hvm/hvm_op.h b/xen/include/public/hvm/hvm_op.h
index eeb0a60..185e33d 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__ */
diff --git a/xen/include/public/trace.h b/xen/include/public/trace.h
index cfcf4aa..b81fc66 100644
--- a/xen/include/public/trace.h
+++ b/xen/include/public/trace.h
@@ -224,11 +224,18 @@
 #define TRC_HVM_NPF             (TRC_HVM_HANDLER + 0x21)
 #define TRC_HVM_REALMODE_EMULATE (TRC_HVM_HANDLER + 0x22)
 #define TRC_HVM_TRAP             (TRC_HVM_HANDLER + 0x23)
+#define TRC_HVM_TRAP64           (TRC_HVM_HANDLER + TRC_64_FLAG + 0x23)
 #define TRC_HVM_TRAP_DEBUG       (TRC_HVM_HANDLER + 0x24)
 #define TRC_HVM_VLAPIC           (TRC_HVM_HANDLER + 0x25)
+#define TRC_HVM_TRAP_GP          (TRC_HVM_HANDLER + 0x26)
+#define TRC_HVM_TRAP_GP64        (TRC_HVM_HANDLER + TRC_64_FLAG + 0x26)
+#define TRC_HVM_VMPORT_READ1     (TRC_HVM_HANDLER + 0x27)
+#define TRC_HVM_VMPORT_READ2     (TRC_HVM_HANDLER + 0x28)
 
 #define TRC_HVM_IOPORT_WRITE    (TRC_HVM_HANDLER + 0x216)
 #define TRC_HVM_IOMEM_WRITE     (TRC_HVM_HANDLER + 0x217)
+#define TRC_HVM_VMPORT_WRITE1   (TRC_HVM_HANDLER + 0x227)
+#define TRC_HVM_VMPORT_WRITE2   (TRC_HVM_HANDLER + 0x228)
 
 /* Trace events for emulated devices */
 #define TRC_HVM_EMUL_HPET_START_TIMER  (TRC_HVM_EMUL + 0x1)
-- 
1.8.4


_______________________________________________
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®.