All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC V2 1/6] xen: Emulate with no writes
@ 2014-07-11 15:43 Razvan Cojocaru
  2014-07-11 15:43 ` [PATCH RFC V2 2/6] xen: Optimize introspection access to guest state Razvan Cojocaru
                   ` (5 more replies)
  0 siblings, 6 replies; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-11 15:43 UTC (permalink / raw)
  To: xen-devel; +Cc: andrew.cooper3, mdontu, tim, Razvan Cojocaru, JBeulich

Added support for emulating an instruction with no memory writes.
Additionally, introduced hvm_emulate_one_full(), which acts upon all
possible return values from the hvm_emulate_one() functions (RETRY,
EXCEPTION, UNHANDLEABLE).

Changes since V1:
 - Removed the Linux code that computes the length of an instruction.
 - Unused function parameters are no longer marked.
 - Refactored the code to eliminate redundancy.
 - Made the exception passed on to the guest by hvm_emulate_one_full()
   configurable.

Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
---
 xen/arch/x86/hvm/emulate.c        |   73 +++++++++++++++++++++++++++++++++++--
 xen/include/asm-x86/hvm/emulate.h |    5 +++
 2 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index eac159f..114a77a 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -688,6 +688,17 @@ static int hvmemul_write(
     return X86EMUL_OKAY;
 }
 
+static int hvmemul_write_dummy(
+    enum x86_segment seg,
+    unsigned long offset,
+    void *p_data,
+    unsigned int bytes,
+    struct x86_emulate_ctxt *ctxt)
+{
+    /* discarding the write */
+    return X86EMUL_OKAY;
+}
+
 static int hvmemul_cmpxchg(
     enum x86_segment seg,
     unsigned long offset,
@@ -1138,8 +1149,8 @@ static const struct x86_emulate_ops hvm_emulate_ops = {
     .invlpg        = hvmemul_invlpg
 };
 
-int hvm_emulate_one(
-    struct hvm_emulate_ctxt *hvmemul_ctxt)
+static int hvm_emulate_one_with_ops(struct hvm_emulate_ctxt *hvmemul_ctxt,
+    const struct x86_emulate_ops *ops)
 {
     struct cpu_user_regs *regs = hvmemul_ctxt->ctxt.regs;
     struct vcpu *curr = current;
@@ -1191,7 +1202,7 @@ int hvm_emulate_one(
     vio->mmio_retrying = vio->mmio_retry;
     vio->mmio_retry = 0;
 
-    rc = x86_emulate(&hvmemul_ctxt->ctxt, &hvm_emulate_ops);
+    rc = x86_emulate(&hvmemul_ctxt->ctxt, ops);
 
     if ( rc == X86EMUL_OKAY && vio->mmio_retry )
         rc = X86EMUL_RETRY;
@@ -1239,6 +1250,62 @@ int hvm_emulate_one(
     return X86EMUL_OKAY;
 }
 
+int hvm_emulate_one(
+    struct hvm_emulate_ctxt *hvmemul_ctxt)
+{
+    return hvm_emulate_one_with_ops(hvmemul_ctxt, &hvm_emulate_ops);
+}
+
+int hvm_emulate_one_no_write(
+    struct hvm_emulate_ctxt *hvmemul_ctxt)
+{
+    struct x86_emulate_ops local_ops = hvm_emulate_ops;
+    local_ops.write = hvmemul_write_dummy;
+
+    return hvm_emulate_one_with_ops(hvmemul_ctxt, &local_ops);
+}
+
+void hvm_emulate_one_full(bool_t nowrite,
+    unsigned int unhandleable_trapnr,
+    int unhandleable_errcode)
+{
+    struct hvm_emulate_ctxt ctx[1] = {};
+    int rc = X86EMUL_RETRY;
+
+    hvm_emulate_prepare(ctx, guest_cpu_user_regs());
+
+    while ( rc == X86EMUL_RETRY )
+    {
+        if ( nowrite )
+            rc = hvm_emulate_one_no_write(ctx);
+        else
+            rc = hvm_emulate_one(ctx);
+    }
+
+    switch ( rc )
+    {
+    case X86EMUL_UNHANDLEABLE:
+        gdprintk(XENLOG_DEBUG, "Emulation failed @ %04x:%lx: "
+               "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+               hvmemul_get_seg_reg(x86_seg_cs, ctx)->sel,
+               ctx->insn_buf_eip,
+               ctx->insn_buf[0], ctx->insn_buf[1],
+               ctx->insn_buf[2], ctx->insn_buf[3],
+               ctx->insn_buf[4], ctx->insn_buf[5],
+               ctx->insn_buf[6], ctx->insn_buf[7],
+               ctx->insn_buf[8], ctx->insn_buf[9]);
+        hvm_inject_hw_exception(unhandleable_trapnr, unhandleable_errcode);
+        break;
+    case X86EMUL_EXCEPTION:
+        if ( ctx->exn_pending )
+            hvm_inject_hw_exception(ctx->exn_vector, ctx->exn_error_code);
+        /* fall through */
+    default:
+        hvm_emulate_writeback(ctx);
+        break;
+    }
+}
+
 void hvm_emulate_prepare(
     struct hvm_emulate_ctxt *hvmemul_ctxt,
     struct cpu_user_regs *regs)
diff --git a/xen/include/asm-x86/hvm/emulate.h b/xen/include/asm-x86/hvm/emulate.h
index 00a06cc..d68b485 100644
--- a/xen/include/asm-x86/hvm/emulate.h
+++ b/xen/include/asm-x86/hvm/emulate.h
@@ -37,6 +37,11 @@ struct hvm_emulate_ctxt {
 
 int hvm_emulate_one(
     struct hvm_emulate_ctxt *hvmemul_ctxt);
+int hvm_emulate_one_no_write(
+    struct hvm_emulate_ctxt *hvmemul_ctxt);
+void hvm_emulate_one_full(bool_t nowrite,
+    unsigned int unhandleable_trapnr,
+    int unhandleable_errcode);
 void hvm_emulate_prepare(
     struct hvm_emulate_ctxt *hvmemul_ctxt,
     struct cpu_user_regs *regs);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH RFC V2 2/6] xen: Optimize introspection access to guest state
  2014-07-11 15:43 [PATCH RFC V2 1/6] xen: Emulate with no writes Razvan Cojocaru
@ 2014-07-11 15:43 ` Razvan Cojocaru
  2014-07-11 16:54   ` Andrew Cooper
  2014-07-11 15:43 ` [PATCH RFC V2 3/6] xen: Force-enable relevant MSR events; optimize the number of sent MSR events Razvan Cojocaru
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-11 15:43 UTC (permalink / raw)
  To: xen-devel; +Cc: andrew.cooper3, mdontu, tim, Razvan Cojocaru, JBeulich

Speed optimization for introspection purposes: a handful of registers
are sent along with each mem_event. This requires enlargement of the
mem_event_request / mem_event_response stuctures, and additional code
to fill in relevant values. Since the EPT event processing code needs
more data than CR3 or MSR event processors, hvm_mem_event_fill_regs()
fills in less data than p2m_mem_event_fill_regs(), in order to avoid
overhead. Struct hvm_hw_cpu has been considered instead of the custom
struct mem_event_regs_st, but its size would cause quick filling up
of the mem_event ring buffer.

Changes since V1:
 - Replaced guest_x86_mode with cs_arbytes in the mem_event_regs_st
   structure.
 - Removed superfluous preprocessor check for __x86_64__ in
   p2m_mem_event_fill_regs().

Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
---
 xen/arch/x86/hvm/hvm.c         |   33 ++++++++++++++++++++++
 xen/arch/x86/mm/p2m.c          |   60 ++++++++++++++++++++++++++++++++++++++++
 xen/include/public/mem_event.h |   38 +++++++++++++++++++++++++
 3 files changed, 131 insertions(+)

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index ef2411c..89a0382 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -6085,6 +6085,38 @@ int hvm_debug_op(struct vcpu *v, int32_t op)
     return rc;
 }
 
+static inline void hvm_mem_event_fill_regs(mem_event_request_t *req)
+{
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    struct vcpu *v = current;
+
+    req->regs.rax = regs->eax;
+    req->regs.rcx = regs->ecx;
+    req->regs.rdx = regs->edx;
+    req->regs.rbx = regs->ebx;
+    req->regs.rsp = regs->esp;
+    req->regs.rbp = regs->ebp;
+    req->regs.rsi = regs->esi;
+    req->regs.rdi = regs->edi;
+
+    req->regs.r8  = regs->r8;
+    req->regs.r9  = regs->r9;
+    req->regs.r10 = regs->r10;
+    req->regs.r11 = regs->r11;
+    req->regs.r12 = regs->r12;
+    req->regs.r13 = regs->r13;
+    req->regs.r14 = regs->r14;
+    req->regs.r15 = regs->r15;
+
+    req->regs.rflags = regs->eflags;
+    req->regs.rip    = regs->eip;
+
+    req->regs.msr_efer = v->arch.hvm_vcpu.guest_efer;
+    req->regs.cr0 = v->arch.hvm_vcpu.guest_cr[0];
+    req->regs.cr3 = v->arch.hvm_vcpu.guest_cr[3];
+    req->regs.cr4 = v->arch.hvm_vcpu.guest_cr[4];
+}
+
 static int hvm_memory_event_traps(long p, uint32_t reason,
                                   unsigned long value, unsigned long old, 
                                   bool_t gla_valid, unsigned long gla) 
@@ -6129,6 +6161,7 @@ static int hvm_memory_event_traps(long p, uint32_t reason,
         req.gla = old;
     }
     
+    hvm_mem_event_fill_regs(&req);
     mem_event_put_request(d, &d->mem_event->access, &req);
     
     return 1;
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 642ec28..13fdf78 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1314,6 +1314,63 @@ void p2m_mem_paging_resume(struct domain *d)
     }
 }
 
+static inline void p2m_mem_event_fill_regs(mem_event_request_t *req)
+{
+    struct cpu_user_regs *regs = guest_cpu_user_regs();
+    struct segment_register seg;
+    struct hvm_hw_cpu ctxt;
+    struct vcpu *v = current;
+
+    memset(&ctxt, 0, sizeof(struct hvm_hw_cpu));
+
+    /* Architecture-specific vmcs/vmcb bits */
+    hvm_funcs.save_cpu_ctxt(v, &ctxt);
+
+    req->regs.rax = regs->eax;
+    req->regs.rcx = regs->ecx;
+    req->regs.rdx = regs->edx;
+    req->regs.rbx = regs->ebx;
+    req->regs.rsp = regs->esp;
+    req->regs.rbp = regs->ebp;
+    req->regs.rsi = regs->esi;
+    req->regs.rdi = regs->edi;
+
+    req->regs.r8  = regs->r8;
+    req->regs.r9  = regs->r9;
+    req->regs.r10 = regs->r10;
+    req->regs.r11 = regs->r11;
+    req->regs.r12 = regs->r12;
+    req->regs.r13 = regs->r13;
+    req->regs.r14 = regs->r14;
+    req->regs.r15 = regs->r15;
+
+    req->regs.rflags = regs->eflags;
+    req->regs.rip    = regs->eip;
+
+    req->regs.dr7 = v->arch.debugreg[7];
+    req->regs.cr0 = ctxt.cr0;
+    req->regs.cr2 = ctxt.cr2;
+    req->regs.cr3 = ctxt.cr3;
+    req->regs.cr4 = ctxt.cr4;
+
+    req->regs.sysenter_cs = ctxt.sysenter_cs;
+    req->regs.sysenter_esp = ctxt.sysenter_esp;
+    req->regs.sysenter_eip = ctxt.sysenter_eip;
+
+    req->regs.msr_efer = ctxt.msr_efer;
+    req->regs.msr_star = ctxt.msr_star;
+    req->regs.msr_lstar = ctxt.msr_lstar;
+
+    hvm_get_segment_register(v, x86_seg_fs, &seg);
+    req->regs.fs_base = seg.base;
+
+    hvm_get_segment_register(v, x86_seg_gs, &seg);
+    req->regs.gs_base = seg.base;
+
+    hvm_get_segment_register(v, x86_seg_cs, &seg);
+    req->regs.cs_arbytes = seg.attr.bytes;;
+}
+
 bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla, 
                           bool_t access_r, bool_t access_w, bool_t access_x,
                           mem_event_request_t **req_ptr)
@@ -1407,6 +1464,9 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
     if ( p2ma != p2m_access_n2rwx )
         vcpu_pause_nosync(v);
 
+    if ( req )
+        p2m_mem_event_fill_regs(req);
+
     /* VCPU may be paused, return whether we promoted automatically */
     return (p2ma == p2m_access_n2rwx);
 }
diff --git a/xen/include/public/mem_event.h b/xen/include/public/mem_event.h
index 3831b41..b9af728 100644
--- a/xen/include/public/mem_event.h
+++ b/xen/include/public/mem_event.h
@@ -48,6 +48,43 @@
 #define MEM_EVENT_REASON_MSR         7    /* MSR was hit: gfn is MSR value, gla is MSR address;
                                              does NOT honour HVMPME_onchangeonly */
 
+/* Using a custom struct (not hvm_hw_cpu) so as to not fill
+ * the mem_event ring buffer too quickly. */
+typedef struct mem_event_regs_st {
+    uint64_t rax;
+    uint64_t rcx;
+    uint64_t rdx;
+    uint64_t rbx;
+    uint64_t rsp;
+    uint64_t rbp;
+    uint64_t rsi;
+    uint64_t rdi;
+    uint64_t r8;
+    uint64_t r9;
+    uint64_t r10;
+    uint64_t r11;
+    uint64_t r12;
+    uint64_t r13;
+    uint64_t r14;
+    uint64_t r15;
+    uint64_t rflags;
+    uint64_t dr7;
+    uint64_t rip;
+    uint64_t cr0;
+    uint64_t cr2;
+    uint64_t cr3;
+    uint64_t cr4;
+    uint64_t sysenter_cs;
+    uint64_t sysenter_esp;
+    uint64_t sysenter_eip;
+    uint64_t msr_efer;
+    uint64_t msr_star;
+    uint64_t msr_lstar;
+    uint64_t fs_base;
+    uint64_t gs_base;
+    uint32_t cs_arbytes;
+} mem_event_regs_t;
+
 typedef struct mem_event_st {
     uint32_t flags;
     uint32_t vcpu_id;
@@ -65,6 +102,7 @@ typedef struct mem_event_st {
     uint16_t available:12;
 
     uint16_t reason;
+    mem_event_regs_t regs;
 } mem_event_request_t, mem_event_response_t;
 
 DEFINE_RING_TYPES(mem_event, mem_event_request_t, mem_event_response_t);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH RFC V2 3/6] xen: Force-enable relevant MSR events; optimize the number of sent MSR events
  2014-07-11 15:43 [PATCH RFC V2 1/6] xen: Emulate with no writes Razvan Cojocaru
  2014-07-11 15:43 ` [PATCH RFC V2 2/6] xen: Optimize introspection access to guest state Razvan Cojocaru
@ 2014-07-11 15:43 ` Razvan Cojocaru
  2014-07-11 17:03   ` Andrew Cooper
  2014-07-11 15:43 ` [PATCH RFC V2 4/6] xen: Support for VMCALL mem_events Razvan Cojocaru
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-11 15:43 UTC (permalink / raw)
  To: xen-devel; +Cc: andrew.cooper3, mdontu, tim, Razvan Cojocaru, JBeulich

Vmx_disable_intercept_for_msr() will now refuse to disable interception of
MSRs needed for memory introspection. It is not possible to gate this on
mem_access being active for the domain, since by the time mem_access does
become active the interception for the interesting MSRs has already been
disabled (vmx_disable_intercept_for_msr() runs very early on).

Changes since V1:
 - Replaced printk() with gdprintk(XENLOG_DEBUG, ...).

Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
---
 xen/arch/x86/hvm/vmx/vmcs.c |   18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index 8ffc562..35fcfcc 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -700,6 +700,24 @@ void vmx_disable_intercept_for_msr(struct vcpu *v, u32 msr, int type)
     if ( msr_bitmap == NULL )
         return;
 
+    /* Filter out MSR-s needed for memory introspection */
+    switch ( msr )
+    {
+    case MSR_IA32_SYSENTER_EIP:
+    case MSR_IA32_SYSENTER_ESP:
+    case MSR_IA32_SYSENTER_CS:
+    case MSR_IA32_MC0_CTL:
+    case MSR_STAR:
+    case MSR_LSTAR:
+
+        gdprintk(XENLOG_DEBUG, "MSR 0x%08x needed for "
+            "memory introspection, still intercepted\n", msr);
+        return;
+
+    default:
+        break;
+    }
+
     /*
      * See Intel PRM Vol. 3, 20.6.9 (MSR-Bitmap Address). Early manuals
      * have the write-low and read-high bitmap offsets the wrong way round.
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH RFC V2 4/6] xen: Support for VMCALL mem_events
  2014-07-11 15:43 [PATCH RFC V2 1/6] xen: Emulate with no writes Razvan Cojocaru
  2014-07-11 15:43 ` [PATCH RFC V2 2/6] xen: Optimize introspection access to guest state Razvan Cojocaru
  2014-07-11 15:43 ` [PATCH RFC V2 3/6] xen: Force-enable relevant MSR events; optimize the number of sent MSR events Razvan Cojocaru
@ 2014-07-11 15:43 ` Razvan Cojocaru
  2014-07-11 17:23   ` Andrew Cooper
  2014-07-11 15:43 ` [PATCH RFC V2 5/6] xen, libxc: Request page fault injection via libxc Razvan Cojocaru
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-11 15:43 UTC (permalink / raw)
  To: xen-devel; +Cc: andrew.cooper3, mdontu, tim, Razvan Cojocaru, JBeulich

Added support for VMCALL events (the memory introspection library
will have the guest trigger VMCALLs, which will then be sent along
via the mem_event mechanism).

Changes since V1:
 - Added a #define and an comment explaining a previous magic
   constant.
 - Had MEM_EVENT_REASON_VMCALL explicitly not honour
   HVMPME_onchangeonly.

Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
---
 xen/arch/x86/hvm/hvm.c          |    9 +++++++++
 xen/arch/x86/hvm/vmx/vmx.c      |   18 +++++++++++++++++-
 xen/include/asm-x86/hvm/hvm.h   |    1 +
 xen/include/public/hvm/params.h |    4 +++-
 xen/include/public/mem_event.h  |    5 +++++
 5 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 89a0382..6e86d7c 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -5564,6 +5564,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
             case HVM_PARAM_MEMORY_EVENT_INT3:
             case HVM_PARAM_MEMORY_EVENT_SINGLE_STEP:
             case HVM_PARAM_MEMORY_EVENT_MSR:
+            case HVM_PARAM_MEMORY_EVENT_VMCALL:
                 if ( d == current->domain )
                 {
                     rc = -EPERM;
@@ -6199,6 +6200,14 @@ void hvm_memory_event_msr(unsigned long msr, unsigned long value)
                            value, ~value, 1, msr);
 }
 
+void hvm_memory_event_vmcall(unsigned long rip, unsigned long eax)
+{
+    hvm_memory_event_traps(current->domain->arch.hvm_domain
+                             .params[HVM_PARAM_MEMORY_EVENT_VMCALL],
+                           MEM_EVENT_REASON_VMCALL,
+                           rip, ~rip, 1, eax);
+}
+
 int hvm_memory_event_int3(unsigned long gla) 
 {
     uint32_t pfec = PFEC_page_present;
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 2caa04a..6c63225 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -2879,8 +2879,24 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
     case EXIT_REASON_VMCALL:
     {
         int rc;
+        unsigned long eax = regs->eax;
+
         HVMTRACE_1D(VMMCALL, regs->eax);
-        rc = hvm_do_hypercall(regs);
+
+        /* Don't send a VMCALL mem_event unless something
+         * caused the guests's eax register to contain the
+         * VMCALL_EVENT_REQUEST constant. */
+        if ( regs->eax != VMCALL_EVENT_REQUEST )
+        {
+            rc = hvm_do_hypercall(regs);
+        }
+        else
+        {
+            hvm_memory_event_vmcall(guest_cpu_user_regs()->eip, eax);
+            update_guest_eip();
+            break;
+        }
+
         if ( rc != HVM_HCALL_preempted )
         {
             update_guest_eip(); /* Safe: VMCALL */
diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h
index 0ebd478..3c0af30 100644
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -475,6 +475,7 @@ void hvm_memory_event_cr0(unsigned long value, unsigned long old);
 void hvm_memory_event_cr3(unsigned long value, unsigned long old);
 void hvm_memory_event_cr4(unsigned long value, unsigned long old);
 void hvm_memory_event_msr(unsigned long msr, unsigned long value);
+void hvm_memory_event_vmcall(unsigned long rip, unsigned long eax);
 /* Called for current VCPU on int3: returns -1 if no listener */
 int hvm_memory_event_int3(unsigned long gla);
 
diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h
index 614ff5f..d8f89b5 100644
--- a/xen/include/public/hvm/params.h
+++ b/xen/include/public/hvm/params.h
@@ -151,6 +151,8 @@
 /* Location of the VM Generation ID in guest physical address space. */
 #define HVM_PARAM_VM_GENERATION_ID_ADDR 34
 
-#define HVM_NR_PARAMS          35
+#define HVM_PARAM_MEMORY_EVENT_VMCALL 35
+
+#define HVM_NR_PARAMS          36
 
 #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
diff --git a/xen/include/public/mem_event.h b/xen/include/public/mem_event.h
index b9af728..7a59083 100644
--- a/xen/include/public/mem_event.h
+++ b/xen/include/public/mem_event.h
@@ -47,6 +47,11 @@
 #define MEM_EVENT_REASON_SINGLESTEP  6    /* single step was invoked: gla/gfn are RIP */
 #define MEM_EVENT_REASON_MSR         7    /* MSR was hit: gfn is MSR value, gla is MSR address;
                                              does NOT honour HVMPME_onchangeonly */
+#define MEM_EVENT_REASON_VMCALL      8    /* VMCALL: gfn is RIP, gla is EAX;
+                                             does NOT honour HVMPME_onchangeonly */
+
+/* VMCALL mem_events will only be sent when the guest's EAX holds this value. */
+#define VMCALL_EVENT_REQUEST 0x494E5452 /* 'INTR' */
 
 /* Using a custom struct (not hvm_hw_cpu) so as to not fill
  * the mem_event ring buffer too quickly. */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH RFC V2 5/6] xen, libxc: Request page fault injection via libxc
  2014-07-11 15:43 [PATCH RFC V2 1/6] xen: Emulate with no writes Razvan Cojocaru
                   ` (2 preceding siblings ...)
  2014-07-11 15:43 ` [PATCH RFC V2 4/6] xen: Support for VMCALL mem_events Razvan Cojocaru
@ 2014-07-11 15:43 ` Razvan Cojocaru
  2014-07-11 18:06   ` Andrew Cooper
  2014-07-11 15:43 ` [PATCH RFC V2 6/6] xen: Handle resumed instruction based on previous mem_event reply Razvan Cojocaru
  2014-07-11 16:23 ` [PATCH RFC V2 1/6] xen: Emulate with no writes Andrew Cooper
  5 siblings, 1 reply; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-11 15:43 UTC (permalink / raw)
  To: xen-devel; +Cc: andrew.cooper3, mdontu, tim, Razvan Cojocaru, JBeulich

Added new XEN_DOMCTL_set_pagefault_info hypercall, used by libxc's
new xc_domain_set_pagefault_info() function to set per-domain page
fault injection information. All a call does is set per-domain info,
and nothing actually happens until VMENTRY time, and then only if
all conditions are met (the guest is in user mode, the set value
matches CR3, and there are no other pending traps).
This mechanism allows bringing in swapped-out pages for inspection.

Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
---
 tools/libxc/xc_domain.c     |   17 +++++++++++++++++
 tools/libxc/xenctrl.h       |    4 ++++
 xen/arch/x86/hvm/vmx/vmx.c  |   39 +++++++++++++++++++++++++++++++++++++++
 xen/common/domain.c         |    5 +++++
 xen/common/domctl.c         |   21 +++++++++++++++++++++
 xen/include/public/domctl.h |   14 ++++++++++++++
 xen/include/xen/sched.h     |    7 +++++++
 7 files changed, 107 insertions(+)

diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 0230c6c..7437c51 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -506,6 +506,23 @@ int xc_domain_hvm_setcontext(xc_interface *xch,
     return ret;
 }
 
+int xc_domain_set_pagefault_info(xc_interface *xch,
+                                 uint32_t domid,
+                                 xen_domctl_set_pagefault_info_t *info)
+{
+    DECLARE_DOMCTL;
+
+    if (info == NULL)
+        return -1;
+
+    domctl.cmd = XEN_DOMCTL_set_pagefault_info;
+    domctl.domain = (domid_t)domid;
+    domctl.u.set_pagefault_info.address_space = info->address_space;
+    domctl.u.set_pagefault_info.virtual_address = info->virtual_address;
+    domctl.u.set_pagefault_info.write_access = info->write_access;
+    return do_domctl(xch, &domctl);
+}
+
 int xc_vcpu_getcontext(xc_interface *xch,
                        uint32_t domid,
                        uint32_t vcpu,
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index 3578b09..302ef0e 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -793,6 +793,10 @@ int xc_domain_hvm_setcontext(xc_interface *xch,
 const char *xc_domain_get_native_protocol(xc_interface *xch,
                                           uint32_t domid);
 
+int xc_domain_set_pagefault_info(xc_interface *xch,
+                                 uint32_t domid,
+                                 xen_domctl_set_pagefault_info_t *info);
+
 /**
  * This function returns information about the execution context of a
  * particular vcpu of a domain.
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 6c63225..835621f 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -416,6 +416,7 @@ static void vmx_restore_dr(struct vcpu *v)
 static void vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c)
 {
     unsigned long ev;
+    unsigned long cs_arbytes;
 
     vmx_vmcs_enter(v);
 
@@ -429,6 +430,9 @@ static void vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c)
     __vmread(GUEST_SYSENTER_CS, &c->sysenter_cs);
     __vmread(GUEST_SYSENTER_ESP, &c->sysenter_esp);
     __vmread(GUEST_SYSENTER_EIP, &c->sysenter_eip);
+    __vmread(GUEST_CS_AR_BYTES, &cs_arbytes);
+
+    c->cs_arbytes = (uint32_t)cs_arbytes;
 
     c->pending_event = 0;
     c->error_code = 0;
@@ -3113,6 +3117,39 @@ out:
         nvmx_idtv_handling();
 }
 
+static void check_pf_injection(void)
+{
+    struct vcpu *curr = current;
+    struct domain *d = curr->domain;
+    struct hvm_hw_cpu ctxt;
+    uint32_t ss_dpl;
+
+    if ( !is_hvm_domain(d) || d->fault_info.virtual_address == 0 )
+        return;
+
+    memset(&ctxt, 0, sizeof(struct hvm_hw_cpu));
+    hvm_funcs.save_cpu_ctxt(curr, &ctxt);
+
+    ss_dpl = (ctxt.cs_arbytes >> 5) & 3;
+
+    if ( ss_dpl == 3 /* Guest is in user mode */
+         && !ctxt.pending_event
+         && ctxt.cr3 == d->fault_info.address_space )
+    {
+        /* Cache */
+        uint64_t virtual_address = d->fault_info.virtual_address;
+        uint32_t write_access = d->fault_info.write_access;
+
+        /* Reset */
+        d->fault_info.address_space = 0;
+        d->fault_info.virtual_address = 0;
+        d->fault_info.write_access = 0;
+
+        hvm_inject_page_fault((write_access << 1) | PFEC_user_mode,
+            virtual_address);
+    }
+}
+
 void vmx_vmenter_helper(const struct cpu_user_regs *regs)
 {
     struct vcpu *curr = current;
@@ -3153,6 +3190,8 @@ void vmx_vmenter_helper(const struct cpu_user_regs *regs)
     if ( unlikely(need_flush) )
         vpid_sync_all();
 
+    check_pf_injection();
+
  out:
     HVMTRACE_ND(VMENTRY, 0, 1/*cycles*/, 0, 0, 0, 0, 0, 0, 0);
 
diff --git a/xen/common/domain.c b/xen/common/domain.c
index cd64aea..e7bd734 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -255,6 +255,11 @@ struct domain *domain_create(
 
     d->domain_id = domid;
 
+    /* Memory introspection page fault variables set-up. */
+    d->fault_info.address_space = 0;
+    d->fault_info.virtual_address = 0;
+    d->fault_info.write_access = 0;
+
     lock_profile_register_struct(LOCKPROF_TYPE_PERDOM, d, domid, "Domain");
 
     if ( (err = xsm_alloc_security_domain(d)) != 0 )
diff --git a/xen/common/domctl.c b/xen/common/domctl.c
index c326aba..4321ca1 100644
--- a/xen/common/domctl.c
+++ b/xen/common/domctl.c
@@ -967,6 +967,27 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
     }
     break;
 
+    case XEN_DOMCTL_set_pagefault_info:
+    {
+        struct domain *d;
+
+        ret = -ESRCH;
+        d = rcu_lock_domain_by_id(op->domain);
+        if ( d != NULL )
+        {
+            d->fault_info.address_space =
+                op->u.set_pagefault_info.address_space;
+            d->fault_info.virtual_address =
+                op->u.set_pagefault_info.virtual_address;
+            d->fault_info.write_access =
+                op->u.set_pagefault_info.write_access;
+
+            rcu_unlock_domain(d);
+            ret = 0;
+        }
+    }
+    break;
+
     default:
         ret = arch_do_domctl(op, d, u_domctl);
         break;
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 5b11bbf..c8bf3f8 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -936,6 +936,18 @@ typedef struct xen_domctl_vcpu_msrs xen_domctl_vcpu_msrs_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_vcpu_msrs_t);
 #endif
 
+/* XEN_DOMCTL_set_pagefault_info requests that a page fault occur at
+ * the next VMENTRY.
+ *  */
+struct xen_domctl_set_pagefault_info {
+    uint64_t address_space;
+    uint64_t virtual_address;
+    uint32_t write_access;
+};
+typedef struct xen_domctl_set_pagefault_info xen_domctl_set_pagefault_info_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_pagefault_info_t);
+
+
 struct xen_domctl {
     uint32_t cmd;
 #define XEN_DOMCTL_createdomain                   1
@@ -1012,6 +1024,7 @@ struct xen_domctl {
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
 #define XEN_DOMCTL_gdbsx_domstatus             1003
+#define XEN_DOMCTL_set_pagefault_info          1004
     uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */
     domid_t  domain;
     union {
@@ -1068,6 +1081,7 @@ struct xen_domctl {
         struct xen_domctl_cacheflush        cacheflush;
         struct xen_domctl_gdbsx_pauseunp_vcpu gdbsx_pauseunp_vcpu;
         struct xen_domctl_gdbsx_domstatus   gdbsx_domstatus;
+        struct xen_domctl_set_pagefault_info set_pagefault_info;
         uint8_t                             pad[128];
     } u;
 };
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index d5bc461..754e070 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -447,6 +447,13 @@ struct domain
     nodemask_t node_affinity;
     unsigned int last_alloc_node;
     spinlock_t node_affinity_lock;
+
+    /* Memory introspection page fault injection data. */
+    struct {
+        uint64_t address_space;
+        uint64_t virtual_address;
+        uint32_t write_access;
+    } fault_info;
 };
 
 struct domain_setup_info
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH RFC V2 6/6] xen: Handle resumed instruction based on previous mem_event reply
  2014-07-11 15:43 [PATCH RFC V2 1/6] xen: Emulate with no writes Razvan Cojocaru
                   ` (3 preceding siblings ...)
  2014-07-11 15:43 ` [PATCH RFC V2 5/6] xen, libxc: Request page fault injection via libxc Razvan Cojocaru
@ 2014-07-11 15:43 ` Razvan Cojocaru
  2014-07-11 18:36   ` Andrew Cooper
  2014-07-11 16:23 ` [PATCH RFC V2 1/6] xen: Emulate with no writes Andrew Cooper
  5 siblings, 1 reply; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-11 15:43 UTC (permalink / raw)
  To: xen-devel; +Cc: andrew.cooper3, mdontu, tim, Razvan Cojocaru, JBeulich

In a scenario where a page fault that triggered a mem_event occured,
p2m_mem_access_check() will now be able to either 1) emulate the
current instruction, or 2) emulate it, but don't allow it to perform
any writes.

Changes since V1:
 - Removed the 'skip' code which required computing the current
   instruction length.
 - Removed the set_ad_bits() code that attempted to modify the
   'accessed' and 'dirty' bits for instructions that the emulator
   can't handle at the moment.

Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
---
 xen/arch/x86/domain.c          |    5 +++
 xen/arch/x86/mm/p2m.c          |   90 ++++++++++++++++++++++++++++++++++++++++
 xen/include/asm-x86/domain.h   |    9 ++++
 xen/include/public/mem_event.h |   12 +++---
 4 files changed, 111 insertions(+), 5 deletions(-)

diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index e896210..5cd283b 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -407,6 +407,11 @@ int vcpu_initialise(struct vcpu *v)
 
     v->arch.flags = TF_kernel_mode;
 
+    /* By default, do not emulate */
+    v->arch.mem_event.emulate_flags = 0;
+    v->arch.mem_event.gpa = 0;
+    v->arch.mem_event.eip = 0;
+
     rc = mapcache_vcpu_init(v);
     if ( rc )
         return rc;
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 13fdf78..7aff480 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1377,6 +1377,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
 {
     struct vcpu *v = current;
     unsigned long gfn = gpa >> PAGE_SHIFT;
+    unsigned long exit_qualification;
     struct domain *d = v->domain;    
     struct p2m_domain* p2m = p2m_get_hostp2m(d);
     mfn_t mfn;
@@ -1384,6 +1385,9 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
     p2m_access_t p2ma;
     mem_event_request_t *req;
     int rc;
+    unsigned long eip = guest_cpu_user_regs()->eip;
+
+    __vmread(EXIT_QUALIFICATION, &exit_qualification);
 
     /* First, handle rx2rw conversion automatically.
      * These calls to p2m->set_entry() must succeed: we have the gfn
@@ -1436,6 +1440,37 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
             return 1;
         }
     }
+    else
+    {
+        /* There's a mem_event listener */
+        if ( (exit_qualification & EPT_GLA_FAULT) == 0 ) /* don't send a mem_event */
+        {
+            if ( v->arch.mem_event.emulate_flags == 0 )
+            {
+                v->arch.mem_event.emulate_flags = MEM_EVENT_FLAG_EMULATE;
+                v->arch.mem_event.gpa = gpa;
+                v->arch.mem_event.eip = eip;
+            }
+        }
+    }
+
+    if ( v->arch.mem_event.gpa != gpa || v->arch.mem_event.eip != eip )
+    {
+        v->arch.mem_event.emulate_flags = 0;
+        v->arch.mem_event.gpa = gpa;
+        v->arch.mem_event.eip = eip;
+    }
+
+    if ( v->arch.mem_event.emulate_flags )
+    {
+        if ( v->arch.mem_event.emulate_flags & MEM_EVENT_FLAG_EMULATE_NOWRITE )
+            hvm_emulate_one_full(1, TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE);
+        else
+            hvm_emulate_one_full(0, TRAP_invalid_op, HVM_DELIVER_NO_ERROR_CODE);
+
+        v->arch.mem_event.emulate_flags = 0;
+        return 1;
+    }
 
     *req_ptr = NULL;
     req = xzalloc(mem_event_request_t);
@@ -1480,6 +1515,61 @@ void p2m_mem_access_resume(struct domain *d)
     {
         if ( rsp.flags & MEM_EVENT_FLAG_DUMMY )
             continue;
+
+        /* Mark vcpu for skipping one instruction upon rescheduling */
+        if ( rsp.flags & MEM_EVENT_FLAG_EMULATE )
+        {
+            xenmem_access_t access;
+            int violation = 1;
+
+            d->vcpu[rsp.vcpu_id]->arch.mem_event.emulate_flags = 0;
+
+            if ( p2m_get_mem_access(d, rsp.gfn, &access) == 0 )
+            {
+                violation = 0;
+
+                switch (access)
+                {
+                case XENMEM_access_n:
+                case XENMEM_access_n2rwx:
+                default:
+                    violation = rsp.access_r || rsp.access_w || rsp.access_x;
+                    break;
+
+                case XENMEM_access_r:
+                    violation = rsp.access_w || rsp.access_x;
+                    break;
+
+                case XENMEM_access_w:
+                    violation = rsp.access_r || rsp.access_x;
+                    break;
+
+                case XENMEM_access_x:
+                    violation = rsp.access_r || rsp.access_w;
+                    break;
+
+                case XENMEM_access_rx:
+                case XENMEM_access_rx2rw:
+                    violation = rsp.access_w;
+                    break;
+
+                case XENMEM_access_wx:
+                    violation = rsp.access_r;
+                    break;
+
+                case XENMEM_access_rw:
+                    violation = rsp.access_x;
+                    break;
+
+                case XENMEM_access_rwx:
+                    break;
+                }
+            }
+
+            if ( violation )
+                d->vcpu[rsp.vcpu_id]->arch.mem_event.emulate_flags = rsp.flags;
+        }
+
         /* Unpause domain */
         if ( rsp.flags & MEM_EVENT_FLAG_VCPU_PAUSED )
             vcpu_unpause(d->vcpu[rsp.vcpu_id]);
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index abf55fb..0fa4d3d 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -446,6 +446,15 @@ struct arch_vcpu
 
     /* A secondary copy of the vcpu time info. */
     XEN_GUEST_HANDLE(vcpu_time_info_t) time_info_guest;
+
+    /* Should we emulate the next matching instruction on VCPU resume
+     * after a mem_event? */
+    struct {
+        uint32_t emulate_flags;
+        unsigned long gpa;
+        unsigned long eip;
+    } mem_event;
+
 } __cacheline_aligned;
 
 /* Shorthands to improve code legibility. */
diff --git a/xen/include/public/mem_event.h b/xen/include/public/mem_event.h
index 7a59083..03cd57d 100644
--- a/xen/include/public/mem_event.h
+++ b/xen/include/public/mem_event.h
@@ -31,11 +31,13 @@
 #include "io/ring.h"
 
 /* Memory event flags */
-#define MEM_EVENT_FLAG_VCPU_PAUSED  (1 << 0)
-#define MEM_EVENT_FLAG_DROP_PAGE    (1 << 1)
-#define MEM_EVENT_FLAG_EVICT_FAIL   (1 << 2)
-#define MEM_EVENT_FLAG_FOREIGN      (1 << 3)
-#define MEM_EVENT_FLAG_DUMMY        (1 << 4)
+#define MEM_EVENT_FLAG_VCPU_PAUSED     (1 << 0)
+#define MEM_EVENT_FLAG_DROP_PAGE       (1 << 1)
+#define MEM_EVENT_FLAG_EVICT_FAIL      (1 << 2)
+#define MEM_EVENT_FLAG_FOREIGN         (1 << 3)
+#define MEM_EVENT_FLAG_DUMMY           (1 << 4)
+#define MEM_EVENT_FLAG_EMULATE         (1 << 5)
+#define MEM_EVENT_FLAG_EMULATE_NOWRITE (1 << 6)
 
 /* Reasons for the memory event request */
 #define MEM_EVENT_REASON_UNKNOWN     0    /* typical reason */
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 1/6] xen: Emulate with no writes
  2014-07-11 15:43 [PATCH RFC V2 1/6] xen: Emulate with no writes Razvan Cojocaru
                   ` (4 preceding siblings ...)
  2014-07-11 15:43 ` [PATCH RFC V2 6/6] xen: Handle resumed instruction based on previous mem_event reply Razvan Cojocaru
@ 2014-07-11 16:23 ` Andrew Cooper
  2014-07-11 18:00   ` Razvan Cojocaru
  2014-07-14  8:37   ` Razvan Cojocaru
  5 siblings, 2 replies; 34+ messages in thread
From: Andrew Cooper @ 2014-07-11 16:23 UTC (permalink / raw)
  To: Razvan Cojocaru, xen-devel; +Cc: mdontu, tim, JBeulich

On 11/07/14 16:43, Razvan Cojocaru wrote:
> Added support for emulating an instruction with no memory writes.
> Additionally, introduced hvm_emulate_one_full(), which acts upon all
> possible return values from the hvm_emulate_one() functions (RETRY,
> EXCEPTION, UNHANDLEABLE).
>
> Changes since V1:
>  - Removed the Linux code that computes the length of an instruction.
>  - Unused function parameters are no longer marked.
>  - Refactored the code to eliminate redundancy.
>  - Made the exception passed on to the guest by hvm_emulate_one_full()
>    configurable.
>
> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
> ---
>  xen/arch/x86/hvm/emulate.c        |   73 +++++++++++++++++++++++++++++++++++--
>  xen/include/asm-x86/hvm/emulate.h |    5 +++
>  2 files changed, 75 insertions(+), 3 deletions(-)
>
> diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
> index eac159f..114a77a 100644
> --- a/xen/arch/x86/hvm/emulate.c
> +++ b/xen/arch/x86/hvm/emulate.c
> @@ -688,6 +688,17 @@ static int hvmemul_write(
>      return X86EMUL_OKAY;
>  }
>  
> +static int hvmemul_write_dummy(

hvmemul_write_discard() would make its purpose more clear.

> +    enum x86_segment seg,
> +    unsigned long offset,
> +    void *p_data,
> +    unsigned int bytes,
> +    struct x86_emulate_ctxt *ctxt)
> +{
> +    /* discarding the write */

Full stop please.

> +    return X86EMUL_OKAY;
> +}
> +
>  static int hvmemul_cmpxchg(
>      enum x86_segment seg,
>      unsigned long offset,
> @@ -1138,8 +1149,8 @@ static const struct x86_emulate_ops hvm_emulate_ops = {
>      .invlpg        = hvmemul_invlpg
>  };
>  
> -int hvm_emulate_one(
> -    struct hvm_emulate_ctxt *hvmemul_ctxt)
> +static int hvm_emulate_one_with_ops(struct hvm_emulate_ctxt *hvmemul_ctxt,
> +    const struct x86_emulate_ops *ops)

You could get away with a renaming this to _hvm_emulate_one() to help
identify that it is basically identical to hvm_emulate_one(), just with
slightly different parameters.

>  {
>      struct cpu_user_regs *regs = hvmemul_ctxt->ctxt.regs;
>      struct vcpu *curr = current;
> @@ -1191,7 +1202,7 @@ int hvm_emulate_one(
>      vio->mmio_retrying = vio->mmio_retry;
>      vio->mmio_retry = 0;
>  
> -    rc = x86_emulate(&hvmemul_ctxt->ctxt, &hvm_emulate_ops);
> +    rc = x86_emulate(&hvmemul_ctxt->ctxt, ops);
>  
>      if ( rc == X86EMUL_OKAY && vio->mmio_retry )
>          rc = X86EMUL_RETRY;
> @@ -1239,6 +1250,62 @@ int hvm_emulate_one(
>      return X86EMUL_OKAY;
>  }
>  
> +int hvm_emulate_one(
> +    struct hvm_emulate_ctxt *hvmemul_ctxt)
> +{
> +    return hvm_emulate_one_with_ops(hvmemul_ctxt, &hvm_emulate_ops);
> +}
> +
> +int hvm_emulate_one_no_write(
> +    struct hvm_emulate_ctxt *hvmemul_ctxt)
> +{
> +    struct x86_emulate_ops local_ops = hvm_emulate_ops;
> +    local_ops.write = hvmemul_write_dummy;

This is runtime constant and somwhat expensive to set up for each
function call.

You could make a static const struct x86_emulate_ops
hvm_emulate_ops_no_write and use that each time.

> +
> +    return hvm_emulate_one_with_ops(hvmemul_ctxt, &local_ops);
> +}
> +
> +void hvm_emulate_one_full(bool_t nowrite,
> +    unsigned int unhandleable_trapnr,
> +    int unhandleable_errcode)
> +{
> +    struct hvm_emulate_ctxt ctx[1] = {};

This construct looks suspect.  What is wrong with

struct hvm_emulate_ctxt ctx = { 0 }; and using &ctx below ?

> +    int rc = X86EMUL_RETRY;
> +
> +    hvm_emulate_prepare(ctx, guest_cpu_user_regs());
> +
> +    while ( rc == X86EMUL_RETRY )
> +    {
> +        if ( nowrite )
> +            rc = hvm_emulate_one_no_write(ctx);
> +        else
> +            rc = hvm_emulate_one(ctx);
> +    }

This however is not appropriate.  X86EMUL_RETRY can include "talk to
dom0 and get the paging subsystem to page in part of the VM", which
given some current work-in-progress can be to the other end of a network
connection on the far side of an optimistic migration.

You can't cause a Xen pcpu to spin like this for that length of time. 
Anything longer than a second and all other pcpus will block against the
time calibration rendezvous, and longer than 5 will panic on the NMI
watchdog.

> +
> +    switch ( rc )
> +    {
> +    case X86EMUL_UNHANDLEABLE:
> +        gdprintk(XENLOG_DEBUG, "Emulation failed @ %04x:%lx: "
> +               "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
> +               hvmemul_get_seg_reg(x86_seg_cs, ctx)->sel,
> +               ctx->insn_buf_eip,
> +               ctx->insn_buf[0], ctx->insn_buf[1],
> +               ctx->insn_buf[2], ctx->insn_buf[3],
> +               ctx->insn_buf[4], ctx->insn_buf[5],
> +               ctx->insn_buf[6], ctx->insn_buf[7],
> +               ctx->insn_buf[8], ctx->insn_buf[9]);

Hmm - I keep meaning to add a new %p custom format to print out hex
buffers like this.  It is sadly quite a long way down my todo list.

> +        hvm_inject_hw_exception(unhandleable_trapnr, unhandleable_errcode);
> +        break;
> +    case X86EMUL_EXCEPTION:
> +        if ( ctx->exn_pending )
> +            hvm_inject_hw_exception(ctx->exn_vector, ctx->exn_error_code);
> +        /* fall through */
> +    default:
> +        hvm_emulate_writeback(ctx);
> +        break;
> +    }
> +}
> +
>  void hvm_emulate_prepare(
>      struct hvm_emulate_ctxt *hvmemul_ctxt,
>      struct cpu_user_regs *regs)
> diff --git a/xen/include/asm-x86/hvm/emulate.h b/xen/include/asm-x86/hvm/emulate.h
> index 00a06cc..d68b485 100644
> --- a/xen/include/asm-x86/hvm/emulate.h
> +++ b/xen/include/asm-x86/hvm/emulate.h
> @@ -37,6 +37,11 @@ struct hvm_emulate_ctxt {
>  
>  int hvm_emulate_one(
>      struct hvm_emulate_ctxt *hvmemul_ctxt);
> +int hvm_emulate_one_no_write(
> +    struct hvm_emulate_ctxt *hvmemul_ctxt);
> +void hvm_emulate_one_full(bool_t nowrite,
> +    unsigned int unhandleable_trapnr,
> +    int unhandleable_errcode);

Prevailing Xen nomenclature would be 'trapnr' and 'error_code'.  The
error code should be unsigned as well.

~Andrew

>  void hvm_emulate_prepare(
>      struct hvm_emulate_ctxt *hvmemul_ctxt,
>      struct cpu_user_regs *regs);

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 2/6] xen: Optimize introspection access to guest state
  2014-07-11 15:43 ` [PATCH RFC V2 2/6] xen: Optimize introspection access to guest state Razvan Cojocaru
@ 2014-07-11 16:54   ` Andrew Cooper
  2014-07-11 16:57     ` Andrew Cooper
  2014-07-11 18:03     ` Razvan Cojocaru
  0 siblings, 2 replies; 34+ messages in thread
From: Andrew Cooper @ 2014-07-11 16:54 UTC (permalink / raw)
  To: Razvan Cojocaru, xen-devel; +Cc: mdontu, tim, JBeulich

On 11/07/14 16:43, Razvan Cojocaru wrote:
> Speed optimization for introspection purposes: a handful of registers
> are sent along with each mem_event. This requires enlargement of the
> mem_event_request / mem_event_response stuctures, and additional code
> to fill in relevant values. Since the EPT event processing code needs
> more data than CR3 or MSR event processors, hvm_mem_event_fill_regs()
> fills in less data than p2m_mem_event_fill_regs(), in order to avoid
> overhead. Struct hvm_hw_cpu has been considered instead of the custom
> struct mem_event_regs_st, but its size would cause quick filling up
> of the mem_event ring buffer.
>
> Changes since V1:
>  - Replaced guest_x86_mode with cs_arbytes in the mem_event_regs_st
>    structure.
>  - Removed superfluous preprocessor check for __x86_64__ in
>    p2m_mem_event_fill_regs().
>
> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
> ---
>  xen/arch/x86/hvm/hvm.c         |   33 ++++++++++++++++++++++
>  xen/arch/x86/mm/p2m.c          |   60 ++++++++++++++++++++++++++++++++++++++++
>  xen/include/public/mem_event.h |   38 +++++++++++++++++++++++++
>  3 files changed, 131 insertions(+)
>
> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index ef2411c..89a0382 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -6085,6 +6085,38 @@ int hvm_debug_op(struct vcpu *v, int32_t op)
>      return rc;
>  }
>  
> +static inline void hvm_mem_event_fill_regs(mem_event_request_t *req)

For C functions like this, the compiler is far better at guessing the
inlineabilty of the function than the programmer.  You don't need to
call it out explicitly.

> +{
> +    struct cpu_user_regs *regs = guest_cpu_user_regs();
> +    struct vcpu *v = current;
> +
> +    req->regs.rax = regs->eax;
> +    req->regs.rcx = regs->ecx;
> +    req->regs.rdx = regs->edx;
> +    req->regs.rbx = regs->ebx;
> +    req->regs.rsp = regs->esp;
> +    req->regs.rbp = regs->ebp;
> +    req->regs.rsi = regs->esi;
> +    req->regs.rdi = regs->edi;
> +
> +    req->regs.r8  = regs->r8;
> +    req->regs.r9  = regs->r9;
> +    req->regs.r10 = regs->r10;
> +    req->regs.r11 = regs->r11;
> +    req->regs.r12 = regs->r12;
> +    req->regs.r13 = regs->r13;
> +    req->regs.r14 = regs->r14;
> +    req->regs.r15 = regs->r15;
> +
> +    req->regs.rflags = regs->eflags;
> +    req->regs.rip    = regs->eip;
> +
> +    req->regs.msr_efer = v->arch.hvm_vcpu.guest_efer;
> +    req->regs.cr0 = v->arch.hvm_vcpu.guest_cr[0];
> +    req->regs.cr3 = v->arch.hvm_vcpu.guest_cr[3];
> +    req->regs.cr4 = v->arch.hvm_vcpu.guest_cr[4];
> +}
> +
>  static int hvm_memory_event_traps(long p, uint32_t reason,
>                                    unsigned long value, unsigned long old, 
>                                    bool_t gla_valid, unsigned long gla) 
> @@ -6129,6 +6161,7 @@ static int hvm_memory_event_traps(long p, uint32_t reason,
>          req.gla = old;
>      }
>      
> +    hvm_mem_event_fill_regs(&req);
>      mem_event_put_request(d, &d->mem_event->access, &req);
>      
>      return 1;
> diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
> index 642ec28..13fdf78 100644
> --- a/xen/arch/x86/mm/p2m.c
> +++ b/xen/arch/x86/mm/p2m.c
> @@ -1314,6 +1314,63 @@ void p2m_mem_paging_resume(struct domain *d)
>      }
>  }
>  
> +static inline void p2m_mem_event_fill_regs(mem_event_request_t *req)
> +{
> +    struct cpu_user_regs *regs = guest_cpu_user_regs();
> +    struct segment_register seg;
> +    struct hvm_hw_cpu ctxt;
> +    struct vcpu *v = current;
> +
> +    memset(&ctxt, 0, sizeof(struct hvm_hw_cpu));

You don't need to zero ctxt if you are about to save into it.

> +
> +    /* Architecture-specific vmcs/vmcb bits */
> +    hvm_funcs.save_cpu_ctxt(v, &ctxt);
> +
> +    req->regs.rax = regs->eax;
> +    req->regs.rcx = regs->ecx;
> +    req->regs.rdx = regs->edx;
> +    req->regs.rbx = regs->ebx;
> +    req->regs.rsp = regs->esp;
> +    req->regs.rbp = regs->ebp;
> +    req->regs.rsi = regs->esi;
> +    req->regs.rdi = regs->edi;
> +
> +    req->regs.r8  = regs->r8;
> +    req->regs.r9  = regs->r9;
> +    req->regs.r10 = regs->r10;
> +    req->regs.r11 = regs->r11;
> +    req->regs.r12 = regs->r12;
> +    req->regs.r13 = regs->r13;
> +    req->regs.r14 = regs->r14;
> +    req->regs.r15 = regs->r15;
> +
> +    req->regs.rflags = regs->eflags;
> +    req->regs.rip    = regs->eip;
> +
> +    req->regs.dr7 = v->arch.debugreg[7];
> +    req->regs.cr0 = ctxt.cr0;
> +    req->regs.cr2 = ctxt.cr2;
> +    req->regs.cr3 = ctxt.cr3;
> +    req->regs.cr4 = ctxt.cr4;
> +
> +    req->regs.sysenter_cs = ctxt.sysenter_cs;
> +    req->regs.sysenter_esp = ctxt.sysenter_esp;
> +    req->regs.sysenter_eip = ctxt.sysenter_eip;
> +
> +    req->regs.msr_efer = ctxt.msr_efer;
> +    req->regs.msr_star = ctxt.msr_star;
> +    req->regs.msr_lstar = ctxt.msr_lstar;
> +
> +    hvm_get_segment_register(v, x86_seg_fs, &seg);
> +    req->regs.fs_base = seg.base;
> +
> +    hvm_get_segment_register(v, x86_seg_gs, &seg);
> +    req->regs.gs_base = seg.base;
> +
> +    hvm_get_segment_register(v, x86_seg_cs, &seg);
> +    req->regs.cs_arbytes = seg.attr.bytes;;

Stray double semicolon.

> +}
> +
>  bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla, 
>                            bool_t access_r, bool_t access_w, bool_t access_x,
>                            mem_event_request_t **req_ptr)
> @@ -1407,6 +1464,9 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
>      if ( p2ma != p2m_access_n2rwx )
>          vcpu_pause_nosync(v);
>  
> +    if ( req )
> +        p2m_mem_event_fill_regs(req);

Should this not be part of the if ( req ) just above the pause_nosync() ?

> +
>      /* VCPU may be paused, return whether we promoted automatically */
>      return (p2ma == p2m_access_n2rwx);
>  }
> diff --git a/xen/include/public/mem_event.h b/xen/include/public/mem_event.h
> index 3831b41..b9af728 100644
> --- a/xen/include/public/mem_event.h
> +++ b/xen/include/public/mem_event.h
> @@ -48,6 +48,43 @@
>  #define MEM_EVENT_REASON_MSR         7    /* MSR was hit: gfn is MSR value, gla is MSR address;
>                                               does NOT honour HVMPME_onchangeonly */
>  
> +/* Using a custom struct (not hvm_hw_cpu) so as to not fill
> + * the mem_event ring buffer too quickly. */
> +typedef struct mem_event_regs_st {
> +    uint64_t rax;
> +    uint64_t rcx;
> +    uint64_t rdx;
> +    uint64_t rbx;
> +    uint64_t rsp;
> +    uint64_t rbp;
> +    uint64_t rsi;
> +    uint64_t rdi;
> +    uint64_t r8;
> +    uint64_t r9;
> +    uint64_t r10;
> +    uint64_t r11;
> +    uint64_t r12;
> +    uint64_t r13;
> +    uint64_t r14;
> +    uint64_t r15;
> +    uint64_t rflags;
> +    uint64_t dr7;
> +    uint64_t rip;
> +    uint64_t cr0;
> +    uint64_t cr2;
> +    uint64_t cr3;
> +    uint64_t cr4;
> +    uint64_t sysenter_cs;
> +    uint64_t sysenter_esp;
> +    uint64_t sysenter_eip;
> +    uint64_t msr_efer;
> +    uint64_t msr_star;
> +    uint64_t msr_lstar;
> +    uint64_t fs_base;
> +    uint64_t gs_base;
> +    uint32_t cs_arbytes;

This trailing uint32_t means that sizeof(mem_event_regs_t) is different
between 32 and 64 bit builds, breaking compatibility between a 64bit xen
and 32bit dom0.

The easiest fix is to add an explicit uint32_t _pad field at the end.

~Andrew

> +} mem_event_regs_t;
> +
>  typedef struct mem_event_st {
>      uint32_t flags;
>      uint32_t vcpu_id;
> @@ -65,6 +102,7 @@ typedef struct mem_event_st {
>      uint16_t available:12;
>  
>      uint16_t reason;
> +    mem_event_regs_t regs;
>  } mem_event_request_t, mem_event_response_t;
>  
>  DEFINE_RING_TYPES(mem_event, mem_event_request_t, mem_event_response_t);

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 2/6] xen: Optimize introspection access to guest state
  2014-07-11 16:54   ` Andrew Cooper
@ 2014-07-11 16:57     ` Andrew Cooper
  2014-07-11 18:03     ` Razvan Cojocaru
  1 sibling, 0 replies; 34+ messages in thread
From: Andrew Cooper @ 2014-07-11 16:57 UTC (permalink / raw)
  To: Razvan Cojocaru, xen-devel; +Cc: mdontu, tim, JBeulich

On 11/07/14 17:54, Andrew Cooper wrote:
> On 11/07/14 16:43, Razvan Cojocaru wrote:
>
>
>> +} mem_event_regs_t;

In addition, anything ending in _t is reserved for the C environment, so
shouldn't be found in our public header files.

There are some bad examples which cant be changed, but we should refrain
from propagating this badness.

~Andrew

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 3/6] xen: Force-enable relevant MSR events; optimize the number of sent MSR events
  2014-07-11 15:43 ` [PATCH RFC V2 3/6] xen: Force-enable relevant MSR events; optimize the number of sent MSR events Razvan Cojocaru
@ 2014-07-11 17:03   ` Andrew Cooper
  2014-07-11 18:09     ` Razvan Cojocaru
  0 siblings, 1 reply; 34+ messages in thread
From: Andrew Cooper @ 2014-07-11 17:03 UTC (permalink / raw)
  To: Razvan Cojocaru, xen-devel; +Cc: mdontu, tim, JBeulich

On 11/07/14 16:43, Razvan Cojocaru wrote:
> Vmx_disable_intercept_for_msr() will now refuse to disable interception of
> MSRs needed for memory introspection. It is not possible to gate this on
> mem_access being active for the domain, since by the time mem_access does
> become active the interception for the interesting MSRs has already been
> disabled (vmx_disable_intercept_for_msr() runs very early on).
>
> Changes since V1:
>  - Replaced printk() with gdprintk(XENLOG_DEBUG, ...).
>
> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
> ---
>  xen/arch/x86/hvm/vmx/vmcs.c |   18 ++++++++++++++++++
>  1 file changed, 18 insertions(+)
>
> diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
> index 8ffc562..35fcfcc 100644
> --- a/xen/arch/x86/hvm/vmx/vmcs.c
> +++ b/xen/arch/x86/hvm/vmx/vmcs.c
> @@ -700,6 +700,24 @@ void vmx_disable_intercept_for_msr(struct vcpu *v, u32 msr, int type)
>      if ( msr_bitmap == NULL )
>          return;
>  
> +    /* Filter out MSR-s needed for memory introspection */
> +    switch ( msr )

This absolutely must be gated on mem_events being enabled for the domain.

It is too much of a performance penalty to apply to domains which are
not being introspected.

> +    {
> +    case MSR_IA32_SYSENTER_EIP:
> +    case MSR_IA32_SYSENTER_ESP:
> +    case MSR_IA32_SYSENTER_CS:
> +    case MSR_IA32_MC0_CTL:
> +    case MSR_STAR:
> +    case MSR_LSTAR:
> +
> +        gdprintk(XENLOG_DEBUG, "MSR 0x%08x needed for "
> +            "memory introspection, still intercepted\n", msr);

I you are going to split this line then do it at the %08x so the string
is still grepable.

How often do these messages trigger?  It seems like it could be
contribute to a lot of logspam.

> +        return;
> +
> +    default:
> +        break;
> +    }
> +
>      /*
>       * See Intel PRM Vol. 3, 20.6.9 (MSR-Bitmap Address). Early manuals
>       * have the write-low and read-high bitmap offsets the wrong way round.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 4/6] xen: Support for VMCALL mem_events
  2014-07-11 15:43 ` [PATCH RFC V2 4/6] xen: Support for VMCALL mem_events Razvan Cojocaru
@ 2014-07-11 17:23   ` Andrew Cooper
  2014-07-11 18:15     ` Razvan Cojocaru
  2015-03-17 13:50     ` Razvan Cojocaru
  0 siblings, 2 replies; 34+ messages in thread
From: Andrew Cooper @ 2014-07-11 17:23 UTC (permalink / raw)
  To: Razvan Cojocaru, xen-devel; +Cc: mdontu, tim, JBeulich

On 11/07/14 16:43, Razvan Cojocaru wrote:
> Added support for VMCALL events (the memory introspection library
> will have the guest trigger VMCALLs, which will then be sent along
> via the mem_event mechanism).
>
> Changes since V1:
>  - Added a #define and an comment explaining a previous magic
>    constant.
>  - Had MEM_EVENT_REASON_VMCALL explicitly not honour
>    HVMPME_onchangeonly.
>
> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
> ---
>  xen/arch/x86/hvm/hvm.c          |    9 +++++++++
>  xen/arch/x86/hvm/vmx/vmx.c      |   18 +++++++++++++++++-
>  xen/include/asm-x86/hvm/hvm.h   |    1 +
>  xen/include/public/hvm/params.h |    4 +++-
>  xen/include/public/mem_event.h  |    5 +++++
>  5 files changed, 35 insertions(+), 2 deletions(-)
>
> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index 89a0382..6e86d7c 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -5564,6 +5564,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
>              case HVM_PARAM_MEMORY_EVENT_INT3:
>              case HVM_PARAM_MEMORY_EVENT_SINGLE_STEP:
>              case HVM_PARAM_MEMORY_EVENT_MSR:
> +            case HVM_PARAM_MEMORY_EVENT_VMCALL:
>                  if ( d == current->domain )
>                  {
>                      rc = -EPERM;
> @@ -6199,6 +6200,14 @@ void hvm_memory_event_msr(unsigned long msr, unsigned long value)
>                             value, ~value, 1, msr);
>  }
>  
> +void hvm_memory_event_vmcall(unsigned long rip, unsigned long eax)
> +{
> +    hvm_memory_event_traps(current->domain->arch.hvm_domain
> +                             .params[HVM_PARAM_MEMORY_EVENT_VMCALL],
> +                           MEM_EVENT_REASON_VMCALL,
> +                           rip, ~rip, 1, eax);
> +}
> +
>  int hvm_memory_event_int3(unsigned long gla) 
>  {
>      uint32_t pfec = PFEC_page_present;
> diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
> index 2caa04a..6c63225 100644
> --- a/xen/arch/x86/hvm/vmx/vmx.c
> +++ b/xen/arch/x86/hvm/vmx/vmx.c
> @@ -2879,8 +2879,24 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
>      case EXIT_REASON_VMCALL:
>      {
>          int rc;
> +        unsigned long eax = regs->eax;
> +
>          HVMTRACE_1D(VMMCALL, regs->eax);
> -        rc = hvm_do_hypercall(regs);
> +
> +        /* Don't send a VMCALL mem_event unless something
> +         * caused the guests's eax register to contain the
> +         * VMCALL_EVENT_REQUEST constant. */
> +        if ( regs->eax != VMCALL_EVENT_REQUEST )
> +        {
> +            rc = hvm_do_hypercall(regs);
> +        }
> +        else
> +        {
> +            hvm_memory_event_vmcall(guest_cpu_user_regs()->eip, eax);
> +            update_guest_eip();
> +            break;
> +        }

Thinking more about this, it is really a hypercall pretending not to
be.  It would be better to introduce a real HVMOP_send_mem_event.

>From the point of view of your in-guest agent, it would be a vmcall with
rax = 34 (hvmop) rdi = $N (send_mem_event subop) rsi = data or pointer
to struct containing data, depending on how exactly you implement the
hypercall.

You would have the bonus of being able to detect errors, e.g. -ENOENT
for "mem_event not active", get SVM support for free, and not need magic
numbers, or vendor specific terms like "vmcall" finding their way into
the Xen public API.

> +
>          if ( rc != HVM_HCALL_preempted )
>          {
>              update_guest_eip(); /* Safe: VMCALL */
> diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h
> index 0ebd478..3c0af30 100644
> --- a/xen/include/asm-x86/hvm/hvm.h
> +++ b/xen/include/asm-x86/hvm/hvm.h
> @@ -475,6 +475,7 @@ void hvm_memory_event_cr0(unsigned long value, unsigned long old);
>  void hvm_memory_event_cr3(unsigned long value, unsigned long old);
>  void hvm_memory_event_cr4(unsigned long value, unsigned long old);
>  void hvm_memory_event_msr(unsigned long msr, unsigned long value);
> +void hvm_memory_event_vmcall(unsigned long rip, unsigned long eax);
>  /* Called for current VCPU on int3: returns -1 if no listener */
>  int hvm_memory_event_int3(unsigned long gla);
>  
> diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h
> index 614ff5f..d8f89b5 100644
> --- a/xen/include/public/hvm/params.h
> +++ b/xen/include/public/hvm/params.h
> @@ -151,6 +151,8 @@
>  /* Location of the VM Generation ID in guest physical address space. */
>  #define HVM_PARAM_VM_GENERATION_ID_ADDR 34
>  
> -#define HVM_NR_PARAMS          35
> +#define HVM_PARAM_MEMORY_EVENT_VMCALL 35

What is this hvmparam actually used for?  This patch only reads it, and
as indicated previously, it is readwrite to the guest which likely
breaks any assumptions you have about the trustworthness of the value
found there.

~Andrew

> +
> +#define HVM_NR_PARAMS          36
>  
>  #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
> diff --git a/xen/include/public/mem_event.h b/xen/include/public/mem_event.h
> index b9af728..7a59083 100644
> --- a/xen/include/public/mem_event.h
> +++ b/xen/include/public/mem_event.h
> @@ -47,6 +47,11 @@
>  #define MEM_EVENT_REASON_SINGLESTEP  6    /* single step was invoked: gla/gfn are RIP */
>  #define MEM_EVENT_REASON_MSR         7    /* MSR was hit: gfn is MSR value, gla is MSR address;
>                                               does NOT honour HVMPME_onchangeonly */
> +#define MEM_EVENT_REASON_VMCALL      8    /* VMCALL: gfn is RIP, gla is EAX;
> +                                             does NOT honour HVMPME_onchangeonly */
> +
> +/* VMCALL mem_events will only be sent when the guest's EAX holds this value. */
> +#define VMCALL_EVENT_REQUEST 0x494E5452 /* 'INTR' */
>  
>  /* Using a custom struct (not hvm_hw_cpu) so as to not fill
>   * the mem_event ring buffer too quickly. */

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 1/6] xen: Emulate with no writes
  2014-07-11 16:23 ` [PATCH RFC V2 1/6] xen: Emulate with no writes Andrew Cooper
@ 2014-07-11 18:00   ` Razvan Cojocaru
  2014-07-14  8:37   ` Razvan Cojocaru
  1 sibling, 0 replies; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-11 18:00 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel; +Cc: mdontu, tim, JBeulich

On 07/11/2014 07:23 PM, Andrew Cooper wrote:
> On 11/07/14 16:43, Razvan Cojocaru wrote:
>> +void hvm_emulate_one_full(bool_t nowrite,
>> +    unsigned int unhandleable_trapnr,
>> +    int unhandleable_errcode)
>> +{
>> +    struct hvm_emulate_ctxt ctx[1] = {};
> 
> This construct looks suspect.  What is wrong with
> 
> struct hvm_emulate_ctxt ctx = { 0 }; and using &ctx below ?

Nothing, will replace it.

>> +    int rc = X86EMUL_RETRY;
>> +
>> +    hvm_emulate_prepare(ctx, guest_cpu_user_regs());
>> +
>> +    while ( rc == X86EMUL_RETRY )
>> +    {
>> +        if ( nowrite )
>> +            rc = hvm_emulate_one_no_write(ctx);
>> +        else
>> +            rc = hvm_emulate_one(ctx);
>> +    }
> 
> This however is not appropriate.  X86EMUL_RETRY can include "talk to
> dom0 and get the paging subsystem to page in part of the VM", which
> given some current work-in-progress can be to the other end of a network
> connection on the far side of an optimistic migration.
> 
> You can't cause a Xen pcpu to spin like this for that length of time. 
> Anything longer than a second and all other pcpus will block against the
> time calibration rendezvous, and longer than 5 will panic on the NMI
> watchdog.

I see. Would you be able to recommend a safer way of handling
X86EMUL_RETRY here? Basically what I'm trying to achieve is simply
making sure that the instruction either ran or was impossible to run
when hvm_emulate_one_full() returns.

I guess I should run hvm_emulate_one() / hvm_emulate_one_no_write() once
and just return on X86EMUL_RETRY?


Thanks,
Razvan Cojocaru

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 2/6] xen: Optimize introspection access to guest state
  2014-07-11 16:54   ` Andrew Cooper
  2014-07-11 16:57     ` Andrew Cooper
@ 2014-07-11 18:03     ` Razvan Cojocaru
  2014-07-11 18:09       ` Andrew Cooper
  1 sibling, 1 reply; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-11 18:03 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel; +Cc: mdontu, tim, JBeulich

On 07/11/2014 07:54 PM, Andrew Cooper wrote:
> On 11/07/14 16:43, Razvan Cojocaru wrote:
>> @@ -1407,6 +1464,9 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
>>      if ( p2ma != p2m_access_n2rwx )
>>          vcpu_pause_nosync(v);
>>  
>> +    if ( req )
>> +        p2m_mem_event_fill_regs(req);
> 
> Should this not be part of the if ( req ) just above the pause_nosync() ?

Yes, that would make it more readable. I wanted to make sure that the
vcpu is paused before filling in register data, but considering the
context in which this code executes, it shouldn't matter if I just move
it up.


Thanks,
Razvan Cojocaru

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 5/6] xen, libxc: Request page fault injection via libxc
  2014-07-11 15:43 ` [PATCH RFC V2 5/6] xen, libxc: Request page fault injection via libxc Razvan Cojocaru
@ 2014-07-11 18:06   ` Andrew Cooper
  2014-07-17 11:53     ` Ian Campbell
  2014-07-17 12:22     ` Razvan Cojocaru
  0 siblings, 2 replies; 34+ messages in thread
From: Andrew Cooper @ 2014-07-11 18:06 UTC (permalink / raw)
  To: Razvan Cojocaru, xen-devel; +Cc: mdontu, tim, JBeulich

On 11/07/14 16:43, Razvan Cojocaru wrote:
> Added new XEN_DOMCTL_set_pagefault_info hypercall, used by libxc's
> new xc_domain_set_pagefault_info() function to set per-domain page
> fault injection information. All a call does is set per-domain info,
> and nothing actually happens until VMENTRY time, and then only if
> all conditions are met (the guest is in user mode, the set value
> matches CR3, and there are no other pending traps).
> This mechanism allows bringing in swapped-out pages for inspection.
>
> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>

For the record, I still think this is a bad idea to be working against a
guest OS paging algorithm, and I am uneasy about whether it is sensible
to introduce abilities like that into the Xen API.

With that problem aside, I have some review anway.

> ---
>  tools/libxc/xc_domain.c     |   17 +++++++++++++++++
>  tools/libxc/xenctrl.h       |    4 ++++
>  xen/arch/x86/hvm/vmx/vmx.c  |   39 +++++++++++++++++++++++++++++++++++++++
>  xen/common/domain.c         |    5 +++++
>  xen/common/domctl.c         |   21 +++++++++++++++++++++
>  xen/include/public/domctl.h |   14 ++++++++++++++
>  xen/include/xen/sched.h     |    7 +++++++
>  7 files changed, 107 insertions(+)
>
> diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
> index 0230c6c..7437c51 100644
> --- a/tools/libxc/xc_domain.c
> +++ b/tools/libxc/xc_domain.c
> @@ -506,6 +506,23 @@ int xc_domain_hvm_setcontext(xc_interface *xch,
>      return ret;
>  }
>  
> +int xc_domain_set_pagefault_info(xc_interface *xch,
> +                                 uint32_t domid,
> +                                 xen_domctl_set_pagefault_info_t *info)
> +{
> +    DECLARE_DOMCTL;
> +
> +    if (info == NULL)
> +        return -1;
> +
> +    domctl.cmd = XEN_DOMCTL_set_pagefault_info;
> +    domctl.domain = (domid_t)domid;
> +    domctl.u.set_pagefault_info.address_space = info->address_space;
> +    domctl.u.set_pagefault_info.virtual_address = info->virtual_address;
> +    domctl.u.set_pagefault_info.write_access = info->write_access;
> +    return do_domctl(xch, &domctl);
> +}
> +
>  int xc_vcpu_getcontext(xc_interface *xch,
>                         uint32_t domid,
>                         uint32_t vcpu,
> diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
> index 3578b09..302ef0e 100644
> --- a/tools/libxc/xenctrl.h
> +++ b/tools/libxc/xenctrl.h
> @@ -793,6 +793,10 @@ int xc_domain_hvm_setcontext(xc_interface *xch,
>  const char *xc_domain_get_native_protocol(xc_interface *xch,
>                                            uint32_t domid);
>  
> +int xc_domain_set_pagefault_info(xc_interface *xch,
> +                                 uint32_t domid,
> +                                 xen_domctl_set_pagefault_info_t *info);
> +
>  /**
>   * This function returns information about the execution context of a
>   * particular vcpu of a domain.
> diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
> index 6c63225..835621f 100644
> --- a/xen/arch/x86/hvm/vmx/vmx.c
> +++ b/xen/arch/x86/hvm/vmx/vmx.c
> @@ -416,6 +416,7 @@ static void vmx_restore_dr(struct vcpu *v)
>  static void vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c)
>  {
>      unsigned long ev;
> +    unsigned long cs_arbytes;
>  
>      vmx_vmcs_enter(v);
>  
> @@ -429,6 +430,9 @@ static void vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c)
>      __vmread(GUEST_SYSENTER_CS, &c->sysenter_cs);
>      __vmread(GUEST_SYSENTER_ESP, &c->sysenter_esp);
>      __vmread(GUEST_SYSENTER_EIP, &c->sysenter_eip);
> +    __vmread(GUEST_CS_AR_BYTES, &cs_arbytes);
> +
> +    c->cs_arbytes = (uint32_t)cs_arbytes;

I am fairly sure this will break migration, as you are changing the bit
representation of c->cs_arbytes in the architectural state.

However, given a comment below, I cant see why you even need it.

>  
>      c->pending_event = 0;
>      c->error_code = 0;
> @@ -3113,6 +3117,39 @@ out:
>          nvmx_idtv_handling();
>  }
>  
> +static void check_pf_injection(void)
> +{
> +    struct vcpu *curr = current;
> +    struct domain *d = curr->domain;
> +    struct hvm_hw_cpu ctxt;
> +    uint32_t ss_dpl;
> +
> +    if ( !is_hvm_domain(d) || d->fault_info.virtual_address == 0 )
> +        return;
> +
> +    memset(&ctxt, 0, sizeof(struct hvm_hw_cpu));
> +    hvm_funcs.save_cpu_ctxt(curr, &ctxt);
> +
> +    ss_dpl = (ctxt.cs_arbytes >> 5) & 3;
> +
> +    if ( ss_dpl == 3 /* Guest is in user mode */

cs dpl is not cpl.  It will be incorrect at various points, e.g.
conforming code segments.

The real ss dpl is always the correct cpl.

There are notes to this effect in both the Intel and AMD architecture
manuals, but I can't for the life of me actually find either of the notes.

> +         && !ctxt.pending_event
> +         && ctxt.cr3 == d->fault_info.address_space )
> +    {
> +        /* Cache */
> +        uint64_t virtual_address = d->fault_info.virtual_address;
> +        uint32_t write_access = d->fault_info.write_access;
> +
> +        /* Reset */
> +        d->fault_info.address_space = 0;
> +        d->fault_info.virtual_address = 0;
> +        d->fault_info.write_access = 0;
> +
> +        hvm_inject_page_fault((write_access << 1) | PFEC_user_mode,

It is sensible in the slightest to have write_access shifted by 1 with
respect to a real pagefault error code?

> +            virtual_address);
> +    }
> +}
> +
>  void vmx_vmenter_helper(const struct cpu_user_regs *regs)
>  {
>      struct vcpu *curr = current;
> @@ -3153,6 +3190,8 @@ void vmx_vmenter_helper(const struct cpu_user_regs *regs)
>      if ( unlikely(need_flush) )
>          vpid_sync_all();
>  
> +    check_pf_injection();
> +
>   out:
>      HVMTRACE_ND(VMENTRY, 0, 1/*cycles*/, 0, 0, 0, 0, 0, 0, 0);
>  
> diff --git a/xen/common/domain.c b/xen/common/domain.c
> index cd64aea..e7bd734 100644
> --- a/xen/common/domain.c
> +++ b/xen/common/domain.c
> @@ -255,6 +255,11 @@ struct domain *domain_create(
>  
>      d->domain_id = domid;
>  
> +    /* Memory introspection page fault variables set-up. */
> +    d->fault_info.address_space = 0;
> +    d->fault_info.virtual_address = 0;
> +    d->fault_info.write_access = 0;
> +

alloc_domain_struct() zeroes the memory beforehand, so you don't need to
repeat it here.

>      lock_profile_register_struct(LOCKPROF_TYPE_PERDOM, d, domid, "Domain");
>  
>      if ( (err = xsm_alloc_security_domain(d)) != 0 )
> diff --git a/xen/common/domctl.c b/xen/common/domctl.c
> index c326aba..4321ca1 100644
> --- a/xen/common/domctl.c
> +++ b/xen/common/domctl.c
> @@ -967,6 +967,27 @@ long do_domctl(XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
>      }
>      break;
>  
> +    case XEN_DOMCTL_set_pagefault_info:
> +    {
> +        struct domain *d;
> +
> +        ret = -ESRCH;
> +        d = rcu_lock_domain_by_id(op->domain);
> +        if ( d != NULL )
> +        {

This should fail with -EINVAL if !has_hvm_container(d)

> +            d->fault_info.address_space =
> +                op->u.set_pagefault_info.address_space;
> +            d->fault_info.virtual_address =
> +                op->u.set_pagefault_info.virtual_address;
> +            d->fault_info.write_access =
> +                op->u.set_pagefault_info.write_access;
> +
> +            rcu_unlock_domain(d);
> +            ret = 0;
> +        }
> +    }
> +    break;
> +
>      default:
>          ret = arch_do_domctl(op, d, u_domctl);
>          break;
> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> index 5b11bbf..c8bf3f8 100644
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -936,6 +936,18 @@ typedef struct xen_domctl_vcpu_msrs xen_domctl_vcpu_msrs_t;
>  DEFINE_XEN_GUEST_HANDLE(xen_domctl_vcpu_msrs_t);
>  #endif
>  
> +/* XEN_DOMCTL_set_pagefault_info requests that a page fault occur at
> + * the next VMENTRY.
> + *  */
> +struct xen_domctl_set_pagefault_info {
> +    uint64_t address_space;
> +    uint64_t virtual_address;
> +    uint32_t write_access;
> +};
> +typedef struct xen_domctl_set_pagefault_info xen_domctl_set_pagefault_info_t;
> +DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_pagefault_info_t);
> +
> +
>  struct xen_domctl {
>      uint32_t cmd;
>  #define XEN_DOMCTL_createdomain                   1
> @@ -1012,6 +1024,7 @@ struct xen_domctl {
>  #define XEN_DOMCTL_gdbsx_pausevcpu             1001
>  #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
>  #define XEN_DOMCTL_gdbsx_domstatus             1003
> +#define XEN_DOMCTL_set_pagefault_info          1004
>      uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */
>      domid_t  domain;
>      union {
> @@ -1068,6 +1081,7 @@ struct xen_domctl {
>          struct xen_domctl_cacheflush        cacheflush;
>          struct xen_domctl_gdbsx_pauseunp_vcpu gdbsx_pauseunp_vcpu;
>          struct xen_domctl_gdbsx_domstatus   gdbsx_domstatus;
> +        struct xen_domctl_set_pagefault_info set_pagefault_info;
>          uint8_t                             pad[128];
>      } u;
>  };
> diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
> index d5bc461..754e070 100644
> --- a/xen/include/xen/sched.h
> +++ b/xen/include/xen/sched.h
> @@ -447,6 +447,13 @@ struct domain
>      nodemask_t node_affinity;
>      unsigned int last_alloc_node;
>      spinlock_t node_affinity_lock;
> +
> +    /* Memory introspection page fault injection data. */
> +    struct {
> +        uint64_t address_space;
> +        uint64_t virtual_address;
> +        uint32_t write_access;
> +    } fault_info;

As currently designed, this is only possible for hvm domains.  It should
live inside struct hvm_domain.

~Andrew

>  };
>  
>  struct domain_setup_info

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 2/6] xen: Optimize introspection access to guest state
  2014-07-11 18:03     ` Razvan Cojocaru
@ 2014-07-11 18:09       ` Andrew Cooper
  0 siblings, 0 replies; 34+ messages in thread
From: Andrew Cooper @ 2014-07-11 18:09 UTC (permalink / raw)
  To: Razvan Cojocaru, xen-devel; +Cc: mdontu, tim, JBeulich

On 11/07/14 19:03, Razvan Cojocaru wrote:
> On 07/11/2014 07:54 PM, Andrew Cooper wrote:
>> On 11/07/14 16:43, Razvan Cojocaru wrote:
>>> @@ -1407,6 +1464,9 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
>>>      if ( p2ma != p2m_access_n2rwx )
>>>          vcpu_pause_nosync(v);
>>>  
>>> +    if ( req )
>>> +        p2m_mem_event_fill_regs(req);
>> Should this not be part of the if ( req ) just above the pause_nosync() ?
> Yes, that would make it more readable. I wanted to make sure that the
> vcpu is paused before filling in register data, but considering the
> context in which this code executes, it shouldn't matter if I just move
> it up.
>
>
> Thanks,
> Razvan Cojocaru

vcpu_pause() & friends are purely scheduler accounting.  Nothing in
there will play with register state.

~Andrew

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 3/6] xen: Force-enable relevant MSR events; optimize the number of sent MSR events
  2014-07-11 17:03   ` Andrew Cooper
@ 2014-07-11 18:09     ` Razvan Cojocaru
       [not found]       ` <CAGU+ausrcu=L7Kf30gZJXRnnxrKe7EMYXTGByOY4agwoK0nXeA@mail.gmail.com>
  2014-07-11 18:19       ` Andrew Cooper
  0 siblings, 2 replies; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-11 18:09 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel; +Cc: mdontu, tim, JBeulich

On 07/11/2014 08:03 PM, Andrew Cooper wrote:
> On 11/07/14 16:43, Razvan Cojocaru wrote:
>> Vmx_disable_intercept_for_msr() will now refuse to disable interception of
>> MSRs needed for memory introspection. It is not possible to gate this on
>> mem_access being active for the domain, since by the time mem_access does
>> become active the interception for the interesting MSRs has already been
>> disabled (vmx_disable_intercept_for_msr() runs very early on).
>>
>> Changes since V1:
>>  - Replaced printk() with gdprintk(XENLOG_DEBUG, ...).
>>
>> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
>> ---
>>  xen/arch/x86/hvm/vmx/vmcs.c |   18 ++++++++++++++++++
>>  1 file changed, 18 insertions(+)
>>
>> diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
>> index 8ffc562..35fcfcc 100644
>> --- a/xen/arch/x86/hvm/vmx/vmcs.c
>> +++ b/xen/arch/x86/hvm/vmx/vmcs.c
>> @@ -700,6 +700,24 @@ void vmx_disable_intercept_for_msr(struct vcpu *v, u32 msr, int type)
>>      if ( msr_bitmap == NULL )
>>          return;
>>  
>> +    /* Filter out MSR-s needed for memory introspection */
>> +    switch ( msr )
> 
> This absolutely must be gated on mem_events being enabled for the domain.
> 
> It is too much of a performance penalty to apply to domains which are
> not being introspected.

I understand, but it really runs very early on, and the mem_event part
comes in after the MSR interception is disabled. This effectively
renders a lot of memory introspection functionality useless.

>> +    {
>> +    case MSR_IA32_SYSENTER_EIP:
>> +    case MSR_IA32_SYSENTER_ESP:
>> +    case MSR_IA32_SYSENTER_CS:
>> +    case MSR_IA32_MC0_CTL:
>> +    case MSR_STAR:
>> +    case MSR_LSTAR:
>> +
>> +        gdprintk(XENLOG_DEBUG, "MSR 0x%08x needed for "
>> +            "memory introspection, still intercepted\n", msr);
> 
> I you are going to split this line then do it at the %08x so the string
> is still grepable.
> 
> How often do these messages trigger?  It seems like it could be
> contribute to a lot of logspam.

As far as I've seen, never more than a handful of them (maybe 5-6 lines)
when the domain starts, never to be seen again. Definitely not log spam
material.


Thanks,
Razvan Cojocaru

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 4/6] xen: Support for VMCALL mem_events
  2014-07-11 17:23   ` Andrew Cooper
@ 2014-07-11 18:15     ` Razvan Cojocaru
  2015-03-17 13:50     ` Razvan Cojocaru
  1 sibling, 0 replies; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-11 18:15 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel; +Cc: mdontu, tim, JBeulich

On 07/11/2014 08:23 PM, Andrew Cooper wrote:
> On 11/07/14 16:43, Razvan Cojocaru wrote:
>> diff --git a/xen/include/public/hvm/params.h b/xen/include/public/hvm/params.h
>> index 614ff5f..d8f89b5 100644
>> --- a/xen/include/public/hvm/params.h
>> +++ b/xen/include/public/hvm/params.h
>> @@ -151,6 +151,8 @@
>>  /* Location of the VM Generation ID in guest physical address space. */
>>  #define HVM_PARAM_VM_GENERATION_ID_ADDR 34
>>  
>> -#define HVM_NR_PARAMS          35
>> +#define HVM_PARAM_MEMORY_EVENT_VMCALL 35
> 
> What is this hvmparam actually used for?  This patch only reads it, and
> as indicated previously, it is readwrite to the guest which likely
> breaks any assumptions you have about the trustworthness of the value
> found there.

I'm now using it to make sure that enabling it will not honour
HVMPME_onchangeonly:

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 89a0382..6e86d7c 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -5564,6 +5564,7 @@ long do_hvm_op(unsigned long op,
XEN_GUEST_HANDLE_PARAM(void) arg)
             case HVM_PARAM_MEMORY_EVENT_INT3:
             case HVM_PARAM_MEMORY_EVENT_SINGLE_STEP:
             case HVM_PARAM_MEMORY_EVENT_MSR:
+            case HVM_PARAM_MEMORY_EVENT_VMCALL:
                 if ( d == current->domain )
                 {
                     rc = -EPERM;


Thanks,
Razvan Cojocaru

^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 3/6] xen: Force-enable relevant MSR events; optimize the number of sent MSR events
       [not found]       ` <CAGU+ausrcu=L7Kf30gZJXRnnxrKe7EMYXTGByOY4agwoK0nXeA@mail.gmail.com>
@ 2014-07-11 18:18         ` Aravindh Puthiyaparambil (aravindp)
  0 siblings, 0 replies; 34+ messages in thread
From: Aravindh Puthiyaparambil (aravindp) @ 2014-07-11 18:18 UTC (permalink / raw)
  To: Razvan Cojocaru
  Cc: Andrew Cooper, mdontu, tim, Jan Beulich (JBeulich@suse.com), xen-devel

>>> diff --git a/xen/arch/x86/hvm/vmx/vmcs.c
>>> b/xen/arch/x86/hvm/vmx/vmcs.c index 8ffc562..35fcfcc 100644
>>> --- a/xen/arch/x86/hvm/vmx/vmcs.c
>>> +++ b/xen/arch/x86/hvm/vmx/vmcs.c
>>> @@ -700,6 +700,24 @@ void vmx_disable_intercept_for_msr(struct vcpu
>*v, u32 msr, int type)
>>>      if ( msr_bitmap == NULL )
>>>          return;
>>>
>>> +    /* Filter out MSR-s needed for memory introspection */
>>> +    switch ( msr )
>>
>> This absolutely must be gated on mem_events being enabled for the
>domain.
>>
>> It is too much of a performance penalty to apply to domains which are
>> not being introspected.
>
>I understand, but it really runs very early on, and the mem_event part comes
>in after the MSR interception is disabled. This effectively renders a lot of
>memory introspection functionality useless.

How about using a Xen command line parameter and gate it based on that rather than a mem_event listener being present? 

Thanks,
Aravindh

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 3/6] xen: Force-enable relevant MSR events; optimize the number of sent MSR events
  2014-07-11 18:09     ` Razvan Cojocaru
       [not found]       ` <CAGU+ausrcu=L7Kf30gZJXRnnxrKe7EMYXTGByOY4agwoK0nXeA@mail.gmail.com>
@ 2014-07-11 18:19       ` Andrew Cooper
  2014-07-11 18:22         ` Razvan Cojocaru
  1 sibling, 1 reply; 34+ messages in thread
From: Andrew Cooper @ 2014-07-11 18:19 UTC (permalink / raw)
  To: Razvan Cojocaru, xen-devel; +Cc: mdontu, tim, JBeulich

On 11/07/14 19:09, Razvan Cojocaru wrote:
> On 07/11/2014 08:03 PM, Andrew Cooper wrote:
>> On 11/07/14 16:43, Razvan Cojocaru wrote:
>>> Vmx_disable_intercept_for_msr() will now refuse to disable interception of
>>> MSRs needed for memory introspection. It is not possible to gate this on
>>> mem_access being active for the domain, since by the time mem_access does
>>> become active the interception for the interesting MSRs has already been
>>> disabled (vmx_disable_intercept_for_msr() runs very early on).
>>>
>>> Changes since V1:
>>>  - Replaced printk() with gdprintk(XENLOG_DEBUG, ...).
>>>
>>> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
>>> ---
>>>  xen/arch/x86/hvm/vmx/vmcs.c |   18 ++++++++++++++++++
>>>  1 file changed, 18 insertions(+)
>>>
>>> diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
>>> index 8ffc562..35fcfcc 100644
>>> --- a/xen/arch/x86/hvm/vmx/vmcs.c
>>> +++ b/xen/arch/x86/hvm/vmx/vmcs.c
>>> @@ -700,6 +700,24 @@ void vmx_disable_intercept_for_msr(struct vcpu *v, u32 msr, int type)
>>>      if ( msr_bitmap == NULL )
>>>          return;
>>>  
>>> +    /* Filter out MSR-s needed for memory introspection */
>>> +    switch ( msr )
>> This absolutely must be gated on mem_events being enabled for the domain.
>>
>> It is too much of a performance penalty to apply to domains which are
>> not being introspected.
> I understand, but it really runs very early on, and the mem_event part
> comes in after the MSR interception is disabled. This effectively
> renders a lot of memory introspection functionality useless.

In which case the hypercall which enables mem_event needs to prod the
vmcs state an explicitly enable intercepts for these MSRs. (and
conversly re-disables intercepts if mem_events are disabled)

You can probably get away with hvm_funcs to enable and disable mem events.

~Andrew

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 3/6] xen: Force-enable relevant MSR events; optimize the number of sent MSR events
  2014-07-11 18:19       ` Andrew Cooper
@ 2014-07-11 18:22         ` Razvan Cojocaru
  2014-07-11 18:29           ` Andrew Cooper
  0 siblings, 1 reply; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-11 18:22 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel; +Cc: mdontu, tim, JBeulich

On 07/11/2014 09:19 PM, Andrew Cooper wrote:
> On 11/07/14 19:09, Razvan Cojocaru wrote:
>> On 07/11/2014 08:03 PM, Andrew Cooper wrote:
>>> On 11/07/14 16:43, Razvan Cojocaru wrote:
>>>> Vmx_disable_intercept_for_msr() will now refuse to disable interception of
>>>> MSRs needed for memory introspection. It is not possible to gate this on
>>>> mem_access being active for the domain, since by the time mem_access does
>>>> become active the interception for the interesting MSRs has already been
>>>> disabled (vmx_disable_intercept_for_msr() runs very early on).
>>>>
>>>> Changes since V1:
>>>>  - Replaced printk() with gdprintk(XENLOG_DEBUG, ...).
>>>>
>>>> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
>>>> ---
>>>>  xen/arch/x86/hvm/vmx/vmcs.c |   18 ++++++++++++++++++
>>>>  1 file changed, 18 insertions(+)
>>>>
>>>> diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
>>>> index 8ffc562..35fcfcc 100644
>>>> --- a/xen/arch/x86/hvm/vmx/vmcs.c
>>>> +++ b/xen/arch/x86/hvm/vmx/vmcs.c
>>>> @@ -700,6 +700,24 @@ void vmx_disable_intercept_for_msr(struct vcpu *v, u32 msr, int type)
>>>>      if ( msr_bitmap == NULL )
>>>>          return;
>>>>  
>>>> +    /* Filter out MSR-s needed for memory introspection */
>>>> +    switch ( msr )
>>> This absolutely must be gated on mem_events being enabled for the domain.
>>>
>>> It is too much of a performance penalty to apply to domains which are
>>> not being introspected.
>> I understand, but it really runs very early on, and the mem_event part
>> comes in after the MSR interception is disabled. This effectively
>> renders a lot of memory introspection functionality useless.
> 
> In which case the hypercall which enables mem_event needs to prod the
> vmcs state an explicitly enable intercepts for these MSRs. (and
> conversly re-disables intercepts if mem_events are disabled)
> 
> You can probably get away with hvm_funcs to enable and disable mem events.

That makes sense. Would Aravindh's solution also be acceptable to you
(using a Xen command line parameter and gate it based on that rather
than a mem_event listener being present)?


Thanks,
Razvan Cojocaru

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 3/6] xen: Force-enable relevant MSR events; optimize the number of sent MSR events
  2014-07-11 18:22         ` Razvan Cojocaru
@ 2014-07-11 18:29           ` Andrew Cooper
  0 siblings, 0 replies; 34+ messages in thread
From: Andrew Cooper @ 2014-07-11 18:29 UTC (permalink / raw)
  To: Razvan Cojocaru, xen-devel; +Cc: mdontu, tim, JBeulich

On 11/07/14 19:22, Razvan Cojocaru wrote:
> On 07/11/2014 09:19 PM, Andrew Cooper wrote:
>> On 11/07/14 19:09, Razvan Cojocaru wrote:
>>> On 07/11/2014 08:03 PM, Andrew Cooper wrote:
>>>> On 11/07/14 16:43, Razvan Cojocaru wrote:
>>>>> Vmx_disable_intercept_for_msr() will now refuse to disable interception of
>>>>> MSRs needed for memory introspection. It is not possible to gate this on
>>>>> mem_access being active for the domain, since by the time mem_access does
>>>>> become active the interception for the interesting MSRs has already been
>>>>> disabled (vmx_disable_intercept_for_msr() runs very early on).
>>>>>
>>>>> Changes since V1:
>>>>>  - Replaced printk() with gdprintk(XENLOG_DEBUG, ...).
>>>>>
>>>>> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
>>>>> ---
>>>>>  xen/arch/x86/hvm/vmx/vmcs.c |   18 ++++++++++++++++++
>>>>>  1 file changed, 18 insertions(+)
>>>>>
>>>>> diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
>>>>> index 8ffc562..35fcfcc 100644
>>>>> --- a/xen/arch/x86/hvm/vmx/vmcs.c
>>>>> +++ b/xen/arch/x86/hvm/vmx/vmcs.c
>>>>> @@ -700,6 +700,24 @@ void vmx_disable_intercept_for_msr(struct vcpu *v, u32 msr, int type)
>>>>>      if ( msr_bitmap == NULL )
>>>>>          return;
>>>>>  
>>>>> +    /* Filter out MSR-s needed for memory introspection */
>>>>> +    switch ( msr )
>>>> This absolutely must be gated on mem_events being enabled for the domain.
>>>>
>>>> It is too much of a performance penalty to apply to domains which are
>>>> not being introspected.
>>> I understand, but it really runs very early on, and the mem_event part
>>> comes in after the MSR interception is disabled. This effectively
>>> renders a lot of memory introspection functionality useless.
>> In which case the hypercall which enables mem_event needs to prod the
>> vmcs state an explicitly enable intercepts for these MSRs. (and
>> conversly re-disables intercepts if mem_events are disabled)
>>
>> You can probably get away with hvm_funcs to enable and disable mem events.
> That makes sense. Would Aravindh's solution also be acceptable to you
> (using a Xen command line parameter and gate it based on that rather
> than a mem_event listener being present)?
>
>
> Thanks,
> Razvan Cojocaru

Its not a question of acceptable to me.  I am not a maintainer or
committer.  I am merely offering an opinion as a member of the Xen
community.

The people you ultimately need to convince are the Intel VT-x
maintainers (who I notice are still missed off the CC list - please use
/scripts/get_maintainers.pl to identify all the people you need to CC
based on code areas your patches touch) and the general x86 maintainers.

In this case, it would be better to dynamically change the interceptions
based on the use of mem_event, rather than having someone wanting to use
mem_events have to apply the same performance penalty to all their other
VMs if they want it to actually work.

~Andrew

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 6/6] xen: Handle resumed instruction based on previous mem_event reply
  2014-07-11 15:43 ` [PATCH RFC V2 6/6] xen: Handle resumed instruction based on previous mem_event reply Razvan Cojocaru
@ 2014-07-11 18:36   ` Andrew Cooper
  2014-07-11 18:41     ` Razvan Cojocaru
  0 siblings, 1 reply; 34+ messages in thread
From: Andrew Cooper @ 2014-07-11 18:36 UTC (permalink / raw)
  To: Razvan Cojocaru, xen-devel; +Cc: mdontu, tim, JBeulich

On 11/07/14 16:43, Razvan Cojocaru wrote:
> In a scenario where a page fault that triggered a mem_event occured,
> p2m_mem_access_check() will now be able to either 1) emulate the
> current instruction, or 2) emulate it, but don't allow it to perform
> any writes.
>
> Changes since V1:
>  - Removed the 'skip' code which required computing the current
>    instruction length.
>  - Removed the set_ad_bits() code that attempted to modify the
>    'accessed' and 'dirty' bits for instructions that the emulator
>    can't handle at the moment.
>
> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
> ---
>  xen/arch/x86/domain.c          |    5 +++
>  xen/arch/x86/mm/p2m.c          |   90 ++++++++++++++++++++++++++++++++++++++++
>  xen/include/asm-x86/domain.h   |    9 ++++
>  xen/include/public/mem_event.h |   12 +++---
>  4 files changed, 111 insertions(+), 5 deletions(-)
>
> diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
> index e896210..5cd283b 100644
> --- a/xen/arch/x86/domain.c
> +++ b/xen/arch/x86/domain.c
> @@ -407,6 +407,11 @@ int vcpu_initialise(struct vcpu *v)
>  
>      v->arch.flags = TF_kernel_mode;
>  
> +    /* By default, do not emulate */
> +    v->arch.mem_event.emulate_flags = 0;
> +    v->arch.mem_event.gpa = 0;
> +    v->arch.mem_event.eip = 0;
> +
>      rc = mapcache_vcpu_init(v);
>      if ( rc )
>          return rc;
> diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
> index 13fdf78..7aff480 100644
> --- a/xen/arch/x86/mm/p2m.c
> +++ b/xen/arch/x86/mm/p2m.c
> @@ -1377,6 +1377,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
>  {
>      struct vcpu *v = current;
>      unsigned long gfn = gpa >> PAGE_SHIFT;
> +    unsigned long exit_qualification;
>      struct domain *d = v->domain;    
>      struct p2m_domain* p2m = p2m_get_hostp2m(d);
>      mfn_t mfn;
> @@ -1384,6 +1385,9 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
>      p2m_access_t p2ma;
>      mem_event_request_t *req;
>      int rc;
> +    unsigned long eip = guest_cpu_user_regs()->eip;
> +
> +    __vmread(EXIT_QUALIFICATION, &exit_qualification);

This absolutely can't be put into common code.  I presume you haven't
attempted to run a Xen patched with this on an AMD cpu ?

~Andrew

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 6/6] xen: Handle resumed instruction based on previous mem_event reply
  2014-07-11 18:36   ` Andrew Cooper
@ 2014-07-11 18:41     ` Razvan Cojocaru
  2014-07-11 19:12       ` Andrew Cooper
  0 siblings, 1 reply; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-11 18:41 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel; +Cc: mdontu, tim, JBeulich

On 07/11/2014 09:36 PM, Andrew Cooper wrote:
> On 11/07/14 16:43, Razvan Cojocaru wrote:
>> In a scenario where a page fault that triggered a mem_event occured,
>> p2m_mem_access_check() will now be able to either 1) emulate the
>> current instruction, or 2) emulate it, but don't allow it to perform
>> any writes.
>>
>> Changes since V1:
>>  - Removed the 'skip' code which required computing the current
>>    instruction length.
>>  - Removed the set_ad_bits() code that attempted to modify the
>>    'accessed' and 'dirty' bits for instructions that the emulator
>>    can't handle at the moment.
>>
>> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
>> ---
>>  xen/arch/x86/domain.c          |    5 +++
>>  xen/arch/x86/mm/p2m.c          |   90 ++++++++++++++++++++++++++++++++++++++++
>>  xen/include/asm-x86/domain.h   |    9 ++++
>>  xen/include/public/mem_event.h |   12 +++---
>>  4 files changed, 111 insertions(+), 5 deletions(-)
>>
>> diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
>> index e896210..5cd283b 100644
>> --- a/xen/arch/x86/domain.c
>> +++ b/xen/arch/x86/domain.c
>> @@ -407,6 +407,11 @@ int vcpu_initialise(struct vcpu *v)
>>  
>>      v->arch.flags = TF_kernel_mode;
>>  
>> +    /* By default, do not emulate */
>> +    v->arch.mem_event.emulate_flags = 0;
>> +    v->arch.mem_event.gpa = 0;
>> +    v->arch.mem_event.eip = 0;
>> +
>>      rc = mapcache_vcpu_init(v);
>>      if ( rc )
>>          return rc;
>> diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
>> index 13fdf78..7aff480 100644
>> --- a/xen/arch/x86/mm/p2m.c
>> +++ b/xen/arch/x86/mm/p2m.c
>> @@ -1377,6 +1377,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
>>  {
>>      struct vcpu *v = current;
>>      unsigned long gfn = gpa >> PAGE_SHIFT;
>> +    unsigned long exit_qualification;
>>      struct domain *d = v->domain;    
>>      struct p2m_domain* p2m = p2m_get_hostp2m(d);
>>      mfn_t mfn;
>> @@ -1384,6 +1385,9 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
>>      p2m_access_t p2ma;
>>      mem_event_request_t *req;
>>      int rc;
>> +    unsigned long eip = guest_cpu_user_regs()->eip;
>> +
>> +    __vmread(EXIT_QUALIFICATION, &exit_qualification);
> 
> This absolutely can't be put into common code.  I presume you haven't
> attempted to run a Xen patched with this on an AMD cpu ?

Indeed, we have not. I think that for a while there wasn't even support
for mem_even when compiling for AMD, so there wasn't really even a choice.

What would be the best way to get that value in a cross-CPU manner?


Thanks,
Razvan Cojocaru

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 6/6] xen: Handle resumed instruction based on previous mem_event reply
  2014-07-11 18:41     ` Razvan Cojocaru
@ 2014-07-11 19:12       ` Andrew Cooper
  0 siblings, 0 replies; 34+ messages in thread
From: Andrew Cooper @ 2014-07-11 19:12 UTC (permalink / raw)
  To: Razvan Cojocaru, xen-devel; +Cc: mdontu, tim, JBeulich

On 11/07/14 19:41, Razvan Cojocaru wrote:
> On 07/11/2014 09:36 PM, Andrew Cooper wrote:
>> On 11/07/14 16:43, Razvan Cojocaru wrote:
>>> In a scenario where a page fault that triggered a mem_event occured,
>>> p2m_mem_access_check() will now be able to either 1) emulate the
>>> current instruction, or 2) emulate it, but don't allow it to perform
>>> any writes.
>>>
>>> Changes since V1:
>>>  - Removed the 'skip' code which required computing the current
>>>    instruction length.
>>>  - Removed the set_ad_bits() code that attempted to modify the
>>>    'accessed' and 'dirty' bits for instructions that the emulator
>>>    can't handle at the moment.
>>>
>>> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
>>> ---
>>>  xen/arch/x86/domain.c          |    5 +++
>>>  xen/arch/x86/mm/p2m.c          |   90 ++++++++++++++++++++++++++++++++++++++++
>>>  xen/include/asm-x86/domain.h   |    9 ++++
>>>  xen/include/public/mem_event.h |   12 +++---
>>>  4 files changed, 111 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
>>> index e896210..5cd283b 100644
>>> --- a/xen/arch/x86/domain.c
>>> +++ b/xen/arch/x86/domain.c
>>> @@ -407,6 +407,11 @@ int vcpu_initialise(struct vcpu *v)
>>>  
>>>      v->arch.flags = TF_kernel_mode;
>>>  
>>> +    /* By default, do not emulate */
>>> +    v->arch.mem_event.emulate_flags = 0;
>>> +    v->arch.mem_event.gpa = 0;
>>> +    v->arch.mem_event.eip = 0;
>>> +
>>>      rc = mapcache_vcpu_init(v);
>>>      if ( rc )
>>>          return rc;
>>> diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
>>> index 13fdf78..7aff480 100644
>>> --- a/xen/arch/x86/mm/p2m.c
>>> +++ b/xen/arch/x86/mm/p2m.c
>>> @@ -1377,6 +1377,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
>>>  {
>>>      struct vcpu *v = current;
>>>      unsigned long gfn = gpa >> PAGE_SHIFT;
>>> +    unsigned long exit_qualification;
>>>      struct domain *d = v->domain;    
>>>      struct p2m_domain* p2m = p2m_get_hostp2m(d);
>>>      mfn_t mfn;
>>> @@ -1384,6 +1385,9 @@ bool_t p2m_mem_access_check(paddr_t gpa, bool_t gla_valid, unsigned long gla,
>>>      p2m_access_t p2ma;
>>>      mem_event_request_t *req;
>>>      int rc;
>>> +    unsigned long eip = guest_cpu_user_regs()->eip;
>>> +
>>> +    __vmread(EXIT_QUALIFICATION, &exit_qualification);
>> This absolutely can't be put into common code.  I presume you haven't
>> attempted to run a Xen patched with this on an AMD cpu ?
> Indeed, we have not. I think that for a while there wasn't even support
> for mem_even when compiling for AMD, so there wasn't really even a choice.
>
> What would be the best way to get that value in a cross-CPU manner?
>
>
> Thanks,
> Razvan Cojocaru

The problem is that it will die with a fatal invalid opcode exception,
as AMD cpus won't know execute the vmread instruction.

Code using __vmread() must live in arch/x86/hvm/vmx/* and have some
generic hvm way of accessing the required information.  Also bear in
mind that the exit qualification is also architecture specific, so you
will need a more general way of representing "the guest exited because
of a pagefault".

~Andrew

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 1/6] xen: Emulate with no writes
  2014-07-11 16:23 ` [PATCH RFC V2 1/6] xen: Emulate with no writes Andrew Cooper
  2014-07-11 18:00   ` Razvan Cojocaru
@ 2014-07-14  8:37   ` Razvan Cojocaru
  1 sibling, 0 replies; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-14  8:37 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel; +Cc: mdontu, tim, JBeulich

On 07/11/2014 07:23 PM, Andrew Cooper wrote:
> On 11/07/14 16:43, Razvan Cojocaru wrote:
>> +void hvm_emulate_one_full(bool_t nowrite,
>> +    unsigned int unhandleable_trapnr,
>> +    int unhandleable_errcode)
>> +{
>> +    struct hvm_emulate_ctxt ctx[1] = {};
> 
> This construct looks suspect.  What is wrong with
> 
> struct hvm_emulate_ctxt ctx = { 0 }; and using &ctx below ?

Modifying the code to address your comments, that code was written to
get around a GCC issue:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119

It's either that or writing

struct hvm_emulate_ctxt ctx = {{ 0 }};

I've changed it to the latter.


Thanks,
Razvan Cojocaru

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 5/6] xen, libxc: Request page fault injection via libxc
  2014-07-11 18:06   ` Andrew Cooper
@ 2014-07-17 11:53     ` Ian Campbell
  2014-07-17 12:07       ` Razvan Cojocaru
  2014-07-17 12:22     ` Razvan Cojocaru
  1 sibling, 1 reply; 34+ messages in thread
From: Ian Campbell @ 2014-07-17 11:53 UTC (permalink / raw)
  To: Andrew Cooper; +Cc: mdontu, tim, JBeulich, Razvan Cojocaru, xen-devel

On Fri, 2014-07-11 at 19:06 +0100, Andrew Cooper wrote:
> On 11/07/14 16:43, Razvan Cojocaru wrote:
> > Added new XEN_DOMCTL_set_pagefault_info hypercall, used by libxc's
> > new xc_domain_set_pagefault_info() function to set per-domain page
> > fault injection information. All a call does is set per-domain info,
> > and nothing actually happens until VMENTRY time, and then only if
> > all conditions are met (the guest is in user mode, the set value
> > matches CR3, and there are no other pending traps).
> > This mechanism allows bringing in swapped-out pages for inspection.
> >
> > Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
> 
> For the record, I still think this is a bad idea to be working against a
> guest OS paging algorithm, and I am uneasy about whether it is sensible
> to introduce abilities like that into the Xen API.

Indeed.

>From the tools side the new libxc function is a correct wrapping of the
underlying hypercall, so if/when the hypervisor maintainers are happy
with the interface it's fine by me, with one minor comment.

> >  
> > +int xc_domain_set_pagefault_info(xc_interface *xch,
> > +                                 uint32_t domid,
> > +                                 xen_domctl_set_pagefault_info_t *info)
> > +{
> > +    DECLARE_DOMCTL;
> > +
> > +    if (info == NULL)
> > +        return -1;
> > +
> > +    domctl.cmd = XEN_DOMCTL_set_pagefault_info;
> > +    domctl.domain = (domid_t)domid;
> > +    domctl.u.set_pagefault_info.address_space = info->address_space;
> > +    domctl.u.set_pagefault_info.virtual_address = info->virtual_address;
> > +    domctl.u.set_pagefault_info.write_access = info->write_access;

Aren't these three lines just "domctl.u.set_pagefault_info = *info;"?

Ian.

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 5/6] xen, libxc: Request page fault injection via libxc
  2014-07-17 11:53     ` Ian Campbell
@ 2014-07-17 12:07       ` Razvan Cojocaru
  0 siblings, 0 replies; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-17 12:07 UTC (permalink / raw)
  To: Ian Campbell, Andrew Cooper; +Cc: mdontu, tim, JBeulich, xen-devel

On 07/17/2014 02:53 PM, Ian Campbell wrote:
> On Fri, 2014-07-11 at 19:06 +0100, Andrew Cooper wrote:
>> On 11/07/14 16:43, Razvan Cojocaru wrote:
>>> Added new XEN_DOMCTL_set_pagefault_info hypercall, used by libxc's
>>> new xc_domain_set_pagefault_info() function to set per-domain page
>>> fault injection information. All a call does is set per-domain info,
>>> and nothing actually happens until VMENTRY time, and then only if
>>> all conditions are met (the guest is in user mode, the set value
>>> matches CR3, and there are no other pending traps).
>>> This mechanism allows bringing in swapped-out pages for inspection.
>>>
>>> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
>>
>> For the record, I still think this is a bad idea to be working against a
>> guest OS paging algorithm, and I am uneasy about whether it is sensible
>> to introduce abilities like that into the Xen API.
> 
> Indeed.
> 
> From the tools side the new libxc function is a correct wrapping of the
> underlying hypercall, so if/when the hypervisor maintainers are happy
> with the interface it's fine by me, with one minor comment.

Thanks for the review!

>>> +int xc_domain_set_pagefault_info(xc_interface *xch,
>>> +                                 uint32_t domid,
>>> +                                 xen_domctl_set_pagefault_info_t *info)
>>> +{
>>> +    DECLARE_DOMCTL;
>>> +
>>> +    if (info == NULL)
>>> +        return -1;
>>> +
>>> +    domctl.cmd = XEN_DOMCTL_set_pagefault_info;
>>> +    domctl.domain = (domid_t)domid;
>>> +    domctl.u.set_pagefault_info.address_space = info->address_space;
>>> +    domctl.u.set_pagefault_info.virtual_address = info->virtual_address;
>>> +    domctl.u.set_pagefault_info.write_access = info->write_access;
> 
> Aren't these three lines just "domctl.u.set_pagefault_info = *info;"?

Yes, they are. I'll change that to the reader-friendlier one-liner.


Thanks,
Razvan Cojocaru

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 5/6] xen, libxc: Request page fault injection via libxc
  2014-07-11 18:06   ` Andrew Cooper
  2014-07-17 11:53     ` Ian Campbell
@ 2014-07-17 12:22     ` Razvan Cojocaru
  2014-07-17 12:38       ` Andrew Cooper
  1 sibling, 1 reply; 34+ messages in thread
From: Razvan Cojocaru @ 2014-07-17 12:22 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel; +Cc: mdontu, tim, JBeulich

On 07/11/2014 09:06 PM, Andrew Cooper wrote:
> On 11/07/14 16:43, Razvan Cojocaru wrote:
>> +         && !ctxt.pending_event
>> +         && ctxt.cr3 == d->fault_info.address_space )
>> +    {
>> +        /* Cache */
>> +        uint64_t virtual_address = d->fault_info.virtual_address;
>> +        uint32_t write_access = d->fault_info.write_access;
>> +
>> +        /* Reset */
>> +        d->fault_info.address_space = 0;
>> +        d->fault_info.virtual_address = 0;
>> +        d->fault_info.write_access = 0;
>> +
>> +        hvm_inject_page_fault((write_access << 1) | PFEC_user_mode,
> 
> It is sensible in the slightest to have write_access shifted by 1 with
> respect to a real pagefault error code?

I'm not sure I follow this comment. Could you please elaborate a bit more?


Thanks,
Razvan Cojocaru

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 5/6] xen, libxc: Request page fault injection via libxc
  2014-07-17 12:22     ` Razvan Cojocaru
@ 2014-07-17 12:38       ` Andrew Cooper
  0 siblings, 0 replies; 34+ messages in thread
From: Andrew Cooper @ 2014-07-17 12:38 UTC (permalink / raw)
  To: Razvan Cojocaru, xen-devel; +Cc: mdontu, tim, JBeulich

On 17/07/14 13:22, Razvan Cojocaru wrote:
> On 07/11/2014 09:06 PM, Andrew Cooper wrote:
>> On 11/07/14 16:43, Razvan Cojocaru wrote:
>>> +         && !ctxt.pending_event
>>> +         && ctxt.cr3 == d->fault_info.address_space )
>>> +    {
>>> +        /* Cache */
>>> +        uint64_t virtual_address = d->fault_info.virtual_address;
>>> +        uint32_t write_access = d->fault_info.write_access;
>>> +
>>> +        /* Reset */
>>> +        d->fault_info.address_space = 0;
>>> +        d->fault_info.virtual_address = 0;
>>> +        d->fault_info.write_access = 0;
>>> +
>>> +        hvm_inject_page_fault((write_access << 1) | PFEC_user_mode,
>> It is sensible in the slightest to have write_access shifted by 1 with
>> respect to a real pagefault error code?
> I'm not sure I follow this comment. Could you please elaborate a bit more?
>
>
> Thanks,
> Razvan Cojocaru

You have a user supplied integer, which you shift left by 1 bit and use
as a pagefault error code.

If it is supposed to be a boolean for read/write only, then it should be
treated as such.  If it is expected to be a full error code, then it
probably shouldn't be shifted.

~Andrew

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 4/6] xen: Support for VMCALL mem_events
  2014-07-11 17:23   ` Andrew Cooper
  2014-07-11 18:15     ` Razvan Cojocaru
@ 2015-03-17 13:50     ` Razvan Cojocaru
  2015-03-17 13:58       ` Jan Beulich
  1 sibling, 1 reply; 34+ messages in thread
From: Razvan Cojocaru @ 2015-03-17 13:50 UTC (permalink / raw)
  To: Andrew Cooper, xen-devel; +Cc: mdontu, tim, JBeulich

On 07/11/2014 08:23 PM, Andrew Cooper wrote:
> On 11/07/14 16:43, Razvan Cojocaru wrote:
>> Added support for VMCALL events (the memory introspection library
>> will have the guest trigger VMCALLs, which will then be sent along
>> via the mem_event mechanism).
>>
>> Changes since V1:
>>  - Added a #define and an comment explaining a previous magic
>>    constant.
>>  - Had MEM_EVENT_REASON_VMCALL explicitly not honour
>>    HVMPME_onchangeonly.
>>
>> Signed-off-by: Razvan Cojocaru <rcojocaru@bitdefender.com>
>> ---
>>  xen/arch/x86/hvm/hvm.c          |    9 +++++++++
>>  xen/arch/x86/hvm/vmx/vmx.c      |   18 +++++++++++++++++-
>>  xen/include/asm-x86/hvm/hvm.h   |    1 +
>>  xen/include/public/hvm/params.h |    4 +++-
>>  xen/include/public/mem_event.h  |    5 +++++
>>  5 files changed, 35 insertions(+), 2 deletions(-)
>>
>> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
>> index 89a0382..6e86d7c 100644
>> --- a/xen/arch/x86/hvm/hvm.c
>> +++ b/xen/arch/x86/hvm/hvm.c
>> @@ -5564,6 +5564,7 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg)
>>              case HVM_PARAM_MEMORY_EVENT_INT3:
>>              case HVM_PARAM_MEMORY_EVENT_SINGLE_STEP:
>>              case HVM_PARAM_MEMORY_EVENT_MSR:
>> +            case HVM_PARAM_MEMORY_EVENT_VMCALL:
>>                  if ( d == current->domain )
>>                  {
>>                      rc = -EPERM;
>> @@ -6199,6 +6200,14 @@ void hvm_memory_event_msr(unsigned long msr, unsigned long value)
>>                             value, ~value, 1, msr);
>>  }
>>  
>> +void hvm_memory_event_vmcall(unsigned long rip, unsigned long eax)
>> +{
>> +    hvm_memory_event_traps(current->domain->arch.hvm_domain
>> +                             .params[HVM_PARAM_MEMORY_EVENT_VMCALL],
>> +                           MEM_EVENT_REASON_VMCALL,
>> +                           rip, ~rip, 1, eax);
>> +}
>> +
>>  int hvm_memory_event_int3(unsigned long gla) 
>>  {
>>      uint32_t pfec = PFEC_page_present;
>> diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
>> index 2caa04a..6c63225 100644
>> --- a/xen/arch/x86/hvm/vmx/vmx.c
>> +++ b/xen/arch/x86/hvm/vmx/vmx.c
>> @@ -2879,8 +2879,24 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
>>      case EXIT_REASON_VMCALL:
>>      {
>>          int rc;
>> +        unsigned long eax = regs->eax;
>> +
>>          HVMTRACE_1D(VMMCALL, regs->eax);
>> -        rc = hvm_do_hypercall(regs);
>> +
>> +        /* Don't send a VMCALL mem_event unless something
>> +         * caused the guests's eax register to contain the
>> +         * VMCALL_EVENT_REQUEST constant. */
>> +        if ( regs->eax != VMCALL_EVENT_REQUEST )
>> +        {
>> +            rc = hvm_do_hypercall(regs);
>> +        }
>> +        else
>> +        {
>> +            hvm_memory_event_vmcall(guest_cpu_user_regs()->eip, eax);
>> +            update_guest_eip();
>> +            break;
>> +        }
> 
> Thinking more about this, it is really a hypercall pretending not to
> be.  It would be better to introduce a real HVMOP_send_mem_event.
> 
> From the point of view of your in-guest agent, it would be a vmcall with
> rax = 34 (hvmop) rdi = $N (send_mem_event subop) rsi = data or pointer
> to struct containing data, depending on how exactly you implement the
> hypercall.
> 
> You would have the bonus of being able to detect errors, e.g. -ENOENT
> for "mem_event not active", get SVM support for free, and not need magic
> numbers, or vendor specific terms like "vmcall" finding their way into
> the Xen public API.

Actually, this only seems to be the case where mode == 8 in
hvm_do_hypercall() (xen/arch/x86/hvm/hvm.c):

4987                      : hvm_hypercall64_table)[eax](rdi, rsi, rdx,
r10, r8, r9);

Otherwise (and this seems to be the case with my Xen build), ebx seems
to be used for the subop:

5033         regs->_eax = hvm_hypercall32_table[eax](ebx, ecx, edx, esi,
edi, ebp);

So, ebx needs to be $N (send_mem_event subop), not rdi. Is this intended
(rdi in one case and ebx in the other)?


Thanks,
Razvan

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 4/6] xen: Support for VMCALL mem_events
  2015-03-17 13:50     ` Razvan Cojocaru
@ 2015-03-17 13:58       ` Jan Beulich
  2015-03-17 14:07         ` Razvan Cojocaru
  0 siblings, 1 reply; 34+ messages in thread
From: Jan Beulich @ 2015-03-17 13:58 UTC (permalink / raw)
  To: Razvan Cojocaru; +Cc: Andrew Cooper, mdontu, tim, xen-devel

>>> On 17.03.15 at 14:50, <rcojocaru@bitdefender.com> wrote:
> On 07/11/2014 08:23 PM, Andrew Cooper wrote:
>> From the point of view of your in-guest agent, it would be a vmcall with
>> rax = 34 (hvmop) rdi = $N (send_mem_event subop) rsi = data or pointer
>> to struct containing data, depending on how exactly you implement the
>> hypercall.
>> 
>> You would have the bonus of being able to detect errors, e.g. -ENOENT
>> for "mem_event not active", get SVM support for free, and not need magic
>> numbers, or vendor specific terms like "vmcall" finding their way into
>> the Xen public API.
> 
> Actually, this only seems to be the case where mode == 8 in
> hvm_do_hypercall() (xen/arch/x86/hvm/hvm.c):
> 
> 4987                      : hvm_hypercall64_table)[eax](rdi, rsi, rdx,
> r10, r8, r9);
> 
> Otherwise (and this seems to be the case with my Xen build), ebx seems
> to be used for the subop:
> 
> 5033         regs->_eax = hvm_hypercall32_table[eax](ebx, ecx, edx, esi,
> edi, ebp);
> 
> So, ebx needs to be $N (send_mem_event subop), not rdi. Is this intended
> (rdi in one case and ebx in the other)?

Of course - the ABIs (and hence the use of registers for certain
specific purposes) of ix86 and x86-64 are different. Since there
are hypercall wrappers in both the kernel and the tool stack, you
shouldn't actually need to care about this on the caller side. And
the handler side doesn't deal with specific registers anyway
(outside of hvm_do_hypercall() that is).

Jan

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 4/6] xen: Support for VMCALL mem_events
  2015-03-17 13:58       ` Jan Beulich
@ 2015-03-17 14:07         ` Razvan Cojocaru
  2015-03-17 14:20           ` Jan Beulich
  0 siblings, 1 reply; 34+ messages in thread
From: Razvan Cojocaru @ 2015-03-17 14:07 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Andrew Cooper, mdontu, tim, xen-devel

On 03/17/2015 03:58 PM, Jan Beulich wrote:
>>>> On 17.03.15 at 14:50, <rcojocaru@bitdefender.com> wrote:
>> On 07/11/2014 08:23 PM, Andrew Cooper wrote:
>>> From the point of view of your in-guest agent, it would be a vmcall with
>>> rax = 34 (hvmop) rdi = $N (send_mem_event subop) rsi = data or pointer
>>> to struct containing data, depending on how exactly you implement the
>>> hypercall.
>>>
>>> You would have the bonus of being able to detect errors, e.g. -ENOENT
>>> for "mem_event not active", get SVM support for free, and not need magic
>>> numbers, or vendor specific terms like "vmcall" finding their way into
>>> the Xen public API.
>>
>> Actually, this only seems to be the case where mode == 8 in
>> hvm_do_hypercall() (xen/arch/x86/hvm/hvm.c):
>>
>> 4987                      : hvm_hypercall64_table)[eax](rdi, rsi, rdx,
>> r10, r8, r9);
>>
>> Otherwise (and this seems to be the case with my Xen build), ebx seems
>> to be used for the subop:
>>
>> 5033         regs->_eax = hvm_hypercall32_table[eax](ebx, ecx, edx, esi,
>> edi, ebp);
>>
>> So, ebx needs to be $N (send_mem_event subop), not rdi. Is this intended
>> (rdi in one case and ebx in the other)?
> 
> Of course - the ABIs (and hence the use of registers for certain
> specific purposes) of ix86 and x86-64 are different. Since there
> are hypercall wrappers in both the kernel and the tool stack, you
> shouldn't actually need to care about this on the caller side. And
> the handler side doesn't deal with specific registers anyway
> (outside of hvm_do_hypercall() that is).

Yes, but Andrew's idea (which I think is very neat) is that instead of
the trickery I used to do in the original patch (create a specific
VMCALL vm_event and compare eax to a magic constant on VMCALL-based
VMEXITS, to figure out if all I wanted to do was send out the event),
that I should instead have the guest set up rax, rdi and rsi and execute
vmcall, which would then be translated to a real hypercall that sends
out a vm_event.

In this case, the (HVM) guest does need to concern itself with what
registers it should set up for that purpose. I suppose a workaround
could be to write the subop in both ebx and rdi, though without any
testing I don't know at this point what, if anything, might be broken
that way.


Thanks,
Razvan

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 4/6] xen: Support for VMCALL mem_events
  2015-03-17 14:07         ` Razvan Cojocaru
@ 2015-03-17 14:20           ` Jan Beulich
  2015-03-17 14:33             ` Razvan Cojocaru
  0 siblings, 1 reply; 34+ messages in thread
From: Jan Beulich @ 2015-03-17 14:20 UTC (permalink / raw)
  To: Razvan Cojocaru; +Cc: Andrew Cooper, mdontu, tim, xen-devel

>>> On 17.03.15 at 15:07, <rcojocaru@bitdefender.com> wrote:
> Yes, but Andrew's idea (which I think is very neat) is that instead of
> the trickery I used to do in the original patch (create a specific
> VMCALL vm_event and compare eax to a magic constant on VMCALL-based
> VMEXITS, to figure out if all I wanted to do was send out the event),
> that I should instead have the guest set up rax, rdi and rsi and execute
> vmcall, which would then be translated to a real hypercall that sends
> out a vm_event.

If you think about a bare HVM guest OS (i.e. without any PV
drivers), then of course you should provide such hypercall
wrappers for code to use instead of open coding it in potentially
many places.

> In this case, the (HVM) guest does need to concern itself with what
> registers it should set up for that purpose. I suppose a workaround
> could be to write the subop in both ebx and rdi, though without any
> testing I don't know at this point what, if anything, might be broken
> that way.

Guest code ought to know what mode it runs in. And introspection
code (in case this is about injection of such code) ought to also
know which mode the monitored guest is in.

Jan

^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH RFC V2 4/6] xen: Support for VMCALL mem_events
  2015-03-17 14:20           ` Jan Beulich
@ 2015-03-17 14:33             ` Razvan Cojocaru
  0 siblings, 0 replies; 34+ messages in thread
From: Razvan Cojocaru @ 2015-03-17 14:33 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Andrew Cooper, mdontu, tim, xen-devel

On 03/17/2015 04:20 PM, Jan Beulich wrote:
>>>> On 17.03.15 at 15:07, <rcojocaru@bitdefender.com> wrote:
>> Yes, but Andrew's idea (which I think is very neat) is that instead of
>> the trickery I used to do in the original patch (create a specific
>> VMCALL vm_event and compare eax to a magic constant on VMCALL-based
>> VMEXITS, to figure out if all I wanted to do was send out the event),
>> that I should instead have the guest set up rax, rdi and rsi and execute
>> vmcall, which would then be translated to a real hypercall that sends
>> out a vm_event.
> 
> If you think about a bare HVM guest OS (i.e. without any PV
> drivers), then of course you should provide such hypercall
> wrappers for code to use instead of open coding it in potentially
> many places.
> 
>> In this case, the (HVM) guest does need to concern itself with what
>> registers it should set up for that purpose. I suppose a workaround
>> could be to write the subop in both ebx and rdi, though without any
>> testing I don't know at this point what, if anything, might be broken
>> that way.
> 
> Guest code ought to know what mode it runs in. And introspection
> code (in case this is about injection of such code) ought to also
> know which mode the monitored guest is in.

Yes, we'll try to handle this, I was mainly asking because based on
Andrew's suggestion (which only mentioned rdi, not ebx) I wanted to make
sure that this is not someting that people might prefer to change at Xen
source code level.


Thanks for the clarification,
Razvan

^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2015-03-17 14:33 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-11 15:43 [PATCH RFC V2 1/6] xen: Emulate with no writes Razvan Cojocaru
2014-07-11 15:43 ` [PATCH RFC V2 2/6] xen: Optimize introspection access to guest state Razvan Cojocaru
2014-07-11 16:54   ` Andrew Cooper
2014-07-11 16:57     ` Andrew Cooper
2014-07-11 18:03     ` Razvan Cojocaru
2014-07-11 18:09       ` Andrew Cooper
2014-07-11 15:43 ` [PATCH RFC V2 3/6] xen: Force-enable relevant MSR events; optimize the number of sent MSR events Razvan Cojocaru
2014-07-11 17:03   ` Andrew Cooper
2014-07-11 18:09     ` Razvan Cojocaru
     [not found]       ` <CAGU+ausrcu=L7Kf30gZJXRnnxrKe7EMYXTGByOY4agwoK0nXeA@mail.gmail.com>
2014-07-11 18:18         ` Aravindh Puthiyaparambil (aravindp)
2014-07-11 18:19       ` Andrew Cooper
2014-07-11 18:22         ` Razvan Cojocaru
2014-07-11 18:29           ` Andrew Cooper
2014-07-11 15:43 ` [PATCH RFC V2 4/6] xen: Support for VMCALL mem_events Razvan Cojocaru
2014-07-11 17:23   ` Andrew Cooper
2014-07-11 18:15     ` Razvan Cojocaru
2015-03-17 13:50     ` Razvan Cojocaru
2015-03-17 13:58       ` Jan Beulich
2015-03-17 14:07         ` Razvan Cojocaru
2015-03-17 14:20           ` Jan Beulich
2015-03-17 14:33             ` Razvan Cojocaru
2014-07-11 15:43 ` [PATCH RFC V2 5/6] xen, libxc: Request page fault injection via libxc Razvan Cojocaru
2014-07-11 18:06   ` Andrew Cooper
2014-07-17 11:53     ` Ian Campbell
2014-07-17 12:07       ` Razvan Cojocaru
2014-07-17 12:22     ` Razvan Cojocaru
2014-07-17 12:38       ` Andrew Cooper
2014-07-11 15:43 ` [PATCH RFC V2 6/6] xen: Handle resumed instruction based on previous mem_event reply Razvan Cojocaru
2014-07-11 18:36   ` Andrew Cooper
2014-07-11 18:41     ` Razvan Cojocaru
2014-07-11 19:12       ` Andrew Cooper
2014-07-11 16:23 ` [PATCH RFC V2 1/6] xen: Emulate with no writes Andrew Cooper
2014-07-11 18:00   ` Razvan Cojocaru
2014-07-14  8:37   ` Razvan Cojocaru

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.