[Xen-devel] [PATCH v1] x86/mm: Supresses vm_events caused by page-walks

2017-10-30 Thread Alexandru Isaila
This patch is adding a way to enable/disable nested pagefault
events. It introduces the xc_monitor_nested_pagefault function
and adds the nested_pagefault_disabled in the monitor structure.
This is needed by the introspection so it will only get gla
faults and not get spammed with other faults.
In p2m_set_ad_bits the v->arch.sse_pg_dirty.eip and
v->arch.sse_pg_dirty.gla are used to mark that this is the
second time a fault occurs and the dirty bit is set.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>
---
 tools/libxc/include/xenctrl.h |  2 ++
 tools/libxc/xc_monitor.c  | 14 ++
 xen/arch/x86/mm/mem_access.c  | 27 +++
 xen/arch/x86/monitor.c| 13 +
 xen/include/asm-x86/domain.h  |  6 ++
 xen/include/asm-x86/monitor.h |  3 ++-
 xen/include/public/domctl.h   |  1 +
 7 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 666db0b..8e70714 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2056,6 +2056,8 @@ int xc_monitor_descriptor_access(xc_interface *xch, 
uint32_t domain_id,
  bool enable);
 int xc_monitor_guest_request(xc_interface *xch, uint32_t domain_id,
  bool enable, bool sync, bool allow_userspace);
+int xc_monitor_nested_pagefault(xc_interface *xch, uint32_t domain_id,
+bool disable);
 int xc_monitor_debug_exceptions(xc_interface *xch, uint32_t domain_id,
 bool enable, bool sync);
 int xc_monitor_cpuid(xc_interface *xch, uint32_t domain_id, bool enable);
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index 2840f14..5aacaa8 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -162,6 +162,20 @@ int xc_monitor_guest_request(xc_interface *xch, uint32_t 
domain_id, bool enable,
 return do_domctl(xch, );
 }
 
+int xc_monitor_nested_pagefault(xc_interface *xch, uint32_t domain_id,
+bool disable)
+{
+DECLARE_DOMCTL;
+
+domctl.cmd = XEN_DOMCTL_monitor_op;
+domctl.domain = domain_id;
+domctl.u.monitor_op.op = disable ? XEN_DOMCTL_MONITOR_OP_ENABLE
+: XEN_DOMCTL_MONITOR_OP_DISABLE;
+domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_NESTED_PAGEFAULT;
+
+return do_domctl(xch, );
+}
+
 int xc_monitor_emulate_each_rep(xc_interface *xch, uint32_t domain_id,
 bool enable)
 {
diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
index c0cd017..07a334b 100644
--- a/xen/arch/x86/mm/mem_access.c
+++ b/xen/arch/x86/mm/mem_access.c
@@ -137,6 +137,23 @@ bool p2m_mem_access_emulate_check(struct vcpu *v,
 return violation;
 }
 
+static void p2m_set_ad_bits(struct vcpu *v, paddr_t ga)
+{
+struct hvm_hw_cpu ctxt;
+uint32_t pfec = 0;
+
+hvm_funcs.save_cpu_ctxt(v, );
+
+if ( guest_cpu_user_regs()->eip == v->arch.pg_dirty.eip
+ && ga == v->arch.pg_dirty.gla )
+pfec = PFEC_write_access;
+
+paging_ga_to_gfn_cr3(v, ctxt.cr3, ga, , NULL);
+
+v->arch.pg_dirty.eip = guest_cpu_user_regs()->eip;
+v->arch.pg_dirty.gla = ga;
+}
+
 bool p2m_mem_access_check(paddr_t gpa, unsigned long gla,
   struct npfec npfec,
   vm_event_request_t **req_ptr)
@@ -208,6 +225,16 @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla,
 }
 }
 
+if ( vm_event_check_ring(d->vm_event_monitor) &&
+ d->arch.monitor.nested_pagefault_disabled &&
+ npfec.kind != npfec_kind_with_gla ) /* don't send a mem_event */
+{
+v->arch.vm_event->emulate_flags = 0;
+p2m_set_ad_bits(v, gla);
+
+return true;
+}
+
 *req_ptr = NULL;
 req = xzalloc(vm_event_request_t);
 if ( req )
diff --git a/xen/arch/x86/monitor.c b/xen/arch/x86/monitor.c
index e59f1f5..3916e76 100644
--- a/xen/arch/x86/monitor.c
+++ b/xen/arch/x86/monitor.c
@@ -220,6 +220,19 @@ int arch_monitor_domctl_event(struct domain *d,
 break;
 }
 
+case XEN_DOMCTL_MONITOR_EVENT_NESTED_PAGEFAULT:
+{
+bool old_status = ad->monitor.nested_pagefault_disabled;
+
+if ( unlikely(old_status == requested_status) )
+return -EEXIST;
+
+domain_pause(d);
+ad->monitor.nested_pagefault_disabled = requested_status;
+domain_unpause(d);
+break;
+}
+
 case XEN_DOMCTL_MONITOR_EVENT_DESC_ACCESS:
 {
 bool old_status = ad->monitor.descriptor_access_enabled;
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index 4d0b77d..40a365f 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -408,6 +408,7 @@ struct arch_domain
 unsigned int descr

[Xen-devel] [PATCH v2] x86/hvm: Add MSR old value

2017-10-13 Thread Alexandru Isaila
This patch adds the old value param and the onchangeonly option
to the VM_EVENT_REASON_MOV_TO_MSR event.

The param was added to the vm_event_mov_to_msr struct and to the
hvm_monitor_msr function. Finally I've changed the bool_t param
to a bool for the hvm_msr_write_intercept function.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>
Acked-by: Tamas K Lengyel <ta...@tklengyel.com>

---
Changes since V1:
- Removed Stray blanks inside the inner parentheses
- Added space after the if statement
- Added * 8 to the set/clear/test_bit statements
- Removed the blank line after monitored_msr.
---
 tools/libxc/include/xenctrl.h |  2 +-
 tools/libxc/xc_monitor.c  |  3 ++-
 xen/arch/x86/hvm/hvm.c| 10 --
 xen/arch/x86/hvm/monitor.c|  9 ++---
 xen/arch/x86/monitor.c| 26 +++---
 xen/include/asm-x86/hvm/monitor.h |  2 +-
 xen/include/asm-x86/hvm/support.h |  2 +-
 xen/include/asm-x86/monitor.h |  1 +
 xen/include/public/domctl.h   |  2 ++
 xen/include/public/vm_event.h |  5 +++--
 10 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 3bcab3c..b99d6eb 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2048,7 +2048,7 @@ int xc_monitor_write_ctrlreg(xc_interface *xch, domid_t 
domain_id,
  * non-architectural indices.
  */
 int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id, uint32_t msr,
-  bool enable);
+  bool enable, bool onchangeonly);
 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);
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index 6046680..09d04be 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -90,7 +90,7 @@ int xc_monitor_write_ctrlreg(xc_interface *xch, domid_t 
domain_id,
 }
 
 int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id, uint32_t msr,
-  bool enable)
+  bool enable, bool onchangeonly)
 {
 DECLARE_DOMCTL;
 
@@ -100,6 +100,7 @@ int xc_monitor_mov_to_msr(xc_interface *xch, domid_t 
domain_id, uint32_t msr,
 : XEN_DOMCTL_MONITOR_OP_DISABLE;
 domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR;
 domctl.u.monitor_op.u.mov_to_msr.msr = msr;
+domctl.u.monitor_op.u.mov_to_msr.onchangeonly = onchangeonly;
 
 return do_domctl(xch, );
 }
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 205b4cb..0238787 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -3489,7 +3489,7 @@ int hvm_msr_read_intercept(unsigned int msr, uint64_t 
*msr_content)
 }
 
 int hvm_msr_write_intercept(unsigned int msr, uint64_t msr_content,
-bool_t may_defer)
+bool may_defer)
 {
 struct vcpu *v = current;
 struct domain *d = v->domain;
@@ -3500,6 +3500,12 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t 
msr_content,
 
 if ( may_defer && unlikely(monitored_msr(v->domain, msr)) )
 {
+uint64_t msr_old_content;
+
+ret = hvm_msr_read_intercept(msr, _old_content);
+if ( ret != X86EMUL_OKAY )
+return ret;
+
 ASSERT(v->arch.vm_event);
 
 /* The actual write will occur in hvm_do_resume() (if permitted). */
@@ -3507,7 +3513,7 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t 
msr_content,
 v->arch.vm_event->write_data.msr = msr;
 v->arch.vm_event->write_data.value = msr_content;
 
-hvm_monitor_msr(msr, msr_content);
+hvm_monitor_msr(msr, msr_content, msr_old_content);
 return X86EMUL_OKAY;
 }
 
diff --git a/xen/arch/x86/hvm/monitor.c b/xen/arch/x86/hvm/monitor.c
index 4ce778c..131b852 100644
--- a/xen/arch/x86/hvm/monitor.c
+++ b/xen/arch/x86/hvm/monitor.c
@@ -74,16 +74,19 @@ bool hvm_monitor_emul_unimplemented(void)
 monitor_traps(curr, true, ) == 1;
 }
 
-void hvm_monitor_msr(unsigned int msr, uint64_t value)
+void hvm_monitor_msr(unsigned int msr, uint64_t new_value, uint64_t old_value)
 {
 struct vcpu *curr = current;
 
-if ( monitored_msr(curr->domain, msr) )
+if ( monitored_msr(curr->domain, msr) &&
+ (!monitored_msr_onchangeonly(curr->domain, msr) ||
+   new_value != old_value) )
 {
 vm_event_request_t req = {
 .reason = VM_EVENT_REASON_MOV_TO_MSR,
 .u.mov_to_msr.msr = msr,
-.u.mov_to_msr.value = value,
+.u.mov_to_msr.new_value = new_value,
+.u.mov_to_msr.old_value = old_value
 };
 
 monitor_traps(curr, 1, );
diff --git a/xen/arch/x86

[Xen-devel] [PATCH v1] x86/hvm: Add MSR old value

2017-10-12 Thread Alexandru Isaila
This patch adds the old value param and the onchangeonly option
to the VM_EVENT_REASON_MOV_TO_MSR event.

The param was added to the vm_event_mov_to_msr struct and to the
hvm_monitor_msr function. Finally I've changed the bool_t param
to a bool for the hvm_msr_write_intercept function.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>
---
 tools/libxc/include/xenctrl.h |  2 +-
 tools/libxc/xc_monitor.c  |  3 ++-
 xen/arch/x86/hvm/hvm.c| 10 --
 xen/arch/x86/hvm/monitor.c|  9 ++---
 xen/arch/x86/monitor.c| 26 +++---
 xen/include/asm-x86/hvm/monitor.h |  2 +-
 xen/include/asm-x86/hvm/support.h |  2 +-
 xen/include/asm-x86/monitor.h |  2 ++
 xen/include/public/domctl.h   |  2 ++
 xen/include/public/vm_event.h |  5 +++--
 10 files changed, 49 insertions(+), 14 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 3bcab3c..b99d6eb 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2048,7 +2048,7 @@ int xc_monitor_write_ctrlreg(xc_interface *xch, domid_t 
domain_id,
  * non-architectural indices.
  */
 int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id, uint32_t msr,
-  bool enable);
+  bool enable, bool onchangeonly);
 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);
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index 6046680..09d04be 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -90,7 +90,7 @@ int xc_monitor_write_ctrlreg(xc_interface *xch, domid_t 
domain_id,
 }
 
 int xc_monitor_mov_to_msr(xc_interface *xch, domid_t domain_id, uint32_t msr,
-  bool enable)
+  bool enable, bool onchangeonly)
 {
 DECLARE_DOMCTL;
 
@@ -100,6 +100,7 @@ int xc_monitor_mov_to_msr(xc_interface *xch, domid_t 
domain_id, uint32_t msr,
 : XEN_DOMCTL_MONITOR_OP_DISABLE;
 domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR;
 domctl.u.monitor_op.u.mov_to_msr.msr = msr;
+domctl.u.monitor_op.u.mov_to_msr.onchangeonly = onchangeonly;
 
 return do_domctl(xch, );
 }
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 205b4cb..0238787 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -3489,7 +3489,7 @@ int hvm_msr_read_intercept(unsigned int msr, uint64_t 
*msr_content)
 }
 
 int hvm_msr_write_intercept(unsigned int msr, uint64_t msr_content,
-bool_t may_defer)
+bool may_defer)
 {
 struct vcpu *v = current;
 struct domain *d = v->domain;
@@ -3500,6 +3500,12 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t 
msr_content,
 
 if ( may_defer && unlikely(monitored_msr(v->domain, msr)) )
 {
+uint64_t msr_old_content;
+
+ret = hvm_msr_read_intercept(msr, _old_content);
+if ( ret != X86EMUL_OKAY )
+return ret;
+
 ASSERT(v->arch.vm_event);
 
 /* The actual write will occur in hvm_do_resume() (if permitted). */
@@ -3507,7 +3513,7 @@ int hvm_msr_write_intercept(unsigned int msr, uint64_t 
msr_content,
 v->arch.vm_event->write_data.msr = msr;
 v->arch.vm_event->write_data.value = msr_content;
 
-hvm_monitor_msr(msr, msr_content);
+hvm_monitor_msr(msr, msr_content, msr_old_content);
 return X86EMUL_OKAY;
 }
 
diff --git a/xen/arch/x86/hvm/monitor.c b/xen/arch/x86/hvm/monitor.c
index 4ce778c..74f83b4 100644
--- a/xen/arch/x86/hvm/monitor.c
+++ b/xen/arch/x86/hvm/monitor.c
@@ -74,16 +74,19 @@ bool hvm_monitor_emul_unimplemented(void)
 monitor_traps(curr, true, ) == 1;
 }
 
-void hvm_monitor_msr(unsigned int msr, uint64_t value)
+void hvm_monitor_msr(unsigned int msr, uint64_t new_value, uint64_t old_value)
 {
 struct vcpu *curr = current;
 
-if ( monitored_msr(curr->domain, msr) )
+if ( monitored_msr(curr->domain, msr) &&
+ ( !monitored_msr_onchangeonly(curr->domain, msr) ||
+   new_value != old_value ) )
 {
 vm_event_request_t req = {
 .reason = VM_EVENT_REASON_MOV_TO_MSR,
 .u.mov_to_msr.msr = msr,
-.u.mov_to_msr.value = value,
+.u.mov_to_msr.new_value = new_value,
+.u.mov_to_msr.old_value = old_value
 };
 
 monitor_traps(curr, 1, );
diff --git a/xen/arch/x86/monitor.c b/xen/arch/x86/monitor.c
index e59f1f5..a3046c6 100644
--- a/xen/arch/x86/monitor.c
+++ b/xen/arch/x86/monitor.c
@@ -25,7 +25,7 @@
 int arch_monitor_init_domain(struct domain *d)
 {
 if ( !d->arch.monitor.msr_bitmap )
-d->arch.monitor.msr_bitmap = xzalloc(struc

[Xen-devel] [PATCH v9] x86/hvm: Implement hvmemul_write() using real mappings

2017-10-09 Thread Alexandru Isaila
From: Andrew Cooper <andrew.coop...@citrix.com>

An access which crosses a page boundary is performed atomically by x86
hardware, albeit with a severe performance penalty.  An important corner case
is when a straddled access hits two pages which differ in whether a
translation exists, or in net access rights.

The use of hvm_copy*() in hvmemul_write() is problematic, because it performs
a translation then completes the partial write, before moving onto the next
translation.

If an individual emulated write straddles two pages, the first of which is
writable, and the second of which is not, the first half of the write will
complete before #PF is raised from the second half.

This results in guest state corruption as a side effect of emulation, which
has been observed to cause windows to crash while under introspection.

Introduce the hvmemul_{,un}map_linear_addr() helpers, which translate an
entire contents of a linear access, and vmap() the underlying frames to
provide a contiguous virtual mapping for the emulator to use.  This is the
same mechanism as used by the shadow emulation code.

This will catch any translation issues and abort the emulation before any
modifications occur.

Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com>
Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V8:
- Removed comment
- Changed the addr formula
- Added blank space in the for statement.

Note: Tested with win32/64 and ubuntu64 guests.
---
 xen/arch/x86/hvm/emulate.c| 179 ++
 xen/include/asm-x86/hvm/emulate.h |   7 ++
 2 files changed, 170 insertions(+), 16 deletions(-)

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index cc874ce..957fc46 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -498,6 +498,160 @@ static int hvmemul_do_mmio_addr(paddr_t mmio_gpa,
 }
 
 /*
+ * Map the frame(s) covering an individual linear access, for writeable
+ * access.  May return NULL for MMIO, or ERR_PTR(~X86EMUL_*) for other errors
+ * including ERR_PTR(~X86EMUL_OKAY) for write-discard mappings.
+ *
+ * In debug builds, map() checks that each slot in hvmemul_ctxt->mfn[] is
+ * clean before use, and poisions unused slots with INVALID_MFN.
+ */
+static void *hvmemul_map_linear_addr(
+unsigned long linear, unsigned int bytes, uint32_t pfec,
+struct hvm_emulate_ctxt *hvmemul_ctxt)
+{
+struct vcpu *curr = current;
+void *err, *mapping;
+unsigned int nr_frames = ((linear + bytes - !!bytes) >> PAGE_SHIFT) -
+(linear >> PAGE_SHIFT) + 1;
+unsigned int i;
+
+/*
+ * mfn points to the next free slot.  All used slots have a page reference
+ * held on them.
+ */
+mfn_t *mfn = _ctxt->mfn[0];
+
+/*
+ * The caller has no legitimate reason for trying a zero-byte write, but
+ * final is calculate to fail safe in release builds.
+ *
+ * The maximum write size depends on the number of adjacent mfns[] which
+ * can be vmap()'d, accouting for possible misalignment within the region.
+ * The higher level emulation callers are responsible for ensuring that
+ * mfns[] is large enough for the requested write size.
+ */
+if ( bytes == 0 ||
+ nr_frames > ARRAY_SIZE(hvmemul_ctxt->mfn) )
+{
+ASSERT_UNREACHABLE();
+printk("goto unhandle ERROR~!~~\n");
+goto unhandleable;
+}
+
+for ( i = 0; i < nr_frames; i++ )
+{
+enum hvm_translation_result res;
+struct page_info *page;
+pagefault_info_t pfinfo;
+p2m_type_t p2mt;
+unsigned long addr = i ? (linear + (i << PAGE_SHIFT)) & PAGE_MASK : 
linear;
+
+if ( hvmemul_ctxt->ctxt.addr_size < 64 )
+addr = (uint32_t)addr;
+
+/* Error checking.  Confirm that the current slot is clean. */
+ASSERT(mfn_x(*mfn) == 0);
+
+res = hvm_translate_get_page(curr, addr, true, pfec,
+ , , NULL, );
+
+switch ( res )
+{
+case HVMTRANS_okay:
+break;
+
+case HVMTRANS_bad_linear_to_gfn:
+x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
+err = ERR_PTR(~X86EMUL_EXCEPTION);
+goto out;
+
+case HVMTRANS_bad_gfn_to_mfn:
+err = NULL;
+goto out;
+
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
+err = ERR_PTR(~X86EMUL_RETRY);
+goto out;
+
+default:
+goto unhandleable;
+}
+
+*mfn++ = _mfn(page_to_mfn(page));
+
+if ( p2m_is_discard_write(p2mt) )
+{
+err = ERR_PTR(~X86EMUL_OKAY);
+goto out;
+}
+}
+
+/* Entire access within a single frame? */
+if ( nr_frames == 1 )
+mapping = map_domain_page(hvmemul_ctxt->mfn[0]

[Xen-devel] [PATCH RFC v2] x86/domctl: Don't pause the whole domain if only getting vcpu state

2017-10-06 Thread Alexandru Isaila
This patch adds the hvm_save_one_cpu_ctxt() function.
It optimizes by only pausing the vcpu on all HVMSR_PER_VCPU save
callbacks where only data for one VCPU is required.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V1:
- Integrated the vcpu check into all the save callbacks
---
 tools/tests/vhpet/emul.h   |   3 +-
 tools/tests/vhpet/main.c   |   2 +-
 xen/arch/x86/cpu/mcheck/vmce.c |  16 ++-
 xen/arch/x86/domctl.c  |   2 -
 xen/arch/x86/hvm/hpet.c|   2 +-
 xen/arch/x86/hvm/hvm.c | 280 ++---
 xen/arch/x86/hvm/i8254.c   |   2 +-
 xen/arch/x86/hvm/irq.c |   6 +-
 xen/arch/x86/hvm/mtrr.c|  32 -
 xen/arch/x86/hvm/pmtimer.c |   2 +-
 xen/arch/x86/hvm/rtc.c |   2 +-
 xen/arch/x86/hvm/save.c|  71 ---
 xen/arch/x86/hvm/vioapic.c |   2 +-
 xen/arch/x86/hvm/viridian.c|  17 ++-
 xen/arch/x86/hvm/vlapic.c  |  23 +++-
 xen/arch/x86/hvm/vpic.c|   2 +-
 xen/include/asm-x86/hvm/hvm.h  |   2 +
 xen/include/asm-x86/hvm/save.h |   5 +-
 18 files changed, 324 insertions(+), 147 deletions(-)

diff --git a/tools/tests/vhpet/emul.h b/tools/tests/vhpet/emul.h
index 383acff..99d5bbd 100644
--- a/tools/tests/vhpet/emul.h
+++ b/tools/tests/vhpet/emul.h
@@ -296,7 +296,8 @@ struct hvm_hw_hpet
 };
 
 typedef int (*hvm_save_handler)(struct domain *d,
-hvm_domain_context_t *h);
+hvm_domain_context_t *h,
+unsigned int instance);
 typedef int (*hvm_load_handler)(struct domain *d,
 hvm_domain_context_t *h);
 
diff --git a/tools/tests/vhpet/main.c b/tools/tests/vhpet/main.c
index 6fe65ea..3d8e7f5 100644
--- a/tools/tests/vhpet/main.c
+++ b/tools/tests/vhpet/main.c
@@ -177,7 +177,7 @@ void __init hvm_register_savevm(uint16_t typecode,
 
 int do_save(uint16_t typecode, struct domain *d, hvm_domain_context_t *h)
 {
-return hvm_sr_handlers[typecode].save(d, h);
+return hvm_sr_handlers[typecode].save(d, h, d->max_vcpus);
 }
 
 int do_load(uint16_t typecode, struct domain *d, hvm_domain_context_t *h)
diff --git a/xen/arch/x86/cpu/mcheck/vmce.c b/xen/arch/x86/cpu/mcheck/vmce.c
index e07cd2f..a1a12a5 100644
--- a/xen/arch/x86/cpu/mcheck/vmce.c
+++ b/xen/arch/x86/cpu/mcheck/vmce.c
@@ -349,12 +349,24 @@ int vmce_wrmsr(uint32_t msr, uint64_t val)
 return ret;
 }
 
-static int vmce_save_vcpu_ctxt(struct domain *d, hvm_domain_context_t *h)
+static int vmce_save_vcpu_ctxt(struct domain *d, hvm_domain_context_t *h, 
unsigned int instance)
 {
 struct vcpu *v;
 int err = 0;
 
-for_each_vcpu ( d, v )
+if( instance < d->max_vcpus )
+{
+struct hvm_vmce_vcpu ctxt;
+
+v = d->vcpu[instance];
+ctxt.caps = v->arch.vmce.mcg_cap;
+ctxt.mci_ctl2_bank0 = v->arch.vmce.bank[0].mci_ctl2;
+ctxt.mci_ctl2_bank1 = v->arch.vmce.bank[1].mci_ctl2;
+ctxt.mcg_ext_ctl = v->arch.vmce.mcg_ext_ctl;
+
+err = hvm_save_entry(VMCE_VCPU, v->vcpu_id, h, );
+}
+else for_each_vcpu ( d, v )
 {
 struct hvm_vmce_vcpu ctxt = {
 .caps = v->arch.vmce.mcg_cap,
diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 540ba08..d3c4e14 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -624,12 +624,10 @@ long arch_do_domctl(
  !is_hvm_domain(d) )
 break;
 
-domain_pause(d);
 ret = hvm_save_one(d, domctl->u.hvmcontext_partial.type,
domctl->u.hvmcontext_partial.instance,
domctl->u.hvmcontext_partial.buffer,
>u.hvmcontext_partial.bufsz);
-domain_unpause(d);
 
 if ( !ret )
 copyback = true;
diff --git a/xen/arch/x86/hvm/hpet.c b/xen/arch/x86/hvm/hpet.c
index 3ea895a..56f4691 100644
--- a/xen/arch/x86/hvm/hpet.c
+++ b/xen/arch/x86/hvm/hpet.c
@@ -509,7 +509,7 @@ static const struct hvm_mmio_ops hpet_mmio_ops = {
 };
 
 
-static int hpet_save(struct domain *d, hvm_domain_context_t *h)
+static int hpet_save(struct domain *d, hvm_domain_context_t *h, unsigned int 
instance)
 {
 HPETState *hp = domain_vhpet(d);
 struct vcpu *v = pt_global_vcpu_target(d);
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 205b4cb..140f2c3 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -728,13 +728,19 @@ void hvm_domain_destroy(struct domain *d)
 }
 }
 
-static int hvm_save_tsc_adjust(struct domain *d, hvm_domain_context_t *h)
+static int hvm_save_tsc_adjust(struct domain *d, hvm_domain_context_t *h, 
unsigned int instance)
 {
 struct vcpu *v;
 struct hvm_tsc_adjust ctxt;
 int err = 0;
 
-for_each_vcpu ( d, v )
+if( instance < d->max_vcpus )
+{
+v = d->vcpu[instance];
+ctxt.tsc_adjust = v->

[Xen-devel] [PATCH v8] x86/hvm: Implement hvmemul_write() using real mappings

2017-10-02 Thread Alexandru Isaila
From: Andrew Cooper <andrew.coop...@citrix.com>

An access which crosses a page boundary is performed atomically by x86
hardware, albeit with a severe performance penalty.  An important corner case
is when a straddled access hits two pages which differ in whether a
translation exists, or in net access rights.

The use of hvm_copy*() in hvmemul_write() is problematic, because it performs
a translation then completes the partial write, before moving onto the next
translation.

If an individual emulated write straddles two pages, the first of which is
writable, and the second of which is not, the first half of the write will
complete before #PF is raised from the second half.

This results in guest state corruption as a side effect of emulation, which
has been observed to cause windows to crash while under introspection.

Introduce the hvmemul_{,un}map_linear_addr() helpers, which translate an
entire contents of a linear access, and vmap() the underlying frames to
provide a contiguous virtual mapping for the emulator to use.  This is the
same mechanism as used by the shadow emulation code.

This will catch any translation issues and abort the emulation before any
modifications occur.

Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com>
Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V7:
- Removed blank lines
- Moved the caluculation onf frame and addr in the for loop
- Changed the if condition to nr_frames == 1
- Converted the while loop to for in the unmap func.

Note: Tested with win32/64 and ubuntu64 guests.
---
 xen/arch/x86/hvm/emulate.c| 182 ++
 xen/include/asm-x86/hvm/emulate.h |   7 ++
 2 files changed, 173 insertions(+), 16 deletions(-)

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index cc874ce..1ba9a1b 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -498,6 +498,163 @@ static int hvmemul_do_mmio_addr(paddr_t mmio_gpa,
 }
 
 /*
+ * Map the frame(s) covering an individual linear access, for writeable
+ * access.  May return NULL for MMIO, or ERR_PTR(~X86EMUL_*) for other errors
+ * including ERR_PTR(~X86EMUL_OKAY) for write-discard mappings.
+ *
+ * In debug builds, map() checks that each slot in hvmemul_ctxt->mfn[] is
+ * clean before use, and poisions unused slots with INVALID_MFN.
+ */
+static void *hvmemul_map_linear_addr(
+unsigned long linear, unsigned int bytes, uint32_t pfec,
+struct hvm_emulate_ctxt *hvmemul_ctxt)
+{
+struct vcpu *curr = current;
+void *err, *mapping;
+
+/* First and final gfns which need mapping. */
+unsigned int nr_frames = ((linear + bytes - !!bytes) >> PAGE_SHIFT) -
+(linear >> PAGE_SHIFT) + 1;
+unsigned int i;
+
+/*
+ * mfn points to the next free slot.  All used slots have a page reference
+ * held on them.
+ */
+mfn_t *mfn = _ctxt->mfn[0];
+
+/*
+ * The caller has no legitimate reason for trying a zero-byte write, but
+ * final is calculate to fail safe in release builds.
+ *
+ * The maximum write size depends on the number of adjacent mfns[] which
+ * can be vmap()'d, accouting for possible misalignment within the region.
+ * The higher level emulation callers are responsible for ensuring that
+ * mfns[] is large enough for the requested write size.
+ */
+if ( bytes == 0 ||
+ nr_frames > ARRAY_SIZE(hvmemul_ctxt->mfn) )
+{
+ASSERT_UNREACHABLE();
+printk("goto unhandle ERROR~!~~\n");
+goto unhandleable;
+}
+
+for( i = 0; i < nr_frames; i++ )
+{
+enum hvm_translation_result res;
+struct page_info *page;
+pagefault_info_t pfinfo;
+p2m_type_t p2mt;
+unsigned long frame = (linear >> PAGE_SHIFT) + i;
+unsigned long addr = frame << PAGE_SHIFT;
+
+if ( hvmemul_ctxt->ctxt.addr_size < 64 )
+addr = (uint32_t)addr;
+
+/* Error checking.  Confirm that the current slot is clean. */
+ASSERT(mfn_x(*mfn) == 0);
+
+res = hvm_translate_get_page(curr, addr, true, pfec,
+ , , NULL, );
+
+switch ( res )
+{
+case HVMTRANS_okay:
+break;
+
+case HVMTRANS_bad_linear_to_gfn:
+x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
+err = ERR_PTR(~X86EMUL_EXCEPTION);
+goto out;
+
+case HVMTRANS_bad_gfn_to_mfn:
+err = NULL;
+goto out;
+
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
+err = ERR_PTR(~X86EMUL_RETRY);
+goto out;
+
+default:
+goto unhandleable;
+}
+
+*mfn++ = _mfn(page_to_mfn(page));
+
+if ( p2m_is_discard_write(p2mt) )
+{
+err = ERR_PTR(~X86EMUL_OKAY);
+   

[Xen-devel] [PATCH v7] x86/hvm: Implement hvmemul_write() using real mappings

2017-09-28 Thread Alexandru Isaila
From: Andrew Cooper <andrew.coop...@citrix.com>

An access which crosses a page boundary is performed atomically by x86
hardware, albeit with a severe performance penalty.  An important corner case
is when a straddled access hits two pages which differ in whether a
translation exists, or in net access rights.

The use of hvm_copy*() in hvmemul_write() is problematic, because it performs
a translation then completes the partial write, before moving onto the next
translation.

If an individual emulated write straddles two pages, the first of which is
writable, and the second of which is not, the first half of the write will
complete before #PF is raised from the second half.

This results in guest state corruption as a side effect of emulation, which
has been observed to cause windows to crash while under introspection.

Introduce the hvmemul_{,un}map_linear_addr() helpers, which translate an
entire contents of a linear access, and vmap() the underlying frames to
provide a contiguous virtual mapping for the emulator to use.  This is the
same mechanism as used by the shadow emulation code.

This will catch any translation issues and abort the emulation before any
modifications occur.

Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com>
Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V6:
- Added a direct way to calculate the nr_frames
- The while loop uses a i counter
- The frame address is calculated in the loop
---
 xen/arch/x86/hvm/emulate.c| 185 ++
 xen/include/asm-x86/hvm/emulate.h |   7 ++
 2 files changed, 176 insertions(+), 16 deletions(-)

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index cc874ce..7d18bf5 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -498,6 +498,166 @@ static int hvmemul_do_mmio_addr(paddr_t mmio_gpa,
 }
 
 /*
+ * Map the frame(s) covering an individual linear access, for writeable
+ * access.  May return NULL for MMIO, or ERR_PTR(~X86EMUL_*) for other errors
+ * including ERR_PTR(~X86EMUL_OKAY) for write-discard mappings.
+ *
+ * In debug builds, map() checks that each slot in hvmemul_ctxt->mfn[] is
+ * clean before use, and poisions unused slots with INVALID_MFN.
+ */
+static void *hvmemul_map_linear_addr(
+unsigned long linear, unsigned int bytes, uint32_t pfec,
+struct hvm_emulate_ctxt *hvmemul_ctxt)
+{
+struct vcpu *curr = current;
+void *err, *mapping;
+
+/* First and final gfns which need mapping. */
+unsigned long frame = linear >> PAGE_SHIFT, first = frame;
+unsigned long final = (linear + bytes - !!bytes) >> PAGE_SHIFT;
+unsigned long nr_frames = ((linear + bytes) >> PAGE_SHIFT) - (linear >> 
PAGE_SHIFT) + 1;
+int i = 0;
+
+/*
+ * mfn points to the next free slot.  All used slots have a page reference
+ * held on them.
+ */
+mfn_t *mfn = _ctxt->mfn[0];
+
+
+/*
+ * The caller has no legitimate reason for trying a zero-byte write, but
+ * final is calculate to fail safe in release builds.
+ *
+ * The maximum write size depends on the number of adjacent mfns[] which
+ * can be vmap()'d, accouting for possible misalignment within the region.
+ * The higher level emulation callers are responsible for ensuring that
+ * mfns[] is large enough for the requested write size.
+ */
+if ( bytes == 0 ||
+ nr_frames > ARRAY_SIZE(hvmemul_ctxt->mfn) )
+{
+ASSERT_UNREACHABLE();
+goto unhandleable;
+}
+
+do {
+enum hvm_translation_result res;
+struct page_info *page;
+pagefault_info_t pfinfo;
+p2m_type_t p2mt;
+
+/* Error checking.  Confirm that the current slot is clean. */
+ASSERT(mfn_x(*mfn) == 0);
+
+res = hvm_translate_get_page(curr, frame, true, pfec,
+ , , NULL, );
+
+switch ( res )
+{
+case HVMTRANS_okay:
+break;
+
+case HVMTRANS_bad_linear_to_gfn:
+x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
+err = ERR_PTR(~X86EMUL_EXCEPTION);
+goto out;
+
+case HVMTRANS_bad_gfn_to_mfn:
+err = NULL;
+goto out;
+
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
+err = ERR_PTR(~X86EMUL_RETRY);
+goto out;
+
+default:
+goto unhandleable;
+}
+
+*mfn++ = _mfn(page_to_mfn(page));
+i++;
+
+if ( p2m_is_discard_write(p2mt) )
+{
+err = ERR_PTR(~X86EMUL_OKAY);
+goto out;
+}
+
+frame = (linear + i);
+if ( hvmemul_ctxt->ctxt.addr_size < 64 )
+frame = (uint32_t)frame;
+frame = frame << PAGE_SHIFT;
+
+} while ( i < nr_frames );
+
+/* Entire access within a single

[Xen-devel] [PATCH v6] x86/hvm: Implement hvmemul_write() using real mappings

2017-09-27 Thread Alexandru Isaila
From: Andrew Cooper <andrew.coop...@citrix.com>

An access which crosses a page boundary is performed atomically by x86
hardware, albeit with a severe performance penalty.  An important corner case
is when a straddled access hits two pages which differ in whether a
translation exists, or in net access rights.

The use of hvm_copy*() in hvmemul_write() is problematic, because it performs
a translation then completes the partial write, before moving onto the next
translation.

If an individual emulated write straddles two pages, the first of which is
writable, and the second of which is not, the first half of the write will
complete before #PF is raised from the second half.

This results in guest state corruption as a side effect of emulation, which
has been observed to cause windows to crash while under introspection.

Introduce the hvmemul_{,un}map_linear_addr() helpers, which translate an
entire contents of a linear access, and vmap() the underlying frames to
provide a contiguous virtual mapping for the emulator to use.  This is the
same mechanism as used by the shadow emulation code.

This will catch any translation issues and abort the emulation before any
modifications occur.

Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com>
Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>
Reviewed-by: Paul Durrant <paul.durr...@citrix.com>

---
Changes since V5:
- Added address size check
- Added a pages local variable that holds the number of pages
- Addded the !mapping check
---
 xen/arch/x86/hvm/emulate.c| 189 ++
 xen/include/asm-x86/hvm/emulate.h |   7 ++
 2 files changed, 180 insertions(+), 16 deletions(-)

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index cc874ce..c563052 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -498,6 +498,170 @@ static int hvmemul_do_mmio_addr(paddr_t mmio_gpa,
 }
 
 /*
+ * Map the frame(s) covering an individual linear access, for writeable
+ * access.  May return NULL for MMIO, or ERR_PTR(~X86EMUL_*) for other errors
+ * including ERR_PTR(~X86EMUL_OKAY) for write-discard mappings.
+ *
+ * In debug builds, map() checks that each slot in hvmemul_ctxt->mfn[] is
+ * clean before use, and poisions unused slots with INVALID_MFN.
+ */
+static void *hvmemul_map_linear_addr(
+unsigned long linear, unsigned int bytes, uint32_t pfec,
+struct hvm_emulate_ctxt *hvmemul_ctxt)
+{
+struct vcpu *curr = current;
+void *err, *mapping;
+
+/* First and final gfns which need mapping. */
+unsigned long frame = linear >> PAGE_SHIFT, first = frame;
+unsigned long final = (linear + bytes - !!bytes) >> PAGE_SHIFT;
+unsigned long pages = final - first + 1;
+
+if ( hvmemul_ctxt->ctxt.addr_size < 64 )
+{
+frame = (uint32_t)frame;
+final = (uint32_t)final;
+pages = (uint32_t)pages;
+}
+
+/*
+ * mfn points to the next free slot.  All used slots have a page reference
+ * held on them.
+ */
+mfn_t *mfn = _ctxt->mfn[0];
+
+/*
+ * The caller has no legitimate reason for trying a zero-byte write, but
+ * final is calculate to fail safe in release builds.
+ *
+ * The maximum write size depends on the number of adjacent mfns[] which
+ * can be vmap()'d, accouting for possible misalignment within the region.
+ * The higher level emulation callers are responsible for ensuring that
+ * mfns[] is large enough for the requested write size.
+ */
+if ( bytes == 0 ||
+ pages > ARRAY_SIZE(hvmemul_ctxt->mfn) )
+{
+ASSERT_UNREACHABLE();
+goto unhandleable;
+}
+
+do {
+enum hvm_translation_result res;
+struct page_info *page;
+pagefault_info_t pfinfo;
+p2m_type_t p2mt;
+
+/* Error checking.  Confirm that the current slot is clean. */
+ASSERT(mfn_x(*mfn) == 0);
+
+res = hvm_translate_get_page(curr, frame << PAGE_SHIFT, true, pfec,
+ , , NULL, );
+
+switch ( res )
+{
+case HVMTRANS_okay:
+break;
+
+case HVMTRANS_bad_linear_to_gfn:
+x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
+err = ERR_PTR(~X86EMUL_EXCEPTION);
+goto out;
+
+case HVMTRANS_bad_gfn_to_mfn:
+err = NULL;
+goto out;
+
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
+err = ERR_PTR(~X86EMUL_RETRY);
+goto out;
+
+default:
+goto unhandleable;
+}
+
+*mfn++ = _mfn(page_to_mfn(page));
+
+if ( p2m_is_discard_write(p2mt) )
+{
+err = ERR_PTR(~X86EMUL_OKAY);
+goto out;
+}
+
+} while ( ++frame < final );
+
+/* Entire access within a single frame? */
+if ( first

[Xen-devel] [PATCH v5] x86/hvm: Implement hvmemul_write() using real mappings

2017-09-27 Thread Alexandru Isaila
From: Andrew Cooper <andrew.coop...@citrix.com>

An access which crosses a page boundary is performed atomically by x86
hardware, albeit with a severe performance penalty.  An important corner case
is when a straddled access hits two pages which differ in whether a
translation exists, or in net access rights.

The use of hvm_copy*() in hvmemul_write() is problematic, because it performs
a translation then completes the partial write, before moving onto the next
translation.

If an individual emulated write straddles two pages, the first of which is
writable, and the second of which is not, the first half of the write will
complete before #PF is raised from the second half.

This results in guest state corruption as a side effect of emulation, which
has been observed to cause windows to crash while under introspection.

Introduce the hvmemul_{,un}map_linear_addr() helpers, which translate an
entire contents of a linear access, and vmap() the underlying frames to
provide a contiguous virtual mapping for the emulator to use.  This is the
same mechanism as used by the shadow emulation code.

This will catch any translation issues and abort the emulation before any
modifications occur.

Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com>
Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V4:
- Moved the mfn increment line back
- Removed the new line between mfn++ and while

Reviewed-by: Paul Durrant <paul.durr...@citrix.com>
---
 xen/arch/x86/hvm/emulate.c| 174 ++
 xen/include/asm-x86/hvm/emulate.h |   7 ++
 2 files changed, 164 insertions(+), 17 deletions(-)

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index cc874ce..9d8be30 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -498,6 +498,156 @@ static int hvmemul_do_mmio_addr(paddr_t mmio_gpa,
 }
 
 /*
+ * Map the frame(s) covering an individual linear access, for writeable
+ * access.  May return NULL for MMIO, or ERR_PTR(~X86EMUL_*) for other errors
+ * including ERR_PTR(~X86EMUL_OKAY) for write-discard mappings.
+ *
+ * In debug builds, map() checks that each slot in hvmemul_ctxt->mfn[] is
+ * clean before use, and poisions unused slots with INVALID_MFN.
+ */
+static void *hvmemul_map_linear_addr(
+unsigned long linear, unsigned int bytes, uint32_t pfec,
+struct hvm_emulate_ctxt *hvmemul_ctxt)
+{
+struct vcpu *curr = current;
+void *err, *mapping;
+
+/* First and final gfns which need mapping. */
+unsigned long frame = linear >> PAGE_SHIFT, first = frame;
+unsigned long final = (linear + bytes - !!bytes) >> PAGE_SHIFT;
+
+/*
+ * mfn points to the next free slot.  All used slots have a page reference
+ * held on them.
+ */
+mfn_t *mfn = _ctxt->mfn[0];
+
+/*
+ * The caller has no legitimate reason for trying a zero-byte write, but
+ * final is calculate to fail safe in release builds.
+ *
+ * The maximum write size depends on the number of adjacent mfns[] which
+ * can be vmap()'d, accouting for possible misalignment within the region.
+ * The higher level emulation callers are responsible for ensuring that
+ * mfns[] is large enough for the requested write size.
+ */
+if ( bytes == 0 ||
+ final - first >= ARRAY_SIZE(hvmemul_ctxt->mfn) )
+{
+ASSERT_UNREACHABLE();
+goto unhandleable;
+}
+
+do {
+enum hvm_translation_result res;
+struct page_info *page;
+pagefault_info_t pfinfo;
+p2m_type_t p2mt;
+
+/* Error checking.  Confirm that the current slot is clean. */
+ASSERT(mfn_x(*mfn) == 0);
+
+res = hvm_translate_get_page(curr, frame << PAGE_SHIFT, true, pfec,
+ , , NULL, );
+
+switch ( res )
+{
+case HVMTRANS_okay:
+break;
+
+case HVMTRANS_bad_linear_to_gfn:
+x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
+err = ERR_PTR(~X86EMUL_EXCEPTION);
+goto out;
+
+case HVMTRANS_bad_gfn_to_mfn:
+err = NULL;
+goto out;
+
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
+err = ERR_PTR(~X86EMUL_RETRY);
+goto out;
+
+default:
+goto unhandleable;
+}
+
+*mfn++ = _mfn(page_to_mfn(page));
+
+if ( p2m_is_discard_write(p2mt) )
+{
+err = ERR_PTR(~X86EMUL_OKAY);
+goto out;
+}
+
+} while ( ++frame < final );
+
+/* Entire access within a single frame? */
+if ( first == final )
+mapping = map_domain_page(hvmemul_ctxt->mfn[0]);
+/* Multiple frames? Need to vmap(). */
+else if ( (mapping = vmap(hvmemul_ctxt->mfn,
+  final - first + 1)) == NULL )
+goto unhandl

[Xen-devel] [PATCH v4 1/3] x86/hvm: Rename enum hvm_copy_result to hvm_translation_result

2017-09-20 Thread Alexandru Isaila
From: Andrew Cooper 

Signed-off-by: Andrew Cooper 
Acked-by: Tim Deegan 
Acked-by: Jan Beulich 
Reviewed-by: Kevin Tian 
Acked-by: George Dunlap 
---
 xen/arch/x86/hvm/dom0_build.c |  2 +-
 xen/arch/x86/hvm/emulate.c| 40 ++--
 xen/arch/x86/hvm/hvm.c| 56 +++
 xen/arch/x86/hvm/intercept.c  | 20 +++---
 xen/arch/x86/hvm/svm/nestedsvm.c  |  5 ++--
 xen/arch/x86/hvm/svm/svm.c|  2 +-
 xen/arch/x86/hvm/viridian.c   |  2 +-
 xen/arch/x86/hvm/vmsi.c   |  2 +-
 xen/arch/x86/hvm/vmx/realmode.c   |  2 +-
 xen/arch/x86/hvm/vmx/vvmx.c   | 14 +-
 xen/arch/x86/mm/shadow/common.c   | 12 -
 xen/common/libelf/libelf-loader.c |  4 +--
 xen/include/asm-x86/hvm/support.h | 40 ++--
 13 files changed, 101 insertions(+), 100 deletions(-)

diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c
index 020c355..e8f746c 100644
--- a/xen/arch/x86/hvm/dom0_build.c
+++ b/xen/arch/x86/hvm/dom0_build.c
@@ -238,7 +238,7 @@ static int __init pvh_setup_vmx_realmode_helpers(struct 
domain *d)
 if ( !pvh_steal_ram(d, HVM_VM86_TSS_SIZE, 128, GB(4), ) )
 {
 if ( hvm_copy_to_guest_phys(gaddr, NULL, HVM_VM86_TSS_SIZE, v) !=
- HVMCOPY_okay )
+ HVMTRANS_okay )
 printk("Unable to zero VM86 TSS area\n");
 d->arch.hvm_domain.params[HVM_PARAM_VM86_TSS_SIZED] =
 VM86_TSS_UPDATED | ((uint64_t)HVM_VM86_TSS_SIZE << 32) | gaddr;
diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index 54811c1..cc874ce 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -100,7 +100,7 @@ static int ioreq_server_read(const struct hvm_io_handler 
*io_handler,
 uint32_t size,
 uint64_t *data)
 {
-if ( hvm_copy_from_guest_phys(data, addr, size) != HVMCOPY_okay )
+if ( hvm_copy_from_guest_phys(data, addr, size) != HVMTRANS_okay )
 return X86EMUL_UNHANDLEABLE;
 
 return X86EMUL_OKAY;
@@ -893,18 +893,18 @@ static int __hvmemul_read(
 
 switch ( rc )
 {
-case HVMCOPY_okay:
+case HVMTRANS_okay:
 break;
-case HVMCOPY_bad_gva_to_gfn:
+case HVMTRANS_bad_linear_to_gfn:
 x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
 return X86EMUL_EXCEPTION;
-case HVMCOPY_bad_gfn_to_mfn:
+case HVMTRANS_bad_gfn_to_mfn:
 if ( access_type == hvm_access_insn_fetch )
 return X86EMUL_UNHANDLEABLE;
 
 return hvmemul_linear_mmio_read(addr, bytes, p_data, pfec, 
hvmemul_ctxt, 0);
-case HVMCOPY_gfn_paged_out:
-case HVMCOPY_gfn_shared:
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
 return X86EMUL_RETRY;
 default:
 return X86EMUL_UNHANDLEABLE;
@@ -1012,15 +1012,15 @@ static int hvmemul_write(
 
 switch ( rc )
 {
-case HVMCOPY_okay:
+case HVMTRANS_okay:
 break;
-case HVMCOPY_bad_gva_to_gfn:
+case HVMTRANS_bad_linear_to_gfn:
 x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
 return X86EMUL_EXCEPTION;
-case HVMCOPY_bad_gfn_to_mfn:
+case HVMTRANS_bad_gfn_to_mfn:
 return hvmemul_linear_mmio_write(addr, bytes, p_data, pfec, 
hvmemul_ctxt, 0);
-case HVMCOPY_gfn_paged_out:
-case HVMCOPY_gfn_shared:
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
 return X86EMUL_RETRY;
 default:
 return X86EMUL_UNHANDLEABLE;
@@ -1384,7 +1384,7 @@ static int hvmemul_rep_movs(
 return rc;
 }
 
-rc = HVMCOPY_okay;
+rc = HVMTRANS_okay;
 }
 else
 /*
@@ -1394,16 +1394,16 @@ static int hvmemul_rep_movs(
  */
 rc = hvm_copy_from_guest_phys(buf, sgpa, bytes);
 
-if ( rc == HVMCOPY_okay )
+if ( rc == HVMTRANS_okay )
 rc = hvm_copy_to_guest_phys(dgpa, buf, bytes, current);
 
 xfree(buf);
 
-if ( rc == HVMCOPY_gfn_paged_out )
+if ( rc == HVMTRANS_gfn_paged_out )
 return X86EMUL_RETRY;
-if ( rc == HVMCOPY_gfn_shared )
+if ( rc == HVMTRANS_gfn_shared )
 return X86EMUL_RETRY;
-if ( rc != HVMCOPY_okay )
+if ( rc != HVMTRANS_okay )
 {
 gdprintk(XENLOG_WARNING, "Failed memory-to-memory REP MOVS: sgpa=%"
  PRIpaddr" dgpa=%"PRIpaddr" reps=%lu bytes_per_rep=%u\n",
@@ -1513,10 +1513,10 @@ static int hvmemul_rep_stos(
 
 switch ( rc )
 {
-case HVMCOPY_gfn_paged_out:
-case HVMCOPY_gfn_shared:
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
 return X86EMUL_RETRY;
-case HVMCOPY_okay:
+case HVMTRANS_okay:
 return X86EMUL_OKAY;
 }
 
@@ -2172,7 +2172,7 @@ void 

[Xen-devel] [PATCH v4 3/3] x86/hvm: Implement hvmemul_write() using real mappings

2017-09-20 Thread Alexandru Isaila
From: Andrew Cooper <andrew.coop...@citrix.com>

An access which crosses a page boundary is performed atomically by x86
hardware, albeit with a severe performance penalty.  An important corner case
is when a straddled access hits two pages which differ in whether a
translation exists, or in net access rights.

The use of hvm_copy*() in hvmemul_write() is problematic, because it performs
a translation then completes the partial write, before moving onto the next
translation.

If an individual emulated write straddles two pages, the first of which is
writable, and the second of which is not, the first half of the write will
complete before #PF is raised from the second half.

This results in guest state corruption as a side effect of emulation, which
has been observed to cause windows to crash while under introspection.

Introduce the hvmemul_{,un}map_linear_addr() helpers, which translate an
entire contents of a linear access, and vmap() the underlying frames to
provide a contiguous virtual mapping for the emulator to use.  This is the
same mechanism as used by the shadow emulation code.

This will catch any translation issues and abort the emulation before any
modifications occur.

Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com>
Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V3:
- Changed the if condition form ... > ... -1 to ... >= ...
- Removed long cast to the err var
- Moved the mfn++ closer to the end of the loop
- Integrated the ++frame in the while condition
---
 xen/arch/x86/hvm/emulate.c| 175 ++
 xen/include/asm-x86/hvm/emulate.h |   7 ++
 2 files changed, 165 insertions(+), 17 deletions(-)

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index cc874ce..9866d64 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -498,6 +498,157 @@ static int hvmemul_do_mmio_addr(paddr_t mmio_gpa,
 }
 
 /*
+ * Map the frame(s) covering an individual linear access, for writeable
+ * access.  May return NULL for MMIO, or ERR_PTR(~X86EMUL_*) for other errors
+ * including ERR_PTR(~X86EMUL_OKAY) for write-discard mappings.
+ *
+ * In debug builds, map() checks that each slot in hvmemul_ctxt->mfn[] is
+ * clean before use, and poisions unused slots with INVALID_MFN.
+ */
+static void *hvmemul_map_linear_addr(
+unsigned long linear, unsigned int bytes, uint32_t pfec,
+struct hvm_emulate_ctxt *hvmemul_ctxt)
+{
+struct vcpu *curr = current;
+void *err, *mapping;
+
+/* First and final gfns which need mapping. */
+unsigned long frame = linear >> PAGE_SHIFT, first = frame;
+unsigned long final = (linear + bytes - !!bytes) >> PAGE_SHIFT;
+
+/*
+ * mfn points to the next free slot.  All used slots have a page reference
+ * held on them.
+ */
+mfn_t *mfn = _ctxt->mfn[0];
+
+/*
+ * The caller has no legitimate reason for trying a zero-byte write, but
+ * final is calculate to fail safe in release builds.
+ *
+ * The maximum write size depends on the number of adjacent mfns[] which
+ * can be vmap()'d, accouting for possible misalignment within the region.
+ * The higher level emulation callers are responsible for ensuring that
+ * mfns[] is large enough for the requested write size.
+ */
+if ( bytes == 0 ||
+ final - first >= ARRAY_SIZE(hvmemul_ctxt->mfn) )
+{
+ASSERT_UNREACHABLE();
+goto unhandleable;
+}
+
+do {
+enum hvm_translation_result res;
+struct page_info *page;
+pagefault_info_t pfinfo;
+p2m_type_t p2mt;
+
+/* Error checking.  Confirm that the current slot is clean. */
+ASSERT(mfn_x(*mfn) == 0);
+
+res = hvm_translate_get_page(curr, frame << PAGE_SHIFT, true, pfec,
+ , , NULL, );
+
+switch ( res )
+{
+case HVMTRANS_okay:
+break;
+
+case HVMTRANS_bad_linear_to_gfn:
+x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
+err = ERR_PTR(~X86EMUL_EXCEPTION);
+goto out;
+
+case HVMTRANS_bad_gfn_to_mfn:
+err = NULL;
+goto out;
+
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
+err = ERR_PTR(~X86EMUL_RETRY);
+goto out;
+
+default:
+goto unhandleable;
+}
+
+if ( p2m_is_discard_write(p2mt) )
+{
+err = ERR_PTR(~X86EMUL_OKAY);
+goto out;
+}
+
+*mfn++ = _mfn(page_to_mfn(page));
+
+} while ( ++frame < final );
+
+/* Entire access within a single frame? */
+if ( first == final )
+mapping = map_domain_page(hvmemul_ctxt->mfn[0]);
+/* Multiple frames? Need to vmap(). */
+else if ( (mapping = vmap(hvmemul_ctxt->mfn,
+   

[Xen-devel] [PATCH v4 0/3] Various XSA followups

2017-09-20 Thread Alexandru Isaila
XSA-219 was discovered while trying to implement the bugfix in patch 3.

Andrew Cooper (3):
 [RFC] x86/hvm: Rename enum hvm_copy_result to hvm_translation_result
 x86/hvm: Break out __hvm_copy()'s translation logic
 x86/hvm: Implement hvmemul_write() using real mappings

Alexandru Isaila (2):
 x86/hvm: Break out __hvm_copy()'s translation logic
 x86/hvm: Implement hvmemul_write() using real mappings






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


[Xen-devel] [PATCH v4 2/3] x86/hvm: Break out __hvm_copy()'s translation logic

2017-09-20 Thread Alexandru Isaila
From: Andrew Cooper <andrew.coop...@citrix.com>

It will be reused by later changes.

Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com>
Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>
Reviewed-by: Paul Durrant <paul.durr...@citrix.com>
Acked-by: Jan Beulich <jbeul...@suse.com>
---
 xen/arch/x86/hvm/hvm.c| 144 +++---
 xen/include/asm-x86/hvm/support.h |  12 
 2 files changed, 98 insertions(+), 58 deletions(-)

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 488acbf..93394c1 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -3069,6 +3069,83 @@ void hvm_task_switch(
 hvm_unmap_entry(nptss_desc);
 }
 
+enum hvm_translation_result hvm_translate_get_page(
+struct vcpu *v, unsigned long addr, bool linear, uint32_t pfec,
+pagefault_info_t *pfinfo, struct page_info **page_p,
+gfn_t *gfn_p, p2m_type_t *p2mt_p)
+{
+struct page_info *page;
+p2m_type_t p2mt;
+gfn_t gfn;
+
+if ( linear )
+{
+gfn = _gfn(paging_gva_to_gfn(v, addr, ));
+
+if ( gfn_eq(gfn, INVALID_GFN) )
+{
+if ( pfec & PFEC_page_paged )
+return HVMTRANS_gfn_paged_out;
+
+if ( pfec & PFEC_page_shared )
+return HVMTRANS_gfn_shared;
+
+if ( pfinfo )
+{
+pfinfo->linear = addr;
+pfinfo->ec = pfec & ~PFEC_implicit;
+}
+
+return HVMTRANS_bad_linear_to_gfn;
+}
+}
+else
+{
+gfn = gaddr_to_gfn(addr);
+ASSERT(!pfinfo);
+}
+
+/*
+ * No need to do the P2M lookup for internally handled MMIO, benefiting
+ * - 32-bit WinXP (& older Windows) on AMD CPUs for LAPIC accesses,
+ * - newer Windows (like Server 2012) for HPET accesses.
+ */
+if ( v == current
+ && !nestedhvm_vcpu_in_guestmode(v)
+ && hvm_mmio_internal(gfn_to_gaddr(gfn)) )
+return HVMTRANS_bad_gfn_to_mfn;
+
+page = get_page_from_gfn(v->domain, gfn_x(gfn), , P2M_UNSHARE);
+
+if ( !page )
+return HVMTRANS_bad_gfn_to_mfn;
+
+if ( p2m_is_paging(p2mt) )
+{
+put_page(page);
+p2m_mem_paging_populate(v->domain, gfn_x(gfn));
+return HVMTRANS_gfn_paged_out;
+}
+if ( p2m_is_shared(p2mt) )
+{
+put_page(page);
+return HVMTRANS_gfn_shared;
+}
+if ( p2m_is_grant(p2mt) )
+{
+put_page(page);
+return HVMTRANS_unhandleable;
+}
+
+*page_p = page;
+if ( gfn_p )
+*gfn_p = gfn;
+if ( p2mt_p )
+*p2mt_p = p2mt;
+
+return HVMTRANS_okay;
+}
+
 #define HVMCOPY_from_guest (0u<<0)
 #define HVMCOPY_to_guest   (1u<<0)
 #define HVMCOPY_phys   (0u<<2)
@@ -3077,7 +3154,7 @@ static enum hvm_translation_result __hvm_copy(
 void *buf, paddr_t addr, int size, struct vcpu *v, unsigned int flags,
 uint32_t pfec, pagefault_info_t *pfinfo)
 {
-unsigned long gfn;
+gfn_t gfn;
 struct page_info *page;
 p2m_type_t p2mt;
 char *p;
@@ -3103,65 +3180,15 @@ static enum hvm_translation_result __hvm_copy(
 
 while ( todo > 0 )
 {
+enum hvm_translation_result res;
 paddr_t gpa = addr & ~PAGE_MASK;
 
 count = min_t(int, PAGE_SIZE - gpa, todo);
 
-if ( flags & HVMCOPY_linear )
-{
-gfn = paging_gva_to_gfn(v, addr, );
-if ( gfn == gfn_x(INVALID_GFN) )
-{
-if ( pfec & PFEC_page_paged )
-return HVMTRANS_gfn_paged_out;
-if ( pfec & PFEC_page_shared )
-return HVMTRANS_gfn_shared;
-if ( pfinfo )
-{
-pfinfo->linear = addr;
-pfinfo->ec = pfec & ~PFEC_implicit;
-}
-return HVMTRANS_bad_linear_to_gfn;
-}
-gpa |= (paddr_t)gfn << PAGE_SHIFT;
-}
-else
-{
-gfn = addr >> PAGE_SHIFT;
-gpa = addr;
-}
-
-/*
- * No need to do the P2M lookup for internally handled MMIO, benefiting
- * - 32-bit WinXP (& older Windows) on AMD CPUs for LAPIC accesses,
- * - newer Windows (like Server 2012) for HPET accesses.
- */
-if ( v == current
- && !nestedhvm_vcpu_in_guestmode(v)
- && hvm_mmio_internal(gpa) )
-return HVMTRANS_bad_gfn_to_mfn;
-
-page = get_page_from_gfn(v->domain, gfn, , P2M_UNSHARE);
-
-if ( !page )
-return HVMTRANS_bad_gfn_to_mfn;
-
-if ( p2m_is_paging(p2mt) )
-{
-put_page(page);
-p2m_mem_paging_populate(v->domain, gfn);
-return HVMTRANS_gfn_paged_out;
-}

[Xen-devel] [PATCH v3 3/3] x86/hvm: Implement hvmemul_write() using real mappings

2017-09-19 Thread Alexandru Isaila
From: Andrew Cooper <andrew.coop...@citrix.com>

An access which crosses a page boundary is performed atomically by x86
hardware, albeit with a severe performance penalty.  An important corner case
is when a straddled access hits two pages which differ in whether a
translation exists, or in net access rights.

The use of hvm_copy*() in hvmemul_write() is problematic, because it performs
a translation then completes the partial write, before moving onto the next
translation.

If an individual emulated write straddles two pages, the first of which is
writable, and the second of which is not, the first half of the write will
complete before #PF is raised from the second half.

This results in guest state corruption as a side effect of emulation, which
has been observed to cause windows to crash while under introspection.

Introduce the hvmemul_{,un}map_linear_addr() helpers, which translate an
entire contents of a linear access, and vmap() the underlying frames to
provide a contiguous virtual mapping for the emulator to use.  This is the
same mechanism as used by the shadow emulation code.

This will catch any translation issues and abort the emulation before any
modifications occur.

Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com>
Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V2:
- Added linear & ~PAGE_MASK to return statement
- Modified mfn - hvmemul_ctxt->mfn to final - first + 1
- Remove useless else statement
---
 xen/arch/x86/hvm/emulate.c| 177 ++
 xen/include/asm-x86/hvm/emulate.h |   7 ++
 2 files changed, 167 insertions(+), 17 deletions(-)

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index cc874ce..5574698 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -498,6 +498,159 @@ static int hvmemul_do_mmio_addr(paddr_t mmio_gpa,
 }
 
 /*
+ * Map the frame(s) covering an individual linear access, for writeable
+ * access.  May return NULL for MMIO, or ERR_PTR(~X86EMUL_*) for other errors
+ * including ERR_PTR(~X86EMUL_OKAY) for write-discard mappings.
+ *
+ * In debug builds, map() checks that each slot in hvmemul_ctxt->mfn[] is
+ * clean before use, and poisions unused slots with INVALID_MFN.
+ */
+static void *hvmemul_map_linear_addr(
+unsigned long linear, unsigned int bytes, uint32_t pfec,
+struct hvm_emulate_ctxt *hvmemul_ctxt)
+{
+struct vcpu *curr = current;
+void *err, *mapping;
+
+/* First and final gfns which need mapping. */
+unsigned long frame = linear >> PAGE_SHIFT, first = frame;
+unsigned long final = (linear + bytes - !!bytes) >> PAGE_SHIFT;
+
+/*
+ * mfn points to the next free slot.  All used slots have a page reference
+ * held on them.
+ */
+mfn_t *mfn = _ctxt->mfn[0];
+
+/*
+ * The caller has no legitimate reason for trying a zero-byte write, but
+ * final is calculate to fail safe in release builds.
+ *
+ * The maximum write size depends on the number of adjacent mfns[] which
+ * can be vmap()'d, accouting for possible misalignment within the region.
+ * The higher level emulation callers are responsible for ensuring that
+ * mfns[] is large enough for the requested write size.
+ */
+if ( bytes == 0 ||
+ final - first > ARRAY_SIZE(hvmemul_ctxt->mfn) - 1 )
+{
+ASSERT_UNREACHABLE();
+goto unhandleable;
+}
+
+do {
+enum hvm_translation_result res;
+struct page_info *page;
+pagefault_info_t pfinfo;
+p2m_type_t p2mt;
+
+/* Error checking.  Confirm that the current slot is clean. */
+ASSERT(mfn_x(*mfn) == 0);
+
+res = hvm_translate_get_page(curr, frame << PAGE_SHIFT, true, pfec,
+ , , NULL, );
+
+switch ( res )
+{
+case HVMTRANS_okay:
+break;
+
+case HVMTRANS_bad_linear_to_gfn:
+x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
+err = ERR_PTR(~(long)X86EMUL_EXCEPTION);
+goto out;
+
+case HVMTRANS_bad_gfn_to_mfn:
+err = NULL;
+goto out;
+
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
+err = ERR_PTR(~(long)X86EMUL_RETRY);
+goto out;
+
+default:
+goto unhandleable;
+}
+
+*mfn++ = _mfn(page_to_mfn(page));
+frame++;
+
+if ( p2m_is_discard_write(p2mt) )
+{
+err = ERR_PTR(~(long)X86EMUL_OKAY);
+goto out;
+}
+
+} while ( frame < final );
+
+/* Entire access within a single frame? */
+if ( first == final )
+mapping = map_domain_page(hvmemul_ctxt->mfn[0]);
+/* Multiple frames? Need to vmap(). */
+else if ( (mapping = vmap(hvmemul_ctxt->mfn,
+  final - 

[Xen-devel] [PATCH v3 2/3] x86/hvm: Break out __hvm_copy()'s translation logic

2017-09-19 Thread Alexandru Isaila
From: Andrew Cooper <andrew.coop...@citrix.com>

It will be reused by later changes.

Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com>
Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V2:
- Changed _gfn() to gaddr_to_gfn
- Changed gfn_x to gfn_to_gaddr
---
 xen/arch/x86/hvm/hvm.c| 144 +++---
 xen/include/asm-x86/hvm/support.h |  12 
 2 files changed, 98 insertions(+), 58 deletions(-)

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 488acbf..93394c1 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -3069,6 +3069,83 @@ void hvm_task_switch(
 hvm_unmap_entry(nptss_desc);
 }
 
+enum hvm_translation_result hvm_translate_get_page(
+struct vcpu *v, unsigned long addr, bool linear, uint32_t pfec,
+pagefault_info_t *pfinfo, struct page_info **page_p,
+gfn_t *gfn_p, p2m_type_t *p2mt_p)
+{
+struct page_info *page;
+p2m_type_t p2mt;
+gfn_t gfn;
+
+if ( linear )
+{
+gfn = _gfn(paging_gva_to_gfn(v, addr, ));
+
+if ( gfn_eq(gfn, INVALID_GFN) )
+{
+if ( pfec & PFEC_page_paged )
+return HVMTRANS_gfn_paged_out;
+
+if ( pfec & PFEC_page_shared )
+return HVMTRANS_gfn_shared;
+
+if ( pfinfo )
+{
+pfinfo->linear = addr;
+pfinfo->ec = pfec & ~PFEC_implicit;
+}
+
+return HVMTRANS_bad_linear_to_gfn;
+}
+}
+else
+{
+gfn = gaddr_to_gfn(addr);
+ASSERT(!pfinfo);
+}
+
+/*
+ * No need to do the P2M lookup for internally handled MMIO, benefiting
+ * - 32-bit WinXP (& older Windows) on AMD CPUs for LAPIC accesses,
+ * - newer Windows (like Server 2012) for HPET accesses.
+ */
+if ( v == current
+ && !nestedhvm_vcpu_in_guestmode(v)
+ && hvm_mmio_internal(gfn_to_gaddr(gfn)) )
+return HVMTRANS_bad_gfn_to_mfn;
+
+page = get_page_from_gfn(v->domain, gfn_x(gfn), , P2M_UNSHARE);
+
+if ( !page )
+return HVMTRANS_bad_gfn_to_mfn;
+
+if ( p2m_is_paging(p2mt) )
+{
+put_page(page);
+p2m_mem_paging_populate(v->domain, gfn_x(gfn));
+return HVMTRANS_gfn_paged_out;
+}
+if ( p2m_is_shared(p2mt) )
+{
+put_page(page);
+return HVMTRANS_gfn_shared;
+}
+if ( p2m_is_grant(p2mt) )
+{
+put_page(page);
+return HVMTRANS_unhandleable;
+}
+
+*page_p = page;
+if ( gfn_p )
+*gfn_p = gfn;
+if ( p2mt_p )
+*p2mt_p = p2mt;
+
+return HVMTRANS_okay;
+}
+
 #define HVMCOPY_from_guest (0u<<0)
 #define HVMCOPY_to_guest   (1u<<0)
 #define HVMCOPY_phys   (0u<<2)
@@ -3077,7 +3154,7 @@ static enum hvm_translation_result __hvm_copy(
 void *buf, paddr_t addr, int size, struct vcpu *v, unsigned int flags,
 uint32_t pfec, pagefault_info_t *pfinfo)
 {
-unsigned long gfn;
+gfn_t gfn;
 struct page_info *page;
 p2m_type_t p2mt;
 char *p;
@@ -3103,65 +3180,15 @@ static enum hvm_translation_result __hvm_copy(
 
 while ( todo > 0 )
 {
+enum hvm_translation_result res;
 paddr_t gpa = addr & ~PAGE_MASK;
 
 count = min_t(int, PAGE_SIZE - gpa, todo);
 
-if ( flags & HVMCOPY_linear )
-{
-gfn = paging_gva_to_gfn(v, addr, );
-if ( gfn == gfn_x(INVALID_GFN) )
-{
-if ( pfec & PFEC_page_paged )
-return HVMTRANS_gfn_paged_out;
-if ( pfec & PFEC_page_shared )
-return HVMTRANS_gfn_shared;
-if ( pfinfo )
-{
-pfinfo->linear = addr;
-pfinfo->ec = pfec & ~PFEC_implicit;
-}
-return HVMTRANS_bad_linear_to_gfn;
-}
-gpa |= (paddr_t)gfn << PAGE_SHIFT;
-}
-else
-{
-gfn = addr >> PAGE_SHIFT;
-gpa = addr;
-}
-
-/*
- * No need to do the P2M lookup for internally handled MMIO, benefiting
- * - 32-bit WinXP (& older Windows) on AMD CPUs for LAPIC accesses,
- * - newer Windows (like Server 2012) for HPET accesses.
- */
-if ( v == current
- && !nestedhvm_vcpu_in_guestmode(v)
- && hvm_mmio_internal(gpa) )
-return HVMTRANS_bad_gfn_to_mfn;
-
-page = get_page_from_gfn(v->domain, gfn, , P2M_UNSHARE);
-
-if ( !page )
-return HVMTRANS_bad_gfn_to_mfn;
-
-if ( p2m_is_paging(p2mt) )
-{
-put_page(page);
-p2m_mem_paging_populate(v->domain, gfn);
-return HVMTRANS_gfn_paged_out;
-}
-if 

[Xen-devel] [PATCH v3 1/3] x86/hvm: Rename enum hvm_copy_result to hvm_translation_result

2017-09-19 Thread Alexandru Isaila
From: Andrew Cooper 

Signed-off-by: Andrew Cooper 

---
Acked-by: Jan Beulich 
Reviewed-by: Kevin Tian 
Acked-by: George Dunlap 
---
 xen/arch/x86/hvm/dom0_build.c |  2 +-
 xen/arch/x86/hvm/emulate.c| 40 ++--
 xen/arch/x86/hvm/hvm.c| 56 +++
 xen/arch/x86/hvm/intercept.c  | 20 +++---
 xen/arch/x86/hvm/svm/nestedsvm.c  |  5 ++--
 xen/arch/x86/hvm/svm/svm.c|  2 +-
 xen/arch/x86/hvm/viridian.c   |  2 +-
 xen/arch/x86/hvm/vmsi.c   |  2 +-
 xen/arch/x86/hvm/vmx/realmode.c   |  2 +-
 xen/arch/x86/hvm/vmx/vvmx.c   | 14 +-
 xen/arch/x86/mm/shadow/common.c   | 12 -
 xen/common/libelf/libelf-loader.c |  4 +--
 xen/include/asm-x86/hvm/support.h | 40 ++--
 13 files changed, 101 insertions(+), 100 deletions(-)

diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c
index 020c355..e8f746c 100644
--- a/xen/arch/x86/hvm/dom0_build.c
+++ b/xen/arch/x86/hvm/dom0_build.c
@@ -238,7 +238,7 @@ static int __init pvh_setup_vmx_realmode_helpers(struct 
domain *d)
 if ( !pvh_steal_ram(d, HVM_VM86_TSS_SIZE, 128, GB(4), ) )
 {
 if ( hvm_copy_to_guest_phys(gaddr, NULL, HVM_VM86_TSS_SIZE, v) !=
- HVMCOPY_okay )
+ HVMTRANS_okay )
 printk("Unable to zero VM86 TSS area\n");
 d->arch.hvm_domain.params[HVM_PARAM_VM86_TSS_SIZED] =
 VM86_TSS_UPDATED | ((uint64_t)HVM_VM86_TSS_SIZE << 32) | gaddr;
diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index 54811c1..cc874ce 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -100,7 +100,7 @@ static int ioreq_server_read(const struct hvm_io_handler 
*io_handler,
 uint32_t size,
 uint64_t *data)
 {
-if ( hvm_copy_from_guest_phys(data, addr, size) != HVMCOPY_okay )
+if ( hvm_copy_from_guest_phys(data, addr, size) != HVMTRANS_okay )
 return X86EMUL_UNHANDLEABLE;
 
 return X86EMUL_OKAY;
@@ -893,18 +893,18 @@ static int __hvmemul_read(
 
 switch ( rc )
 {
-case HVMCOPY_okay:
+case HVMTRANS_okay:
 break;
-case HVMCOPY_bad_gva_to_gfn:
+case HVMTRANS_bad_linear_to_gfn:
 x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
 return X86EMUL_EXCEPTION;
-case HVMCOPY_bad_gfn_to_mfn:
+case HVMTRANS_bad_gfn_to_mfn:
 if ( access_type == hvm_access_insn_fetch )
 return X86EMUL_UNHANDLEABLE;
 
 return hvmemul_linear_mmio_read(addr, bytes, p_data, pfec, 
hvmemul_ctxt, 0);
-case HVMCOPY_gfn_paged_out:
-case HVMCOPY_gfn_shared:
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
 return X86EMUL_RETRY;
 default:
 return X86EMUL_UNHANDLEABLE;
@@ -1012,15 +1012,15 @@ static int hvmemul_write(
 
 switch ( rc )
 {
-case HVMCOPY_okay:
+case HVMTRANS_okay:
 break;
-case HVMCOPY_bad_gva_to_gfn:
+case HVMTRANS_bad_linear_to_gfn:
 x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
 return X86EMUL_EXCEPTION;
-case HVMCOPY_bad_gfn_to_mfn:
+case HVMTRANS_bad_gfn_to_mfn:
 return hvmemul_linear_mmio_write(addr, bytes, p_data, pfec, 
hvmemul_ctxt, 0);
-case HVMCOPY_gfn_paged_out:
-case HVMCOPY_gfn_shared:
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
 return X86EMUL_RETRY;
 default:
 return X86EMUL_UNHANDLEABLE;
@@ -1384,7 +1384,7 @@ static int hvmemul_rep_movs(
 return rc;
 }
 
-rc = HVMCOPY_okay;
+rc = HVMTRANS_okay;
 }
 else
 /*
@@ -1394,16 +1394,16 @@ static int hvmemul_rep_movs(
  */
 rc = hvm_copy_from_guest_phys(buf, sgpa, bytes);
 
-if ( rc == HVMCOPY_okay )
+if ( rc == HVMTRANS_okay )
 rc = hvm_copy_to_guest_phys(dgpa, buf, bytes, current);
 
 xfree(buf);
 
-if ( rc == HVMCOPY_gfn_paged_out )
+if ( rc == HVMTRANS_gfn_paged_out )
 return X86EMUL_RETRY;
-if ( rc == HVMCOPY_gfn_shared )
+if ( rc == HVMTRANS_gfn_shared )
 return X86EMUL_RETRY;
-if ( rc != HVMCOPY_okay )
+if ( rc != HVMTRANS_okay )
 {
 gdprintk(XENLOG_WARNING, "Failed memory-to-memory REP MOVS: sgpa=%"
  PRIpaddr" dgpa=%"PRIpaddr" reps=%lu bytes_per_rep=%u\n",
@@ -1513,10 +1513,10 @@ static int hvmemul_rep_stos(
 
 switch ( rc )
 {
-case HVMCOPY_gfn_paged_out:
-case HVMCOPY_gfn_shared:
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
 return X86EMUL_RETRY;
-case HVMCOPY_okay:
+case HVMTRANS_okay:
 return X86EMUL_OKAY;
 }
 
@@ -2172,7 +2172,7 @@ void hvm_emulate_init_per_insn(
   

[Xen-devel] [PATCH v3 0/3] Various XSA followups

2017-09-19 Thread Alexandru Isaila
XSA-219 was discovered while trying to implement the bugfix in patch 3.

Andrew Cooper (3):
 [RFC] x86/hvm: Rename enum hvm_copy_result to hvm_translation_result
 x86/hvm: Break out __hvm_copy()'s translation logic
 x86/hvm: Implement hvmemul_write() using real mappings

Alexandru Isaila (2):
 x86/hvm: Break out __hvm_copy()'s translation logic
 x86/hvm: Implement hvmemul_write() using real mappings

---
Change log : I did not address the comments that are still in debate




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


[Xen-devel] [PATCH] x86/domctl: Don't pause the whole domain if only getting vcpu state

2017-09-12 Thread Alexandru Isaila
This patch adds the hvm_save_one_cpu_ctxt() function, called for the
XEN_DOMCTL_gethvmcontext_partial domctl.
It optimizes by only pausing the vcpu, and no longer the whole domain.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>
---
 xen/arch/x86/domctl.c |  20 +
 xen/arch/x86/hvm/hvm.c| 194 ++
 xen/include/asm-x86/hvm/hvm.h |   2 +
 3 files changed, 122 insertions(+), 94 deletions(-)

diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 127c84e..6c55622 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -625,6 +625,26 @@ long arch_do_domctl(
  !is_hvm_domain(d) )
 break;
 
+if ( domctl->u.hvmcontext_partial.type == HVM_SAVE_CODE(CPU) &&
+ domctl->u.hvmcontext_partial.instance < d->max_vcpus )
+{
+ struct vcpu *v = d->vcpu[domctl->u.hvmcontext_partial.instance];
+ struct hvm_hw_cpu ctx;
+
+ vcpu_pause(v);
+
+ hvm_save_one_cpu_ctxt(v, );
+
+ vcpu_unpause(v);
+
+ if ( copy_to_guest(domctl->u.hvmcontext_partial.buffer,
+(void *), sizeof(ctx)) )
+ret = -EFAULT;
+ else
+ret = 0;
+ break;
+}
+
 domain_pause(d);
 ret = hvm_save_one(d, domctl->u.hvmcontext_partial.type,
domctl->u.hvmcontext_partial.instance,
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 6cb903d..23f624b 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -768,11 +768,109 @@ static int hvm_load_tsc_adjust(struct domain *d, 
hvm_domain_context_t *h)
 HVM_REGISTER_SAVE_RESTORE(TSC_ADJUST, hvm_save_tsc_adjust,
   hvm_load_tsc_adjust, 1, HVMSR_PER_VCPU);
 
+void hvm_save_one_cpu_ctxt(struct vcpu *v, struct hvm_hw_cpu *ctxt)
+{
+struct segment_register seg;
+
+/* Architecture-specific vmcs/vmcb bits */
+hvm_funcs.save_cpu_ctxt(v, ctxt);
+
+ctxt->tsc = hvm_get_guest_tsc_fixed(v, 
v->domain->arch.hvm_domain.sync_tsc);
+
+ctxt->msr_tsc_aux = hvm_msr_tsc_aux(v);
+
+hvm_get_segment_register(v, x86_seg_idtr, );
+ctxt->idtr_limit = seg.limit;
+ctxt->idtr_base = seg.base;
+
+hvm_get_segment_register(v, x86_seg_gdtr, );
+ctxt->gdtr_limit = seg.limit;
+ctxt->gdtr_base = seg.base;
+
+hvm_get_segment_register(v, x86_seg_cs, );
+ctxt->cs_sel = seg.sel;
+ctxt->cs_limit = seg.limit;
+ctxt->cs_base = seg.base;
+ctxt->cs_arbytes = seg.attr;
+
+hvm_get_segment_register(v, x86_seg_ds, );
+ctxt->ds_sel = seg.sel;
+ctxt->ds_limit = seg.limit;
+ctxt->ds_base = seg.base;
+ctxt->ds_arbytes = seg.attr;
+
+hvm_get_segment_register(v, x86_seg_es, );
+ctxt->es_sel = seg.sel;
+ctxt->es_limit = seg.limit;
+ctxt->es_base = seg.base;
+ctxt->es_arbytes = seg.attr;
+
+hvm_get_segment_register(v, x86_seg_ss, );
+ctxt->ss_sel = seg.sel;
+ctxt->ss_limit = seg.limit;
+ctxt->ss_base = seg.base;
+ctxt->ss_arbytes = seg.attr;
+
+hvm_get_segment_register(v, x86_seg_fs, );
+ctxt->fs_sel = seg.sel;
+ctxt->fs_limit = seg.limit;
+ctxt->fs_base = seg.base;
+ctxt->fs_arbytes = seg.attr;
+
+hvm_get_segment_register(v, x86_seg_gs, );
+ctxt->gs_sel = seg.sel;
+ctxt->gs_limit = seg.limit;
+ctxt->gs_base = seg.base;
+ctxt->gs_arbytes = seg.attr;
+
+hvm_get_segment_register(v, x86_seg_tr, );
+ctxt->tr_sel = seg.sel;
+ctxt->tr_limit = seg.limit;
+ctxt->tr_base = seg.base;
+ctxt->tr_arbytes = seg.attr;
+
+hvm_get_segment_register(v, x86_seg_ldtr, );
+ctxt->ldtr_sel = seg.sel;
+ctxt->ldtr_limit = seg.limit;
+ctxt->ldtr_base = seg.base;
+ctxt->ldtr_arbytes = seg.attr;
+
+if ( v->fpu_initialised )
+{
+memcpy(ctxt->fpu_regs, v->arch.fpu_ctxt, sizeof(ctxt->fpu_regs));
+ctxt->flags = XEN_X86_FPU_INITIALISED;
+}
+
+ctxt->rax = v->arch.user_regs.eax;
+ctxt->rbx = v->arch.user_regs.ebx;
+ctxt->rcx = v->arch.user_regs.ecx;
+ctxt->rdx = v->arch.user_regs.edx;
+ctxt->rbp = v->arch.user_regs.ebp;
+ctxt->rsi = v->arch.user_regs.esi;
+ctxt->rdi = v->arch.user_regs.edi;
+ctxt->rsp = v->arch.user_regs.esp;
+ctxt->rip = v->arch.user_regs.eip;
+ctxt->rflags = v->arch.user_regs.eflags;
+ctxt->r8  = v->arch.user_regs.r8;
+ctxt->r9  = v->arch.user_regs.r9;
+ctxt->r10 = v->arch.user_regs.r10;
+ctxt->r11 = v->arch.user_regs.r11;
+ctxt->r12 = v->arch.user_regs.r12;
+ctxt->r13 = v->arch.user_regs.r13;
+ctxt->r14 = v->arch.user_regs.r14;
+ctxt->r15 = v-&g

[Xen-devel] [PATCH v2 2/4] x86/hvm: Rename enum hvm_copy_result to hvm_translation_result

2017-09-08 Thread Alexandru Isaila
From: Andrew Cooper 

Signed-off-by: Andrew Cooper 
---
CC: Jan Beulich 
---
 xen/arch/x86/hvm/dom0_build.c |  2 +-
 xen/arch/x86/hvm/emulate.c| 40 ++--
 xen/arch/x86/hvm/hvm.c| 56 +++
 xen/arch/x86/hvm/intercept.c  | 20 +++---
 xen/arch/x86/hvm/svm/nestedsvm.c  |  5 ++--
 xen/arch/x86/hvm/svm/svm.c|  2 +-
 xen/arch/x86/hvm/viridian.c   |  2 +-
 xen/arch/x86/hvm/vmsi.c   |  2 +-
 xen/arch/x86/hvm/vmx/realmode.c   |  2 +-
 xen/arch/x86/hvm/vmx/vvmx.c   | 14 +-
 xen/arch/x86/mm/shadow/common.c   | 12 -
 xen/common/libelf/libelf-loader.c |  4 +--
 xen/include/asm-x86/hvm/support.h | 40 ++--
 13 files changed, 101 insertions(+), 100 deletions(-)

diff --git a/xen/arch/x86/hvm/dom0_build.c b/xen/arch/x86/hvm/dom0_build.c
index 020c355..e8f746c 100644
--- a/xen/arch/x86/hvm/dom0_build.c
+++ b/xen/arch/x86/hvm/dom0_build.c
@@ -238,7 +238,7 @@ static int __init pvh_setup_vmx_realmode_helpers(struct 
domain *d)
 if ( !pvh_steal_ram(d, HVM_VM86_TSS_SIZE, 128, GB(4), ) )
 {
 if ( hvm_copy_to_guest_phys(gaddr, NULL, HVM_VM86_TSS_SIZE, v) !=
- HVMCOPY_okay )
+ HVMTRANS_okay )
 printk("Unable to zero VM86 TSS area\n");
 d->arch.hvm_domain.params[HVM_PARAM_VM86_TSS_SIZED] =
 VM86_TSS_UPDATED | ((uint64_t)HVM_VM86_TSS_SIZE << 32) | gaddr;
diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index 64454c7..c871cb3 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -100,7 +100,7 @@ static int ioreq_server_read(const struct hvm_io_handler 
*io_handler,
 uint32_t size,
 uint64_t *data)
 {
-if ( hvm_copy_from_guest_phys(data, addr, size) != HVMCOPY_okay )
+if ( hvm_copy_from_guest_phys(data, addr, size) != HVMTRANS_okay )
 return X86EMUL_UNHANDLEABLE;
 
 return X86EMUL_OKAY;
@@ -892,18 +892,18 @@ static int __hvmemul_read(
 
 switch ( rc )
 {
-case HVMCOPY_okay:
+case HVMTRANS_okay:
 break;
-case HVMCOPY_bad_gva_to_gfn:
+case HVMTRANS_bad_linear_to_gfn:
 x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
 return X86EMUL_EXCEPTION;
-case HVMCOPY_bad_gfn_to_mfn:
+case HVMTRANS_bad_gfn_to_mfn:
 if ( access_type == hvm_access_insn_fetch )
 return X86EMUL_UNHANDLEABLE;
 
 return hvmemul_linear_mmio_read(addr, bytes, p_data, pfec, 
hvmemul_ctxt, 0);
-case HVMCOPY_gfn_paged_out:
-case HVMCOPY_gfn_shared:
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
 return X86EMUL_RETRY;
 default:
 return X86EMUL_UNHANDLEABLE;
@@ -1011,15 +1011,15 @@ static int hvmemul_write(
 
 switch ( rc )
 {
-case HVMCOPY_okay:
+case HVMTRANS_okay:
 break;
-case HVMCOPY_bad_gva_to_gfn:
+case HVMTRANS_bad_linear_to_gfn:
 x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
 return X86EMUL_EXCEPTION;
-case HVMCOPY_bad_gfn_to_mfn:
+case HVMTRANS_bad_gfn_to_mfn:
 return hvmemul_linear_mmio_write(addr, bytes, p_data, pfec, 
hvmemul_ctxt, 0);
-case HVMCOPY_gfn_paged_out:
-case HVMCOPY_gfn_shared:
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
 return X86EMUL_RETRY;
 default:
 return X86EMUL_UNHANDLEABLE;
@@ -1383,7 +1383,7 @@ static int hvmemul_rep_movs(
 return rc;
 }
 
-rc = HVMCOPY_okay;
+rc = HVMTRANS_okay;
 }
 else
 /*
@@ -1393,16 +1393,16 @@ static int hvmemul_rep_movs(
  */
 rc = hvm_copy_from_guest_phys(buf, sgpa, bytes);
 
-if ( rc == HVMCOPY_okay )
+if ( rc == HVMTRANS_okay )
 rc = hvm_copy_to_guest_phys(dgpa, buf, bytes, current);
 
 xfree(buf);
 
-if ( rc == HVMCOPY_gfn_paged_out )
+if ( rc == HVMTRANS_gfn_paged_out )
 return X86EMUL_RETRY;
-if ( rc == HVMCOPY_gfn_shared )
+if ( rc == HVMTRANS_gfn_shared )
 return X86EMUL_RETRY;
-if ( rc != HVMCOPY_okay )
+if ( rc != HVMTRANS_okay )
 {
 gdprintk(XENLOG_WARNING, "Failed memory-to-memory REP MOVS: sgpa=%"
  PRIpaddr" dgpa=%"PRIpaddr" reps=%lu bytes_per_rep=%u\n",
@@ -1512,10 +1512,10 @@ static int hvmemul_rep_stos(
 
 switch ( rc )
 {
-case HVMCOPY_gfn_paged_out:
-case HVMCOPY_gfn_shared:
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
 return X86EMUL_RETRY;
-case HVMCOPY_okay:
+case HVMTRANS_okay:
 return X86EMUL_OKAY;
 }
 
@@ -2171,7 +2171,7 @@ void hvm_emulate_init_per_insn(
 ) &&
  hvm_fetch_from_guest_linear(hvmemul_ctxt->insn_buf, addr,
  

[Xen-devel] [PATCH v2 3/4] x86/hvm: Break out __hvm_copy()'s translation logic

2017-09-08 Thread Alexandru Isaila
From: Andrew Cooper <andrew.coop...@citrix.com>

It will be reused by later changes.

Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com>
Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
CC: Jan Beulich <jbeul...@suse.com>

Changes since V1:
- Changed param name
- Added ASSERT
---
 xen/arch/x86/hvm/hvm.c| 144 +++---
 xen/include/asm-x86/hvm/support.h |  12 
 2 files changed, 98 insertions(+), 58 deletions(-)

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 488acbf..a60149a 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -3069,6 +3069,83 @@ void hvm_task_switch(
 hvm_unmap_entry(nptss_desc);
 }
 
+enum hvm_translation_result hvm_translate_get_page(
+struct vcpu *v, unsigned long addr, bool linear, uint32_t pfec,
+pagefault_info_t *pfinfo, struct page_info **page_p,
+gfn_t *gfn_p, p2m_type_t *p2mt_p)
+{
+struct page_info *page;
+p2m_type_t p2mt;
+gfn_t gfn;
+
+if ( linear )
+{
+gfn = _gfn(paging_gva_to_gfn(v, addr, ));
+
+if ( gfn_eq(gfn, INVALID_GFN) )
+{
+if ( pfec & PFEC_page_paged )
+return HVMTRANS_gfn_paged_out;
+
+if ( pfec & PFEC_page_shared )
+return HVMTRANS_gfn_shared;
+
+if ( pfinfo )
+{
+pfinfo->linear = addr;
+pfinfo->ec = pfec & ~PFEC_implicit;
+}
+
+return HVMTRANS_bad_linear_to_gfn;
+}
+}
+else
+{
+gfn = _gfn(addr >> PAGE_SHIFT);
+ASSERT(!pfinfo);
+}
+
+/*
+ * No need to do the P2M lookup for internally handled MMIO, benefiting
+ * - 32-bit WinXP (& older Windows) on AMD CPUs for LAPIC accesses,
+ * - newer Windows (like Server 2012) for HPET accesses.
+ */
+if ( v == current
+ && !nestedhvm_vcpu_in_guestmode(v)
+ && hvm_mmio_internal(gfn_x(gfn) << PAGE_SHIFT) )
+return HVMTRANS_bad_gfn_to_mfn;
+
+page = get_page_from_gfn(v->domain, gfn_x(gfn), , P2M_UNSHARE);
+
+if ( !page )
+return HVMTRANS_bad_gfn_to_mfn;
+
+if ( p2m_is_paging(p2mt) )
+{
+put_page(page);
+p2m_mem_paging_populate(v->domain, gfn_x(gfn));
+return HVMTRANS_gfn_paged_out;
+}
+if ( p2m_is_shared(p2mt) )
+{
+put_page(page);
+return HVMTRANS_gfn_shared;
+}
+if ( p2m_is_grant(p2mt) )
+{
+put_page(page);
+return HVMTRANS_unhandleable;
+}
+
+*page_p = page;
+if ( gfn_p )
+*gfn_p = gfn;
+if ( p2mt_p )
+*p2mt_p = p2mt;
+
+return HVMTRANS_okay;
+}
+
 #define HVMCOPY_from_guest (0u<<0)
 #define HVMCOPY_to_guest   (1u<<0)
 #define HVMCOPY_phys   (0u<<2)
@@ -3077,7 +3154,7 @@ static enum hvm_translation_result __hvm_copy(
 void *buf, paddr_t addr, int size, struct vcpu *v, unsigned int flags,
 uint32_t pfec, pagefault_info_t *pfinfo)
 {
-unsigned long gfn;
+gfn_t gfn;
 struct page_info *page;
 p2m_type_t p2mt;
 char *p;
@@ -3103,65 +3180,15 @@ static enum hvm_translation_result __hvm_copy(
 
 while ( todo > 0 )
 {
+enum hvm_translation_result res;
 paddr_t gpa = addr & ~PAGE_MASK;
 
 count = min_t(int, PAGE_SIZE - gpa, todo);
 
-if ( flags & HVMCOPY_linear )
-{
-gfn = paging_gva_to_gfn(v, addr, );
-if ( gfn == gfn_x(INVALID_GFN) )
-{
-if ( pfec & PFEC_page_paged )
-return HVMTRANS_gfn_paged_out;
-if ( pfec & PFEC_page_shared )
-return HVMTRANS_gfn_shared;
-if ( pfinfo )
-{
-pfinfo->linear = addr;
-pfinfo->ec = pfec & ~PFEC_implicit;
-}
-return HVMTRANS_bad_linear_to_gfn;
-}
-gpa |= (paddr_t)gfn << PAGE_SHIFT;
-}
-else
-{
-gfn = addr >> PAGE_SHIFT;
-gpa = addr;
-}
-
-/*
- * No need to do the P2M lookup for internally handled MMIO, benefiting
- * - 32-bit WinXP (& older Windows) on AMD CPUs for LAPIC accesses,
- * - newer Windows (like Server 2012) for HPET accesses.
- */
-if ( v == current
- && !nestedhvm_vcpu_in_guestmode(v)
- && hvm_mmio_internal(gpa) )
-return HVMTRANS_bad_gfn_to_mfn;
-
-page = get_page_from_gfn(v->domain, gfn, , P2M_UNSHARE);
-
-if ( !page )
-return HVMTRANS_bad_gfn_to_mfn;
-
-if ( p2m_is_paging(p2mt) )
-{
-put_page(page);
-p2m_mem_paging_populate(v->domain, gfn);
-

[Xen-devel] [PATCH v2 1/4] x86/shadow: Use ERR_PTR infrastructure for sh_emulate_map_dest()

2017-09-08 Thread Alexandru Isaila
From: Andrew Cooper 

sh_emulate_map_dest() predates the introduction of the generic ERR_PTR()
infrastructure, but take the opportunity to avoid opencoding it.

The chosen error constants require need to be negative to work with IS_ERR(),
but no other changes.

Signed-off-by: Andrew Cooper 

---
CC: Jan Beulich 
CC: Tim Deegan 

v2:
 * Use ~(long)X86EMUL rather than -X86EMUL so MAPPING_SILENT_FAIL is
   considered an error to IS_ERR()
---
 xen/arch/x86/mm/shadow/multi.c   | 8 
 xen/arch/x86/mm/shadow/private.h | 7 +++
 2 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c
index f7efe66..8d4f244 100644
--- a/xen/arch/x86/mm/shadow/multi.c
+++ b/xen/arch/x86/mm/shadow/multi.c
@@ -4754,8 +4754,8 @@ sh_x86_emulate_write(struct vcpu *v, unsigned long vaddr, 
void *src,
 return X86EMUL_UNHANDLEABLE;
 
 addr = sh_emulate_map_dest(v, vaddr, bytes, sh_ctxt);
-if ( sh_emulate_map_dest_failed(addr) )
-return (long)addr;
+if ( IS_ERR(addr) )
+return ~PTR_ERR(addr);
 
 paging_lock(v->domain);
 memcpy(addr, src, bytes);
@@ -4796,8 +4796,8 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long 
vaddr,
 return X86EMUL_UNHANDLEABLE;
 
 addr = sh_emulate_map_dest(v, vaddr, bytes, sh_ctxt);
-if ( sh_emulate_map_dest_failed(addr) )
-return (long)addr;
+if ( IS_ERR(addr) )
+return ~PTR_ERR(addr);
 
 paging_lock(v->domain);
 switch ( bytes )
diff --git a/xen/arch/x86/mm/shadow/private.h b/xen/arch/x86/mm/shadow/private.h
index 46d9bab..6a03370 100644
--- a/xen/arch/x86/mm/shadow/private.h
+++ b/xen/arch/x86/mm/shadow/private.h
@@ -395,10 +395,9 @@ void shadow_unhook_mappings(struct domain *d, mfn_t smfn, 
int user_only);
 
 /* Returns a mapped pointer to write to, or one of the following error
  * indicators. */
-#define MAPPING_UNHANDLEABLE ((void *)(unsigned long)X86EMUL_UNHANDLEABLE)
-#define MAPPING_EXCEPTION((void *)(unsigned long)X86EMUL_EXCEPTION)
-#define MAPPING_SILENT_FAIL  ((void *)(unsigned long)X86EMUL_OKAY)
-#define sh_emulate_map_dest_failed(rc) ((unsigned long)(rc) <= 3)
+#define MAPPING_UNHANDLEABLE ERR_PTR(~(long)X86EMUL_UNHANDLEABLE)
+#define MAPPING_EXCEPTIONERR_PTR(~(long)X86EMUL_EXCEPTION)
+#define MAPPING_SILENT_FAIL  ERR_PTR(~(long)X86EMUL_OKAY)
 void *sh_emulate_map_dest(struct vcpu *v, unsigned long vaddr,
   unsigned int bytes, struct sh_emulate_ctxt *sh_ctxt);
 void sh_emulate_unmap_dest(struct vcpu *v, void *addr, unsigned int bytes,
-- 
2.7.4


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


[Xen-devel] [PATCH v2 0/4] Various XSA followups

2017-09-08 Thread Alexandru Isaila
XSA-219 was discovered while trying to implement the bugfix in patch 4.

Andrew Cooper (4):
 x86/shadow: Use ERR_PTR infrastructure for sh_emulate_map_dest()
 [RFC] x86/hvm: Rename enum hvm_copy_result to hvm_translation_result
 x86/hvm: Break out __hvm_copy()'s translation logic
 x86/hvm: Implement hvmemul_write() using real mappings

Alexandru Isaila (2):
 x86/hvm: Break out __hvm_copy()'s translation logic
 x86/hvm: Implement hvmemul_write() using real mappings




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


[Xen-devel] [PATCH v2 4/4] x86/hvm: Implement hvmemul_write() using real mappings

2017-09-08 Thread Alexandru Isaila
From: Andrew Cooper <andrew.coop...@citrix.com>

An access which crosses a page boundary is performed atomically by x86
hardware, albeit with a severe performance penalty.  An important corner case
is when a straddled access hits two pages which differ in whether a
translation exists, or in net access rights.

The use of hvm_copy*() in hvmemul_write() is problematic, because it performs
a translation then completes the partial write, before moving onto the next
translation.

If an individual emulated write straddles two pages, the first of which is
writable, and the second of which is not, the first half of the write will
complete before #PF is raised from the second half.

This results in guest state corruption as a side effect of emulation, which
has been observed to cause windows to crash while under introspection.

Introduce the hvmemul_{,un}map_linear_addr() helpers, which translate an
entire contents of a linear access, and vmap() the underlying frames to
provide a contiguous virtual mapping for the emulator to use.  This is the
same mechanism as used by the shadow emulation code.

This will catch any translation issues and abort the emulation before any
modifications occur.

Signed-off-by: Andrew Cooper <andrew.coop...@citrix.com>
Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>
---
CC: Jan Beulich <jbeul...@suse.com>
CC: Paul Durrant <paul.durr...@citrix.com>
CC: Razvan Cojocaru <rcojoc...@bitdefender.com>
CC: Mihai Donțu <mdo...@bitdefender.com>

Changes since V1:
- Moved ASSERT to the begining of the loop
- Corrected the decrement on mfn int the while statement
- Modified the comment to PAGE_SIZE+1

While the maximum size of linear mapping is capped at 1 page, the logic
in the helpers is written to work properly as hvmemul_ctxt->mfn[] gets longer,
specifically with XSAVE instruction emulation in mind.

This has only had light testing so far.
---
 xen/arch/x86/hvm/emulate.c| 179 ++
 xen/include/asm-x86/hvm/emulate.h |   7 ++
 2 files changed, 169 insertions(+), 17 deletions(-)

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index c871cb3..196a77c 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -498,6 +498,159 @@ static int hvmemul_do_mmio_addr(paddr_t mmio_gpa,
 }
 
 /*
+ * Map the frame(s) covering an individual linear access, for writeable
+ * access.  May return NULL for MMIO, or ERR_PTR(~X86EMUL_*) for other errors
+ * including ERR_PTR(~X86EMUL_OKAY) for write-discard mappings.
+ *
+ * In debug builds, map() checks that each slot in hvmemul_ctxt->mfn[] is
+ * clean before use, and poisions unused slots with INVALID_MFN.
+ */
+static void *hvmemul_map_linear_addr(
+unsigned long linear, unsigned int bytes, uint32_t pfec,
+struct hvm_emulate_ctxt *hvmemul_ctxt)
+{
+struct vcpu *curr = current;
+void *err, *mapping;
+
+/* First and final gfns which need mapping. */
+unsigned long frame = linear >> PAGE_SHIFT, first = frame;
+unsigned long final = (linear + bytes - !!bytes) >> PAGE_SHIFT;
+
+/*
+ * mfn points to the next free slot.  All used slots have a page reference
+ * held on them.
+ */
+mfn_t *mfn = _ctxt->mfn[0];
+
+/*
+ * The caller has no legitimate reason for trying a zero-byte write, but
+ * final is calculate to fail safe in release builds.
+ *
+ * The maximum write size depends on the number of adjacent mfns[] which
+ * can be vmap()'d, accouting for possible misalignment within the region.
+ * The higher level emulation callers are responsible for ensuring that
+ * mfns[] is large enough for the requested write size.
+ */
+if ( bytes == 0 ||
+ final - first > ARRAY_SIZE(hvmemul_ctxt->mfn) - 1 )
+{
+ASSERT_UNREACHABLE();
+goto unhandleable;
+}
+
+do {
+enum hvm_translation_result res;
+struct page_info *page;
+pagefault_info_t pfinfo;
+p2m_type_t p2mt;
+
+/* Error checking.  Confirm that the current slot is clean. */
+ASSERT(mfn_x(*mfn) == 0);
+
+res = hvm_translate_get_page(curr, frame << PAGE_SHIFT, true, pfec,
+ , , NULL, );
+
+switch ( res )
+{
+case HVMTRANS_okay:
+break;
+
+case HVMTRANS_bad_linear_to_gfn:
+x86_emul_pagefault(pfinfo.ec, pfinfo.linear, _ctxt->ctxt);
+err = ERR_PTR(~(long)X86EMUL_EXCEPTION);
+goto out;
+
+case HVMTRANS_bad_gfn_to_mfn:
+err = NULL;
+goto out;
+
+case HVMTRANS_gfn_paged_out:
+case HVMTRANS_gfn_shared:
+err = ERR_PTR(~(long)X86EMUL_RETRY);
+goto out;
+
+default:
+goto unhandleable;
+}
+
+*mfn++ = _mfn(page_to_mfn(page));
+frame++;
+
+

[Xen-devel] [PATCH v1] x86/hvm: Expose MSR_SHADOW_GS_BASE

2017-09-01 Thread Alexandru Isaila
This patch is adding an new param in the hvm_hw_cpu structure
so it can be exposed to user space.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>
---
 xen/arch/x86/hvm/hvm.c | 4 
 xen/include/public/arch-x86/hvm/save.h | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 6cb903d..519333c 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -834,6 +834,8 @@ static int hvm_save_cpu_ctxt(struct domain *d, 
hvm_domain_context_t *h)
 ctxt.gs_base = seg.base;
 ctxt.gs_arbytes = seg.attr;
 
+rdmsrl(MSR_SHADOW_GS_BASE, ctxt.shadow_gs_base);
+
 hvm_get_segment_register(v, x86_seg_tr, );
 ctxt.tr_sel = seg.sel;
 ctxt.tr_limit = seg.limit;
@@ -1090,6 +1092,8 @@ static int hvm_load_cpu_ctxt(struct domain *d, 
hvm_domain_context_t *h)
 seg.attr = ctxt.gs_arbytes;
 hvm_set_segment_register(v, x86_seg_gs, );
 
+wrmsrl(MSR_SHADOW_GS_BASE, ctxt.shadow_gs_base);
+
 seg.sel = ctxt.tr_sel;
 seg.limit = ctxt.tr_limit;
 seg.base = ctxt.tr_base;
diff --git a/xen/include/public/arch-x86/hvm/save.h 
b/xen/include/public/arch-x86/hvm/save.h
index fd7bf3f..e6e8e87 100644
--- a/xen/include/public/arch-x86/hvm/save.h
+++ b/xen/include/public/arch-x86/hvm/save.h
@@ -134,6 +134,8 @@ struct hvm_hw_cpu {
 /* msr for em64t */
 uint64_t shadow_gs;
 
+uint64_t shadow_gs_base;
+
 /* msr content saved/restored. */
 uint64_t msr_flags; /* Obsolete, ignored. */
 uint64_t msr_lstar;
-- 
2.7.4


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


[Xen-devel] [PATCH v6] common/vm_event: Initialize vm_event lists on domain creation

2017-08-30 Thread Alexandru Isaila
The patch splits the vm_event into three structures:vm_event_share,
vm_event_paging, vm_event_monitor. The allocation for the
structure is moved to vm_event_enable so that it can be
allocated/init when needed and freed in vm_event_disable.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V5:
- Removed unnecessary parentheses
- Alingned code in vm_event_enable
- Added ifdef config option in the struct
declaration

Note: Did not test on arm, compliled on arm and x86.
---
 xen/arch/arm/mem_access.c |   2 +-
 xen/arch/x86/mm/mem_access.c  |   2 +-
 xen/arch/x86/mm/mem_paging.c  |   3 +-
 xen/arch/x86/mm/mem_sharing.c |   4 +-
 xen/arch/x86/mm/p2m.c |  10 +--
 xen/common/domain.c   |  13 ++--
 xen/common/mem_access.c   |   2 +-
 xen/common/monitor.c  |   4 +-
 xen/common/vm_event.c | 146 --
 xen/drivers/passthrough/pci.c |   3 +-
 xen/include/xen/sched.h   |  22 +++
 11 files changed, 119 insertions(+), 92 deletions(-)

diff --git a/xen/arch/arm/mem_access.c b/xen/arch/arm/mem_access.c
index e0888bb..a7f0cae 100644
--- a/xen/arch/arm/mem_access.c
+++ b/xen/arch/arm/mem_access.c
@@ -256,7 +256,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const 
struct npfec npfec)
 }
 
 /* Otherwise, check if there is a vm_event monitor subscriber */
-if ( !vm_event_check_ring(>domain->vm_event->monitor) )
+if ( !vm_event_check_ring(v->domain->vm_event_monitor) )
 {
 /* No listener */
 if ( p2m->access_required )
diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
index 5adaf6d..414e38f 100644
--- a/xen/arch/x86/mm/mem_access.c
+++ b/xen/arch/x86/mm/mem_access.c
@@ -179,7 +179,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, unsigned long gla,
 gfn_unlock(p2m, gfn, 0);
 
 /* Otherwise, check if there is a memory event listener, and send the 
message along */
-if ( !vm_event_check_ring(>vm_event->monitor) || !req_ptr )
+if ( !vm_event_check_ring(d->vm_event_monitor) || !req_ptr )
 {
 /* No listener */
 if ( p2m->access_required )
diff --git a/xen/arch/x86/mm/mem_paging.c b/xen/arch/x86/mm/mem_paging.c
index a049e0d..54a94fa 100644
--- a/xen/arch/x86/mm/mem_paging.c
+++ b/xen/arch/x86/mm/mem_paging.c
@@ -22,6 +22,7 @@
 
 #include 
 #include 
+#include 
 #include 
 
 int mem_paging_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_paging_op_t) arg)
@@ -43,7 +44,7 @@ int 
mem_paging_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_paging_op_t) arg)
 goto out;
 
 rc = -ENODEV;
-if ( unlikely(!d->vm_event->paging.ring_page) )
+if ( unlikely(!vm_event_check_ring(d->vm_event_paging)) )
 goto out;
 
 switch( mpo.op )
diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
index 1f20ce7..12fb9cc 100644
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -563,7 +563,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned 
long gfn,
 };
 
 if ( (rc = __vm_event_claim_slot(d, 
->vm_event->share, allow_sleep)) < 0 )
+d->vm_event_share, allow_sleep)) < 0 )
 return rc;
 
 if ( v->domain == d )
@@ -572,7 +572,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned 
long gfn,
 vm_event_vcpu_pause(v);
 }
 
-vm_event_put_request(d, >vm_event->share, );
+vm_event_put_request(d, d->vm_event_share, );
 
 return 0;
 }
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index e8a57d1..6ae23be 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1454,7 +1454,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned 
long gfn,
  * correctness of the guest execution at this point.  If this is the only
  * page that happens to be paged-out, we'll be okay..  but it's likely the
  * guest will crash shortly anyways. */
-int rc = vm_event_claim_slot(d, >vm_event->paging);
+int rc = vm_event_claim_slot(d, d->vm_event_paging);
 if ( rc < 0 )
 return;
 
@@ -1468,7 +1468,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned 
long gfn,
 /* Evict will fail now, tag this request for pager */
 req.u.mem_paging.flags |= MEM_PAGING_EVICT_FAIL;
 
-vm_event_put_request(d, >vm_event->paging, );
+vm_event_put_request(d, d->vm_event_paging, );
 }
 
 /**
@@ -1505,7 +1505,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned 
long gfn)
 struct p2m_domain *p2m = p2m_get_hostp2m(d);
 
 /* We're paging. There should be a ring */
-int rc = vm_event_claim_slot(d, >vm_event->paging);
+int rc = vm_event_claim_slot(d, d->vm_event_paging);
 if ( rc == -ENOSYS )
 {
 gdprintk(XENLOG_ERR, "Domain %hu paging gfn %lx yet no ring "
@@ -1543,7 +1543,7

[Xen-devel] [PATCH v5] common/vm_event: Initialize vm_event lists on domain creation

2017-08-29 Thread Alexandru Isaila
The patch splits the vm_event into three structures:vm_event_share,
vm_event_paging, vm_event_monitor. The allocation for the
structure is moved to vm_event_enable so that it can be
allocated/init when needed and freed in vm_event_disable.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V4:
- Replaced all NULL checks with vm_event_check_ring

Note: Did not test on arm, compliled on arm and x86.
---
 xen/arch/arm/mem_access.c |   2 +-
 xen/arch/x86/mm/mem_access.c  |   2 +-
 xen/arch/x86/mm/mem_paging.c  |   3 +-
 xen/arch/x86/mm/mem_sharing.c |   4 +-
 xen/arch/x86/mm/p2m.c |  10 +--
 xen/common/domain.c   |  13 ++--
 xen/common/mem_access.c   |   2 +-
 xen/common/monitor.c  |   4 +-
 xen/common/vm_event.c | 146 --
 xen/drivers/passthrough/pci.c |   3 +-
 xen/include/xen/sched.h   |  18 ++
 11 files changed, 115 insertions(+), 92 deletions(-)

diff --git a/xen/arch/arm/mem_access.c b/xen/arch/arm/mem_access.c
index e0888bb..a7f0cae 100644
--- a/xen/arch/arm/mem_access.c
+++ b/xen/arch/arm/mem_access.c
@@ -256,7 +256,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const 
struct npfec npfec)
 }
 
 /* Otherwise, check if there is a vm_event monitor subscriber */
-if ( !vm_event_check_ring(>domain->vm_event->monitor) )
+if ( !vm_event_check_ring(v->domain->vm_event_monitor) )
 {
 /* No listener */
 if ( p2m->access_required )
diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
index 5adaf6d..414e38f 100644
--- a/xen/arch/x86/mm/mem_access.c
+++ b/xen/arch/x86/mm/mem_access.c
@@ -179,7 +179,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, unsigned long gla,
 gfn_unlock(p2m, gfn, 0);
 
 /* Otherwise, check if there is a memory event listener, and send the 
message along */
-if ( !vm_event_check_ring(>vm_event->monitor) || !req_ptr )
+if ( !vm_event_check_ring(d->vm_event_monitor) || !req_ptr )
 {
 /* No listener */
 if ( p2m->access_required )
diff --git a/xen/arch/x86/mm/mem_paging.c b/xen/arch/x86/mm/mem_paging.c
index a049e0d..54a94fa 100644
--- a/xen/arch/x86/mm/mem_paging.c
+++ b/xen/arch/x86/mm/mem_paging.c
@@ -22,6 +22,7 @@
 
 #include 
 #include 
+#include 
 #include 
 
 int mem_paging_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_paging_op_t) arg)
@@ -43,7 +44,7 @@ int 
mem_paging_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_paging_op_t) arg)
 goto out;
 
 rc = -ENODEV;
-if ( unlikely(!d->vm_event->paging.ring_page) )
+if ( unlikely(!vm_event_check_ring(d->vm_event_paging)) )
 goto out;
 
 switch( mpo.op )
diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
index 1f20ce7..12fb9cc 100644
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -563,7 +563,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned 
long gfn,
 };
 
 if ( (rc = __vm_event_claim_slot(d, 
->vm_event->share, allow_sleep)) < 0 )
+d->vm_event_share, allow_sleep)) < 0 )
 return rc;
 
 if ( v->domain == d )
@@ -572,7 +572,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned 
long gfn,
 vm_event_vcpu_pause(v);
 }
 
-vm_event_put_request(d, >vm_event->share, );
+vm_event_put_request(d, d->vm_event_share, );
 
 return 0;
 }
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index e8a57d1..6ae23be 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1454,7 +1454,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned 
long gfn,
  * correctness of the guest execution at this point.  If this is the only
  * page that happens to be paged-out, we'll be okay..  but it's likely the
  * guest will crash shortly anyways. */
-int rc = vm_event_claim_slot(d, >vm_event->paging);
+int rc = vm_event_claim_slot(d, d->vm_event_paging);
 if ( rc < 0 )
 return;
 
@@ -1468,7 +1468,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned 
long gfn,
 /* Evict will fail now, tag this request for pager */
 req.u.mem_paging.flags |= MEM_PAGING_EVICT_FAIL;
 
-vm_event_put_request(d, >vm_event->paging, );
+vm_event_put_request(d, d->vm_event_paging, );
 }
 
 /**
@@ -1505,7 +1505,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned 
long gfn)
 struct p2m_domain *p2m = p2m_get_hostp2m(d);
 
 /* We're paging. There should be a ring */
-int rc = vm_event_claim_slot(d, >vm_event->paging);
+int rc = vm_event_claim_slot(d, d->vm_event_paging);
 if ( rc == -ENOSYS )
 {
 gdprintk(XENLOG_ERR, "Domain %hu paging gfn %lx yet no ring "
@@ -1543,7 +1543,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned 
long gfn)
 else if ( p2mt != p2m_ra

[Xen-devel] [PATCH v10] x86/hvm: Allow guest_request vm_events coming from userspace

2017-08-29 Thread Alexandru Isaila
In some introspection usecases, an in-guest agent needs to communicate
with the external introspection agent.  An existing mechanism is
HVMOP_guest_request_vm_event, but this is restricted to kernel usecases
like all other hypercalls.

Introduce a mechanism whereby the introspection agent can whitelist the
use of HVMOP_guest_request_vm_event directly from userspace.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>
Acked-by: Wei Liu <wei.l...@citrix.com>

---
Changes since V9:
- Changed allow_userspace type from uint8_t ro bool
- Added Wei Liu's ack from v7

Note: Could not test on ARM, compiled both on arm and x86
---
 tools/libxc/include/xenctrl.h |  2 +-
 tools/libxc/xc_monitor.c  |  3 ++-
 xen/arch/x86/hvm/hypercall.c  |  5 +
 xen/common/monitor.c  |  1 +
 xen/include/asm-arm/monitor.h |  6 ++
 xen/include/asm-x86/domain.h  | 19 ++-
 xen/include/asm-x86/monitor.h |  6 ++
 xen/include/public/domctl.h   |  1 +
 8 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index bde8313..a3d0929 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2021,7 +2021,7 @@ int xc_monitor_software_breakpoint(xc_interface *xch, 
domid_t domain_id,
 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);
+ bool enable, bool sync, bool allow_userspace);
 int xc_monitor_debug_exceptions(xc_interface *xch, domid_t domain_id,
 bool enable, bool sync);
 int xc_monitor_cpuid(xc_interface *xch, domid_t domain_id, bool enable);
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index b44ce93..a677820 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -147,7 +147,7 @@ int xc_monitor_descriptor_access(xc_interface *xch, domid_t 
domain_id,
 }
 
 int xc_monitor_guest_request(xc_interface *xch, domid_t domain_id, bool enable,
- bool sync)
+ bool sync, bool allow_userspace)
 {
 DECLARE_DOMCTL;
 
@@ -157,6 +157,7 @@ int xc_monitor_guest_request(xc_interface *xch, domid_t 
domain_id, bool enable,
 : XEN_DOMCTL_MONITOR_OP_DISABLE;
 domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST;
 domctl.u.monitor_op.u.guest_request.sync = sync;
+domctl.u.monitor_op.u.guest_request.allow_userspace = enable ? 
allow_userspace : false;
 
 return do_domctl(xch, );
 }
diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c
index e7238ce..5742dd1 100644
--- a/xen/arch/x86/hvm/hypercall.c
+++ b/xen/arch/x86/hvm/hypercall.c
@@ -155,6 +155,11 @@ int hvm_hypercall(struct cpu_user_regs *regs)
 /* Fallthrough to permission check. */
 case 4:
 case 2:
+if ( currd->arch.monitor.guest_request_userspace_enabled &&
+eax == __HYPERVISOR_hvm_op &&
+(mode == 8 ? regs->rdi : regs->ebx) == 
HVMOP_guest_request_vm_event )
+break;
+
 if ( unlikely(hvm_get_cpl(curr)) )
 {
 default:
diff --git a/xen/common/monitor.c b/xen/common/monitor.c
index 451f42f..4c540e5 100644
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -75,6 +75,7 @@ int monitor_domctl(struct domain *d, struct 
xen_domctl_monitor_op *mop)
 domain_pause(d);
 d->monitor.guest_request_sync = mop->u.guest_request.sync;
 d->monitor.guest_request_enabled = requested_status;
+arch_monitor_allow_userspace(d, mop->u.guest_request.allow_userspace);
 domain_unpause(d);
 break;
 }
diff --git a/xen/include/asm-arm/monitor.h b/xen/include/asm-arm/monitor.h
index 1c4fea3..2bdad7d 100644
--- a/xen/include/asm-arm/monitor.h
+++ b/xen/include/asm-arm/monitor.h
@@ -26,6 +26,12 @@
 #include 
 
 static inline
+void arch_monitor_allow_userspace(struct domain *d, bool allow_userspace)
+{
+return;
+}
+
+static inline
 int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop)
 {
 /* No arch-specific monitor ops on ARM. */
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index c10522b..de02507 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -396,15 +396,16 @@ struct arch_domain
 
 /* Arch-specific monitor options */
 struct {
-unsigned int write_ctrlreg_enabled   : 4;
-unsigned int write_ctrlreg_sync  : 4;
-unsigned int write_ctrlreg_onchangeonly  : 4;
-unsigned int singlestep_enabled  : 1;
-unsigned int software_breakpoint_enabled : 1;
-unsigned int debug_exception_enabled : 1;
-unsigned int debug

[Xen-devel] [PATCH v9] x86/hvm: Allow guest_request vm_events coming from userspace

2017-08-29 Thread Alexandru Isaila
In some introspection usecases, an in-guest agent needs to communicate
with the external introspection agent.  An existing mechanism is
HVMOP_guest_request_vm_event, but this is restricted to kernel usecases
like all other hypercalls.

Introduce a mechanism whereby the introspection agent can whitelist the
use of HVMOP_guest_request_vm_event directly from userspace.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>
Acked-by: Wei Liu <wei.l...@citrix.com>

---
Changes since V8:
- Changed funtion name from arch_allow_userspace to
arch_monitor_allow_userspace
- Added Wei Liu's ack from v7

Note: Could not test on ARM, compiled both on arm and x86
---
 tools/libxc/include/xenctrl.h |  2 +-
 tools/libxc/xc_monitor.c  |  3 ++-
 xen/arch/x86/hvm/hypercall.c  |  5 +
 xen/common/monitor.c  |  1 +
 xen/include/asm-arm/monitor.h |  6 ++
 xen/include/asm-x86/domain.h  | 19 ++-
 xen/include/asm-x86/monitor.h |  6 ++
 xen/include/public/domctl.h   |  1 +
 8 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index bde8313..a3d0929 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2021,7 +2021,7 @@ int xc_monitor_software_breakpoint(xc_interface *xch, 
domid_t domain_id,
 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);
+ bool enable, bool sync, bool allow_userspace);
 int xc_monitor_debug_exceptions(xc_interface *xch, domid_t domain_id,
 bool enable, bool sync);
 int xc_monitor_cpuid(xc_interface *xch, domid_t domain_id, bool enable);
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index b44ce93..a677820 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -147,7 +147,7 @@ int xc_monitor_descriptor_access(xc_interface *xch, domid_t 
domain_id,
 }
 
 int xc_monitor_guest_request(xc_interface *xch, domid_t domain_id, bool enable,
- bool sync)
+ bool sync, bool allow_userspace)
 {
 DECLARE_DOMCTL;
 
@@ -157,6 +157,7 @@ int xc_monitor_guest_request(xc_interface *xch, domid_t 
domain_id, bool enable,
 : XEN_DOMCTL_MONITOR_OP_DISABLE;
 domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST;
 domctl.u.monitor_op.u.guest_request.sync = sync;
+domctl.u.monitor_op.u.guest_request.allow_userspace = enable ? 
allow_userspace : false;
 
 return do_domctl(xch, );
 }
diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c
index e7238ce..5742dd1 100644
--- a/xen/arch/x86/hvm/hypercall.c
+++ b/xen/arch/x86/hvm/hypercall.c
@@ -155,6 +155,11 @@ int hvm_hypercall(struct cpu_user_regs *regs)
 /* Fallthrough to permission check. */
 case 4:
 case 2:
+if ( currd->arch.monitor.guest_request_userspace_enabled &&
+eax == __HYPERVISOR_hvm_op &&
+(mode == 8 ? regs->rdi : regs->ebx) == 
HVMOP_guest_request_vm_event )
+break;
+
 if ( unlikely(hvm_get_cpl(curr)) )
 {
 default:
diff --git a/xen/common/monitor.c b/xen/common/monitor.c
index 451f42f..4c540e5 100644
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -75,6 +75,7 @@ int monitor_domctl(struct domain *d, struct 
xen_domctl_monitor_op *mop)
 domain_pause(d);
 d->monitor.guest_request_sync = mop->u.guest_request.sync;
 d->monitor.guest_request_enabled = requested_status;
+arch_monitor_allow_userspace(d, mop->u.guest_request.allow_userspace);
 domain_unpause(d);
 break;
 }
diff --git a/xen/include/asm-arm/monitor.h b/xen/include/asm-arm/monitor.h
index 1c4fea3..e9dbcdb 100644
--- a/xen/include/asm-arm/monitor.h
+++ b/xen/include/asm-arm/monitor.h
@@ -26,6 +26,12 @@
 #include 
 
 static inline
+void arch_monitor_allow_userspace(struct domain *d, uint8_t allow_userspace)
+{
+return;
+}
+
+static inline
 int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop)
 {
 /* No arch-specific monitor ops on ARM. */
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index c10522b..de02507 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -396,15 +396,16 @@ struct arch_domain
 
 /* Arch-specific monitor options */
 struct {
-unsigned int write_ctrlreg_enabled   : 4;
-unsigned int write_ctrlreg_sync  : 4;
-unsigned int write_ctrlreg_onchangeonly  : 4;
-unsigned int singlestep_enabled  : 1;
-unsigned int software_breakpoint_enabled : 1;
-unsigned int debug

[Xen-devel] [PATCH v8] x86/hvm: Allow guest_request vm_events coming from userspace

2017-08-28 Thread Alexandru Isaila
In some introspection usecases, an in-guest agent needs to communicate
with the external introspection agent.  An existing mechanism is
HVMOP_guest_request_vm_event, but this is restricted to kernel usecases
like all other hypercalls.

Introduce a mechanism whereby the introspection agent can whitelist the
use of HVMOP_guest_request_vm_event directly from userspace.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>
Acked-by: Jan Beulich <jbeul...@suse.com>
Acked-by: Wei Liu <wei.l...@citrix.com>

---
Changes since V7:
- Passed domain* instead of arch* for the new arch specific
function
- Added Wei Liu's ack from v5
- Added Jan's ack from v7

Note: Could not test on ARM, compiled both on arm and x86
---
 tools/libxc/include/xenctrl.h |  2 +-
 tools/libxc/xc_monitor.c  |  3 ++-
 xen/arch/x86/hvm/hypercall.c  |  5 +
 xen/common/monitor.c  |  1 +
 xen/include/asm-arm/monitor.h |  6 ++
 xen/include/asm-x86/domain.h  | 19 ++-
 xen/include/asm-x86/monitor.h |  6 ++
 xen/include/public/domctl.h   |  1 +
 8 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index bde8313..a3d0929 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2021,7 +2021,7 @@ int xc_monitor_software_breakpoint(xc_interface *xch, 
domid_t domain_id,
 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);
+ bool enable, bool sync, bool allow_userspace);
 int xc_monitor_debug_exceptions(xc_interface *xch, domid_t domain_id,
 bool enable, bool sync);
 int xc_monitor_cpuid(xc_interface *xch, domid_t domain_id, bool enable);
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index b44ce93..a677820 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -147,7 +147,7 @@ int xc_monitor_descriptor_access(xc_interface *xch, domid_t 
domain_id,
 }
 
 int xc_monitor_guest_request(xc_interface *xch, domid_t domain_id, bool enable,
- bool sync)
+ bool sync, bool allow_userspace)
 {
 DECLARE_DOMCTL;
 
@@ -157,6 +157,7 @@ int xc_monitor_guest_request(xc_interface *xch, domid_t 
domain_id, bool enable,
 : XEN_DOMCTL_MONITOR_OP_DISABLE;
 domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST;
 domctl.u.monitor_op.u.guest_request.sync = sync;
+domctl.u.monitor_op.u.guest_request.allow_userspace = enable ? 
allow_userspace : false;
 
 return do_domctl(xch, );
 }
diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c
index e7238ce..5742dd1 100644
--- a/xen/arch/x86/hvm/hypercall.c
+++ b/xen/arch/x86/hvm/hypercall.c
@@ -155,6 +155,11 @@ int hvm_hypercall(struct cpu_user_regs *regs)
 /* Fallthrough to permission check. */
 case 4:
 case 2:
+if ( currd->arch.monitor.guest_request_userspace_enabled &&
+eax == __HYPERVISOR_hvm_op &&
+(mode == 8 ? regs->rdi : regs->ebx) == 
HVMOP_guest_request_vm_event )
+break;
+
 if ( unlikely(hvm_get_cpl(curr)) )
 {
 default:
diff --git a/xen/common/monitor.c b/xen/common/monitor.c
index 451f42f..59f2cf3 100644
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -75,6 +75,7 @@ int monitor_domctl(struct domain *d, struct 
xen_domctl_monitor_op *mop)
 domain_pause(d);
 d->monitor.guest_request_sync = mop->u.guest_request.sync;
 d->monitor.guest_request_enabled = requested_status;
+arch_allow_userspace(d, mop->u.guest_request.allow_userspace);
 domain_unpause(d);
 break;
 }
diff --git a/xen/include/asm-arm/monitor.h b/xen/include/asm-arm/monitor.h
index 1c4fea3..9f352be 100644
--- a/xen/include/asm-arm/monitor.h
+++ b/xen/include/asm-arm/monitor.h
@@ -26,6 +26,12 @@
 #include 
 
 static inline
+void arch_allow_userspace(struct domain *d, uint8_t allow_userspace)
+{
+return;
+}
+
+static inline
 int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop)
 {
 /* No arch-specific monitor ops on ARM. */
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index c10522b..de02507 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -396,15 +396,16 @@ struct arch_domain
 
 /* Arch-specific monitor options */
 struct {
-unsigned int write_ctrlreg_enabled   : 4;
-unsigned int write_ctrlreg_sync  : 4;
-unsigned int write_ctrlreg_onchangeonly  : 4;
-unsigned int singlestep_enabled  : 1;
-unsigned int software_breakpoint_ena

[Xen-devel] [PATCH v4] common/vm_event: Initialize vm_event lists on domain creation

2017-08-28 Thread Alexandru Isaila
The patch splits the vm_event into three structures:vm_event_share,
vm_event_paging, vm_event_monitor. The allocation for the
structure is moved to vm_event_enable so that it can be
allocated/init when needed and freed in vm_event_disable.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V3:
- Moved the d->vm_event_paging to the if below in the
assign_device function

Note: Did not test on arm, compliled on arm and x86.
---
 xen/arch/arm/mem_access.c |   2 +-
 xen/arch/x86/mm/mem_access.c  |   2 +-
 xen/arch/x86/mm/mem_paging.c  |   2 +-
 xen/arch/x86/mm/mem_sharing.c |   4 +-
 xen/arch/x86/mm/p2m.c |  10 +--
 xen/common/domain.c   |  13 ++--
 xen/common/mem_access.c   |   2 +-
 xen/common/monitor.c  |   4 +-
 xen/common/vm_event.c | 156 +-
 xen/drivers/passthrough/pci.c |   2 +-
 xen/include/xen/sched.h   |  18 ++---
 11 files changed, 124 insertions(+), 91 deletions(-)

diff --git a/xen/arch/arm/mem_access.c b/xen/arch/arm/mem_access.c
index e0888bb..a7f0cae 100644
--- a/xen/arch/arm/mem_access.c
+++ b/xen/arch/arm/mem_access.c
@@ -256,7 +256,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const 
struct npfec npfec)
 }
 
 /* Otherwise, check if there is a vm_event monitor subscriber */
-if ( !vm_event_check_ring(>domain->vm_event->monitor) )
+if ( !vm_event_check_ring(v->domain->vm_event_monitor) )
 {
 /* No listener */
 if ( p2m->access_required )
diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
index 5adaf6d..414e38f 100644
--- a/xen/arch/x86/mm/mem_access.c
+++ b/xen/arch/x86/mm/mem_access.c
@@ -179,7 +179,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, unsigned long gla,
 gfn_unlock(p2m, gfn, 0);
 
 /* Otherwise, check if there is a memory event listener, and send the 
message along */
-if ( !vm_event_check_ring(>vm_event->monitor) || !req_ptr )
+if ( !vm_event_check_ring(d->vm_event_monitor) || !req_ptr )
 {
 /* No listener */
 if ( p2m->access_required )
diff --git a/xen/arch/x86/mm/mem_paging.c b/xen/arch/x86/mm/mem_paging.c
index a049e0d..20214ac 100644
--- a/xen/arch/x86/mm/mem_paging.c
+++ b/xen/arch/x86/mm/mem_paging.c
@@ -43,7 +43,7 @@ int 
mem_paging_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_paging_op_t) arg)
 goto out;
 
 rc = -ENODEV;
-if ( unlikely(!d->vm_event->paging.ring_page) )
+if ( !d->vm_event_paging || unlikely(!d->vm_event_paging->ring_page) )
 goto out;
 
 switch( mpo.op )
diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
index 1f20ce7..12fb9cc 100644
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -563,7 +563,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned 
long gfn,
 };
 
 if ( (rc = __vm_event_claim_slot(d, 
->vm_event->share, allow_sleep)) < 0 )
+d->vm_event_share, allow_sleep)) < 0 )
 return rc;
 
 if ( v->domain == d )
@@ -572,7 +572,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned 
long gfn,
 vm_event_vcpu_pause(v);
 }
 
-vm_event_put_request(d, >vm_event->share, );
+vm_event_put_request(d, d->vm_event_share, );
 
 return 0;
 }
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index e8a57d1..6ae23be 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1454,7 +1454,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned 
long gfn,
  * correctness of the guest execution at this point.  If this is the only
  * page that happens to be paged-out, we'll be okay..  but it's likely the
  * guest will crash shortly anyways. */
-int rc = vm_event_claim_slot(d, >vm_event->paging);
+int rc = vm_event_claim_slot(d, d->vm_event_paging);
 if ( rc < 0 )
 return;
 
@@ -1468,7 +1468,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned 
long gfn,
 /* Evict will fail now, tag this request for pager */
 req.u.mem_paging.flags |= MEM_PAGING_EVICT_FAIL;
 
-vm_event_put_request(d, >vm_event->paging, );
+vm_event_put_request(d, d->vm_event_paging, );
 }
 
 /**
@@ -1505,7 +1505,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned 
long gfn)
 struct p2m_domain *p2m = p2m_get_hostp2m(d);
 
 /* We're paging. There should be a ring */
-int rc = vm_event_claim_slot(d, >vm_event->paging);
+int rc = vm_event_claim_slot(d, d->vm_event_paging);
 if ( rc == -ENOSYS )
 {
 gdprintk(XENLOG_ERR, "Domain %hu paging gfn %lx yet no ring "
@@ -1543,7 +1543,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned 
long gfn)
 else if ( p2mt != p2m_ram_paging_out && p2mt != p2m_ram_paged )
 {
 /* gfn is already 

[Xen-devel] [PATCH v7] x86/hvm: Allow guest_request vm_events coming from userspace

2017-08-28 Thread Alexandru Isaila
In some introspection usecases, an in-guest agent needs to communicate
with the external introspection agent.  An existing mechanism is
HVMOP_guest_request_vm_event, but this is restricted to kernel usecases
like all other hypercalls.

Introduce a mechanism whereby the introspection agent can whitelist the
use of HVMOP_guest_request_vm_event directly from userspace.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V6:
- Added arch specific function in both x86 monitor and arm
  monitor to replace the assignment from common monitor

Note: Could not test on ARN, compiled both on arm and x86
---
 tools/libxc/include/xenctrl.h |  2 +-
 tools/libxc/xc_monitor.c  |  3 ++-
 xen/arch/x86/hvm/hypercall.c  |  5 +
 xen/common/monitor.c  |  1 +
 xen/include/asm-arm/monitor.h |  6 ++
 xen/include/asm-x86/domain.h  | 19 ++-
 xen/include/asm-x86/monitor.h |  6 ++
 xen/include/public/domctl.h   |  1 +
 8 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index bde8313..a3d0929 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2021,7 +2021,7 @@ int xc_monitor_software_breakpoint(xc_interface *xch, 
domid_t domain_id,
 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);
+ bool enable, bool sync, bool allow_userspace);
 int xc_monitor_debug_exceptions(xc_interface *xch, domid_t domain_id,
 bool enable, bool sync);
 int xc_monitor_cpuid(xc_interface *xch, domid_t domain_id, bool enable);
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index b44ce93..a677820 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -147,7 +147,7 @@ int xc_monitor_descriptor_access(xc_interface *xch, domid_t 
domain_id,
 }
 
 int xc_monitor_guest_request(xc_interface *xch, domid_t domain_id, bool enable,
- bool sync)
+ bool sync, bool allow_userspace)
 {
 DECLARE_DOMCTL;
 
@@ -157,6 +157,7 @@ int xc_monitor_guest_request(xc_interface *xch, domid_t 
domain_id, bool enable,
 : XEN_DOMCTL_MONITOR_OP_DISABLE;
 domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST;
 domctl.u.monitor_op.u.guest_request.sync = sync;
+domctl.u.monitor_op.u.guest_request.allow_userspace = enable ? 
allow_userspace : false;
 
 return do_domctl(xch, );
 }
diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c
index e7238ce..5742dd1 100644
--- a/xen/arch/x86/hvm/hypercall.c
+++ b/xen/arch/x86/hvm/hypercall.c
@@ -155,6 +155,11 @@ int hvm_hypercall(struct cpu_user_regs *regs)
 /* Fallthrough to permission check. */
 case 4:
 case 2:
+if ( currd->arch.monitor.guest_request_userspace_enabled &&
+eax == __HYPERVISOR_hvm_op &&
+(mode == 8 ? regs->rdi : regs->ebx) == 
HVMOP_guest_request_vm_event )
+break;
+
 if ( unlikely(hvm_get_cpl(curr)) )
 {
 default:
diff --git a/xen/common/monitor.c b/xen/common/monitor.c
index 451f42f..0c3e645 100644
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -75,6 +75,7 @@ int monitor_domctl(struct domain *d, struct 
xen_domctl_monitor_op *mop)
 domain_pause(d);
 d->monitor.guest_request_sync = mop->u.guest_request.sync;
 d->monitor.guest_request_enabled = requested_status;
+arch_allow_userspace(>arch, mop->u.guest_request.allow_userspace);
 domain_unpause(d);
 break;
 }
diff --git a/xen/include/asm-arm/monitor.h b/xen/include/asm-arm/monitor.h
index 1c4fea3..a2eec52 100644
--- a/xen/include/asm-arm/monitor.h
+++ b/xen/include/asm-arm/monitor.h
@@ -26,6 +26,12 @@
 #include 
 
 static inline
+void arch_allow_userspace(struct arch_domain *arch, uint8_t allow_userspace)
+{
+return;
+}
+
+static inline
 int arch_monitor_domctl_op(struct domain *d, struct xen_domctl_monitor_op *mop)
 {
 /* No arch-specific monitor ops on ARM. */
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index c10522b..de02507 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -396,15 +396,16 @@ struct arch_domain
 
 /* Arch-specific monitor options */
 struct {
-unsigned int write_ctrlreg_enabled   : 4;
-unsigned int write_ctrlreg_sync  : 4;
-unsigned int write_ctrlreg_onchangeonly  : 4;
-unsigned int singlestep_enabled  : 1;
-unsigned int software_breakpoint_enabled : 1;
-unsigned int debug_exception_enabled : 1;
-unsigned int debug_ex

[Xen-devel] [PATCH v3] common/vm_event: Initialize vm_event lists on domain creation

2017-08-25 Thread Alexandru Isaila
The patch splits the vm_event into three structures:vm_event_share,
vm_event_paging, vm_event_monitor. The allocation for the
structure is moved to vm_event_enable so that it can be
allocated/init when needed and freed in vm_event_disable.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V2:
- Removed parentheses from around *ved in vm_event_enable
- Moved both ifs in on if in vm_event_disable
- Moved the xfree in vm_event_disable out of the if
- Changed the return value in __vm_event_claim_slot
- Added a local var for v->domain
- Moved the !d->vm_event_paging to the if above in the
assign_device function
---
 xen/arch/arm/mem_access.c |   2 +-
 xen/arch/x86/mm/mem_access.c  |   2 +-
 xen/arch/x86/mm/mem_paging.c  |   2 +-
 xen/arch/x86/mm/mem_sharing.c |   4 +-
 xen/arch/x86/mm/p2m.c |  10 +--
 xen/common/domain.c   |  13 ++--
 xen/common/mem_access.c   |   2 +-
 xen/common/monitor.c  |   4 +-
 xen/common/vm_event.c | 156 +-
 xen/drivers/passthrough/pci.c |   4 +-
 xen/include/xen/sched.h   |  18 ++---
 11 files changed, 125 insertions(+), 92 deletions(-)

diff --git a/xen/arch/arm/mem_access.c b/xen/arch/arm/mem_access.c
index e0888bb..a7f0cae 100644
--- a/xen/arch/arm/mem_access.c
+++ b/xen/arch/arm/mem_access.c
@@ -256,7 +256,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const 
struct npfec npfec)
 }
 
 /* Otherwise, check if there is a vm_event monitor subscriber */
-if ( !vm_event_check_ring(>domain->vm_event->monitor) )
+if ( !vm_event_check_ring(v->domain->vm_event_monitor) )
 {
 /* No listener */
 if ( p2m->access_required )
diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
index 5adaf6d..414e38f 100644
--- a/xen/arch/x86/mm/mem_access.c
+++ b/xen/arch/x86/mm/mem_access.c
@@ -179,7 +179,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, unsigned long gla,
 gfn_unlock(p2m, gfn, 0);
 
 /* Otherwise, check if there is a memory event listener, and send the 
message along */
-if ( !vm_event_check_ring(>vm_event->monitor) || !req_ptr )
+if ( !vm_event_check_ring(d->vm_event_monitor) || !req_ptr )
 {
 /* No listener */
 if ( p2m->access_required )
diff --git a/xen/arch/x86/mm/mem_paging.c b/xen/arch/x86/mm/mem_paging.c
index a049e0d..20214ac 100644
--- a/xen/arch/x86/mm/mem_paging.c
+++ b/xen/arch/x86/mm/mem_paging.c
@@ -43,7 +43,7 @@ int 
mem_paging_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_paging_op_t) arg)
 goto out;
 
 rc = -ENODEV;
-if ( unlikely(!d->vm_event->paging.ring_page) )
+if ( !d->vm_event_paging || unlikely(!d->vm_event_paging->ring_page) )
 goto out;
 
 switch( mpo.op )
diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
index 1f20ce7..12fb9cc 100644
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -563,7 +563,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned 
long gfn,
 };
 
 if ( (rc = __vm_event_claim_slot(d, 
->vm_event->share, allow_sleep)) < 0 )
+d->vm_event_share, allow_sleep)) < 0 )
 return rc;
 
 if ( v->domain == d )
@@ -572,7 +572,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned 
long gfn,
 vm_event_vcpu_pause(v);
 }
 
-vm_event_put_request(d, >vm_event->share, );
+vm_event_put_request(d, d->vm_event_share, );
 
 return 0;
 }
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index e8a57d1..6ae23be 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1454,7 +1454,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned 
long gfn,
  * correctness of the guest execution at this point.  If this is the only
  * page that happens to be paged-out, we'll be okay..  but it's likely the
  * guest will crash shortly anyways. */
-int rc = vm_event_claim_slot(d, >vm_event->paging);
+int rc = vm_event_claim_slot(d, d->vm_event_paging);
 if ( rc < 0 )
 return;
 
@@ -1468,7 +1468,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned 
long gfn,
 /* Evict will fail now, tag this request for pager */
 req.u.mem_paging.flags |= MEM_PAGING_EVICT_FAIL;
 
-vm_event_put_request(d, >vm_event->paging, );
+vm_event_put_request(d, d->vm_event_paging, );
 }
 
 /**
@@ -1505,7 +1505,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned 
long gfn)
 struct p2m_domain *p2m = p2m_get_hostp2m(d);
 
 /* We're paging. There should be a ring */
-int rc = vm_event_claim_slot(d, >vm_event->paging);
+int rc = vm_event_claim_slot(d, d->vm_event_paging);
 if ( rc == -ENOSYS )
 {
 gdprintk(XENLOG_ERR, "Domain %

[Xen-devel] [PATCH v2] common/vm_event: Initialize vm_event lists on domain creation

2017-08-24 Thread Alexandru Isaila
The patch splits the vm_event into three structures:vm_event_share,
vm_event_paging, vm_event_monitor. The allocation for the
structure is moved to vm_event_enable so that it can be
allocated/init when needed and freed in vm_event_disable.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>
---
 xen/arch/arm/mem_access.c |   2 +-
 xen/arch/x86/mm/mem_access.c  |   2 +-
 xen/arch/x86/mm/mem_paging.c  |   2 +-
 xen/arch/x86/mm/mem_sharing.c |   4 +-
 xen/arch/x86/mm/p2m.c |  10 +--
 xen/common/domain.c   |  13 ++--
 xen/common/mem_access.c   |   3 +-
 xen/common/monitor.c  |   4 +-
 xen/common/vm_event.c | 153 +-
 xen/drivers/passthrough/pci.c |   4 +-
 xen/include/xen/sched.h   |  18 ++---
 11 files changed, 123 insertions(+), 92 deletions(-)

diff --git a/xen/arch/arm/mem_access.c b/xen/arch/arm/mem_access.c
index e0888bb..a7f0cae 100644
--- a/xen/arch/arm/mem_access.c
+++ b/xen/arch/arm/mem_access.c
@@ -256,7 +256,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, vaddr_t gla, const 
struct npfec npfec)
 }
 
 /* Otherwise, check if there is a vm_event monitor subscriber */
-if ( !vm_event_check_ring(>domain->vm_event->monitor) )
+if ( !vm_event_check_ring(v->domain->vm_event_monitor) )
 {
 /* No listener */
 if ( p2m->access_required )
diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c
index 5adaf6d..414e38f 100644
--- a/xen/arch/x86/mm/mem_access.c
+++ b/xen/arch/x86/mm/mem_access.c
@@ -179,7 +179,7 @@ bool_t p2m_mem_access_check(paddr_t gpa, unsigned long gla,
 gfn_unlock(p2m, gfn, 0);
 
 /* Otherwise, check if there is a memory event listener, and send the 
message along */
-if ( !vm_event_check_ring(>vm_event->monitor) || !req_ptr )
+if ( !vm_event_check_ring(d->vm_event_monitor) || !req_ptr )
 {
 /* No listener */
 if ( p2m->access_required )
diff --git a/xen/arch/x86/mm/mem_paging.c b/xen/arch/x86/mm/mem_paging.c
index a049e0d..20214ac 100644
--- a/xen/arch/x86/mm/mem_paging.c
+++ b/xen/arch/x86/mm/mem_paging.c
@@ -43,7 +43,7 @@ int 
mem_paging_memop(XEN_GUEST_HANDLE_PARAM(xen_mem_paging_op_t) arg)
 goto out;
 
 rc = -ENODEV;
-if ( unlikely(!d->vm_event->paging.ring_page) )
+if ( !d->vm_event_paging || unlikely(!d->vm_event_paging->ring_page) )
 goto out;
 
 switch( mpo.op )
diff --git a/xen/arch/x86/mm/mem_sharing.c b/xen/arch/x86/mm/mem_sharing.c
index 1f20ce7..12fb9cc 100644
--- a/xen/arch/x86/mm/mem_sharing.c
+++ b/xen/arch/x86/mm/mem_sharing.c
@@ -563,7 +563,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned 
long gfn,
 };
 
 if ( (rc = __vm_event_claim_slot(d, 
->vm_event->share, allow_sleep)) < 0 )
+d->vm_event_share, allow_sleep)) < 0 )
 return rc;
 
 if ( v->domain == d )
@@ -572,7 +572,7 @@ int mem_sharing_notify_enomem(struct domain *d, unsigned 
long gfn,
 vm_event_vcpu_pause(v);
 }
 
-vm_event_put_request(d, >vm_event->share, );
+vm_event_put_request(d, d->vm_event_share, );
 
 return 0;
 }
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index e8a57d1..6ae23be 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1454,7 +1454,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned 
long gfn,
  * correctness of the guest execution at this point.  If this is the only
  * page that happens to be paged-out, we'll be okay..  but it's likely the
  * guest will crash shortly anyways. */
-int rc = vm_event_claim_slot(d, >vm_event->paging);
+int rc = vm_event_claim_slot(d, d->vm_event_paging);
 if ( rc < 0 )
 return;
 
@@ -1468,7 +1468,7 @@ void p2m_mem_paging_drop_page(struct domain *d, unsigned 
long gfn,
 /* Evict will fail now, tag this request for pager */
 req.u.mem_paging.flags |= MEM_PAGING_EVICT_FAIL;
 
-vm_event_put_request(d, >vm_event->paging, );
+vm_event_put_request(d, d->vm_event_paging, );
 }
 
 /**
@@ -1505,7 +1505,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned 
long gfn)
 struct p2m_domain *p2m = p2m_get_hostp2m(d);
 
 /* We're paging. There should be a ring */
-int rc = vm_event_claim_slot(d, >vm_event->paging);
+int rc = vm_event_claim_slot(d, d->vm_event_paging);
 if ( rc == -ENOSYS )
 {
 gdprintk(XENLOG_ERR, "Domain %hu paging gfn %lx yet no ring "
@@ -1543,7 +1543,7 @@ void p2m_mem_paging_populate(struct domain *d, unsigned 
long gfn)
 else if ( p2mt != p2m_ram_paging_out && p2mt != p2m_ram_paged )
 {
 /* gfn is already on its way back and vcpu is not paused */
-vm_event_cancel_slot(d, >vm_event->paging);
+vm_event_cancel_slot(d, d->vm_event_paging);
 retu

[Xen-devel] [PATCH v6] x86/hvm: Allow guest_request vm_events coming from userspace

2017-08-17 Thread Alexandru Isaila
In some introspection usecases, an in-guest agent needs to communicate
with the external introspection agent.  An existing mechanism is
HVMOP_guest_request_vm_event, but this is restricted to kernel usecases
like all other hypercalls.

Introduce a mechanism whereby the introspection agent can whitelist the
use of HVMOP_guest_request_vm_event directly from userspace.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V5:
- Added the bool allow_userspace to the xc_monitor_guest_request
 function
---
 tools/libxc/include/xenctrl.h |  2 +-
 tools/libxc/xc_monitor.c  |  3 ++-
 xen/arch/x86/hvm/hypercall.c  |  5 +
 xen/common/monitor.c  |  1 +
 xen/include/asm-x86/domain.h  | 19 ++-
 xen/include/public/domctl.h   |  1 +
 6 files changed, 20 insertions(+), 11 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index bde8313..a3d0929 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2021,7 +2021,7 @@ int xc_monitor_software_breakpoint(xc_interface *xch, 
domid_t domain_id,
 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);
+ bool enable, bool sync, bool allow_userspace);
 int xc_monitor_debug_exceptions(xc_interface *xch, domid_t domain_id,
 bool enable, bool sync);
 int xc_monitor_cpuid(xc_interface *xch, domid_t domain_id, bool enable);
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index b44ce93..a677820 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -147,7 +147,7 @@ int xc_monitor_descriptor_access(xc_interface *xch, domid_t 
domain_id,
 }
 
 int xc_monitor_guest_request(xc_interface *xch, domid_t domain_id, bool enable,
- bool sync)
+ bool sync, bool allow_userspace)
 {
 DECLARE_DOMCTL;
 
@@ -157,6 +157,7 @@ int xc_monitor_guest_request(xc_interface *xch, domid_t 
domain_id, bool enable,
 : XEN_DOMCTL_MONITOR_OP_DISABLE;
 domctl.u.monitor_op.event = XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST;
 domctl.u.monitor_op.u.guest_request.sync = sync;
+domctl.u.monitor_op.u.guest_request.allow_userspace = enable ? 
allow_userspace : false;
 
 return do_domctl(xch, );
 }
diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c
index e7238ce..5742dd1 100644
--- a/xen/arch/x86/hvm/hypercall.c
+++ b/xen/arch/x86/hvm/hypercall.c
@@ -155,6 +155,11 @@ int hvm_hypercall(struct cpu_user_regs *regs)
 /* Fallthrough to permission check. */
 case 4:
 case 2:
+if ( currd->arch.monitor.guest_request_userspace_enabled &&
+eax == __HYPERVISOR_hvm_op &&
+(mode == 8 ? regs->rdi : regs->ebx) == 
HVMOP_guest_request_vm_event )
+break;
+
 if ( unlikely(hvm_get_cpl(curr)) )
 {
 default:
diff --git a/xen/common/monitor.c b/xen/common/monitor.c
index 451f42f..20463e0 100644
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -75,6 +75,7 @@ int monitor_domctl(struct domain *d, struct 
xen_domctl_monitor_op *mop)
 domain_pause(d);
 d->monitor.guest_request_sync = mop->u.guest_request.sync;
 d->monitor.guest_request_enabled = requested_status;
+d->arch.monitor.guest_request_userspace_enabled = 
mop->u.guest_request.allow_userspace;
 domain_unpause(d);
 break;
 }
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index c10522b..de02507 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -396,15 +396,16 @@ struct arch_domain
 
 /* Arch-specific monitor options */
 struct {
-unsigned int write_ctrlreg_enabled   : 4;
-unsigned int write_ctrlreg_sync  : 4;
-unsigned int write_ctrlreg_onchangeonly  : 4;
-unsigned int singlestep_enabled  : 1;
-unsigned int software_breakpoint_enabled : 1;
-unsigned int debug_exception_enabled : 1;
-unsigned int debug_exception_sync: 1;
-unsigned int cpuid_enabled   : 1;
-unsigned int descriptor_access_enabled   : 1;
+unsigned int write_ctrlreg_enabled : 4;
+unsigned int write_ctrlreg_sync: 4;
+unsigned int write_ctrlreg_onchangeonly: 4;
+unsigned int singlestep_enabled: 1;
+unsigned int software_breakpoint_enabled   : 1;
+unsigned int debug_exception_enabled   :

[Xen-devel] [PATCH v5] x86/hvm: Allow guest_request vm_events coming from userspace

2017-08-08 Thread Alexandru Isaila
In some introspection usecases, an in-guest agent needs to communicate
with the external introspection agent.  An existing mechanism is
HVMOP_guest_request_vm_event, but this is restricted to kernel usecases
like all other hypercalls.

Introduce a mechanism whereby the introspection agent can whitelist the
use of HVMOP_guest_request_vm_event directly from userspace.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V4:
- Changed function mane from xc_allow_guest_userspace_event
  to xc_monitor_guest_userspace_event
- Fixed guest_request_enabled check
- Delete the guest_request_sync
- Changed guest_request_userspace_event to
  guest_request_userspace_enabled
- Moved guest_request_userspace_enabled flag from sched.h to
  domain.h
---
 tools/libxc/include/xenctrl.h |  1 +
 tools/libxc/xc_monitor.c  | 14 ++
 xen/arch/x86/hvm/hypercall.c  |  5 +
 xen/common/monitor.c  | 13 +
 xen/include/asm-x86/domain.h  | 19 ++-
 xen/include/public/domctl.h   | 21 +++--
 6 files changed, 54 insertions(+), 19 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index bde8313..c72e12d 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2022,6 +2022,7 @@ 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_guest_userspace_event(xc_interface *xch, domid_t domain_id, 
bool enable);
 int xc_monitor_debug_exceptions(xc_interface *xch, domid_t domain_id,
 bool enable, bool sync);
 int xc_monitor_cpuid(xc_interface *xch, domid_t domain_id, bool enable);
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index b44ce93..bd8cbcf 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -161,6 +161,20 @@ int xc_monitor_guest_request(xc_interface *xch, domid_t 
domain_id, bool enable,
 return do_domctl(xch, );
 }
 
+int xc_monitor_guest_userspace_event(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_GUEST_USERSPACE_EVENT;
+
+return do_domctl(xch, );
+}
+
+
 int xc_monitor_emulate_each_rep(xc_interface *xch, domid_t domain_id,
 bool enable)
 {
diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c
index e7238ce..5742dd1 100644
--- a/xen/arch/x86/hvm/hypercall.c
+++ b/xen/arch/x86/hvm/hypercall.c
@@ -155,6 +155,11 @@ int hvm_hypercall(struct cpu_user_regs *regs)
 /* Fallthrough to permission check. */
 case 4:
 case 2:
+if ( currd->arch.monitor.guest_request_userspace_enabled &&
+eax == __HYPERVISOR_hvm_op &&
+(mode == 8 ? regs->rdi : regs->ebx) == 
HVMOP_guest_request_vm_event )
+break;
+
 if ( unlikely(hvm_get_cpl(curr)) )
 {
 default:
diff --git a/xen/common/monitor.c b/xen/common/monitor.c
index 451f42f..080a405 100644
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -79,6 +79,19 @@ int monitor_domctl(struct domain *d, struct 
xen_domctl_monitor_op *mop)
 break;
 }
 
+case XEN_DOMCTL_MONITOR_EVENT_GUEST_USERSPACE_EVENT:
+{
+bool old_status = d->arch.monitor.guest_request_userspace_enabled;
+
+if ( unlikely(old_status == requested_status) )
+return -EEXIST;
+
+domain_pause(d);
+d->arch.monitor.guest_request_userspace_enabled = requested_status;
+domain_unpause(d);
+break;
+}
+
 default:
 /* Give arch-side the chance to handle this event */
 return arch_monitor_domctl_event(d, mop);
diff --git a/xen/include/asm-x86/domain.h b/xen/include/asm-x86/domain.h
index c10522b..de02507 100644
--- a/xen/include/asm-x86/domain.h
+++ b/xen/include/asm-x86/domain.h
@@ -396,15 +396,16 @@ struct arch_domain
 
 /* Arch-specific monitor options */
 struct {
-unsigned int write_ctrlreg_enabled   : 4;
-unsigned int write_ctrlreg_sync  : 4;
-unsigned int write_ctrlreg_onchangeonly  : 4;
-unsigned int singlestep_enabled  : 1;
-unsigned int software_breakpoint_enabled : 1;
-unsigned int debug_exception_enabled : 1;
-unsigned int debug_exception_sync: 1;
-unsigned int cpuid_enabled   : 1;
-unsigned int descriptor_access_enabled   : 1;
+unsigned int write_ctrlreg_enable

[Xen-devel] [PATCH v4] x86/hvm: Allow guest_request vm_events coming from userspace

2017-08-04 Thread Alexandru Isaila
In some introspection usecases, an in-guest agent needs to communicate
with the external introspection agent.  An existing mechanism is
HVMOP_guest_request_vm_event, but this is restricted to kernel usecases
like all other hypercalls.

Introduce a mechanism whereby the introspection agent can whitelist the
use of HVMOP_guest_request_vm_event directly from userspace.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V3:
- Changed commit message
- Added new lines
- Indent the maximum space on the defines
- Chaned the name of the define/function name/struct member
  from vmcall to event
---
 tools/libxc/include/xenctrl.h |  1 +
 tools/libxc/xc_monitor.c  | 14 ++
 xen/arch/x86/hvm/hypercall.c  |  5 +
 xen/common/monitor.c  | 14 ++
 xen/include/public/domctl.h   | 21 +++--
 xen/include/xen/sched.h   |  5 +++--
 6 files changed, 48 insertions(+), 12 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index bde8313..90a056f 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2022,6 +2022,7 @@ 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_allow_guest_userspace_event(xc_interface *xch, domid_t domain_id, bool 
enable);
 int xc_monitor_debug_exceptions(xc_interface *xch, domid_t domain_id,
 bool enable, bool sync);
 int xc_monitor_cpuid(xc_interface *xch, domid_t domain_id, bool enable);
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index b44ce93..6064c39 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -161,6 +161,20 @@ int xc_monitor_guest_request(xc_interface *xch, domid_t 
domain_id, bool enable,
 return do_domctl(xch, );
 }
 
+int xc_allow_guest_userspace_event(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_GUEST_USERSPACE_EVENT;
+
+return do_domctl(xch, );
+}
+
+
 int xc_monitor_emulate_each_rep(xc_interface *xch, domid_t domain_id,
 bool enable)
 {
diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c
index e7238ce..8eb5f49 100644
--- a/xen/arch/x86/hvm/hypercall.c
+++ b/xen/arch/x86/hvm/hypercall.c
@@ -155,6 +155,11 @@ int hvm_hypercall(struct cpu_user_regs *regs)
 /* Fallthrough to permission check. */
 case 4:
 case 2:
+if ( currd->monitor.guest_request_userspace_event &&
+eax == __HYPERVISOR_hvm_op &&
+(mode == 8 ? regs->rdi : regs->ebx) == 
HVMOP_guest_request_vm_event )
+break;
+
 if ( unlikely(hvm_get_cpl(curr)) )
 {
 default:
diff --git a/xen/common/monitor.c b/xen/common/monitor.c
index 451f42f..21a1457 100644
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -79,6 +79,20 @@ int monitor_domctl(struct domain *d, struct 
xen_domctl_monitor_op *mop)
 break;
 }
 
+case XEN_DOMCTL_MONITOR_EVENT_GUEST_USERSPACE_EVENT:
+{
+bool_t old_status = d->monitor.guest_request_enabled;
+
+if ( unlikely(old_status == requested_status) )
+return -EEXIST;
+
+domain_pause(d);
+d->monitor.guest_request_sync = mop->u.guest_request.sync;
+d->monitor.guest_request_userspace_event = requested_status;
+domain_unpause(d);
+break;
+}
+
 default:
 /* Give arch-side the chance to handle this event */
 return arch_monitor_domctl_event(d, mop);
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index ff39762..870495c 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -1073,16 +1073,17 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cmt_op_t);
 #define XEN_DOMCTL_MONITOR_OP_GET_CAPABILITIES  2
 #define XEN_DOMCTL_MONITOR_OP_EMULATE_EACH_REP  3
 
-#define XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG 0
-#define XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR1
-#define XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP2
-#define XEN_DOMCTL_MONITOR_EVENT_SOFTWARE_BREAKPOINT   3
-#define XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST 4
-#define XEN_DOMCTL_MONITOR_EVENT_DEBUG_EXCEPTION   5
-#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
+#de

[Xen-devel] [PATCH v3] x86/hvm: Allow guest_request vm_events coming from userspace

2017-08-03 Thread Alexandru Isaila
Allow guest userspace code to request that a vm_event be sent out
via VMCALL. This functionality seems to be handy for a number of
Xen developers, as stated on the mailing list (thread "[Xen-devel]
HVMOP_guest_request_vm_event only works from guest in ring0").
This is a use case in communication between a userspace application
in the guest and the introspection application in dom0.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V2:
-Added a new flag to enable the vm  call from the guest
userspace
---
 tools/libxc/include/xenctrl.h |  2 ++
 tools/libxc/xc_monitor.c  | 14 ++
 xen/arch/x86/hvm/hypercall.c  |  8 
 xen/common/monitor.c  | 13 +
 xen/include/public/domctl.h   | 21 +++--
 xen/include/xen/sched.h   |  5 +++--
 6 files changed, 51 insertions(+), 12 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index bde8313..eed60db 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2022,6 +2022,8 @@ 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_guest_userspace_vmcall(xc_interface *xch, domid_t domain_id,
+  bool enable);
 int xc_monitor_debug_exceptions(xc_interface *xch, domid_t domain_id,
 bool enable, bool sync);
 int xc_monitor_cpuid(xc_interface *xch, domid_t domain_id, bool enable);
diff --git a/tools/libxc/xc_monitor.c b/tools/libxc/xc_monitor.c
index b44ce93..63c6320 100644
--- a/tools/libxc/xc_monitor.c
+++ b/tools/libxc/xc_monitor.c
@@ -161,6 +161,20 @@ int xc_monitor_guest_request(xc_interface *xch, domid_t 
domain_id, bool enable,
 return do_domctl(xch, );
 }
 
+int xc_allow_guest_userspace_vmcall(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_GUEST_USERSPACE_VMCALL;
+
+return do_domctl(xch, );
+}
+
+
 int xc_monitor_emulate_each_rep(xc_interface *xch, domid_t domain_id,
 bool enable)
 {
diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c
index e7238ce..c7fab4b 100644
--- a/xen/arch/x86/hvm/hypercall.c
+++ b/xen/arch/x86/hvm/hypercall.c
@@ -152,9 +152,17 @@ int hvm_hypercall(struct cpu_user_regs *regs)
 {
 case 8:
 eax = regs->rax;
+if ( currd->monitor.guest_request_userspace_vmcall &&
+ eax == __HYPERVISOR_hvm_op &&
+ regs->rdi == HVMOP_guest_request_vm_event )
+break;
 /* Fallthrough to permission check. */
 case 4:
 case 2:
+if ( mode != 8 && currd->monitor.guest_request_userspace_vmcall &&
+ eax == __HYPERVISOR_hvm_op &&
+ regs->ebx == HVMOP_guest_request_vm_event )
+break;
 if ( unlikely(hvm_get_cpl(curr)) )
 {
 default:
diff --git a/xen/common/monitor.c b/xen/common/monitor.c
index 451f42f..4011dc3 100644
--- a/xen/common/monitor.c
+++ b/xen/common/monitor.c
@@ -78,6 +78,19 @@ int monitor_domctl(struct domain *d, struct 
xen_domctl_monitor_op *mop)
 domain_unpause(d);
 break;
 }
+case XEN_DOMCTL_MONITOR_EVENT_GUEST_USERSPACE_VMCALL:
+{
+bool_t old_status = d->monitor.guest_request_enabled;
+
+if ( unlikely(old_status == requested_status) )
+return -EEXIST;
+
+domain_pause(d);
+d->monitor.guest_request_sync = mop->u.guest_request.sync;
+d->monitor.guest_request_userspace_vmcall = requested_status;
+domain_unpause(d);
+break;
+}
 
 default:
 /* Give arch-side the chance to handle this event */
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index ff39762..e782517 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -1073,16 +1073,17 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_psr_cmt_op_t);
 #define XEN_DOMCTL_MONITOR_OP_GET_CAPABILITIES  2
 #define XEN_DOMCTL_MONITOR_OP_EMULATE_EACH_REP  3
 
-#define XEN_DOMCTL_MONITOR_EVENT_WRITE_CTRLREG 0
-#define XEN_DOMCTL_MONITOR_EVENT_MOV_TO_MSR1
-#define XEN_DOMCTL_MONITOR_EVENT_SINGLESTEP2
-#define XEN_DOMCTL_MONITOR_EVENT_SOFTWARE_BREAKPOINT   3
-#define XEN_DOMCTL_MONITOR_EVENT_GUEST_REQUEST 4
-#define XEN_DOMCTL_MONITOR_EVENT_DEBUG_EXCEPTION   5
-#define XEN_DOMCTL_MONITOR_EVENT_CPUID 6
-#define XEN_DOMCT

[Xen-devel] [PATCH v2] x86/hvm: Allow guest_request vm_events coming from userspace

2017-08-01 Thread Alexandru Isaila
Allow guest userspace code to request that a vm_event be sent out
via VMCALL. This functionality seems to be handy for a number of
Xen developers, as stated on the mailing list (thread "[Xen-devel]
HVMOP_guest_request_vm_event only works from guest in ring0").
This is a use case in communication between a userspace application
in the guest and the introspection application in dom0.

Signed-off-by: Alexandru Isaila <aisa...@bitdefender.com>

---
Changes since V1:
- Added Fallthrough check on mode == 2
---
 xen/arch/x86/hvm/hypercall.c | 6 ++
 1 file changed, 6 insertions(+)

diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c
index e7238ce..1c067c3 100644
--- a/xen/arch/x86/hvm/hypercall.c
+++ b/xen/arch/x86/hvm/hypercall.c
@@ -152,9 +152,15 @@ int hvm_hypercall(struct cpu_user_regs *regs)
 {
 case 8:
 eax = regs->rax;
+if ( eax == __HYPERVISOR_hvm_op &&
+ regs->rdi == HVMOP_guest_request_vm_event )
+break;
 /* Fallthrough to permission check. */
 case 4:
 case 2:
+if ( mode != 8 && eax == __HYPERVISOR_hvm_op &&
+ regs->ebx == HVMOP_guest_request_vm_event )
+break;
 if ( unlikely(hvm_get_cpl(curr)) )
 {
 default:
-- 
2.7.4


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