[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 |