|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC] x86/vm_event: Allow returning i-cache for emulation
When emulating instructions the emulator maintains a small i-cache fetched
from the guest memory. Under certain scenarios this memory region may contain
instructions that a monitor subscriber would prefer to hide, namely INT3, and
instead would prefer to emulate a different instruction in-place.
This patch extends the vm_event interface to allow returning this i-cache via
the vm_event response.
Signed-off-by: Tamas K Lengyel <tamas.lengyel@xxxxxxxxxxxx>
---
Cc: Paul Durrant <paul.durrant@xxxxxxxxxx>
Cc: Jan Beulich <jbeulich@xxxxxxxx>
Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
Cc: Jun Nakajima <jun.nakajima@xxxxxxxxx>
Cc: Kevin Tian <kevin.tian@xxxxxxxxx>
Cc: George Dunlap <george.dunlap@xxxxxxxxxxxxx>
Cc: Razvan Cojocaru <rcojocaru@xxxxxxxxxxxxxxx>
Cc: Tamas K Lengyel <tamas@xxxxxxxxxxxxx>
Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>
Cc: Julien Grall <julien.grall@xxxxxxx>
---
xen/arch/x86/hvm/emulate.c | 47 +++++++++++++++++++++++++--------------
xen/arch/x86/hvm/hvm.c | 2 +-
xen/arch/x86/hvm/vmx/vmx.c | 1 +
xen/arch/x86/mm/p2m.c | 7 ++++--
xen/arch/x86/vm_event.c | 10 +++++++++
xen/common/vm_event.c | 5 ++++-
xen/include/asm-arm/vm_event.h | 6 +++++
xen/include/asm-x86/hvm/emulate.h | 6 +++--
xen/include/asm-x86/vm_event.h | 4 +++-
xen/include/public/vm_event.h | 11 +++++++--
10 files changed, 73 insertions(+), 26 deletions(-)
diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index c55ad7b..968fb7b 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -76,9 +76,12 @@ static int set_context_data(void *buffer, unsigned int size)
if ( curr->arch.vm_event )
{
unsigned int safe_size =
- min(size, curr->arch.vm_event->emul_read_data.size);
+ min(size, curr->arch.vm_event->emul_data.size);
- memcpy(buffer, curr->arch.vm_event->emul_read_data.data, safe_size);
+ gdprintk(XENLOG_WARNING, "Got buffer of size: %u. Request is for %u.
Safe size: %u\n",
+ curr->arch.vm_event->emul_data.size, size, safe_size);
+
+ memcpy(buffer, curr->arch.vm_event->emul_data.data, safe_size);
memset(buffer + safe_size, 0, size - safe_size);
return X86EMUL_OKAY;
}
@@ -825,7 +828,7 @@ static int hvmemul_read(
struct hvm_emulate_ctxt *hvmemul_ctxt =
container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
- if ( unlikely(hvmemul_ctxt->set_context) )
+ if ( unlikely(hvmemul_ctxt->set_context_data) )
return set_context_data(p_data, bytes);
return __hvmemul_read(
@@ -1027,7 +1030,7 @@ static int hvmemul_cmpxchg(
struct hvm_emulate_ctxt *hvmemul_ctxt =
container_of(ctxt, struct hvm_emulate_ctxt, ctxt);
- if ( unlikely(hvmemul_ctxt->set_context) )
+ if ( unlikely(hvmemul_ctxt->set_context_data) )
{
int rc = set_context_data(p_new, bytes);
@@ -1120,7 +1123,7 @@ static int hvmemul_rep_outs(
p2m_type_t p2mt;
int rc;
- if ( unlikely(hvmemul_ctxt->set_context) )
+ if ( unlikely(hvmemul_ctxt->set_context_data) )
return hvmemul_rep_outs_set_context(src_seg, src_offset, dst_port,
bytes_per_rep, reps, ctxt);
@@ -1262,7 +1265,7 @@ static int hvmemul_rep_movs(
if ( buf == NULL )
return X86EMUL_UNHANDLEABLE;
- if ( unlikely(hvmemul_ctxt->set_context) )
+ if ( unlikely(hvmemul_ctxt->set_context_data) )
{
rc = set_context_data(buf, bytes);
@@ -1460,7 +1463,7 @@ static int hvmemul_read_io(
*val = 0;
- if ( unlikely(hvmemul_ctxt->set_context) )
+ if ( unlikely(hvmemul_ctxt->set_context_data) )
return set_context_data(val, bytes);
return hvmemul_do_pio_buffer(port, bytes, IOREQ_READ, val);
@@ -1783,7 +1786,14 @@ static int _hvm_emulate_one(struct hvm_emulate_ctxt
*hvmemul_ctxt,
pfec |= PFEC_user_mode;
hvmemul_ctxt->insn_buf_eip = regs->eip;
- if ( !vio->mmio_insn_bytes )
+
+ if ( unlikely(hvmemul_ctxt->set_context_insn) )
+ {
+ memcpy(hvmemul_ctxt->insn_buf, curr->arch.vm_event->emul_data.data,
+ curr->arch.vm_event->emul_data.size);
+ hvmemul_ctxt->insn_buf_bytes = curr->arch.vm_event->emul_data.size;
+ }
+ else if ( !vio->mmio_insn_bytes )
{
hvmemul_ctxt->insn_buf_bytes =
hvm_get_insn_bytes(curr, hvmemul_ctxt->insn_buf) ?:
@@ -1927,17 +1937,19 @@ void hvm_mem_access_emulate_one(enum emul_kind kind,
unsigned int trapnr,
struct hvm_emulate_ctxt ctx = {{ 0 }};
int rc;
+ gdprintk(XENLOG_WARNING, "memaccess emulate one called\n");
+
hvm_emulate_prepare(&ctx, guest_cpu_user_regs());
- switch ( kind )
- {
- case EMUL_KIND_NOWRITE:
+ if ( kind == EMUL_KIND_NOWRITE )
rc = hvm_emulate_one_no_write(&ctx);
- break;
- case EMUL_KIND_SET_CONTEXT:
- ctx.set_context = 1;
- /* Intentional fall-through. */
- default:
+ else
+ {
+ if ( kind == EMUL_KIND_SET_CONTEXT_DATA )
+ ctx.set_context_data = 1;
+ else if ( kind == EMUL_KIND_SET_CONTEXT_INSN )
+ ctx.set_context_insn = 1;
+
rc = hvm_emulate_one(&ctx);
}
@@ -1973,7 +1985,8 @@ void hvm_emulate_prepare(
hvmemul_ctxt->ctxt.force_writeback = 1;
hvmemul_ctxt->seg_reg_accessed = 0;
hvmemul_ctxt->seg_reg_dirty = 0;
- hvmemul_ctxt->set_context = 0;
+ hvmemul_ctxt->set_context_data = 0;
+ hvmemul_ctxt->set_context_insn = 0;
hvmemul_get_seg_reg(x86_seg_cs, hvmemul_ctxt);
hvmemul_get_seg_reg(x86_seg_ss, hvmemul_ctxt);
}
diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 2c89984..fb11f3b 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -481,7 +481,7 @@ void hvm_do_resume(struct vcpu *v)
if ( v->arch.vm_event->emulate_flags &
VM_EVENT_FLAG_SET_EMUL_READ_DATA )
- kind = EMUL_KIND_SET_CONTEXT;
+ kind = EMUL_KIND_SET_CONTEXT_DATA;
else if ( v->arch.vm_event->emulate_flags &
VM_EVENT_FLAG_EMULATE_NOWRITE )
kind = EMUL_KIND_NOWRITE;
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index bb7a329..41dc678 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -57,6 +57,7 @@
#include <asm/altp2m.h>
#include <asm/event.h>
#include <asm/monitor.h>
+#include <asm/vm_event.h>
#include <public/arch-x86/cpuid.h>
static bool_t __initdata opt_force_ept;
diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 812dbf6..dfed0b3 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -1641,8 +1641,11 @@ void p2m_mem_access_emulate_check(struct vcpu *v,
v->arch.vm_event->emulate_flags = violation ? rsp->flags : 0;
- if ( (rsp->flags & VM_EVENT_FLAG_SET_EMUL_READ_DATA) )
- v->arch.vm_event->emul_read_data = rsp->data.emul_read_data;
+ if ( !!(rsp->flags & VM_EVENT_FLAG_SET_EMUL_READ_DATA) )
+ {
+ gdprintk(XENLOG_WARNING, "Mem access emulate check setting emul
read data buffer\n");
+ v->arch.vm_event->emul_data = rsp->data.emul_data;
+ }
}
}
diff --git a/xen/arch/x86/vm_event.c b/xen/arch/x86/vm_event.c
index e938ca3..4a9327f 100644
--- a/xen/arch/x86/vm_event.c
+++ b/xen/arch/x86/vm_event.c
@@ -66,6 +66,16 @@ void vm_event_toggle_singlestep(struct domain *d, struct
vcpu *v)
hvm_toggle_singlestep(v);
}
+void vm_event_interrupt_emulate_check(struct vcpu *v, vm_event_response_t *rsp)
+{
+ if ( !!(rsp->flags & VM_EVENT_FLAG_EMULATE) &&
+ !!(rsp->flags & VM_EVENT_FLAG_SET_EMUL_INSN_DATA) )
+ {
+ v->arch.vm_event->emulate_flags = rsp->flags;
+ v->arch.vm_event->emul_data = rsp->data.emul_data;
+ }
+}
+
void vm_event_register_write_resume(struct vcpu *v, vm_event_response_t *rsp)
{
if ( rsp->flags & VM_EVENT_FLAG_DENY )
diff --git a/xen/common/vm_event.c b/xen/common/vm_event.c
index 8398af7..161d149 100644
--- a/xen/common/vm_event.c
+++ b/xen/common/vm_event.c
@@ -407,8 +407,11 @@ void vm_event_resume(struct domain *d, struct
vm_event_domain *ved)
vm_event_register_write_resume(v, &rsp);
break;
+ case VM_EVENT_REASON_SOFTWARE_BREAKPOINT:
+ vm_event_interrupt_emulate_check(v, &rsp);
+ break;
+
#ifdef CONFIG_HAS_MEM_ACCESS
- case VM_EVENT_REASON_MEM_ACCESS:
mem_access_resume(v, &rsp);
break;
#endif
diff --git a/xen/include/asm-arm/vm_event.h b/xen/include/asm-arm/vm_event.h
index ccc4b60..e56bc78 100644
--- a/xen/include/asm-arm/vm_event.h
+++ b/xen/include/asm-arm/vm_event.h
@@ -40,6 +40,12 @@ static inline void vm_event_toggle_singlestep(struct domain
*d, struct vcpu *v)
}
static inline
+void vm_event_interrupt_emulate_check(struct vcpu *v, vm_event_response_t *rsp)
+{
+ /* Not supported on ARM. */
+}
+
+static inline
void vm_event_register_write_resume(struct vcpu *v, vm_event_response_t *rsp)
{
/* Not supported on ARM. */
diff --git a/xen/include/asm-x86/hvm/emulate.h
b/xen/include/asm-x86/hvm/emulate.h
index 142d1b6..8e69371 100644
--- a/xen/include/asm-x86/hvm/emulate.h
+++ b/xen/include/asm-x86/hvm/emulate.h
@@ -33,13 +33,15 @@ struct hvm_emulate_ctxt {
uint32_t intr_shadow;
- bool_t set_context;
+ bool_t set_context_data;
+ bool_t set_context_insn;
};
enum emul_kind {
EMUL_KIND_NORMAL,
EMUL_KIND_NOWRITE,
- EMUL_KIND_SET_CONTEXT
+ EMUL_KIND_SET_CONTEXT_DATA,
+ EMUL_KIND_SET_CONTEXT_INSN
};
int hvm_emulate_one(
diff --git a/xen/include/asm-x86/vm_event.h b/xen/include/asm-x86/vm_event.h
index 7e6adff..2e3f30b 100644
--- a/xen/include/asm-x86/vm_event.h
+++ b/xen/include/asm-x86/vm_event.h
@@ -27,7 +27,7 @@
*/
struct arch_vm_event {
uint32_t emulate_flags;
- struct vm_event_emul_read_data emul_read_data;
+ struct vm_event_emul_data emul_data;
struct monitor_write_data write_data;
};
@@ -37,6 +37,8 @@ void vm_event_cleanup_domain(struct domain *d);
void vm_event_toggle_singlestep(struct domain *d, struct vcpu *v);
+void vm_event_interrupt_emulate_check(struct vcpu *v, vm_event_response_t
*rsp);
+
void vm_event_register_write_resume(struct vcpu *v, vm_event_response_t *rsp);
void vm_event_set_registers(struct vcpu *v, vm_event_response_t *rsp);
diff --git a/xen/include/public/vm_event.h b/xen/include/public/vm_event.h
index 99d60ea..b83b57d 100644
--- a/xen/include/public/vm_event.h
+++ b/xen/include/public/vm_event.h
@@ -97,6 +97,13 @@
* Requires the vCPU to be paused already (synchronous events only).
*/
#define VM_EVENT_FLAG_SET_REGISTERS (1 << 8)
+/*
+ * Instruction cache is being sent back to the hypervisor in the event response
+ * to be used by the emulator. This flag is only useful when combined with
+ * VM_EVENT_FLAG_EMULATE and is incompatible with also setting
+ * VM_EVENT_FLAG_EMULATE_NOWRITE or VM_EVENT_FLAG_SET_EMUL_READ_DATA.
+ */
+#define VM_EVENT_FLAG_SET_EMUL_INSN_DATA (1 << 9)
/*
* Reasons for the vm event request
@@ -246,7 +253,7 @@ struct vm_event_sharing {
uint32_t _pad;
};
-struct vm_event_emul_read_data {
+struct vm_event_emul_data {
uint32_t size;
/* The struct is used in a union with vm_event_regs_x86. */
uint8_t data[sizeof(struct vm_event_regs_x86) - sizeof(uint32_t)];
@@ -277,7 +284,7 @@ typedef struct vm_event_st {
struct vm_event_regs_x86 x86;
} regs;
- struct vm_event_emul_read_data emul_read_data;
+ struct vm_event_emul_data emul_data;
} data;
} vm_event_request_t, vm_event_response_t;
--
2.9.3
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |