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

[Xen-devel] [PATCH v11 6/9] xen: Add ring 3 vmware_port support



Summary is that VMware treats "in (%dx),%eax" (or "out %eax,(%dx)")
to port 0x5658 specially.  Note: since many operations return data
in EAX, "in (%dx),%eax" is the one to use.  The other lengths like
"in (%dx),%al" will still do things, only AL part of EAX will be
changed.  For "out %eax,(%dx)" of all lengths, EAX will remain
unchanged.

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.

Enable no-fault of pio in x86_emulate for VMware port

Also adjust the emulation registers after doing a VMware
backdoor operation.

Add new routine hvm_emulate_one_gp() to be used by the #GP fault
handler.

Some of the best info is at:

https://sites.google.com/site/chitchatvmback/backdoor

Signed-off-by: Don Slutz <dslutz@xxxxxxxxxxx>
---
v11:
  No change

v10:
   Re-worked to be simpler.

v9:
   Split #GP handling (or skipping of #GP) code out of previous
   patch to help with the review process.
   Switch to x86_emulator to handle #GP
   I think the hvm_emulate_ops_gp() covers all needed ops.  Not able to validate
   all paths though _hvm_emulate_one().

 xen/arch/x86/hvm/emulate.c             | 54 ++++++++++++++++++++++++++++++++--
 xen/arch/x86/hvm/svm/svm.c             | 26 ++++++++++++++++
 xen/arch/x86/hvm/svm/vmcb.c            |  2 ++
 xen/arch/x86/hvm/vmware/vmport.c       | 11 +++++++
 xen/arch/x86/hvm/vmx/vmcs.c            |  2 ++
 xen/arch/x86/hvm/vmx/vmx.c             | 37 +++++++++++++++++++++++
 xen/arch/x86/x86_emulate/x86_emulate.c | 13 +++++++-
 xen/arch/x86/x86_emulate/x86_emulate.h |  5 ++++
 xen/include/asm-x86/hvm/emulate.h      |  2 ++
 xen/include/asm-x86/hvm/hvm.h          |  1 +
 10 files changed, 150 insertions(+), 3 deletions(-)

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index ac9c9d6..d5e6468 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -803,6 +803,27 @@ static int hvmemul_wbinvd_discard(
     return X86EMUL_OKAY;
 }
 
+static int hvmemul_write_gp(
+    unsigned int seg,
+    unsigned long offset,
+    void *p_data,
+    unsigned int bytes,
+    struct x86_emulate_ctxt *ctxt)
+{
+    return X86EMUL_EXCEPTION;
+}
+
+static int hvmemul_cmpxchg_gp(
+    unsigned int seg,
+    unsigned long offset,
+    void *old,
+    void *new,
+    unsigned int bytes,
+    struct x86_emulate_ctxt *ctxt)
+{
+    return X86EMUL_EXCEPTION;
+}
+
 static int hvmemul_cmpxchg(
     enum x86_segment seg,
     unsigned long offset,
@@ -1356,6 +1377,13 @@ static int hvmemul_invlpg(
     return rc;
 }
 
+static int hvmemul_vmport_check(
+    unsigned int first_port,
+    struct x86_emulate_ctxt *ctxt)
+{
+    return vmport_check_port(first_port);
+}
+
 static const struct x86_emulate_ops hvm_emulate_ops = {
     .read          = hvmemul_read,
     .insn_fetch    = hvmemul_insn_fetch,
@@ -1379,7 +1407,8 @@ static const struct x86_emulate_ops hvm_emulate_ops = {
     .inject_sw_interrupt = hvmemul_inject_sw_interrupt,
     .get_fpu       = hvmemul_get_fpu,
     .put_fpu       = hvmemul_put_fpu,
-    .invlpg        = hvmemul_invlpg
+    .invlpg        = hvmemul_invlpg,
+    .vmport_check  = hvmemul_vmport_check,
 };
 
 static const struct x86_emulate_ops hvm_emulate_ops_no_write = {
@@ -1405,7 +1434,22 @@ static const struct x86_emulate_ops 
hvm_emulate_ops_no_write = {
     .inject_sw_interrupt = hvmemul_inject_sw_interrupt,
     .get_fpu       = hvmemul_get_fpu,
     .put_fpu       = hvmemul_put_fpu,
-    .invlpg        = hvmemul_invlpg
+    .invlpg        = hvmemul_invlpg,
+    .vmport_check  = hvmemul_vmport_check,
+};
+
+static const struct x86_emulate_ops hvm_emulate_ops_gp = {
+    .read          = hvmemul_read,
+    .insn_fetch    = hvmemul_insn_fetch,
+    .write         = hvmemul_write_gp,
+    .cmpxchg       = hvmemul_cmpxchg_gp,
+    .read_segment  = hvmemul_read_segment,
+    .write_segment = hvmemul_write_segment,
+    .read_io       = hvmemul_read_io,
+    .write_io      = hvmemul_write_io,
+    .inject_hw_exception = hvmemul_inject_hw_exception,
+    .inject_sw_interrupt = hvmemul_inject_sw_interrupt,
+    .vmport_check  = hvmemul_vmport_check,
 };
 
 static int _hvm_emulate_one(struct hvm_emulate_ctxt *hvmemul_ctxt,
@@ -1522,6 +1566,12 @@ int hvm_emulate_one(
     return _hvm_emulate_one(hvmemul_ctxt, &hvm_emulate_ops);
 }
 
+int hvm_emulate_one_gp(
+    struct hvm_emulate_ctxt *hvmemul_ctxt)
+{
+    return _hvm_emulate_one(hvmemul_ctxt, &hvm_emulate_ops_gp);
+}
+
 int hvm_emulate_one_no_write(
     struct hvm_emulate_ctxt *hvmemul_ctxt)
 {
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 6734fb6..62baf3c 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -2119,6 +2119,28 @@ 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;
+    int rc;
+
+    if ( vmcb->exitinfo1 != 0 || vmcb->exitinfo2 != 0 )
+        rc = X86EMUL_EXCEPTION;
+    else
+    {
+        struct hvm_emulate_ctxt ctxt;
+
+        hvm_emulate_prepare(&ctxt, regs);
+        rc = hvm_emulate_one_gp(&ctxt);
+
+        if ( rc == X86EMUL_OKAY )
+            hvm_emulate_writeback(&ctxt);
+    }
+    if ( rc != X86EMUL_OKAY && rc != X86EMUL_RETRY )
+        hvm_inject_hw_exception(TRAP_gp_fault, vmcb->exitinfo1);
+}
+
 static void svm_vmexit_ud_intercept(struct cpu_user_regs *regs)
 {
     struct hvm_emulate_ctxt ctxt;
@@ -2484,6 +2506,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 6339d2a..7683c09 100644
--- a/xen/arch/x86/hvm/svm/vmcb.c
+++ b/xen/arch/x86/hvm/svm/vmcb.c
@@ -195,6 +195,8 @@ static int construct_vmcb(struct vcpu *v)
         HVM_TRAP_MASK
         | (1U << TRAP_no_device);
 
+    if ( v->domain->arch.hvm_domain.is_vmware_port_enabled )
+        vmcb->_exception_intercepts |= 1U << TRAP_gp_fault;
     if ( paging_mode_hap(v->domain) )
     {
         vmcb->_np_enable = 1; /* enable nested paging */
diff --git a/xen/arch/x86/hvm/vmware/vmport.c b/xen/arch/x86/hvm/vmware/vmport.c
index f24d8e3..36e3f1b 100644
--- a/xen/arch/x86/hvm/vmware/vmport.c
+++ b/xen/arch/x86/hvm/vmware/vmport.c
@@ -137,6 +137,17 @@ void vmport_register(struct domain *d)
     register_portio_handler(d, BDOOR_PORT, 4, vmport_ioport);
 }
 
+int vmport_check_port(unsigned int port)
+{
+    struct vcpu *curr = current;
+    struct domain *currd = curr->domain;
+
+    if ( port == BDOOR_PORT && is_hvm_domain(currd) &&
+         currd->arch.hvm_domain.is_vmware_port_enabled )
+        return 0;
+    return 1;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index 877ec10..54360b0 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -1151,6 +1151,8 @@ 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))
+              | (v->domain->arch.hvm_domain.is_vmware_port_enabled ?
+                 (1U << TRAP_gp_fault) : 0)
               | (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 74f563f..fe88afe 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1312,6 +1312,8 @@ 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))
+                          | (v->domain->arch.hvm_domain.is_vmware_port_enabled 
?
+                             (1U << TRAP_gp_fault) : 0)
                           | (1U << TRAP_no_device);
                 vmx_update_exception_bitmap(v);
                 vmx_update_debug_state(v);
@@ -2671,6 +2673,38 @@ static void vmx_idtv_reinject(unsigned long idtv_info)
     }
 }
 
+static void vmx_vmexit_gp_intercept(struct cpu_user_regs *regs,
+                                    struct vcpu *v)
+{
+    unsigned long exit_qualification;
+    unsigned long ecode;
+    int rc;
+    unsigned long vector;
+
+    __vmread(VM_EXIT_INTR_INFO, &vector);
+    ASSERT(vector & INTR_INFO_VALID_MASK);
+    ASSERT(vector & INTR_INFO_DELIVER_CODE_MASK);
+
+    __vmread(EXIT_QUALIFICATION, &exit_qualification);
+    __vmread(VM_EXIT_INTR_ERROR_CODE, &ecode);
+
+    if ( ecode != 0 || exit_qualification != 0 )
+        rc = X86EMUL_EXCEPTION;
+    else
+    {
+        struct hvm_emulate_ctxt ctxt;
+
+        hvm_emulate_prepare(&ctxt, regs);
+        rc = hvm_emulate_one_gp(&ctxt);
+
+        if ( rc == X86EMUL_OKAY )
+            hvm_emulate_writeback(&ctxt);
+    }
+
+    if ( rc != X86EMUL_OKAY && rc != X86EMUL_RETRY )
+        hvm_inject_hw_exception(TRAP_gp_fault, ecode);
+}
+
 static int vmx_handle_apic_write(void)
 {
     unsigned long exit_qualification;
@@ -2895,6 +2929,9 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
             HVMTRACE_1D(TRAP, vector);
             vmx_fpu_dirty_intercept();
             break;
+        case TRAP_gp_fault:
+            vmx_vmexit_gp_intercept(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/x86_emulate/x86_emulate.c 
b/xen/arch/x86/x86_emulate/x86_emulate.c
index c017c69..d3ea143 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -3393,8 +3393,11 @@ x86_emulate(
         unsigned int port = ((b < 0xe8)
                              ? insn_fetch_type(uint8_t)
                              : (uint16_t)_regs.edx);
+       bool_t vmport = (ops->vmport_check && /* Vmware backdoor? */
+                        (ops->vmport_check(port, ctxt) == 0));
         op_bytes = !(b & 1) ? 1 : (op_bytes == 8) ? 4 : op_bytes;
-        if ( (rc = ioport_access_check(port, op_bytes, ctxt, ops)) != 0 )
+        if ( !vmport &&
+            (rc = ioport_access_check(port, op_bytes, ctxt, ops)) != 0 )
             goto done;
         if ( b & 2 )
         {
@@ -3413,6 +3416,14 @@ x86_emulate(
         }
         if ( rc != 0 )
             goto done;
+       if ( vmport )
+       {
+            _regs._ebx = ctxt->regs->_ebx;
+            _regs._ecx = ctxt->regs->_ecx;
+            _regs._edx = ctxt->regs->_edx;
+            _regs._esi = ctxt->regs->_esi;
+            _regs._edi = ctxt->regs->_edi;
+       }
         break;
     }
 
diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h 
b/xen/arch/x86/x86_emulate/x86_emulate.h
index 064b8f4..d914b5e 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.h
+++ b/xen/arch/x86/x86_emulate/x86_emulate.h
@@ -397,6 +397,11 @@ struct x86_emulate_ops
         enum x86_segment seg,
         unsigned long offset,
         struct x86_emulate_ctxt *ctxt);
+
+    /* vmport_check */
+    int (*vmport_check)(
+        unsigned int port,
+        struct x86_emulate_ctxt *ctxt);
 };
 
 struct cpu_user_regs;
diff --git a/xen/include/asm-x86/hvm/emulate.h 
b/xen/include/asm-x86/hvm/emulate.h
index b3971c8..4386169 100644
--- a/xen/include/asm-x86/hvm/emulate.h
+++ b/xen/include/asm-x86/hvm/emulate.h
@@ -36,6 +36,8 @@ struct hvm_emulate_ctxt {
 
 int hvm_emulate_one(
     struct hvm_emulate_ctxt *hvmemul_ctxt);
+int hvm_emulate_one_gp(
+    struct hvm_emulate_ctxt *hvmemul_ctxt);
 int hvm_emulate_one_no_write(
     struct hvm_emulate_ctxt *hvmemul_ctxt);
 void hvm_mem_access_emulate_one(bool_t nowrite,
diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h
index e76f612..c42f7d8 100644
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -523,6 +523,7 @@ extern bool_t opt_hvm_fep;
 #endif
 
 void vmport_register(struct domain *d);
+int vmport_check_port(unsigned int port);
 
 #endif /* __ASM_X86_HVM_HVM_H__ */
 
-- 
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®.