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

[Xen-devel] [RFC] x86/vm_event: Allow returning i-cache for emulation



When emulating instructions the emulator maintains a small i-cache fetched
from the guest memory. Under certain scenarios this memory region may contain
instructions that a monitor subscriber would prefer to hide, namely INT3, and
instead would prefer to emulate a different instruction in-place.

This patch extends the vm_event interface to allow returning this i-cache via
the vm_event response.

Signed-off-by: Tamas K Lengyel <tamas.lengyel@xxxxxxxxxxxx>
---
Cc: Paul Durrant <paul.durrant@xxxxxxxxxx>
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
Cc: Jun Nakajima <jun.nakajima@xxxxxxxxx>
Cc: Kevin Tian <kevin.tian@xxxxxxxxx>
Cc: George Dunlap <george.dunlap@xxxxxxxxxxxxx>
Cc: Razvan Cojocaru <rcojocaru@xxxxxxxxxxxxxxx>
Cc: Tamas K Lengyel <tamas@xxxxxxxxxxxxx>
Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>
Cc: Julien Grall <julien.grall@xxxxxxx>
---
 xen/arch/x86/hvm/emulate.c        | 47 +++++++++++++++++++++++++--------------
 xen/arch/x86/hvm/hvm.c            |  2 +-
 xen/arch/x86/hvm/vmx/vmx.c        |  1 +
 xen/arch/x86/mm/p2m.c             |  7 ++++--
 xen/arch/x86/vm_event.c           | 10 +++++++++
 xen/common/vm_event.c             |  5 ++++-
 xen/include/asm-arm/vm_event.h    |  6 +++++
 xen/include/asm-x86/hvm/emulate.h |  6 +++--
 xen/include/asm-x86/vm_event.h    |  4 +++-
 xen/include/public/vm_event.h     | 11 +++++++--
 10 files changed, 73 insertions(+), 26 deletions(-)

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index c55ad7b..968fb7b 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -76,9 +76,12 @@ static int set_context_data(void *buffer, unsigned int size)
     if ( curr->arch.vm_event )
     {
         unsigned int safe_size =
-            min(size, curr->arch.vm_event->emul_read_data.size);
+            min(size, curr->arch.vm_event->emul_data.size);
 
-        memcpy(buffer, curr->arch.vm_event->emul_read_data.data, safe_size);
+        gdprintk(XENLOG_WARNING, "Got buffer of size: %u. Request is for %u. 
Safe size: %u\n",
+                 curr->arch.vm_event->emul_data.size, size, safe_size);
+
+        memcpy(buffer, curr->arch.vm_event->emul_data.data, safe_size);
         memset(buffer + safe_size, 0, size - safe_size);
         return X86EMUL_OKAY;
     }
@@ -825,7 +828,7 @@ static int hvmemul_read(
     struct hvm_emulate_ctxt *hvmemul_ctxt =
         container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
 
-    if ( unlikely(hvmemul_ctxt->set_context) )
+    if ( unlikely(hvmemul_ctxt->set_context_data) )
         return set_context_data(p_data, bytes);
 
     return __hvmemul_read(
@@ -1027,7 +1030,7 @@ static int hvmemul_cmpxchg(
     struct hvm_emulate_ctxt *hvmemul_ctxt =
         container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
 
-    if ( unlikely(hvmemul_ctxt->set_context) )
+    if ( unlikely(hvmemul_ctxt->set_context_data) )
     {
         int rc = set_context_data(p_new, bytes);
 
@@ -1120,7 +1123,7 @@ static int hvmemul_rep_outs(
     p2m_type_t p2mt;
     int rc;
 
-    if ( unlikely(hvmemul_ctxt->set_context) )
+    if ( unlikely(hvmemul_ctxt->set_context_data) )
         return hvmemul_rep_outs_set_context(src_seg, src_offset, dst_port,
                                             bytes_per_rep, reps, ctxt);
 
@@ -1262,7 +1265,7 @@ static int hvmemul_rep_movs(
     if ( buf == NULL )
         return X86EMUL_UNHANDLEABLE;
 
-    if ( unlikely(hvmemul_ctxt->set_context) )
+    if ( unlikely(hvmemul_ctxt->set_context_data) )
     {
         rc = set_context_data(buf, bytes);
 
@@ -1460,7 +1463,7 @@ static int hvmemul_read_io(
 
     *val = 0;
 
-    if ( unlikely(hvmemul_ctxt->set_context) )
+    if ( unlikely(hvmemul_ctxt->set_context_data) )
         return set_context_data(val, bytes);
 
     return hvmemul_do_pio_buffer(port, bytes, IOREQ_READ, val);
@@ -1783,7 +1786,14 @@ static int _hvm_emulate_one(struct hvm_emulate_ctxt 
*hvmemul_ctxt,
         pfec |= PFEC_user_mode;
 
     hvmemul_ctxt->insn_buf_eip = regs->eip;
-    if ( !vio->mmio_insn_bytes )
+
+    if ( unlikely(hvmemul_ctxt->set_context_insn) )
+    {
+        memcpy(hvmemul_ctxt->insn_buf, curr->arch.vm_event->emul_data.data,
+               curr->arch.vm_event->emul_data.size);
+        hvmemul_ctxt->insn_buf_bytes = curr->arch.vm_event->emul_data.size;
+    }
+    else if ( !vio->mmio_insn_bytes )
     {
         hvmemul_ctxt->insn_buf_bytes =
             hvm_get_insn_bytes(curr, hvmemul_ctxt->insn_buf) ?:
@@ -1927,17 +1937,19 @@ void hvm_mem_access_emulate_one(enum emul_kind kind, 
unsigned int trapnr,
     struct hvm_emulate_ctxt ctx = {{ 0 }};
     int rc;
 
+    gdprintk(XENLOG_WARNING, "memaccess emulate one called\n");
+
     hvm_emulate_prepare(&ctx, guest_cpu_user_regs());
 
-    switch ( kind )
-    {
-    case EMUL_KIND_NOWRITE:
+    if ( kind == EMUL_KIND_NOWRITE )
         rc = hvm_emulate_one_no_write(&ctx);
-        break;
-    case EMUL_KIND_SET_CONTEXT:
-        ctx.set_context = 1;
-        /* Intentional fall-through. */
-    default:
+    else
+    {
+         if ( kind == EMUL_KIND_SET_CONTEXT_DATA )
+            ctx.set_context_data = 1;
+         else if ( kind == EMUL_KIND_SET_CONTEXT_INSN )
+            ctx.set_context_insn = 1;
+
         rc = hvm_emulate_one(&ctx);
     }
 
@@ -1973,7 +1985,8 @@ void hvm_emulate_prepare(
     hvmemul_ctxt->ctxt.force_writeback = 1;
     hvmemul_ctxt->seg_reg_accessed = 0;
     hvmemul_ctxt->seg_reg_dirty = 0;
-    hvmemul_ctxt->set_context = 0;
+    hvmemul_ctxt->set_context_data = 0;
+    hvmemul_ctxt->set_context_insn = 0;
     hvmemul_get_seg_reg(x86_seg_cs, hvmemul_ctxt);
     hvmemul_get_seg_reg(x86_seg_ss, hvmemul_ctxt);
 }
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 2c89984..fb11f3b 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -481,7 +481,7 @@ void hvm_do_resume(struct vcpu *v)
 
             if ( v->arch.vm_event->emulate_flags &
                  VM_EVENT_FLAG_SET_EMUL_READ_DATA )
-                kind = EMUL_KIND_SET_CONTEXT;
+                kind = EMUL_KIND_SET_CONTEXT_DATA;
             else if ( v->arch.vm_event->emulate_flags &
                       VM_EVENT_FLAG_EMULATE_NOWRITE )
                 kind = EMUL_KIND_NOWRITE;
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index bb7a329..41dc678 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -57,6 +57,7 @@
 #include <asm/altp2m.h>
 #include <asm/event.h>
 #include <asm/monitor.h>
+#include <asm/vm_event.h>
 #include <public/arch-x86/cpuid.h>
 
 static bool_t __initdata opt_force_ept;
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 812dbf6..dfed0b3 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1641,8 +1641,11 @@ void p2m_mem_access_emulate_check(struct vcpu *v,
 
         v->arch.vm_event->emulate_flags = violation ? rsp->flags : 0;
 
-        if ( (rsp->flags & VM_EVENT_FLAG_SET_EMUL_READ_DATA) )
-            v->arch.vm_event->emul_read_data = rsp->data.emul_read_data;
+        if ( !!(rsp->flags & VM_EVENT_FLAG_SET_EMUL_READ_DATA) )
+        {
+            gdprintk(XENLOG_WARNING, "Mem access emulate check setting emul 
read data buffer\n");
+            v->arch.vm_event->emul_data = rsp->data.emul_data;
+        }
     }
 }
 
diff --git a/xen/arch/x86/vm_event.c b/xen/arch/x86/vm_event.c
index e938ca3..4a9327f 100644
--- a/xen/arch/x86/vm_event.c
+++ b/xen/arch/x86/vm_event.c
@@ -66,6 +66,16 @@ void vm_event_toggle_singlestep(struct domain *d, struct 
vcpu *v)
     hvm_toggle_singlestep(v);
 }
 
+void vm_event_interrupt_emulate_check(struct vcpu *v, vm_event_response_t *rsp)
+{
+    if ( !!(rsp->flags & VM_EVENT_FLAG_EMULATE) &&
+         !!(rsp->flags & VM_EVENT_FLAG_SET_EMUL_INSN_DATA) )
+    {
+        v->arch.vm_event->emulate_flags = rsp->flags;
+        v->arch.vm_event->emul_data = rsp->data.emul_data;
+    }
+}
+
 void vm_event_register_write_resume(struct vcpu *v, vm_event_response_t *rsp)
 {
     if ( rsp->flags & VM_EVENT_FLAG_DENY )
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 8398af7..161d149 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -407,8 +407,11 @@ void vm_event_resume(struct domain *d, struct 
vm_event_domain *ved)
             vm_event_register_write_resume(v, &rsp);
             break;
 
+        case VM_EVENT_REASON_SOFTWARE_BREAKPOINT:
+            vm_event_interrupt_emulate_check(v, &rsp);
+            break;
+
 #ifdef CONFIG_HAS_MEM_ACCESS
-        case VM_EVENT_REASON_MEM_ACCESS:
             mem_access_resume(v, &rsp);
             break;
 #endif
diff --git a/xen/include/asm-arm/vm_event.h b/xen/include/asm-arm/vm_event.h
index ccc4b60..e56bc78 100644
--- a/xen/include/asm-arm/vm_event.h
+++ b/xen/include/asm-arm/vm_event.h
@@ -40,6 +40,12 @@ static inline void vm_event_toggle_singlestep(struct domain 
*d, struct vcpu *v)
 }
 
 static inline
+void vm_event_interrupt_emulate_check(struct vcpu *v, vm_event_response_t *rsp)
+{
+    /* Not supported on ARM. */
+}
+
+static inline
 void vm_event_register_write_resume(struct vcpu *v, vm_event_response_t *rsp)
 {
     /* Not supported on ARM. */
diff --git a/xen/include/asm-x86/hvm/emulate.h 
b/xen/include/asm-x86/hvm/emulate.h
index 142d1b6..8e69371 100644
--- a/xen/include/asm-x86/hvm/emulate.h
+++ b/xen/include/asm-x86/hvm/emulate.h
@@ -33,13 +33,15 @@ struct hvm_emulate_ctxt {
 
     uint32_t intr_shadow;
 
-    bool_t set_context;
+    bool_t set_context_data;
+    bool_t set_context_insn;
 };
 
 enum emul_kind {
     EMUL_KIND_NORMAL,
     EMUL_KIND_NOWRITE,
-    EMUL_KIND_SET_CONTEXT
+    EMUL_KIND_SET_CONTEXT_DATA,
+    EMUL_KIND_SET_CONTEXT_INSN
 };
 
 int hvm_emulate_one(
diff --git a/xen/include/asm-x86/vm_event.h b/xen/include/asm-x86/vm_event.h
index 7e6adff..2e3f30b 100644
--- a/xen/include/asm-x86/vm_event.h
+++ b/xen/include/asm-x86/vm_event.h
@@ -27,7 +27,7 @@
  */
 struct arch_vm_event {
     uint32_t emulate_flags;
-    struct vm_event_emul_read_data emul_read_data;
+    struct vm_event_emul_data emul_data;
     struct monitor_write_data write_data;
 };
 
@@ -37,6 +37,8 @@ void vm_event_cleanup_domain(struct domain *d);
 
 void vm_event_toggle_singlestep(struct domain *d, struct vcpu *v);
 
+void vm_event_interrupt_emulate_check(struct vcpu *v, vm_event_response_t 
*rsp);
+
 void vm_event_register_write_resume(struct vcpu *v, vm_event_response_t *rsp);
 
 void vm_event_set_registers(struct vcpu *v, vm_event_response_t *rsp);
diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h
index 99d60ea..b83b57d 100644
--- a/xen/include/public/vm_event.h
+++ b/xen/include/public/vm_event.h
@@ -97,6 +97,13 @@
  * Requires the vCPU to be paused already (synchronous events only).
  */
 #define VM_EVENT_FLAG_SET_REGISTERS      (1 << 8)
+/*
+ * Instruction cache is being sent back to the hypervisor in the event response
+ * to be used by the emulator. This flag is only useful when combined with
+ * VM_EVENT_FLAG_EMULATE and is incompatible with also setting
+ * VM_EVENT_FLAG_EMULATE_NOWRITE or VM_EVENT_FLAG_SET_EMUL_READ_DATA.
+ */
+#define VM_EVENT_FLAG_SET_EMUL_INSN_DATA (1 << 9)
 
 /*
  * Reasons for the vm event request
@@ -246,7 +253,7 @@ struct vm_event_sharing {
     uint32_t _pad;
 };
 
-struct vm_event_emul_read_data {
+struct vm_event_emul_data {
     uint32_t size;
     /* The struct is used in a union with vm_event_regs_x86. */
     uint8_t  data[sizeof(struct vm_event_regs_x86) - sizeof(uint32_t)];
@@ -277,7 +284,7 @@ typedef struct vm_event_st {
             struct vm_event_regs_x86 x86;
         } regs;
 
-        struct vm_event_emul_read_data emul_read_data;
+        struct vm_event_emul_data emul_data;
     } data;
 } vm_event_request_t, vm_event_response_t;
 
-- 
2.9.3


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

 


Rackspace

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