All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] x86/monitor: add support for descriptor access events
@ 2017-03-10 15:50 Vlad Ioan Topan
  2017-03-10 19:41 ` Tamas K Lengyel
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Vlad Ioan Topan @ 2017-03-10 15:50 UTC (permalink / raw)
  To: xen-devel
  Cc: Kevin Tian, Tamas K Lengyel, Wei Liu, Suravee Suthikulpanit,
	Razvan Cojocaru, Jun Nakajima, Andrew Cooper, Ian Jackson,
	Jan Beulich, Vlad Ioan Topan, Boris Ostrovsky

Adds monitor support for descriptor access events (reads & writes of
IDTR/GDTR/LDTR/TR) for the x86 architecture (VMX and SVM).

Signed-off-by: Vlad Ioan Topan <itopan@bitdefender.com>
---
 tools/libxc/include/xenctrl.h       |  2 ++
 tools/libxc/xc_monitor.c            | 14 +++++++++++
 tools/tests/xen-access/xen-access.c | 29 ++++++++++++++++++++-
 xen/arch/x86/hvm/hvm.c              | 35 ++++++++++++++++++++++++++
 xen/arch/x86/hvm/monitor.c          | 16 ++++++++++++
 xen/arch/x86/hvm/svm/svm.c          | 50 +++++++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/vmx/vmx.c          | 45 +++++++++++++++++++++++++++++++++
 xen/arch/x86/monitor.c              | 18 +++++++++++++
 xen/arch/x86/vm_event.c             |  6 +++++
 xen/include/asm-x86/domain.h        |  1 +
 xen/include/asm-x86/hvm/hvm.h       |  2 ++
 xen/include/asm-x86/hvm/monitor.h   |  3 +++
 xen/include/asm-x86/hvm/support.h   |  2 ++
 xen/include/asm-x86/monitor.h       |  1 +
 xen/include/public/domctl.h         |  1 +
 xen/include/public/vm_event.h       | 21 ++++++++++++++++
 16 files changed, 245 insertions(+), 1 deletion(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index a48981a..2de6c61 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -1984,6 +1984,8 @@ int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id, uint32_t msr,
 int xc_monitor_singlestep(xc_interface *xch, domid_t domain_id, bool enable);
 int xc_monitor_software_breakpoint(xc_interface *xch, domid_t domain_id,
                                    bool enable);
+int xc_monitor_descriptor_access(xc_interface *xch, domid_t domain_id,
+                                 bool enable);
 int xc_monitor_guest_request(xc_interface *xch, domid_t domain_id,
                              bool enable, bool sync);
 int xc_monitor_debug_exceptions(xc_interface *xch, domid_t domain_id,
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index 15a7c32..f99b6e3 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -129,6 +129,20 @@ int xc_monitor_singlestep(xc_interface *xch, domid_t domain_id,
     return do_domctl(xch, &domctl);
 }
 
+int xc_monitor_descriptor_access(xc_interface *xch, domid_t domain_id,
+                                 bool enable)
+{
+    DECLARE_DOMCTL;
+
+    domctl.cmd = XEN_DOMCTL_monitor_op;
+    domctl.domain = domain_id;
+    domctl.u.monitor_op.op = enable ? XEN_DOMCTL_MONITOR_OP_ENABLE
+                                    : XEN_DOMCTL_MONITOR_OP_DISABLE;
+    domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS;
+
+    return do_domctl(xch, &domctl);
+}
+
 int xc_monitor_guest_request(xc_interface *xch, domid_t domain_id, bool enable,
                              bool sync)
 {
diff --git a/tools/tests/xen-access/xen-access.c b/tools/tests/xen-access/xen-access.c
index 9d4f957..c567cc0 100644
--- a/tools/tests/xen-access/xen-access.c
+++ b/tools/tests/xen-access/xen-access.c
@@ -337,7 +337,7 @@ void usage(char* progname)
 {
     fprintf(stderr, "Usage: %s [-m] <domain_id> write|exec", progname);
 #if defined(__i386__) || defined(__x86_64__)
-            fprintf(stderr, "|breakpoint|altp2m_write|altp2m_exec|debug|cpuid");
+            fprintf(stderr, "|breakpoint|altp2m_write|altp2m_exec|debug|cpuid|desc_access");
 #elif defined(__arm__) || defined(__aarch64__)
             fprintf(stderr, "|privcall");
 #endif
@@ -368,6 +368,7 @@ int main(int argc, char *argv[])
     int altp2m = 0;
     int debug = 0;
     int cpuid = 0;
+    int desc_access = 0;
     uint16_t altp2m_view_id = 0;
 
     char* progname = argv[0];
@@ -434,6 +435,10 @@ int main(int argc, char *argv[])
     {
         cpuid = 1;
     }
+    else if ( !strcmp(argv[0], "desc_access") )
+    {
+        desc_access = 1;
+    }
 #elif defined(__arm__) || defined(__aarch64__)
     else if ( !strcmp(argv[0], "privcall") )
     {
@@ -570,6 +575,16 @@ int main(int argc, char *argv[])
             goto exit;
         }
     }
+    
+    if ( desc_access )
+    {
+        rc = xc_monitor_descriptor_access(xch, domain_id, 1);
+        if ( rc < 0 )
+        {
+            ERROR("Error %d setting descriptor access listener with vm_event\n", rc);
+            goto exit;
+        }
+    }
 
     if ( privcall )
     {
@@ -595,6 +610,8 @@ int main(int argc, char *argv[])
                 rc = xc_monitor_debug_exceptions(xch, domain_id, 0, 0);
             if ( cpuid )
                 rc = xc_monitor_cpuid(xch, domain_id, 0);
+            if ( desc_access )
+                rc = xc_monitor_descriptor_access(xch, domain_id, 0);
 
             if ( privcall )
                 rc = xc_monitor_privileged_call(xch, domain_id, 0);
@@ -779,6 +796,16 @@ int main(int argc, char *argv[])
                 rsp.data = req.data;
                 rsp.data.regs.x86.rip += req.u.cpuid.insn_length;
                 break;
+            case VM_EVENT_REASON_DESCRIPTOR_ACCESS:
+                printf("Descriptor access: rip=%016"PRIx64", vcpu %d: "\
+                       "VMExit info=0x%"PRIx64", descriptor=%d, is write=%d\n",
+                       req.data.regs.x86.rip,
+                       req.vcpu_id,
+                       req.u.desc_access.vmexit.info,
+                       req.u.desc_access.descriptor,
+                       req.u.desc_access.is_write);
+                rsp.flags |= VM_EVENT_FLAG_EMULATE;
+                break;
             default:
                 fprintf(stderr, "UNKNOWN REASON CODE %d\n", req.reason);
             }
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index ccfae4f..cfe5aa2 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -3645,6 +3645,41 @@ gp_fault:
     return X86EMUL_EXCEPTION;
 }
 
+int hvm_descriptor_access_intercept(uint64_t exit_info, uint64_t exit_qualification, 
+                                    uint8_t descriptor, bool_t is_write)
+{
+    struct vcpu *v = current;
+    struct domain *d = v->domain;
+    struct hvm_emulate_ctxt ctxt = {};
+    int rc;
+
+    if ( d->arch.monitor.descriptor_access_enabled )
+    {
+        ASSERT(v->arch.vm_event);
+        hvm_monitor_descriptor_access(exit_info, exit_qualification, descriptor, is_write);
+    }
+    else
+    {
+        hvm_emulate_init_once(&ctxt, NULL, guest_cpu_user_regs());
+        rc = hvm_emulate_one(&ctxt);
+        switch ( rc )
+        {
+        case X86EMUL_UNHANDLEABLE:
+            hvm_inject_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC);
+            break;
+        case X86EMUL_EXCEPTION:
+            if ( ctxt.ctxt.event_pending )
+                hvm_inject_event(&ctxt.ctxt.event);
+            /* fall through */
+        default:
+            hvm_emulate_writeback(&ctxt);
+            break;
+        }
+    }
+
+    return X86EMUL_OKAY;
+}
+
 static bool is_cross_vendor(const struct x86_emulate_state *state,
                             const struct x86_emulate_ctxt *ctxt)
 {
diff --git a/xen/arch/x86/hvm/monitor.c b/xen/arch/x86/hvm/monitor.c
index f5cd245..719fd8d 100644
--- a/xen/arch/x86/hvm/monitor.c
+++ b/xen/arch/x86/hvm/monitor.c
@@ -72,6 +72,22 @@ void hvm_monitor_msr(unsigned int msr, uint64_t value)
     }
 }
 
+void hvm_monitor_descriptor_access(uint64_t exit_info,
+                                   uint64_t exit_qualification, 
+                                   uint8_t descriptor, bool_t is_write)
+{
+    struct vcpu *curr = current;
+    vm_event_request_t req = {
+        .reason = VM_EVENT_REASON_DESCRIPTOR_ACCESS,
+        .u.desc_access.vmexit.info = exit_info,
+        .u.desc_access.exit_qualification = exit_qualification,
+        .u.desc_access.descriptor = descriptor,
+        .u.desc_access.is_write = is_write,
+    };
+
+    monitor_traps(curr, 1, &req);
+}
+
 static inline unsigned long gfn_of_rip(unsigned long rip)
 {
     struct vcpu *curr = current;
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 43241d6..63fa253 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -856,6 +856,23 @@ static void svm_set_rdtsc_exiting(struct vcpu *v, bool_t enable)
     vmcb_set_general2_intercepts(vmcb, general2_intercepts);
 }
 
+static void svm_set_descriptor_access_exiting(struct vcpu *v, bool_t enable)
+{
+    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
+    u32 general1_intercepts = vmcb_get_general1_intercepts(vmcb);
+    u32 mask = GENERAL1_INTERCEPT_IDTR_READ | GENERAL1_INTERCEPT_GDTR_READ \
+            | GENERAL1_INTERCEPT_LDTR_READ | GENERAL1_INTERCEPT_TR_READ \
+            | GENERAL1_INTERCEPT_IDTR_WRITE | GENERAL1_INTERCEPT_GDTR_WRITE \
+            | GENERAL1_INTERCEPT_LDTR_WRITE | GENERAL1_INTERCEPT_TR_WRITE;
+
+    if ( enable )
+        general1_intercepts |= mask;
+    else
+        general1_intercepts &= ~mask;
+
+    vmcb_set_general1_intercepts(vmcb, general1_intercepts);
+}
+
 static unsigned int svm_get_insn_bytes(struct vcpu *v, uint8_t *buf)
 {
     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
@@ -2224,6 +2241,7 @@ static struct hvm_function_table __initdata svm_function_table = {
     .msr_read_intercept   = svm_msr_read_intercept,
     .msr_write_intercept  = svm_msr_write_intercept,
     .set_rdtsc_exiting    = svm_set_rdtsc_exiting,
+    .set_descriptor_access_exiting = svm_set_descriptor_access_exiting,
     .get_insn_bytes       = svm_get_insn_bytes,
 
     .nhvm_vcpu_initialise = nsvm_vcpu_initialise,
@@ -2642,6 +2660,38 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
     case VMEXIT_PAUSE:
         svm_vmexit_do_pause(regs);
         break;
+    
+    case VMEXIT_IDTR_READ:
+        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 0);
+        break;
+
+    case VMEXIT_GDTR_READ:
+        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 0);
+        break;
+
+    case VMEXIT_LDTR_READ:
+        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 0);
+        break;
+
+    case VMEXIT_TR_READ:
+        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 0);
+        break;
+
+    case VMEXIT_IDTR_WRITE:
+        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 1);
+        break;
+
+    case VMEXIT_GDTR_WRITE:
+        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 1);
+        break;
+
+    case VMEXIT_LDTR_WRITE:
+        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 1);
+        break;
+
+    case VMEXIT_TR_WRITE:
+        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 1);
+        break;
 
     default:
     unexpected_exit_type:
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 894d7d4..2b2d193 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1343,6 +1343,20 @@ static void vmx_set_rdtsc_exiting(struct vcpu *v, bool_t enable)
     vmx_vmcs_exit(v);
 }
 
+static void vmx_set_descriptor_access_exiting(struct vcpu *v, bool_t enable)
+{
+    if ( enable )
+        v->arch.hvm_vmx.secondary_exec_control |=
+            SECONDARY_EXEC_DESCRIPTOR_TABLE_EXITING;
+    else
+        v->arch.hvm_vmx.secondary_exec_control &=
+            ~SECONDARY_EXEC_DESCRIPTOR_TABLE_EXITING;
+
+    vmx_vmcs_enter(v);
+    vmx_update_secondary_exec_control(v);
+    vmx_vmcs_exit(v);
+}
+
 static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page)
 {
     char *p;
@@ -2232,6 +2246,7 @@ static struct hvm_function_table __initdata vmx_function_table = {
     .handle_cd            = vmx_handle_cd,
     .set_info_guest       = vmx_set_info_guest,
     .set_rdtsc_exiting    = vmx_set_rdtsc_exiting,
+    .set_descriptor_access_exiting = vmx_set_descriptor_access_exiting,
     .nhvm_vcpu_initialise = nvmx_vcpu_initialise,
     .nhvm_vcpu_destroy    = nvmx_vcpu_destroy,
     .nhvm_vcpu_reset      = nvmx_vcpu_reset,
@@ -3369,6 +3384,33 @@ static void vmx_handle_xrstors(void)
     domain_crash(current->domain);
 }
 
+static void vmx_handle_descriptor_access(uint32_t exit_reason)
+{
+    uint8_t instr_id;
+    uint64_t instr_info;
+    uint64_t exit_qualification;
+    uint8_t descriptor = VM_EVENT_DESC_INVALID;
+
+    __vmread(EXIT_QUALIFICATION, &exit_qualification);
+    __vmread(VMX_INSTRUCTION_INFO, &instr_info);
+
+    instr_id = (instr_info >> 28) & 3; /* Instruction identity: bits 29:28 */
+
+    if ( exit_reason == EXIT_REASON_ACCESS_GDTR_OR_IDTR )
+        if ( instr_id & 1 )
+            descriptor = VM_EVENT_DESC_IDTR;
+        else
+            descriptor = VM_EVENT_DESC_GDTR;
+    else
+        if ( instr_id & 1 )
+            descriptor = VM_EVENT_DESC_TR;
+        else
+            descriptor = VM_EVENT_DESC_LDTR;
+
+    hvm_descriptor_access_intercept(instr_info, exit_qualification, descriptor,
+                                    instr_id >= 2);
+}
+
 static int vmx_handle_apic_write(void)
 {
     unsigned long exit_qualification;
@@ -3981,6 +4023,9 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
 
     case EXIT_REASON_ACCESS_GDTR_OR_IDTR:
     case EXIT_REASON_ACCESS_LDTR_OR_TR:
+        vmx_handle_descriptor_access(exit_reason);
+        break;
+
     case EXIT_REASON_VMX_PREEMPTION_TIMER_EXPIRED:
     case EXIT_REASON_INVPCID:
     /* fall through */
diff --git a/xen/arch/x86/monitor.c b/xen/arch/x86/monitor.c
index 5f60743..bec63ee 100644
--- a/xen/arch/x86/monitor.c
+++ b/xen/arch/x86/monitor.c
@@ -211,6 +211,24 @@ int arch_monitor_domctl_event(struct domain *d,
         break;
     }
 
+    case XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS:
+    {
+        bool_t old_status = ad->monitor.descriptor_access_enabled;
+        struct vcpu *v;
+
+        if ( unlikely(old_status == requested_status) )
+            return -EEXIST;
+
+        domain_pause(d);
+        ad->monitor.descriptor_access_enabled = requested_status;
+    
+        for_each_vcpu ( d, v )
+            hvm_funcs.set_descriptor_access_exiting(v, requested_status);
+
+        domain_unpause(d);
+        break;
+    }
+
     case XEN_DOMCTL_MONITOR_EVENT_SOFTWARE_BREAKPOINT:
     {
         bool_t old_status = ad->monitor.software_breakpoint_enabled;
diff --git a/xen/arch/x86/vm_event.c b/xen/arch/x86/vm_event.c
index a7ce6ca..502ccc2 100644
--- a/xen/arch/x86/vm_event.c
+++ b/xen/arch/x86/vm_event.c
@@ -229,6 +229,12 @@ void vm_event_emulate_check(struct vcpu *v, vm_event_response_t *rsp)
         }
         break;
 
+    case VM_EVENT_REASON_DESCRIPTOR_ACCESS:
+        if ( rsp->flags & VM_EVENT_FLAG_SET_EMUL_READ_DATA )
+            v->arch.vm_event->emul.read = rsp->data.emul.read;
+        v->arch.vm_event->emulate_flags = rsp->flags;
+        break;
+
     default:
         break;
     };
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index ff5267f..b1410a1 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -405,6 +405,7 @@ struct arch_domain
         unsigned int debug_exception_enabled     : 1;
         unsigned int debug_exception_sync        : 1;
         unsigned int cpuid_enabled               : 1;
+        unsigned int descriptor_access_enabled   : 1;
         struct monitor_msr_bitmap *msr_bitmap;
     } monitor;
 
diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h
index eccc25e..ceec7fa 100644
--- a/xen/include/asm-x86/hvm/hvm.h
+++ b/xen/include/asm-x86/hvm/hvm.h
@@ -174,6 +174,7 @@ struct hvm_function_table {
     void (*handle_cd)(struct vcpu *v, unsigned long value);
     void (*set_info_guest)(struct vcpu *v);
     void (*set_rdtsc_exiting)(struct vcpu *v, bool_t);
+    void (*set_descriptor_access_exiting)(struct vcpu *v, bool_t);
 
     /* Nested HVM */
     int (*nhvm_vcpu_initialise)(struct vcpu *v);
@@ -444,6 +445,7 @@ int hvm_event_needs_reinjection(uint8_t type, uint8_t vector);
 uint8_t hvm_combine_hw_exceptions(uint8_t vec1, uint8_t vec2);
 
 void hvm_set_rdtsc_exiting(struct domain *d, bool_t enable);
+void hvm_set_descriptor_access_exiting(struct domain *d, bool_t enable);
 
 static inline int hvm_cpu_up(void)
 {
diff --git a/xen/include/asm-x86/hvm/monitor.h b/xen/include/asm-x86/hvm/monitor.h
index 85ca678..35f8b7a 100644
--- a/xen/include/asm-x86/hvm/monitor.h
+++ b/xen/include/asm-x86/hvm/monitor.h
@@ -38,6 +38,9 @@ bool_t hvm_monitor_cr(unsigned int index, unsigned long value,
 #define hvm_monitor_crX(cr, new, old) \
                         hvm_monitor_cr(VM_EVENT_X86_##cr, new, old)
 void hvm_monitor_msr(unsigned int msr, uint64_t value);
+void hvm_monitor_descriptor_access(uint64_t exit_info,
+                                   uint64_t exit_qualification, 
+                                   uint8_t descriptor, bool_t is_write);
 int hvm_monitor_debug(unsigned long rip, enum hvm_monitor_debug_type type,
                       unsigned long trap_type, unsigned long insn_length);
 int hvm_monitor_cpuid(unsigned long insn_length, unsigned int leaf,
diff --git a/xen/include/asm-x86/hvm/support.h b/xen/include/asm-x86/hvm/support.h
index 632eb90..900bfe6 100644
--- a/xen/include/asm-x86/hvm/support.h
+++ b/xen/include/asm-x86/hvm/support.h
@@ -128,6 +128,8 @@ int hvm_set_efer(uint64_t value);
 int hvm_set_cr0(unsigned long value, bool_t may_defer);
 int hvm_set_cr3(unsigned long value, bool_t may_defer);
 int hvm_set_cr4(unsigned long value, bool_t may_defer);
+int hvm_descriptor_access_intercept(uint64_t exit_info, uint64_t exit_qualification, 
+                                    uint8_t descriptor, bool_t is_write);
 int hvm_mov_to_cr(unsigned int cr, unsigned int gpr);
 int hvm_mov_from_cr(unsigned int cr, unsigned int gpr);
 void hvm_ud_intercept(struct cpu_user_regs *);
diff --git a/xen/include/asm-x86/monitor.h b/xen/include/asm-x86/monitor.h
index e409373..5eeab3a 100644
--- a/xen/include/asm-x86/monitor.h
+++ b/xen/include/asm-x86/monitor.h
@@ -77,6 +77,7 @@ static inline uint32_t arch_monitor_get_capabilities(struct domain *d)
                    (1U << XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST) |
                    (1U << XEN_DOMCTL_MONITOR_EVENT_DEBUG_EXCEPTION) |
                    (1U << XEN_DOMCTL_MONITOR_EVENT_CPUID) |
+                   (1U << XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS) |
                    (1U << XEN_DOMCTL_MONITOR_EVENT_INTERRUPT);
 
     /* Since we know this is on VMX, we can just call the hvm func */
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 85cbb7c..8ffb38d 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -1087,6 +1087,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cmt_op_t);
 #define XEN_DOMCTL_MONITOR_EVENT_CPUID                 6
 #define XEN_DOMCTL_MONITOR_EVENT_PRIVILEGED_CALL       7
 #define XEN_DOMCTL_MONITOR_EVENT_INTERRUPT             8
+#define XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS           9
 
 struct xen_domctl_monitor_op {
     uint32_t op; /* XEN_DOMCTL_MONITOR_OP_* */
diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h
index b7487a1..7b18ee4 100644
--- a/xen/include/public/vm_event.h
+++ b/xen/include/public/vm_event.h
@@ -146,6 +146,8 @@
 #define VM_EVENT_REASON_PRIVILEGED_CALL         11
 /* An interrupt has been delivered. */
 #define VM_EVENT_REASON_INTERRUPT               12
+/* A descriptor table register was accessed. */
+#define VM_EVENT_REASON_DESCRIPTOR_ACCESS       13
 
 /* Supported values for the vm_event_write_ctrlreg index. */
 #define VM_EVENT_X86_CR0    0
@@ -259,6 +261,24 @@ struct vm_event_mov_to_msr {
     uint64_t value;
 };
 
+#define VM_EVENT_DESC_INVALID        0
+#define VM_EVENT_DESC_IDTR           1
+#define VM_EVENT_DESC_GDTR           2
+#define VM_EVENT_DESC_LDTR           3
+#define VM_EVENT_DESC_TR             4
+
+struct vm_event_desc_access {
+    union {
+        uint32_t vmx_instr_info;    /* VMX: VMCS Instruction-Information Field */
+        uint64_t svm_exitinfo;      /* SVM: VMCB EXITINFO Field */
+        uint64_t info;
+    } vmexit;
+    uint64_t exit_qualification;    /* VMX only: VMCS Exit Qualification Field */
+    uint8_t descriptor;             /* VM_EVENT_DESC_* */
+    uint8_t is_write;
+    uint8_t _pad[6];
+};
+
 struct vm_event_cpuid {
     uint32_t insn_length;
     uint32_t leaf;
@@ -313,6 +333,7 @@ typedef struct vm_event_st {
         struct vm_event_mem_access            mem_access;
         struct vm_event_write_ctrlreg         write_ctrlreg;
         struct vm_event_mov_to_msr            mov_to_msr;
+        struct vm_event_desc_access           desc_access;
         struct vm_event_singlestep            singlestep;
         struct vm_event_debug                 software_breakpoint;
         struct vm_event_debug                 debug_exception;
-- 
2.7.4


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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-10 15:50 [PATCH] x86/monitor: add support for descriptor access events Vlad Ioan Topan
@ 2017-03-10 19:41 ` Tamas K Lengyel
  2017-03-14 12:07   ` Vlad-Ioan TOPAN
  2017-03-13 21:24 ` Boris Ostrovsky
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Tamas K Lengyel @ 2017-03-10 19:41 UTC (permalink / raw)
  To: Vlad Ioan Topan
  Cc: Kevin Tian, Wei Liu, Suravee Suthikulpanit, Razvan Cojocaru,
	Jun Nakajima, Andrew Cooper, Ian Jackson, Jan Beulich, Xen-devel,
	Boris Ostrovsky

On Fri, Mar 10, 2017 at 8:50 AM, Vlad Ioan Topan <itopan@bitdefender.com> wrote:
> Adds monitor support for descriptor access events (reads & writes of
> IDTR/GDTR/LDTR/TR) for the x86 architecture (VMX and SVM).
>
> Signed-off-by: Vlad Ioan Topan <itopan@bitdefender.com>
> ---
>  tools/libxc/include/xenctrl.h       |  2 ++
>  tools/libxc/xc_monitor.c            | 14 +++++++++++
>  tools/tests/xen-access/xen-access.c | 29 ++++++++++++++++++++-
>  xen/arch/x86/hvm/hvm.c              | 35 ++++++++++++++++++++++++++
>  xen/arch/x86/hvm/monitor.c          | 16 ++++++++++++
>  xen/arch/x86/hvm/svm/svm.c          | 50 +++++++++++++++++++++++++++++++++++++
>  xen/arch/x86/hvm/vmx/vmx.c          | 45 +++++++++++++++++++++++++++++++++
>  xen/arch/x86/monitor.c              | 18 +++++++++++++
>  xen/arch/x86/vm_event.c             |  6 +++++
>  xen/include/asm-x86/domain.h        |  1 +
>  xen/include/asm-x86/hvm/hvm.h       |  2 ++
>  xen/include/asm-x86/hvm/monitor.h   |  3 +++
>  xen/include/asm-x86/hvm/support.h   |  2 ++
>  xen/include/asm-x86/monitor.h       |  1 +
>  xen/include/public/domctl.h         |  1 +
>  xen/include/public/vm_event.h       | 21 ++++++++++++++++
>  16 files changed, 245 insertions(+), 1 deletion(-)
>
> diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
> index a48981a..2de6c61 100644
> --- a/tools/libxc/include/xenctrl.h
> +++ b/tools/libxc/include/xenctrl.h
> @@ -1984,6 +1984,8 @@ int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id, uint32_t msr,
>  int xc_monitor_singlestep(xc_interface *xch, domid_t domain_id, bool enable);
>  int xc_monitor_software_breakpoint(xc_interface *xch, domid_t domain_id,
>                                     bool enable);
> +int xc_monitor_descriptor_access(xc_interface *xch, domid_t domain_id,
> +                                 bool enable);
>  int xc_monitor_guest_request(xc_interface *xch, domid_t domain_id,
>                               bool enable, bool sync);
>  int xc_monitor_debug_exceptions(xc_interface *xch, domid_t domain_id,
> diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
> index 15a7c32..f99b6e3 100644
> --- a/tools/libxc/xc_monitor.c
> +++ b/tools/libxc/xc_monitor.c
> @@ -129,6 +129,20 @@ int xc_monitor_singlestep(xc_interface *xch, domid_t domain_id,
>      return do_domctl(xch, &domctl);
>  }
>
> +int xc_monitor_descriptor_access(xc_interface *xch, domid_t domain_id,
> +                                 bool enable)
> +{
> +    DECLARE_DOMCTL;
> +
> +    domctl.cmd = XEN_DOMCTL_monitor_op;
> +    domctl.domain = domain_id;
> +    domctl.u.monitor_op.op = enable ? XEN_DOMCTL_MONITOR_OP_ENABLE
> +                                    : XEN_DOMCTL_MONITOR_OP_DISABLE;
> +    domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS;
> +
> +    return do_domctl(xch, &domctl);
> +}
> +
>  int xc_monitor_guest_request(xc_interface *xch, domid_t domain_id, bool enable,
>                               bool sync)
>  {
> diff --git a/tools/tests/xen-access/xen-access.c b/tools/tests/xen-access/xen-access.c
> index 9d4f957..c567cc0 100644
> --- a/tools/tests/xen-access/xen-access.c
> +++ b/tools/tests/xen-access/xen-access.c
> @@ -337,7 +337,7 @@ void usage(char* progname)
>  {
>      fprintf(stderr, "Usage: %s [-m] <domain_id> write|exec", progname);
>  #if defined(__i386__) || defined(__x86_64__)
> -            fprintf(stderr, "|breakpoint|altp2m_write|altp2m_exec|debug|cpuid");
> +            fprintf(stderr, "|breakpoint|altp2m_write|altp2m_exec|debug|cpuid|desc_access");
>  #elif defined(__arm__) || defined(__aarch64__)
>              fprintf(stderr, "|privcall");
>  #endif
> @@ -368,6 +368,7 @@ int main(int argc, char *argv[])
>      int altp2m = 0;
>      int debug = 0;
>      int cpuid = 0;
> +    int desc_access = 0;
>      uint16_t altp2m_view_id = 0;
>
>      char* progname = argv[0];
> @@ -434,6 +435,10 @@ int main(int argc, char *argv[])
>      {
>          cpuid = 1;
>      }
> +    else if ( !strcmp(argv[0], "desc_access") )
> +    {
> +        desc_access = 1;
> +    }
>  #elif defined(__arm__) || defined(__aarch64__)
>      else if ( !strcmp(argv[0], "privcall") )
>      {
> @@ -570,6 +575,16 @@ int main(int argc, char *argv[])
>              goto exit;
>          }
>      }
> +
> +    if ( desc_access )
> +    {
> +        rc = xc_monitor_descriptor_access(xch, domain_id, 1);
> +        if ( rc < 0 )
> +        {
> +            ERROR("Error %d setting descriptor access listener with vm_event\n", rc);
> +            goto exit;
> +        }
> +    }
>
>      if ( privcall )
>      {
> @@ -595,6 +610,8 @@ int main(int argc, char *argv[])
>                  rc = xc_monitor_debug_exceptions(xch, domain_id, 0, 0);
>              if ( cpuid )
>                  rc = xc_monitor_cpuid(xch, domain_id, 0);
> +            if ( desc_access )
> +                rc = xc_monitor_descriptor_access(xch, domain_id, 0);
>
>              if ( privcall )
>                  rc = xc_monitor_privileged_call(xch, domain_id, 0);
> @@ -779,6 +796,16 @@ int main(int argc, char *argv[])
>                  rsp.data = req.data;
>                  rsp.data.regs.x86.rip += req.u.cpuid.insn_length;
>                  break;
> +            case VM_EVENT_REASON_DESCRIPTOR_ACCESS:
> +                printf("Descriptor access: rip=%016"PRIx64", vcpu %d: "\
> +                       "VMExit info=0x%"PRIx64", descriptor=%d, is write=%d\n",
> +                       req.data.regs.x86.rip,
> +                       req.vcpu_id,
> +                       req.u.desc_access.vmexit.info,
> +                       req.u.desc_access.descriptor,
> +                       req.u.desc_access.is_write);
> +                rsp.flags |= VM_EVENT_FLAG_EMULATE;
> +                break;
>              default:
>                  fprintf(stderr, "UNKNOWN REASON CODE %d\n", req.reason);
>              }
> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index ccfae4f..cfe5aa2 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -3645,6 +3645,41 @@ gp_fault:
>      return X86EMUL_EXCEPTION;
>  }
>
> +int hvm_descriptor_access_intercept(uint64_t exit_info, uint64_t exit_qualification,
> +                                    uint8_t descriptor, bool_t is_write)
> +{
> +    struct vcpu *v = current;
> +    struct domain *d = v->domain;
> +    struct hvm_emulate_ctxt ctxt = {};
> +    int rc;
> +
> +    if ( d->arch.monitor.descriptor_access_enabled )
> +    {
> +        ASSERT(v->arch.vm_event);
> +        hvm_monitor_descriptor_access(exit_info, exit_qualification, descriptor, is_write);
> +    }
> +    else
> +    {
> +        hvm_emulate_init_once(&ctxt, NULL, guest_cpu_user_regs());
> +        rc = hvm_emulate_one(&ctxt);
> +        switch ( rc )
> +        {
> +        case X86EMUL_UNHANDLEABLE:
> +            hvm_inject_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC);
> +            break;
> +        case X86EMUL_EXCEPTION:
> +            if ( ctxt.ctxt.event_pending )
> +                hvm_inject_event(&ctxt.ctxt.event);
> +            /* fall through */
> +        default:
> +            hvm_emulate_writeback(&ctxt);
> +            break;
> +        }
> +    }
> +
> +    return X86EMUL_OKAY;
> +}
> +
>  static bool is_cross_vendor(const struct x86_emulate_state *state,
>                              const struct x86_emulate_ctxt *ctxt)
>  {
> diff --git a/xen/arch/x86/hvm/monitor.c b/xen/arch/x86/hvm/monitor.c
> index f5cd245..719fd8d 100644
> --- a/xen/arch/x86/hvm/monitor.c
> +++ b/xen/arch/x86/hvm/monitor.c
> @@ -72,6 +72,22 @@ void hvm_monitor_msr(unsigned int msr, uint64_t value)
>      }
>  }
>
> +void hvm_monitor_descriptor_access(uint64_t exit_info,
> +                                   uint64_t exit_qualification,
> +                                   uint8_t descriptor, bool_t is_write)
> +{
> +    struct vcpu *curr = current;
> +    vm_event_request_t req = {
> +        .reason = VM_EVENT_REASON_DESCRIPTOR_ACCESS,
> +        .u.desc_access.vmexit.info = exit_info,
> +        .u.desc_access.exit_qualification = exit_qualification,
> +        .u.desc_access.descriptor = descriptor,
> +        .u.desc_access.is_write = is_write,
> +    };
> +
> +    monitor_traps(curr, 1, &req);
> +}
> +
>  static inline unsigned long gfn_of_rip(unsigned long rip)
>  {
>      struct vcpu *curr = current;
> diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
> index 43241d6..63fa253 100644
> --- a/xen/arch/x86/hvm/svm/svm.c
> +++ b/xen/arch/x86/hvm/svm/svm.c
> @@ -856,6 +856,23 @@ static void svm_set_rdtsc_exiting(struct vcpu *v, bool_t enable)
>      vmcb_set_general2_intercepts(vmcb, general2_intercepts);
>  }
>
> +static void svm_set_descriptor_access_exiting(struct vcpu *v, bool_t enable)
> +{
> +    struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
> +    u32 general1_intercepts = vmcb_get_general1_intercepts(vmcb);
> +    u32 mask = GENERAL1_INTERCEPT_IDTR_READ | GENERAL1_INTERCEPT_GDTR_READ \
> +            | GENERAL1_INTERCEPT_LDTR_READ | GENERAL1_INTERCEPT_TR_READ \
> +            | GENERAL1_INTERCEPT_IDTR_WRITE | GENERAL1_INTERCEPT_GDTR_WRITE \
> +            | GENERAL1_INTERCEPT_LDTR_WRITE | GENERAL1_INTERCEPT_TR_WRITE;
> +
> +    if ( enable )
> +        general1_intercepts |= mask;
> +    else
> +        general1_intercepts &= ~mask;
> +
> +    vmcb_set_general1_intercepts(vmcb, general1_intercepts);
> +}
> +
>  static unsigned int svm_get_insn_bytes(struct vcpu *v, uint8_t *buf)
>  {
>      struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
> @@ -2224,6 +2241,7 @@ static struct hvm_function_table __initdata svm_function_table = {
>      .msr_read_intercept   = svm_msr_read_intercept,
>      .msr_write_intercept  = svm_msr_write_intercept,
>      .set_rdtsc_exiting    = svm_set_rdtsc_exiting,
> +    .set_descriptor_access_exiting = svm_set_descriptor_access_exiting,
>      .get_insn_bytes       = svm_get_insn_bytes,
>
>      .nhvm_vcpu_initialise = nsvm_vcpu_initialise,
> @@ -2642,6 +2660,38 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
>      case VMEXIT_PAUSE:
>          svm_vmexit_do_pause(regs);
>          break;
> +
> +    case VMEXIT_IDTR_READ:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 0);
> +        break;
> +
> +    case VMEXIT_GDTR_READ:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 0);
> +        break;
> +
> +    case VMEXIT_LDTR_READ:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 0);
> +        break;
> +
> +    case VMEXIT_TR_READ:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 0);
> +        break;
> +
> +    case VMEXIT_IDTR_WRITE:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 1);
> +        break;
> +
> +    case VMEXIT_GDTR_WRITE:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 1);
> +        break;
> +
> +    case VMEXIT_LDTR_WRITE:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 1);
> +        break;
> +
> +    case VMEXIT_TR_WRITE:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 1);
> +        break;
>
>      default:
>      unexpected_exit_type:
> diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
> index 894d7d4..2b2d193 100644
> --- a/xen/arch/x86/hvm/vmx/vmx.c
> +++ b/xen/arch/x86/hvm/vmx/vmx.c
> @@ -1343,6 +1343,20 @@ static void vmx_set_rdtsc_exiting(struct vcpu *v, bool_t enable)
>      vmx_vmcs_exit(v);
>  }
>
> +static void vmx_set_descriptor_access_exiting(struct vcpu *v, bool_t enable)
> +{
> +    if ( enable )
> +        v->arch.hvm_vmx.secondary_exec_control |=
> +            SECONDARY_EXEC_DESCRIPTOR_TABLE_EXITING;
> +    else
> +        v->arch.hvm_vmx.secondary_exec_control &=
> +            ~SECONDARY_EXEC_DESCRIPTOR_TABLE_EXITING;
> +
> +    vmx_vmcs_enter(v);
> +    vmx_update_secondary_exec_control(v);
> +    vmx_vmcs_exit(v);
> +}
> +
>  static void vmx_init_hypercall_page(struct domain *d, void *hypercall_page)
>  {
>      char *p;
> @@ -2232,6 +2246,7 @@ static struct hvm_function_table __initdata vmx_function_table = {
>      .handle_cd            = vmx_handle_cd,
>      .set_info_guest       = vmx_set_info_guest,
>      .set_rdtsc_exiting    = vmx_set_rdtsc_exiting,
> +    .set_descriptor_access_exiting = vmx_set_descriptor_access_exiting,
>      .nhvm_vcpu_initialise = nvmx_vcpu_initialise,
>      .nhvm_vcpu_destroy    = nvmx_vcpu_destroy,
>      .nhvm_vcpu_reset      = nvmx_vcpu_reset,
> @@ -3369,6 +3384,33 @@ static void vmx_handle_xrstors(void)
>      domain_crash(current->domain);
>  }
>
> +static void vmx_handle_descriptor_access(uint32_t exit_reason)
> +{
> +    uint8_t instr_id;
> +    uint64_t instr_info;
> +    uint64_t exit_qualification;
> +    uint8_t descriptor = VM_EVENT_DESC_INVALID;
> +
> +    __vmread(EXIT_QUALIFICATION, &exit_qualification);
> +    __vmread(VMX_INSTRUCTION_INFO, &instr_info);
> +
> +    instr_id = (instr_info >> 28) & 3; /* Instruction identity: bits 29:28 */
> +
> +    if ( exit_reason == EXIT_REASON_ACCESS_GDTR_OR_IDTR )
> +        if ( instr_id & 1 )
> +            descriptor = VM_EVENT_DESC_IDTR;
> +        else
> +            descriptor = VM_EVENT_DESC_GDTR;
> +    else
> +        if ( instr_id & 1 )
> +            descriptor = VM_EVENT_DESC_TR;
> +        else
> +            descriptor = VM_EVENT_DESC_LDTR;
> +
> +    hvm_descriptor_access_intercept(instr_info, exit_qualification, descriptor,
> +                                    instr_id >= 2);
> +}
> +
>  static int vmx_handle_apic_write(void)
>  {
>      unsigned long exit_qualification;
> @@ -3981,6 +4023,9 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
>
>      case EXIT_REASON_ACCESS_GDTR_OR_IDTR:
>      case EXIT_REASON_ACCESS_LDTR_OR_TR:
> +        vmx_handle_descriptor_access(exit_reason);
> +        break;
> +
>      case EXIT_REASON_VMX_PREEMPTION_TIMER_EXPIRED:
>      case EXIT_REASON_INVPCID:
>      /* fall through */
> diff --git a/xen/arch/x86/monitor.c b/xen/arch/x86/monitor.c
> index 5f60743..bec63ee 100644
> --- a/xen/arch/x86/monitor.c
> +++ b/xen/arch/x86/monitor.c
> @@ -211,6 +211,24 @@ int arch_monitor_domctl_event(struct domain *d,
>          break;
>      }
>
> +    case XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS:
> +    {
> +        bool_t old_status = ad->monitor.descriptor_access_enabled;
> +        struct vcpu *v;
> +
> +        if ( unlikely(old_status == requested_status) )
> +            return -EEXIST;
> +
> +        domain_pause(d);
> +        ad->monitor.descriptor_access_enabled = requested_status;
> +
> +        for_each_vcpu ( d, v )
> +            hvm_funcs.set_descriptor_access_exiting(v, requested_status);
> +
> +        domain_unpause(d);
> +        break;
> +    }
> +
>      case XEN_DOMCTL_MONITOR_EVENT_SOFTWARE_BREAKPOINT:
>      {
>          bool_t old_status = ad->monitor.software_breakpoint_enabled;
> diff --git a/xen/arch/x86/vm_event.c b/xen/arch/x86/vm_event.c
> index a7ce6ca..502ccc2 100644
> --- a/xen/arch/x86/vm_event.c
> +++ b/xen/arch/x86/vm_event.c
> @@ -229,6 +229,12 @@ void vm_event_emulate_check(struct vcpu *v, vm_event_response_t *rsp)
>          }
>          break;
>
> +    case VM_EVENT_REASON_DESCRIPTOR_ACCESS:
> +        if ( rsp->flags & VM_EVENT_FLAG_SET_EMUL_READ_DATA )
> +            v->arch.vm_event->emul.read = rsp->data.emul.read;
> +        v->arch.vm_event->emulate_flags = rsp->flags;
> +        break;
> +
>      default:
>          break;
>      };
> diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
> index ff5267f..b1410a1 100644
> --- a/xen/include/asm-x86/domain.h
> +++ b/xen/include/asm-x86/domain.h
> @@ -405,6 +405,7 @@ struct arch_domain
>          unsigned int debug_exception_enabled     : 1;
>          unsigned int debug_exception_sync        : 1;
>          unsigned int cpuid_enabled               : 1;
> +        unsigned int descriptor_access_enabled   : 1;
>          struct monitor_msr_bitmap *msr_bitmap;
>      } monitor;
>
> diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h
> index eccc25e..ceec7fa 100644
> --- a/xen/include/asm-x86/hvm/hvm.h
> +++ b/xen/include/asm-x86/hvm/hvm.h
> @@ -174,6 +174,7 @@ struct hvm_function_table {
>      void (*handle_cd)(struct vcpu *v, unsigned long value);
>      void (*set_info_guest)(struct vcpu *v);
>      void (*set_rdtsc_exiting)(struct vcpu *v, bool_t);
> +    void (*set_descriptor_access_exiting)(struct vcpu *v, bool_t);
>
>      /* Nested HVM */
>      int (*nhvm_vcpu_initialise)(struct vcpu *v);
> @@ -444,6 +445,7 @@ int hvm_event_needs_reinjection(uint8_t type, uint8_t vector);
>  uint8_t hvm_combine_hw_exceptions(uint8_t vec1, uint8_t vec2);
>
>  void hvm_set_rdtsc_exiting(struct domain *d, bool_t enable);
> +void hvm_set_descriptor_access_exiting(struct domain *d, bool_t enable);
>
>  static inline int hvm_cpu_up(void)
>  {
> diff --git a/xen/include/asm-x86/hvm/monitor.h b/xen/include/asm-x86/hvm/monitor.h
> index 85ca678..35f8b7a 100644
> --- a/xen/include/asm-x86/hvm/monitor.h
> +++ b/xen/include/asm-x86/hvm/monitor.h
> @@ -38,6 +38,9 @@ bool_t hvm_monitor_cr(unsigned int index, unsigned long value,
>  #define hvm_monitor_crX(cr, new, old) \
>                          hvm_monitor_cr(VM_EVENT_X86_##cr, new, old)
>  void hvm_monitor_msr(unsigned int msr, uint64_t value);
> +void hvm_monitor_descriptor_access(uint64_t exit_info,
> +                                   uint64_t exit_qualification,
> +                                   uint8_t descriptor, bool_t is_write);
>  int hvm_monitor_debug(unsigned long rip, enum hvm_monitor_debug_type type,
>                        unsigned long trap_type, unsigned long insn_length);
>  int hvm_monitor_cpuid(unsigned long insn_length, unsigned int leaf,
> diff --git a/xen/include/asm-x86/hvm/support.h b/xen/include/asm-x86/hvm/support.h
> index 632eb90..900bfe6 100644
> --- a/xen/include/asm-x86/hvm/support.h
> +++ b/xen/include/asm-x86/hvm/support.h
> @@ -128,6 +128,8 @@ int hvm_set_efer(uint64_t value);
>  int hvm_set_cr0(unsigned long value, bool_t may_defer);
>  int hvm_set_cr3(unsigned long value, bool_t may_defer);
>  int hvm_set_cr4(unsigned long value, bool_t may_defer);
> +int hvm_descriptor_access_intercept(uint64_t exit_info, uint64_t exit_qualification,
> +                                    uint8_t descriptor, bool_t is_write);
>  int hvm_mov_to_cr(unsigned int cr, unsigned int gpr);
>  int hvm_mov_from_cr(unsigned int cr, unsigned int gpr);
>  void hvm_ud_intercept(struct cpu_user_regs *);
> diff --git a/xen/include/asm-x86/monitor.h b/xen/include/asm-x86/monitor.h
> index e409373..5eeab3a 100644
> --- a/xen/include/asm-x86/monitor.h
> +++ b/xen/include/asm-x86/monitor.h
> @@ -77,6 +77,7 @@ static inline uint32_t arch_monitor_get_capabilities(struct domain *d)
>                     (1U << XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST) |
>                     (1U << XEN_DOMCTL_MONITOR_EVENT_DEBUG_EXCEPTION) |
>                     (1U << XEN_DOMCTL_MONITOR_EVENT_CPUID) |
> +                   (1U << XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS) |
>                     (1U << XEN_DOMCTL_MONITOR_EVENT_INTERRUPT);
>
>      /* Since we know this is on VMX, we can just call the hvm func */
> diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> index 85cbb7c..8ffb38d 100644
> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -1087,6 +1087,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cmt_op_t);
>  #define XEN_DOMCTL_MONITOR_EVENT_CPUID                 6
>  #define XEN_DOMCTL_MONITOR_EVENT_PRIVILEGED_CALL       7
>  #define XEN_DOMCTL_MONITOR_EVENT_INTERRUPT             8
> +#define XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS           9
>
>  struct xen_domctl_monitor_op {
>      uint32_t op; /* XEN_DOMCTL_MONITOR_OP_* */
> diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h
> index b7487a1..7b18ee4 100644
> --- a/xen/include/public/vm_event.h
> +++ b/xen/include/public/vm_event.h
> @@ -146,6 +146,8 @@
>  #define VM_EVENT_REASON_PRIVILEGED_CALL         11
>  /* An interrupt has been delivered. */
>  #define VM_EVENT_REASON_INTERRUPT               12
> +/* A descriptor table register was accessed. */
> +#define VM_EVENT_REASON_DESCRIPTOR_ACCESS       13
>
>  /* Supported values for the vm_event_write_ctrlreg index. */
>  #define VM_EVENT_X86_CR0    0
> @@ -259,6 +261,24 @@ struct vm_event_mov_to_msr {
>      uint64_t value;
>  };
>
> +#define VM_EVENT_DESC_INVALID        0
> +#define VM_EVENT_DESC_IDTR           1
> +#define VM_EVENT_DESC_GDTR           2
> +#define VM_EVENT_DESC_LDTR           3
> +#define VM_EVENT_DESC_TR             4
> +
> +struct vm_event_desc_access {
> +    union {
> +        uint32_t vmx_instr_info;    /* VMX: VMCS Instruction-Information Field */
> +        uint64_t svm_exitinfo;      /* SVM: VMCB EXITINFO Field */
> +        uint64_t info;
> +    } vmexit;
> +    uint64_t exit_qualification;    /* VMX only: VMCS Exit Qualification Field */

IMHO it might be a bit cleaner if we had two sub-structs here, one for
vmx and one for svm, and have them in a union. The vmx struct would
have vmx_instr_info and exit_qualification, while the svm would only
have svm_exitinfo.

> +    uint8_t descriptor;             /* VM_EVENT_DESC_* */
> +    uint8_t is_write;
> +    uint8_t _pad[6];
> +};
> +
>  struct vm_event_cpuid {
>      uint32_t insn_length;
>      uint32_t leaf;
> @@ -313,6 +333,7 @@ typedef struct vm_event_st {
>          struct vm_event_mem_access            mem_access;
>          struct vm_event_write_ctrlreg         write_ctrlreg;
>          struct vm_event_mov_to_msr            mov_to_msr;
> +        struct vm_event_desc_access           desc_access;
>          struct vm_event_singlestep            singlestep;
>          struct vm_event_debug                 software_breakpoint;
>          struct vm_event_debug                 debug_exception;
> --
> 2.7.4

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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-10 15:50 [PATCH] x86/monitor: add support for descriptor access events Vlad Ioan Topan
  2017-03-10 19:41 ` Tamas K Lengyel
@ 2017-03-13 21:24 ` Boris Ostrovsky
  2017-03-14 12:15   ` Vlad-Ioan TOPAN
  2017-03-14 12:39 ` Wei Liu
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 15+ messages in thread
From: Boris Ostrovsky @ 2017-03-13 21:24 UTC (permalink / raw)
  To: Vlad Ioan Topan, xen-devel
  Cc: Kevin Tian, Tamas K Lengyel, Wei Liu, Suravee Suthikulpanit,
	Razvan Cojocaru, Jun Nakajima, Andrew Cooper, Ian Jackson,
	Jan Beulich


> @@ -2642,6 +2660,38 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
>      case VMEXIT_PAUSE:
>          svm_vmexit_do_pause(regs);
>          break;
> +    
> +    case VMEXIT_IDTR_READ:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 0);
> +        break;
> +
> +    case VMEXIT_GDTR_READ:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 0);
> +        break;
> +
> +    case VMEXIT_LDTR_READ:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 0);
> +        break;
> +
> +    case VMEXIT_TR_READ:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 0);
> +        break;
> +
> +    case VMEXIT_IDTR_WRITE:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 1);
> +        break;
> +
> +    case VMEXIT_GDTR_WRITE:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 1);
> +        break;
> +
> +    case VMEXIT_LDTR_WRITE:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 1);
> +        break;
> +
> +    case VMEXIT_TR_WRITE:
> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 1);
> +        break;

I think this can be halved in size by having
'hvm_descriptor_access_intercept(..., exit_reason_write?1:0)'

And maybe even collapse completely by having a lookup table mapping exit
reason to event.

-boris



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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-10 19:41 ` Tamas K Lengyel
@ 2017-03-14 12:07   ` Vlad-Ioan TOPAN
  0 siblings, 0 replies; 15+ messages in thread
From: Vlad-Ioan TOPAN @ 2017-03-14 12:07 UTC (permalink / raw)
  To: Tamas K Lengyel
  Cc: Kevin Tian, Wei Liu, Suravee Suthikulpanit, Razvan Cojocaru,
	Andrew Cooper, Ian Jackson, Jan Beulich, Jun Nakajima, Xen-devel,
	Boris Ostrovsky

> > +struct vm_event_desc_access {
> > +    union {
> > +        uint32_t vmx_instr_info;    /* VMX: VMCS Instruction-Information Field */
> > +        uint64_t svm_exitinfo;      /* SVM: VMCB EXITINFO Field */
> > +        uint64_t info;
> > +    } vmexit;
> > +    uint64_t exit_qualification;    /* VMX only: VMCS Exit Qualification Field */
> 
> IMHO it might be a bit cleaner if we had two sub-structs here, one for
> vmx and one for svm, and have them in a union. The vmx struct would
> have vmx_instr_info and exit_qualification, while the svm would only
> have svm_exitinfo.

Makes sense, will do.

--
Vlad-Ioan TOPAN
Linux Kernel Development Lead
Bitdefender

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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-13 21:24 ` Boris Ostrovsky
@ 2017-03-14 12:15   ` Vlad-Ioan TOPAN
  2017-03-14 12:50     ` Razvan Cojocaru
  2017-03-14 13:18     ` Jan Beulich
  0 siblings, 2 replies; 15+ messages in thread
From: Vlad-Ioan TOPAN @ 2017-03-14 12:15 UTC (permalink / raw)
  To: Boris Ostrovsky
  Cc: Kevin Tian, Tamas K Lengyel, Wei Liu, Jun Nakajima,
	Razvan Cojocaru, Andrew Cooper, Ian Jackson, Jan Beulich,
	Suravee Suthikulpanit, xen-devel

> > @@ -2642,6 +2660,38 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
> >      case VMEXIT_PAUSE:
> >          svm_vmexit_do_pause(regs);
> >          break;
> > +    
> > +    case VMEXIT_IDTR_READ:
> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 0);
> > +        break;
> > +
> > +    case VMEXIT_GDTR_READ:
> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 0);
> > +        break;
> > +
> > +    case VMEXIT_LDTR_READ:
> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 0);
> > +        break;
> > +
> > +    case VMEXIT_TR_READ:
> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 0);
> > +        break;
> > +
> > +    case VMEXIT_IDTR_WRITE:
> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 1);
> > +        break;
> > +
> > +    case VMEXIT_GDTR_WRITE:
> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 1);
> > +        break;
> > +
> > +    case VMEXIT_LDTR_WRITE:
> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 1);
> > +        break;
> > +
> > +    case VMEXIT_TR_WRITE:
> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 1);
> > +        break;
> 
> I think this can be halved in size by having
> 'hvm_descriptor_access_intercept(..., exit_reason_write?1:0)'
> 
> And maybe even collapse completely by having a lookup table mapping exit
> reason to event.

The problem with both ideas is that they depend on assumptions about the
values of the VMEXIT_* constants to make the code shorter and still
keep it readable, which in my opinion would be bad. Although they will
most likely stay sequential and keep their current numeric values, it's
not something I'd hardcode. Without those assumptions, it's either
another switch or a very long if, which would mean roughly the same
amount of code, but less readable (it's the way I've written it
initally before coming to this version).

--
Vlad-Ioan TOPAN
Linux Kernel Development Lead
Bitdefender

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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-10 15:50 [PATCH] x86/monitor: add support for descriptor access events Vlad Ioan Topan
  2017-03-10 19:41 ` Tamas K Lengyel
  2017-03-13 21:24 ` Boris Ostrovsky
@ 2017-03-14 12:39 ` Wei Liu
  2017-03-17 11:03 ` Jan Beulich
  2017-03-21 12:04 ` Andrew Cooper
  4 siblings, 0 replies; 15+ messages in thread
From: Wei Liu @ 2017-03-14 12:39 UTC (permalink / raw)
  To: Vlad Ioan Topan
  Cc: Kevin Tian, Tamas K Lengyel, Wei Liu, Suravee Suthikulpanit,
	Razvan Cojocaru, Jun Nakajima, Andrew Cooper, Ian Jackson,
	Jan Beulich, xen-devel, Boris Ostrovsky

On Fri, Mar 10, 2017 at 05:50:34PM +0200, Vlad Ioan Topan wrote:
> Adds monitor support for descriptor access events (reads & writes of
> IDTR/GDTR/LDTR/TR) for the x86 architecture (VMX and SVM).
> 
> Signed-off-by: Vlad Ioan Topan <itopan@bitdefender.com>
> ---
>  tools/libxc/include/xenctrl.h       |  2 ++
>  tools/libxc/xc_monitor.c            | 14 +++++++++++
>  tools/tests/xen-access/xen-access.c | 29 ++++++++++++++++++++-

Acked-by: Wei Liu <wei.liu2@citrix.com>

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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-14 12:15   ` Vlad-Ioan TOPAN
@ 2017-03-14 12:50     ` Razvan Cojocaru
  2017-03-14 13:15       ` Boris Ostrovsky
  2017-03-14 13:18     ` Jan Beulich
  1 sibling, 1 reply; 15+ messages in thread
From: Razvan Cojocaru @ 2017-03-14 12:50 UTC (permalink / raw)
  To: Vlad-Ioan TOPAN, Boris Ostrovsky
  Cc: Kevin Tian, Tamas K Lengyel, Wei Liu, Suravee Suthikulpanit,
	Andrew Cooper, Ian Jackson, Jan Beulich, Jun Nakajima, xen-devel

On 03/14/2017 02:15 PM, Vlad-Ioan TOPAN wrote:
>>> @@ -2642,6 +2660,38 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
>>>      case VMEXIT_PAUSE:
>>>          svm_vmexit_do_pause(regs);
>>>          break;
>>> +    
>>> +    case VMEXIT_IDTR_READ:
>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 0);
>>> +        break;
>>> +
>>> +    case VMEXIT_GDTR_READ:
>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 0);
>>> +        break;
>>> +
>>> +    case VMEXIT_LDTR_READ:
>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 0);
>>> +        break;
>>> +
>>> +    case VMEXIT_TR_READ:
>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 0);
>>> +        break;
>>> +
>>> +    case VMEXIT_IDTR_WRITE:
>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 1);
>>> +        break;
>>> +
>>> +    case VMEXIT_GDTR_WRITE:
>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 1);
>>> +        break;
>>> +
>>> +    case VMEXIT_LDTR_WRITE:
>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 1);
>>> +        break;
>>> +
>>> +    case VMEXIT_TR_WRITE:
>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 1);
>>> +        break;
>>
>> I think this can be halved in size by having
>> 'hvm_descriptor_access_intercept(..., exit_reason_write?1:0)'
>>
>> And maybe even collapse completely by having a lookup table mapping exit
>> reason to event.
> 
> The problem with both ideas is that they depend on assumptions about the
> values of the VMEXIT_* constants to make the code shorter and still
> keep it readable, which in my opinion would be bad. Although they will
> most likely stay sequential and keep their current numeric values, it's
> not something I'd hardcode. Without those assumptions, it's either
> another switch or a very long if, which would mean roughly the same
> amount of code, but less readable (it's the way I've written it
> initally before coming to this version).

I'm reading Boris' suggestion to mean:

case VMEXIT_IDTR_READ:
case VMEXIT_IDTR_WRITE:
    hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0,
        VM_EVENT_DESC_IDTR, exit_reason == VMEXIT_IDTR_WRITE);
    break;

I could be wrong.


Thanks,
Razvan

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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-14 12:50     ` Razvan Cojocaru
@ 2017-03-14 13:15       ` Boris Ostrovsky
  2017-03-16  9:25         ` Vlad-Ioan TOPAN
  0 siblings, 1 reply; 15+ messages in thread
From: Boris Ostrovsky @ 2017-03-14 13:15 UTC (permalink / raw)
  To: Razvan Cojocaru, Vlad-Ioan TOPAN
  Cc: Kevin Tian, Tamas K Lengyel, Wei Liu, Suravee Suthikulpanit,
	Andrew Cooper, Ian Jackson, Jan Beulich, Jun Nakajima, xen-devel



On 03/14/2017 08:50 AM, Razvan Cojocaru wrote:
> On 03/14/2017 02:15 PM, Vlad-Ioan TOPAN wrote:
>>>> @@ -2642,6 +2660,38 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
>>>>      case VMEXIT_PAUSE:
>>>>          svm_vmexit_do_pause(regs);
>>>>          break;
>>>> +
>>>> +    case VMEXIT_IDTR_READ:
>>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 0);
>>>> +        break;
>>>> +
>>>> +    case VMEXIT_GDTR_READ:
>>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 0);
>>>> +        break;
>>>> +
>>>> +    case VMEXIT_LDTR_READ:
>>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 0);
>>>> +        break;
>>>> +
>>>> +    case VMEXIT_TR_READ:
>>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 0);
>>>> +        break;
>>>> +
>>>> +    case VMEXIT_IDTR_WRITE:
>>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 1);
>>>> +        break;
>>>> +
>>>> +    case VMEXIT_GDTR_WRITE:
>>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 1);
>>>> +        break;
>>>> +
>>>> +    case VMEXIT_LDTR_WRITE:
>>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 1);
>>>> +        break;
>>>> +
>>>> +    case VMEXIT_TR_WRITE:
>>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 1);
>>>> +        break;
>>>
>>> I think this can be halved in size by having
>>> 'hvm_descriptor_access_intercept(..., exit_reason_write?1:0)'
>>>
>>> And maybe even collapse completely by having a lookup table mapping exit
>>> reason to event.
>>
>> The problem with both ideas is that they depend on assumptions about the
>> values of the VMEXIT_* constants to make the code shorter and still
>> keep it readable, which in my opinion would be bad. Although they will
>> most likely stay sequential and keep their current numeric values, it's
>> not something I'd hardcode. Without those assumptions, it's either
>> another switch or a very long if, which would mean roughly the same
>> amount of code, but less readable (it's the way I've written it
>> initally before coming to this version).
>
> I'm reading Boris' suggestion to mean:
>
> case VMEXIT_IDTR_READ:
> case VMEXIT_IDTR_WRITE:
>     hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0,
>         VM_EVENT_DESC_IDTR, exit_reason == VMEXIT_IDTR_WRITE);
>     break;
>
> I could be wrong.


Right, that's exactly what I meant, thanks.

As for getting rid of all but one cases --- yes, it may be a a bit 
tricky to do it in a reasonably compact manner.

-boris

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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-14 12:15   ` Vlad-Ioan TOPAN
  2017-03-14 12:50     ` Razvan Cojocaru
@ 2017-03-14 13:18     ` Jan Beulich
  1 sibling, 0 replies; 15+ messages in thread
From: Jan Beulich @ 2017-03-14 13:18 UTC (permalink / raw)
  To: Vlad-Ioan TOPAN
  Cc: Kevin Tian, TamasK Lengyel, Wei Liu, Jun Nakajima,
	Razvan Cojocaru, AndrewCooper, Ian Jackson, SuraveeSuthikulpanit,
	xen-devel, Boris Ostrovsky

>>> On 14.03.17 at 13:15, <itopan@bitdefender.com> wrote:
>> > @@ -2642,6 +2660,38 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
>> >      case VMEXIT_PAUSE:
>> >          svm_vmexit_do_pause(regs);
>> >          break;
>> > +    
>> > +    case VMEXIT_IDTR_READ:
>> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, 
> VM_EVENT_DESC_IDTR, 0);
>> > +        break;
>> > +
>> > +    case VMEXIT_GDTR_READ:
>> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, 
> VM_EVENT_DESC_GDTR, 0);
>> > +        break;
>> > +
>> > +    case VMEXIT_LDTR_READ:
>> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, 
> VM_EVENT_DESC_LDTR, 0);
>> > +        break;
>> > +
>> > +    case VMEXIT_TR_READ:
>> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, 
> VM_EVENT_DESC_TR, 0);
>> > +        break;
>> > +
>> > +    case VMEXIT_IDTR_WRITE:
>> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, 
> VM_EVENT_DESC_IDTR, 1);
>> > +        break;
>> > +
>> > +    case VMEXIT_GDTR_WRITE:
>> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, 
> VM_EVENT_DESC_GDTR, 1);
>> > +        break;
>> > +
>> > +    case VMEXIT_LDTR_WRITE:
>> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, 
> VM_EVENT_DESC_LDTR, 1);
>> > +        break;
>> > +
>> > +    case VMEXIT_TR_WRITE:
>> > +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, 
> VM_EVENT_DESC_TR, 1);
>> > +        break;
>> 
>> I think this can be halved in size by having
>> 'hvm_descriptor_access_intercept(..., exit_reason_write?1:0)'
>> 
>> And maybe even collapse completely by having a lookup table mapping exit
>> reason to event.
> 
> The problem with both ideas is that they depend on assumptions about the
> values of the VMEXIT_* constants to make the code shorter and still
> keep it readable, which in my opinion would be bad.

I see nothing bad here, we make similar assumptions elsewhere.

> Although they will
> most likely stay sequential and keep their current numeric values,

They're sure to stay the same forever, or else everyone's code
will break.

Jan


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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-14 13:15       ` Boris Ostrovsky
@ 2017-03-16  9:25         ` Vlad-Ioan TOPAN
  0 siblings, 0 replies; 15+ messages in thread
From: Vlad-Ioan TOPAN @ 2017-03-16  9:25 UTC (permalink / raw)
  To: Boris Ostrovsky
  Cc: Kevin Tian, Tamas K Lengyel, Wei Liu, Jan Beulich,
	Razvan Cojocaru, Jun Nakajima, Andrew Cooper, Ian Jackson,
	Suravee Suthikulpanit, xen-devel

On Tue, 14 Mar 2017 09:15:04 -0400
Boris Ostrovsky <boris.ostrovsky@oracle.com> wrote:

> 
> 
> On 03/14/2017 08:50 AM, Razvan Cojocaru wrote:
> > On 03/14/2017 02:15 PM, Vlad-Ioan TOPAN wrote:
> >>>> @@ -2642,6 +2660,38 @@ void svm_vmexit_handler(struct cpu_user_regs *regs)
> >>>>      case VMEXIT_PAUSE:
> >>>>          svm_vmexit_do_pause(regs);
> >>>>          break;
> >>>> +
> >>>> +    case VMEXIT_IDTR_READ:
> >>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 0);
> >>>> +        break;
> >>>> +
> >>>> +    case VMEXIT_GDTR_READ:
> >>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 0);
> >>>> +        break;
> >>>> +
> >>>> +    case VMEXIT_LDTR_READ:
> >>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 0);
> >>>> +        break;
> >>>> +
> >>>> +    case VMEXIT_TR_READ:
> >>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 0);
> >>>> +        break;
> >>>> +
> >>>> +    case VMEXIT_IDTR_WRITE:
> >>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_IDTR, 1);
> >>>> +        break;
> >>>> +
> >>>> +    case VMEXIT_GDTR_WRITE:
> >>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_GDTR, 1);
> >>>> +        break;
> >>>> +
> >>>> +    case VMEXIT_LDTR_WRITE:
> >>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_LDTR, 1);
> >>>> +        break;
> >>>> +
> >>>> +    case VMEXIT_TR_WRITE:
> >>>> +        hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0, VM_EVENT_DESC_TR, 1);
> >>>> +        break;
> >>>
> >>> I think this can be halved in size by having
> >>> 'hvm_descriptor_access_intercept(..., exit_reason_write?1:0)'
> >>>
> >>> And maybe even collapse completely by having a lookup table mapping exit
> >>> reason to event.
> >>
> >> The problem with both ideas is that they depend on assumptions about the
> >> values of the VMEXIT_* constants to make the code shorter and still
> >> keep it readable, which in my opinion would be bad. Although they will
> >> most likely stay sequential and keep their current numeric values, it's
> >> not something I'd hardcode. Without those assumptions, it's either
> >> another switch or a very long if, which would mean roughly the same
> >> amount of code, but less readable (it's the way I've written it
> >> initally before coming to this version).
> >
> > I'm reading Boris' suggestion to mean:
> >
> > case VMEXIT_IDTR_READ:
> > case VMEXIT_IDTR_WRITE:
> >     hvm_descriptor_access_intercept(vmcb->exitintinfo.bytes, 0,
> >         VM_EVENT_DESC_IDTR, exit_reason == VMEXIT_IDTR_WRITE);
> >     break;
> >
> > I could be wrong.
>
> Right, that's exactly what I meant, thanks.

That's the "roughly same amount of code, but less readable" option, but
it works for me if that's the consensus.

> As for getting rid of all but one cases --- yes, it may be a a bit 
> tricky to do it in a reasonably compact manner.
> 
> -boris

Okay then, I'll post v2 of the patch with the two suggested changes.

--
Vlad-Ioan TOPAN
Linux Kernel Development Lead
Bitdefender

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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-10 15:50 [PATCH] x86/monitor: add support for descriptor access events Vlad Ioan Topan
                   ` (2 preceding siblings ...)
  2017-03-14 12:39 ` Wei Liu
@ 2017-03-17 11:03 ` Jan Beulich
  2017-03-20 19:21   ` Vlad-Ioan TOPAN
  2017-03-21 12:04 ` Andrew Cooper
  4 siblings, 1 reply; 15+ messages in thread
From: Jan Beulich @ 2017-03-17 11:03 UTC (permalink / raw)
  To: Vlad Ioan Topan
  Cc: Kevin Tian, Tamas K Lengyel, Wei Liu, Jun Nakajima,
	Razvan Cojocaru, Andrew Cooper, Ian Jackson,
	Suravee Suthikulpanit, xen-devel, Boris Ostrovsky

>>> On 10.03.17 at 16:50, <itopan@bitdefender.com> wrote:
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -3645,6 +3645,41 @@ gp_fault:
>      return X86EMUL_EXCEPTION;
>  }
>  
> +int hvm_descriptor_access_intercept(uint64_t exit_info, uint64_t exit_qualification, 
> +                                    uint8_t descriptor, bool_t is_write)

bool (also elsewhere)

> +{
> +    struct vcpu *v = current;
> +    struct domain *d = v->domain;

curr and currd respectively.

> +    struct hvm_emulate_ctxt ctxt = {};

Please move this into the more narrow scope it's needed in.

> +    int rc;
> +
> +    if ( d->arch.monitor.descriptor_access_enabled )
> +    {
> +        ASSERT(v->arch.vm_event);
> +        hvm_monitor_descriptor_access(exit_info, exit_qualification, descriptor, is_write);
> +    }
> +    else
> +    {
> +        hvm_emulate_init_once(&ctxt, NULL, guest_cpu_user_regs());
> +        rc = hvm_emulate_one(&ctxt);
> +        switch ( rc )
> +        {
> +        case X86EMUL_UNHANDLEABLE:
> +            hvm_inject_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC);

Is #UD the right exception here? In fact, is delivering an exception
sensible in this case at all?

> @@ -3369,6 +3384,33 @@ static void vmx_handle_xrstors(void)
>      domain_crash(current->domain);
>  }
>  
> +static void vmx_handle_descriptor_access(uint32_t exit_reason)
> +{
> +    uint8_t instr_id;
> +    uint64_t instr_info;
> +    uint64_t exit_qualification;
> +    uint8_t descriptor = VM_EVENT_DESC_INVALID;
> +
> +    __vmread(EXIT_QUALIFICATION, &exit_qualification);
> +    __vmread(VMX_INSTRUCTION_INFO, &instr_info);
> +
> +    instr_id = (instr_info >> 28) & 3; /* Instruction identity: bits 29:28 */
> +
> +    if ( exit_reason == EXIT_REASON_ACCESS_GDTR_OR_IDTR )
> +        if ( instr_id & 1 )
> +            descriptor = VM_EVENT_DESC_IDTR;
> +        else
> +            descriptor = VM_EVENT_DESC_GDTR;
> +    else
> +        if ( instr_id & 1 )
> +            descriptor = VM_EVENT_DESC_TR;
> +        else
> +            descriptor = VM_EVENT_DESC_LDTR;

Please use conditional expressions instead of if/else in such cases.

> +    hvm_descriptor_access_intercept(instr_info, exit_qualification, descriptor,
> +                                    instr_id >= 2);

instr_id & 2 (to be consistent with the other code. But anyway, even
better would be to use manifest constants instead of all these literal
numbers.

> @@ -444,6 +445,7 @@ int hvm_event_needs_reinjection(uint8_t type, uint8_t vector);
>  uint8_t hvm_combine_hw_exceptions(uint8_t vec1, uint8_t vec2);
>  
>  void hvm_set_rdtsc_exiting(struct domain *d, bool_t enable);
> +void hvm_set_descriptor_access_exiting(struct domain *d, bool_t enable);

Dead declaration.

> --- a/xen/include/asm-x86/monitor.h
> +++ b/xen/include/asm-x86/monitor.h
> @@ -77,6 +77,7 @@ static inline uint32_t arch_monitor_get_capabilities(struct domain *d)
>                     (1U << XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST) |
>                     (1U << XEN_DOMCTL_MONITOR_EVENT_DEBUG_EXCEPTION) |
>                     (1U << XEN_DOMCTL_MONITOR_EVENT_CPUID) |
> +                   (1U << XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS) |
>                     (1U << XEN_DOMCTL_MONITOR_EVENT_INTERRUPT);

If I was the maintainer of this code, I'd ask for the elements to
remain ordered numerically, i.e. matching ...

> --- a/xen/include/public/domctl.h
> +++ b/xen/include/public/domctl.h
> @@ -1087,6 +1087,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cmt_op_t);
>  #define XEN_DOMCTL_MONITOR_EVENT_CPUID                 6
>  #define XEN_DOMCTL_MONITOR_EVENT_PRIVILEGED_CALL       7
>  #define XEN_DOMCTL_MONITOR_EVENT_INTERRUPT             8
> +#define XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS           9

... the sequence here.

> @@ -259,6 +261,24 @@ struct vm_event_mov_to_msr {
>      uint64_t value;
>  };
>  
> +#define VM_EVENT_DESC_INVALID        0

What is this good for?

Jan


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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-17 11:03 ` Jan Beulich
@ 2017-03-20 19:21   ` Vlad-Ioan TOPAN
  2017-03-21  8:04     ` Jan Beulich
  0 siblings, 1 reply; 15+ messages in thread
From: Vlad-Ioan TOPAN @ 2017-03-20 19:21 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Kevin Tian, Tamas K Lengyel, Wei Liu, Suravee Suthikulpanit,
	Razvan Cojocaru, Andrew Cooper, Ian Jackson, Jun Nakajima,
	xen-devel, Boris Ostrovsky

On Fri, 17 Mar 2017 05:03:44 -0600
"Jan Beulich" <JBeulich@suse.com> wrote:

> >>> On 10.03.17 at 16:50, <itopan@bitdefender.com> wrote:
> > --- a/xen/arch/x86/hvm/hvm.c
> > +++ b/xen/arch/x86/hvm/hvm.c
> > @@ -3645,6 +3645,41 @@ gp_fault:
> >      return X86EMUL_EXCEPTION;
> >  }
> >  
> > +int hvm_descriptor_access_intercept(uint64_t exit_info, uint64_t exit_qualification, 
> > +                                    uint8_t descriptor, bool_t is_write)
> 
> bool (also elsewhere)

Ok.

> > +{
> > +    struct vcpu *v = current;
> > +    struct domain *d = v->domain;
> 
> curr and currd respectively.

Ok.

> > +    struct hvm_emulate_ctxt ctxt = {};
> 
> Please move this into the more narrow scope it's needed in.

Ok.

> > +    int rc;
> > +
> > +    if ( d->arch.monitor.descriptor_access_enabled )
> > +    {
> > +        ASSERT(v->arch.vm_event);
> > +        hvm_monitor_descriptor_access(exit_info, exit_qualification, descriptor, is_write);
> > +    }
> > +    else
> > +    {
> > +        hvm_emulate_init_once(&ctxt, NULL, guest_cpu_user_regs());
> > +        rc = hvm_emulate_one(&ctxt);
> > +        switch ( rc )
> > +        {
> > +        case X86EMUL_UNHANDLEABLE:
> > +            hvm_inject_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC);
> 
> Is #UD the right exception here? In fact, is delivering an exception
> sensible in this case at all?

Possibly not; it's how that case is handled elsewhere. For the given
set of instructions at least, X86EMUL_UNHANDLEABLE should only be
returnable due to some internal bug/error (e.g. invalid/unknown
HVMCOPY_* constant returned by hvm_fetch_from_guest_linear() or an
invalid selector passed to ->write_segment() etc.); what would be the
best way to handle that case?

> > @@ -3369,6 +3384,33 @@ static void vmx_handle_xrstors(void)
> >      domain_crash(current->domain);
> >  }
> >  
> > +static void vmx_handle_descriptor_access(uint32_t exit_reason)
> > +{
> > +    uint8_t instr_id;
> > +    uint64_t instr_info;
> > +    uint64_t exit_qualification;
> > +    uint8_t descriptor = VM_EVENT_DESC_INVALID;
> > +
> > +    __vmread(EXIT_QUALIFICATION, &exit_qualification);
> > +    __vmread(VMX_INSTRUCTION_INFO, &instr_info);
> > +
> > +    instr_id = (instr_info >> 28) & 3; /* Instruction identity: bits 29:28 */
> > +
> > +    if ( exit_reason == EXIT_REASON_ACCESS_GDTR_OR_IDTR )
> > +        if ( instr_id & 1 )
> > +            descriptor = VM_EVENT_DESC_IDTR;
> > +        else
> > +            descriptor = VM_EVENT_DESC_GDTR;
> > +    else
> > +        if ( instr_id & 1 )
> > +            descriptor = VM_EVENT_DESC_TR;
> > +        else
> > +            descriptor = VM_EVENT_DESC_LDTR;
> 
> Please use conditional expressions instead of if/else in such cases.

Ok.

> > +    hvm_descriptor_access_intercept(instr_info, exit_qualification, descriptor,
> > +                                    instr_id >= 2);
> 
> instr_id & 2 (to be consistent with the other code. But anyway, even
> better would be to use manifest constants instead of all these literal
> numbers.

(instr_id & 2) makes sense, but the 1 & 2 literals are unnamed criteria
inferred from the encoding to simplify the code, they don't have an
explicit meaning (at least in the Intel docs).

> > @@ -444,6 +445,7 @@ int hvm_event_needs_reinjection(uint8_t type, uint8_t vector);
> >  uint8_t hvm_combine_hw_exceptions(uint8_t vec1, uint8_t vec2);
> >  
> >  void hvm_set_rdtsc_exiting(struct domain *d, bool_t enable);
> > +void hvm_set_descriptor_access_exiting(struct domain *d, bool_t enable);
> 
> Dead declaration.

It somehow got away from a previous (internal) version of the patch; it
will be removed.

> > --- a/xen/include/asm-x86/monitor.h
> > +++ b/xen/include/asm-x86/monitor.h
> > @@ -77,6 +77,7 @@ static inline uint32_t arch_monitor_get_capabilities(struct domain *d)
> >                     (1U << XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST) |
> >                     (1U << XEN_DOMCTL_MONITOR_EVENT_DEBUG_EXCEPTION) |
> >                     (1U << XEN_DOMCTL_MONITOR_EVENT_CPUID) |
> > +                   (1U << XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS) |
> >                     (1U << XEN_DOMCTL_MONITOR_EVENT_INTERRUPT);
> 
> If I was the maintainer of this code, I'd ask for the elements to
> remain ordered numerically, i.e. matching ...
> 
> > --- a/xen/include/public/domctl.h
> > +++ b/xen/include/public/domctl.h
> > @@ -1087,6 +1087,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cmt_op_t);
> >  #define XEN_DOMCTL_MONITOR_EVENT_CPUID                 6
> >  #define XEN_DOMCTL_MONITOR_EVENT_PRIVILEGED_CALL       7
> >  #define XEN_DOMCTL_MONITOR_EVENT_INTERRUPT             8
> > +#define XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS           9
> 
> ... the sequence here.

Ok.

> > @@ -259,6 +261,24 @@ struct vm_event_mov_to_msr {
> >      uint64_t value;
> >  };
> >  
> > +#define VM_EVENT_DESC_INVALID        0
> 
> What is this good for?

The default (uninitialized) value is given a semantic of "invalid" to
make potential problems due to incorrectly / incompletely initialized
or corrupted data more obvious (I assume the .pad* fields are checked to
be 0 for the same reason).

> Jan

Thank you for the review; pending further feedback on the
X86EMUL_UNHANDLEABLE case I'll post an updated patch.

--
Vlad-Ioan TOPAN
Linux Kernel Development Lead
Bitdefender

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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-20 19:21   ` Vlad-Ioan TOPAN
@ 2017-03-21  8:04     ` Jan Beulich
  0 siblings, 0 replies; 15+ messages in thread
From: Jan Beulich @ 2017-03-21  8:04 UTC (permalink / raw)
  To: Vlad-Ioan TOPAN
  Cc: Kevin Tian, Tamas K Lengyel, Wei Liu, Jun Nakajima,
	Razvan Cojocaru, Andrew Cooper, Ian Jackson,
	Suravee Suthikulpanit, xen-devel, BorisOstrovsky

>>> On 20.03.17 at 20:21, <itopan@bitdefender.com> wrote:
> On Fri, 17 Mar 2017 05:03:44 -0600
> "Jan Beulich" <JBeulich@suse.com> wrote:
>> >>> On 10.03.17 at 16:50, <itopan@bitdefender.com> wrote:
>> > +    else
>> > +    {
>> > +        hvm_emulate_init_once(&ctxt, NULL, guest_cpu_user_regs());
>> > +        rc = hvm_emulate_one(&ctxt);
>> > +        switch ( rc )
>> > +        {
>> > +        case X86EMUL_UNHANDLEABLE:
>> > +            hvm_inject_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC);
>> 
>> Is #UD the right exception here? In fact, is delivering an exception
>> sensible in this case at all?
> 
> Possibly not; it's how that case is handled elsewhere. For the given
> set of instructions at least, X86EMUL_UNHANDLEABLE should only be
> returnable due to some internal bug/error (e.g. invalid/unknown
> HVMCOPY_* constant returned by hvm_fetch_from_guest_linear() or an
> invalid selector passed to ->write_segment() etc.); what would be the
> best way to handle that case?

I think crashing the domain in such cases is better - injecting
whatever non-architectural exception is only going to defer
problems, making later analysis more difficult.

>> > +    hvm_descriptor_access_intercept(instr_info, exit_qualification, descriptor,
>> > +                                    instr_id >= 2);
>> 
>> instr_id & 2 (to be consistent with the other code. But anyway, even
>> better would be to use manifest constants instead of all these literal
>> numbers.
> 
> (instr_id & 2) makes sense, but the 1 & 2 literals are unnamed criteria
> inferred from the encoding to simplify the code, they don't have an
> explicit meaning (at least in the Intel docs).

I don't follow - if there are no names, you're free to give them
names. I'm sure you and the VMX maintainers can agree on
something suitable.

>> > @@ -259,6 +261,24 @@ struct vm_event_mov_to_msr {
>> >      uint64_t value;
>> >  };
>> >  
>> > +#define VM_EVENT_DESC_INVALID        0
>> 
>> What is this good for?
> 
> The default (uninitialized) value is given a semantic of "invalid" to
> make potential problems due to incorrectly / incompletely initialized
> or corrupted data more obvious

No need to give it a name though, afaics - just start valid values
at 1.

> (I assume the .pad* fields are checked to
> be 0 for the same reason).

No, they're being checked so that later assigning them a meaning
will be possible without breaking backwards compatibility.

Jan


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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-10 15:50 [PATCH] x86/monitor: add support for descriptor access events Vlad Ioan Topan
                   ` (3 preceding siblings ...)
  2017-03-17 11:03 ` Jan Beulich
@ 2017-03-21 12:04 ` Andrew Cooper
  2017-03-28 12:32   ` Vlad-Ioan TOPAN
  4 siblings, 1 reply; 15+ messages in thread
From: Andrew Cooper @ 2017-03-21 12:04 UTC (permalink / raw)
  To: Vlad Ioan Topan, xen-devel
  Cc: Kevin Tian, Tamas K Lengyel, Wei Liu, Suravee Suthikulpanit,
	Razvan Cojocaru, Jun Nakajima, Ian Jackson, Jan Beulich,
	Boris Ostrovsky

On 10/03/17 15:50, Vlad Ioan Topan wrote:
> Adds monitor support for descriptor access events (reads & writes of
> IDTR/GDTR/LDTR/TR) for the x86 architecture (VMX and SVM).
>
> Signed-off-by: Vlad Ioan Topan <itopan@bitdefender.com>

How much extra overhead does this typically give?  (I am curious, more
than anything else)

> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index ccfae4f..cfe5aa2 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -3645,6 +3645,41 @@ gp_fault:
>      return X86EMUL_EXCEPTION;
>  }
>  
> +int hvm_descriptor_access_intercept(uint64_t exit_info, uint64_t exit_qualification, 
> +                                    uint8_t descriptor, bool_t is_write)
> +{
> +    struct vcpu *v = current;
> +    struct domain *d = v->domain;
> +    struct hvm_emulate_ctxt ctxt = {};
> +    int rc;
> +
> +    if ( d->arch.monitor.descriptor_access_enabled )
> +    {
> +        ASSERT(v->arch.vm_event);
> +        hvm_monitor_descriptor_access(exit_info, exit_qualification, descriptor, is_write);
> +    }
> +    else
> +    {
> +        hvm_emulate_init_once(&ctxt, NULL, guest_cpu_user_regs());
> +        rc = hvm_emulate_one(&ctxt);
> +        switch ( rc )
> +        {
> +        case X86EMUL_UNHANDLEABLE:
> +            hvm_inject_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC);
> +            break;
> +        case X86EMUL_EXCEPTION:
> +            if ( ctxt.ctxt.event_pending )

You can drop this if().  The expected behaviour of x86_emulate() makes
this true, and we now have an assertion to catch it being wrong.  (I
should update other areas of code).

> +                hvm_inject_event(&ctxt.ctxt.event);
> +            /* fall through */
> +        default:
> +            hvm_emulate_writeback(&ctxt);
> +            break;
> +        }
> +    }
> +
> +    return X86EMUL_OKAY;
> +}
> +
>  static bool is_cross_vendor(const struct x86_emulate_state *state,
>                              const struct x86_emulate_ctxt *ctxt)
>  {
> diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
> index 894d7d4..2b2d193 100644
> @@ -3369,6 +3384,33 @@ static void vmx_handle_xrstors(void)
>      domain_crash(current->domain);
>  }
>  
> +static void vmx_handle_descriptor_access(uint32_t exit_reason)
> +{
> +    uint8_t instr_id;
> +    uint64_t instr_info;
> +    uint64_t exit_qualification;
> +    uint8_t descriptor = VM_EVENT_DESC_INVALID;
> +
> +    __vmread(EXIT_QUALIFICATION, &exit_qualification);
> +    __vmread(VMX_INSTRUCTION_INFO, &instr_info);

Rather than all this hand decoding, can I ask you to introduce a
structure like ept_qual_t?

~Andrew

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

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

* Re: [PATCH] x86/monitor: add support for descriptor access events
  2017-03-21 12:04 ` Andrew Cooper
@ 2017-03-28 12:32   ` Vlad-Ioan TOPAN
  0 siblings, 0 replies; 15+ messages in thread
From: Vlad-Ioan TOPAN @ 2017-03-28 12:32 UTC (permalink / raw)
  To: Andrew Cooper
  Cc: Kevin Tian, Tamas K Lengyel, Wei Liu, Suravee Suthikulpanit,
	Razvan Cojocaru, Jun Nakajima, Ian Jackson, Jan Beulich,
	xen-devel, Boris Ostrovsky

On Tue, 21 Mar 2017 12:04:02 +0000
Andrew Cooper <andrew.cooper3@citrix.com> wrote:

> On 10/03/17 15:50, Vlad Ioan Topan wrote:
> > Adds monitor support for descriptor access events (reads & writes of
> > IDTR/GDTR/LDTR/TR) for the x86 architecture (VMX and SVM).
> >
> > Signed-off-by: Vlad Ioan Topan <itopan@bitdefender.com>
> 
> How much extra overhead does this typically give?  (I am curious, more
> than anything else)

Without a monitor attached, none at all; with a monitor attached and
with exits activated, there are probably a few hundred exits during
the OS startup process; during normal OS runtime there should be no
descriptor register access.

The other suggestions will be incorporated by my colleagues who will
take over the patch(es).

Thank you,
--
Vlad-Ioan TOPAN
Linux Kernel Development Lead
Bitdefender

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

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

end of thread, other threads:[~2017-03-28 12:32 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-10 15:50 [PATCH] x86/monitor: add support for descriptor access events Vlad Ioan Topan
2017-03-10 19:41 ` Tamas K Lengyel
2017-03-14 12:07   ` Vlad-Ioan TOPAN
2017-03-13 21:24 ` Boris Ostrovsky
2017-03-14 12:15   ` Vlad-Ioan TOPAN
2017-03-14 12:50     ` Razvan Cojocaru
2017-03-14 13:15       ` Boris Ostrovsky
2017-03-16  9:25         ` Vlad-Ioan TOPAN
2017-03-14 13:18     ` Jan Beulich
2017-03-14 12:39 ` Wei Liu
2017-03-17 11:03 ` Jan Beulich
2017-03-20 19:21   ` Vlad-Ioan TOPAN
2017-03-21  8:04     ` Jan Beulich
2017-03-21 12:04 ` Andrew Cooper
2017-03-28 12:32   ` Vlad-Ioan TOPAN

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.