Re: [Xen-devel] [PATCH v5] x86/monitor: Notify monitor if an emulation fails.

2017-07-18 Thread Paul Durrant
> -Original Message-
> From: Petre Pircalabu [mailto:ppircal...@bitdefender.com]
> Sent: 17 July 2017 17:47
> To: xen-devel@lists.xen.org
> Cc: rcojoc...@bitdefender.com; ta...@tklengyel.com; Ian Jackson
> ; Wei Liu ; Paul Durrant
> ; jbeul...@suse.com; Andrew Cooper
> ; Petre Pircalabu
> 
> Subject: [PATCH v5] x86/monitor: Notify monitor if an emulation fails.
> 
> If case of a vm_event with the emulate_flags set, if the instruction
> cannot be emulated, the monitor should be notified instead of directly
> injecting a hw exception.
> This behavior can be used to re-execute an instruction not supported by
> the emulator using the real processor (e.g. altp2m) instead of just
> crashing.
> 
> Signed-off-by: Petre Pircalabu 
> 
> ---
> Changed since v1:
>   * Removed the emulation kind check when calling
> hvm_inject_hw_exception
> 
> Changed since v2:
>   * Removed a file added by mistake
> 
> Changed since v3:
>   * Removed extra stray line
>   * Added the _enabled suffix to the emul_unhandleable monitor option
> 
> Changed since v4
>   * Fixed return expression of hvm_monitor_emul_unhandleable handle
>   monitor_traps failures.
>   * Removed stray parantheses.
> ---
>  tools/libxc/include/xenctrl.h |  2 ++
>  tools/libxc/xc_monitor.c  | 14 ++
>  xen/arch/x86/hvm/emulate.c|  7 ++-
>  xen/arch/x86/hvm/monitor.c| 17 +
>  xen/arch/x86/monitor.c| 12 
>  xen/include/asm-x86/domain.h  |  1 +
>  xen/include/asm-x86/hvm/monitor.h |  1 +
>  xen/include/asm-x86/monitor.h |  3 ++-
>  xen/include/public/domctl.h   |  1 +
>  xen/include/public/vm_event.h |  2 ++
>  10 files changed, 58 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
> index c51bb3b..8deb5ac 100644
> --- a/tools/libxc/include/xenctrl.h
> +++ b/tools/libxc/include/xenctrl.h
> @@ -2029,6 +2029,8 @@ int xc_monitor_debug_exceptions(xc_interface
> *xch, domid_t domain_id,
>  int xc_monitor_cpuid(xc_interface *xch, domid_t domain_id, bool enable);
>  int xc_monitor_privileged_call(xc_interface *xch, domid_t domain_id,
> bool enable);
> +int xc_monitor_emul_unhandleable(xc_interface *xch, domid_t
> domain_id,
> + bool enable);
>  /**
>   * This function enables / disables emulation for each REP for a
>   * REP-compatible instruction.
> diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
> index b44ce93..8e72c6c 100644
> --- a/tools/libxc/xc_monitor.c
> +++ b/tools/libxc/xc_monitor.c
> @@ -216,6 +216,20 @@ int xc_monitor_privileged_call(xc_interface *xch,
> domid_t domain_id,
>  return do_domctl(xch, );
>  }
> 
> +int xc_monitor_emul_unhandleable(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_EMUL_UNHANDLEABLE;
> +
> +return do_domctl(xch, );
> +}
> +
>  /*
>   * Local variables:
>   * mode: C
> diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
> index b2068ad..e1177f8 100644
> --- a/xen/arch/x86/hvm/emulate.c
> +++ b/xen/arch/x86/hvm/emulate.c
> @@ -14,12 +14,14 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -2104,7 +2106,10 @@ void hvm_emulate_one_vm_event(enum
> emul_kind kind, unsigned int trapnr,
>  return;
>  case X86EMUL_UNHANDLEABLE:
>  hvm_dump_emulation_state(XENLOG_G_DEBUG, "Mem event", );
> -hvm_inject_hw_exception(trapnr, errcode);
> +if ( hvm_monitor_emul_unhandleable() )
> +return;
> +else

Unnecessary else.

> +hvm_inject_hw_exception(trapnr, errcode);
>  break;
>  case X86EMUL_EXCEPTION:
>  hvm_inject_event();
> diff --git a/xen/arch/x86/hvm/monitor.c b/xen/arch/x86/hvm/monitor.c
> index a7ccfc4..e77b05e 100644
> --- a/xen/arch/x86/hvm/monitor.c
> +++ b/xen/arch/x86/hvm/monitor.c
> @@ -57,6 +57,23 @@ bool_t hvm_monitor_cr(unsigned int index, unsigned
> long value, unsigned long old
>  return 0;
>  }
> 
> +bool hvm_monitor_emul_unhandleable(void)
> +{
> +struct vcpu *curr = current;
> +
> +/*
> + * Send a vm_event to the monitor to signal that the current
> + * instruction couldn't be emulated.
> + */
> +vm_event_request_t req = {
> +.reason = VM_EVENT_REASON_EMUL_UNHANDLEABLE,
> +.vcpu_id  = curr->vcpu_id,

[Xen-devel] [PATCH v5] x86/monitor: Notify monitor if an emulation fails.

2017-07-17 Thread Petre Pircalabu
If case of a vm_event with the emulate_flags set, if the instruction
cannot be emulated, the monitor should be notified instead of directly
injecting a hw exception.
This behavior can be used to re-execute an instruction not supported by
the emulator using the real processor (e.g. altp2m) instead of just
crashing.

Signed-off-by: Petre Pircalabu 

---
Changed since v1:
  * Removed the emulation kind check when calling hvm_inject_hw_exception

Changed since v2:
  * Removed a file added by mistake

Changed since v3:
  * Removed extra stray line
  * Added the _enabled suffix to the emul_unhandleable monitor option

Changed since v4
  * Fixed return expression of hvm_monitor_emul_unhandleable handle
  monitor_traps failures.
  * Removed stray parantheses.
---
 tools/libxc/include/xenctrl.h |  2 ++
 tools/libxc/xc_monitor.c  | 14 ++
 xen/arch/x86/hvm/emulate.c|  7 ++-
 xen/arch/x86/hvm/monitor.c| 17 +
 xen/arch/x86/monitor.c| 12 
 xen/include/asm-x86/domain.h  |  1 +
 xen/include/asm-x86/hvm/monitor.h |  1 +
 xen/include/asm-x86/monitor.h |  3 ++-
 xen/include/public/domctl.h   |  1 +
 xen/include/public/vm_event.h |  2 ++
 10 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index c51bb3b..8deb5ac 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2029,6 +2029,8 @@ int xc_monitor_debug_exceptions(xc_interface *xch, 
domid_t domain_id,
 int xc_monitor_cpuid(xc_interface *xch, domid_t domain_id, bool enable);
 int xc_monitor_privileged_call(xc_interface *xch, domid_t domain_id,
bool enable);
+int xc_monitor_emul_unhandleable(xc_interface *xch, domid_t domain_id,
+ bool enable);
 /**
  * This function enables / disables emulation for each REP for a
  * REP-compatible instruction.
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index b44ce93..8e72c6c 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -216,6 +216,20 @@ int xc_monitor_privileged_call(xc_interface *xch, domid_t 
domain_id,
 return do_domctl(xch, );
 }
 
+int xc_monitor_emul_unhandleable(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_EMUL_UNHANDLEABLE;
+
+return do_domctl(xch, );
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index b2068ad..e1177f8 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -14,12 +14,14 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2104,7 +2106,10 @@ void hvm_emulate_one_vm_event(enum emul_kind kind, 
unsigned int trapnr,
 return;
 case X86EMUL_UNHANDLEABLE:
 hvm_dump_emulation_state(XENLOG_G_DEBUG, "Mem event", );
-hvm_inject_hw_exception(trapnr, errcode);
+if ( hvm_monitor_emul_unhandleable() )
+return;
+else
+hvm_inject_hw_exception(trapnr, errcode);
 break;
 case X86EMUL_EXCEPTION:
 hvm_inject_event();
diff --git a/xen/arch/x86/hvm/monitor.c b/xen/arch/x86/hvm/monitor.c
index a7ccfc4..e77b05e 100644
--- a/xen/arch/x86/hvm/monitor.c
+++ b/xen/arch/x86/hvm/monitor.c
@@ -57,6 +57,23 @@ bool_t hvm_monitor_cr(unsigned int index, unsigned long 
value, unsigned long old
 return 0;
 }
 
+bool hvm_monitor_emul_unhandleable(void)
+{
+struct vcpu *curr = current;
+
+/*
+ * Send a vm_event to the monitor to signal that the current
+ * instruction couldn't be emulated.
+ */
+vm_event_request_t req = {
+.reason = VM_EVENT_REASON_EMUL_UNHANDLEABLE,
+.vcpu_id  = curr->vcpu_id,
+};
+
+return curr->domain->arch.monitor.emul_unhandleable_enabled &&
+monitor_traps(curr, true, ) == 1;
+}
+
 void hvm_monitor_msr(unsigned int msr, uint64_t value)
 {
 struct vcpu *curr = current;
diff --git a/xen/arch/x86/monitor.c b/xen/arch/x86/monitor.c
index 706454f..f791372 100644
--- a/xen/arch/x86/monitor.c
+++ b/xen/arch/x86/monitor.c
@@ -283,6 +283,18 @@ int arch_monitor_domctl_event(struct domain *d,
 break;
 }
 
+case XEN_DOMCTL_MONITOR_EVENT_EMUL_UNHANDLEABLE:
+{
+bool old_status = ad->monitor.emul_unhandleable_enabled;
+if ( unlikely(old_status == requested_status) )
+return -EEXIST;
+
+domain_pause(d);
+ad->monitor.emul_unhandleable_enabled = requested_status;
+