]> xenbits.xensource.com Git - people/tklengyel/xen.git/commitdiff
Add new vmexit vm_event
authorTamas K Lengyel <tamas.lengyel@intel.com>
Fri, 11 Mar 2022 20:43:55 +0000 (20:43 +0000)
committerTamas K Lengyel <tamas@tklengyel.com>
Fri, 25 Mar 2022 16:50:30 +0000 (16:50 +0000)
tools/include/xenctrl.h
tools/libs/ctrl/xc_monitor.c
xen/arch/x86/hvm/monitor.c
xen/arch/x86/hvm/vmx/vmx.c
xen/arch/x86/include/asm/domain.h
xen/arch/x86/include/asm/hvm/monitor.h
xen/arch/x86/include/asm/monitor.h
xen/arch/x86/monitor.c
xen/arch/x86/vm_event.c
xen/include/public/domctl.h
xen/include/public/vm_event.h

index 95bd5eca677f3f1d2b111aafa5a01435544052f6..1df41d6033f20375445a1c755244b271e1538979 100644 (file)
@@ -2096,6 +2096,8 @@ int xc_monitor_privileged_call(xc_interface *xch, uint32_t domain_id,
                                bool enable);
 int xc_monitor_emul_unimplemented(xc_interface *xch, uint32_t domain_id,
                                   bool enable);
+int xc_monitor_vmexit(xc_interface *xch, uint32_t domain_id, bool enable,
+                      bool sync);
 /**
  * This function enables / disables emulation for each REP for a
  * REP-compatible instruction.
index 4ac823e775656ae825138fea71af4392c1d8b5a0..4ef8a1e9aaedbecc1934dc0ecc30ad42849093df 100644 (file)
@@ -246,6 +246,21 @@ int xc_monitor_emul_unimplemented(xc_interface *xch, uint32_t domain_id,
     return do_domctl(xch, &domctl);
 }
 
+int xc_monitor_vmexit(xc_interface *xch, uint32_t domain_id, bool enable,
+                      bool sync)
+{
+    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_VMEXIT;
+    domctl.u.monitor_op.vmexit.sync = sync;
+
+    return do_domctl(xch, &domctl);
+}
+
 /*
  * Local variables:
  * mode: C
index b44a1e1dfee8430ef84a9bf9c84222ba8e4e1323..ea572f91bf43fe4e690a340c858ad4936ba89a9b 100644 (file)
@@ -328,6 +328,32 @@ bool hvm_monitor_check_p2m(unsigned long gla, gfn_t gfn, uint32_t pfec,
     return monitor_traps(curr, true, &req) >= 0;
 }
 
+int hvm_monitor_vmexit(unsigned long exit_reason,
+                       unsigned long exit_qualification)
+{
+   /*
+    * !rc    continue normally
+    * rc     paused waiting for response, work here is done
+    */
+    struct vcpu *curr = current;
+    struct arch_domain *ad = &curr->domain->arch;
+    vm_event_request_t req = {};
+
+    if ( !ad->monitor.vmexit_enabled )
+        return 0;
+
+    req.reason = VM_EVENT_REASON_VMEXIT;
+    req.u.vmexit.reason = exit_reason;
+    req.u.vmexit.qualification = exit_qualification;
+
+    set_npt_base(curr, &req);
+
+    if ( ad->monitor.vmexit_sync )
+        hvm_maybe_deassert_evtchn_irq();
+
+    return monitor_traps(curr, !!ad->monitor.vmexit_sync, &req);
+}
+
 /*
  * Local variables:
  * mode: C
index fa243d01dbe6f11e7b81dc44725b57dec36b2c2b..d61c3d64d378f2adbc88f7a5e1c83e03a159a0e3 100644 (file)
@@ -3959,6 +3959,7 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
     }
 
     __vmread(VM_EXIT_REASON, &exit_reason);
+    __vmread(EXIT_QUALIFICATION, &exit_qualification);
 
     if ( hvm_long_mode_active(v) )
         HVMTRACE_ND(VMEXIT64, 0, 1/*cycles*/, exit_reason,
@@ -3996,6 +3997,9 @@ void vmx_vmexit_handler(struct cpu_user_regs *regs)
     /* Now enable interrupts so it's safe to take locks. */
     local_irq_enable();
 
+    if ( unlikely(hvm_monitor_vmexit(exit_reason, exit_qualification)) )
+        return;
+
     /*
      * If the guest has the ability to switch EPTP without an exit,
      * figure out whether it has done so and update the altp2m data.
index e62e109598014529d642ee5efd0426626287c3a7..855db352c0623a9fe385038533977fe80e0726f0 100644 (file)
@@ -430,6 +430,8 @@ struct arch_domain
          */
         unsigned int inguest_pagefault_disabled                            : 1;
         unsigned int control_register_values                               : 1;
+        unsigned int vmexit_enabled                                        : 1;
+        unsigned int vmexit_sync                                           : 1;
         struct monitor_msr_bitmap *msr_bitmap;
         uint64_t write_ctrlreg_mask[4];
     } monitor;
index a75cd8545cef8a9b6ec2ed1048a7dadd0ac1158d..639f6dfa374cf18b9f9088bd45007c1962eb452f 100644 (file)
@@ -51,6 +51,8 @@ bool hvm_monitor_emul_unimplemented(void);
 
 bool hvm_monitor_check_p2m(unsigned long gla, gfn_t gfn, uint32_t pfec,
                            uint16_t kind);
+int hvm_monitor_vmexit(unsigned long exit_reason,
+                       unsigned long exit_qualification);
 
 #endif /* __ASM_X86_HVM_MONITOR_H__ */
 
index 01c6d63bb9c9e9a01528103fbd5f7c640bdac54d..d8d54c5f23d691fd1af049680552b11fd7b2267f 100644 (file)
@@ -89,7 +89,8 @@ static inline uint32_t arch_monitor_get_capabilities(struct domain *d)
                     (1U << XEN_DOMCTL_MONITOR_EVENT_DEBUG_EXCEPTION) |
                     (1U << XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG) |
                     (1U << XEN_DOMCTL_MONITOR_EVENT_EMUL_UNIMPLEMENTED) |
-                    (1U << XEN_DOMCTL_MONITOR_EVENT_INGUEST_PAGEFAULT));
+                    (1U << XEN_DOMCTL_MONITOR_EVENT_INGUEST_PAGEFAULT) |
+                    (1U << XEN_DOMCTL_MONITOR_EVENT_VMEXIT));
 
     if ( hvm_is_singlestep_supported() )
         capabilities |= (1U << XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP);
index 3079726a8bb02bb0945339b920003ea7e11b4272..30ca71432c0b822dea660b7ee391b79ed2951f76 100644 (file)
@@ -332,6 +332,20 @@ int arch_monitor_domctl_event(struct domain *d,
         break;
     }
 
+    case XEN_DOMCTL_MONITOR_EVENT_VMEXIT:
+    {
+        bool old_status = ad->monitor.vmexit_enabled;
+
+        if ( unlikely(old_status == requested_status) )
+            return -EEXIST;
+
+        domain_pause(d);
+        ad->monitor.vmexit_enabled = requested_status;
+        ad->monitor.vmexit_sync = mop->u.vmexit.sync;
+        domain_unpause(d);
+        break;
+    }
+
     default:
         /*
          * Should not be reached unless arch_monitor_get_capabilities() is
index 7027c08a926b3a9be0f296c56f7be5d4de537058..c623bb311712a37825ced8e94ed37e8396a26223 100644 (file)
@@ -21,6 +21,7 @@
 #include <xen/sched.h>
 #include <xen/mem_access.h>
 #include <asm/vm_event.h>
+#include <asm/mem_sharing.h>
 
 /* Implicitly serialized by the domctl lock. */
 int vm_event_init_domain(struct domain *d)
index b85e6170b0aa9ca104b70cc59ef02fdd5c637946..4803ed7afc538d36581ece5d9d82082d0b3b3144 100644 (file)
@@ -1057,6 +1057,7 @@ struct xen_domctl_psr_cmt_op {
 #define XEN_DOMCTL_MONITOR_EVENT_EMUL_UNIMPLEMENTED    10
 /* Enabled by default */
 #define XEN_DOMCTL_MONITOR_EVENT_INGUEST_PAGEFAULT     11
+#define XEN_DOMCTL_MONITOR_EVENT_VMEXIT                12
 
 struct xen_domctl_monitor_op {
     uint32_t op; /* XEN_DOMCTL_MONITOR_OP_* */
@@ -1107,6 +1108,11 @@ struct xen_domctl_monitor_op {
             /* Pause vCPU until response */
             uint8_t sync;
         } debug_exception;
+
+        struct {
+            /* Send event and don't process vmexit */
+            uint8_t sync;
+        } vmexit;
     } u;
 };
 
index bb003d21d078a431796e6121d3d48f4cf3f042cb..d443a2486296bca4d45fa674682e3231df3bfa26 100644 (file)
 #define VM_EVENT_REASON_DESCRIPTOR_ACCESS       13
 /* Current instruction is not implemented by the emulator */
 #define VM_EVENT_REASON_EMUL_UNIMPLEMENTED      14
+/* VMEXIT */
+#define VM_EVENT_REASON_VMEXIT                  15
 
 /* Supported values for the vm_event_write_ctrlreg index. */
 #define VM_EVENT_X86_CR0    0
@@ -386,6 +388,11 @@ struct vm_event_emul_insn_data {
     uint8_t data[16]; /* Has to be completely filled */
 };
 
+struct vm_event_vmexit {
+    uint64_t reason;
+    uint64_t qualification;
+};
+
 typedef struct vm_event_st {
     uint32_t version;   /* VM_EVENT_INTERFACE_VERSION */
     uint32_t flags;     /* VM_EVENT_FLAG_* */
@@ -406,6 +413,7 @@ typedef struct vm_event_st {
         struct vm_event_debug                 software_breakpoint;
         struct vm_event_debug                 debug_exception;
         struct vm_event_cpuid                 cpuid;
+        struct vm_event_vmexit                vmexit;
         union {
             struct vm_event_interrupt_x86     x86;
         } interrupt;