[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC V10 1/5] xen: Emulate with no writes
Added support for emulating an instruction with no memory writes. Additionally, introduced hvm_emulate_one_full(), which inspects possible return values from the hvm_emulate_one() functions (EXCEPTION, UNHANDLEABLE) and acts on them. Signed-off-by: Razvan Cojocaru <rcojocaru@xxxxxxxxxxxxxxx> Acked-by: Jan Beulich <jbeulich@xxxxxxxx> --- Changes since V7: - Renamed hvm_emulate_one_full() to hvm_mem_event_emulate_one(). - Added a comment explaining how X86EMUL_RETRY is being treated. Changes since V6: - Added discard versions of write_msr and wbinvd. - Now calling hvm_emulate_writeback() for the X86EMUL_UNHANDLEABLE case as well. Changes since V5: - Added discard versions of write_io and rep_outs. Changes since V4: - Also discarding IO reads (dummy read_io handler). Changes since V3: - The rep_ins, rep_movs and cmpxchg handlers are now also inactive. Changes since V2: - Renamed hvmemul_write_dummy() to hvmemul_write_discard(). - Fixed a comment (Xen coding style rules). - Renamed hvm_emulate_one_with_ops() to _hvm_emulate_one(). - Changed stack variable hvm_emulate_ops_no_write into a static const. - Modified struct hvm_emulate_ctxt ctx initialization syntax. - Renamed unhandleable_trapnr to trapnr and unhandleable_errcode to errcode. - Changed errcode's type to unsigned int. - Removed hvm_emulate_one() loop that went on until it returned something other than X86EMUL_RETRY (to prevent potential blocking against the time calibration rendezvous). Changes since V1: - Removed the Linux code that computes the length of an instruction. - Unused function parameters are no longer marked. - Refactored the code to eliminate redundancy. - Made the exception passed on to the guest by hvm_emulate_one_full() configurable. --- xen/arch/x86/hvm/emulate.c | 175 ++++++++++++++++++++++++++++++++++++- xen/include/asm-x86/hvm/emulate.h | 5 ++ 2 files changed, 177 insertions(+), 3 deletions(-) diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index 86cf432..6ab06e0 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -690,6 +690,94 @@ static int hvmemul_write( return X86EMUL_OKAY; } +static int hvmemul_write_discard( + enum x86_segment seg, + unsigned long offset, + void *p_data, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + /* Discarding the write. */ + return X86EMUL_OKAY; +} + +static int hvmemul_rep_ins_discard( + uint16_t src_port, + enum x86_segment dst_seg, + unsigned long dst_offset, + unsigned int bytes_per_rep, + unsigned long *reps, + struct x86_emulate_ctxt *ctxt) +{ + return X86EMUL_OKAY; +} + +static int hvmemul_rep_movs_discard( + enum x86_segment src_seg, + unsigned long src_offset, + enum x86_segment dst_seg, + unsigned long dst_offset, + unsigned int bytes_per_rep, + unsigned long *reps, + struct x86_emulate_ctxt *ctxt) +{ + return X86EMUL_OKAY; +} + +static int hvmemul_rep_outs_discard( + enum x86_segment src_seg, + unsigned long src_offset, + uint16_t dst_port, + unsigned int bytes_per_rep, + unsigned long *reps, + struct x86_emulate_ctxt *ctxt) +{ + return X86EMUL_OKAY; +} + +static int hvmemul_cmpxchg_discard( + enum x86_segment seg, + unsigned long offset, + void *p_old, + void *p_new, + unsigned int bytes, + struct x86_emulate_ctxt *ctxt) +{ + return X86EMUL_OKAY; +} + +static int hvmemul_read_io_discard( + unsigned int port, + unsigned int bytes, + unsigned long *val, + struct x86_emulate_ctxt *ctxt) +{ + return X86EMUL_OKAY; +} + +static int hvmemul_write_io_discard( + unsigned int port, + unsigned int bytes, + unsigned long val, + struct x86_emulate_ctxt *ctxt) +{ + return X86EMUL_OKAY; +} + +static int hvmemul_write_msr_discard( + unsigned long reg, + uint64_t val, + struct x86_emulate_ctxt *ctxt) +{ + return X86EMUL_OKAY; +} + +static int hvmemul_wbinvd_discard( + struct x86_emulate_ctxt *ctxt) +{ + return X86EMUL_OKAY; +} + static int hvmemul_cmpxchg( enum x86_segment seg, unsigned long offset, @@ -1140,8 +1228,33 @@ static const struct x86_emulate_ops hvm_emulate_ops = { .invlpg = hvmemul_invlpg }; -int hvm_emulate_one( - struct hvm_emulate_ctxt *hvmemul_ctxt) +static const struct x86_emulate_ops hvm_emulate_ops_no_write = { + .read = hvmemul_read, + .insn_fetch = hvmemul_insn_fetch, + .write = hvmemul_write_discard, + .cmpxchg = hvmemul_cmpxchg_discard, + .rep_ins = hvmemul_rep_ins_discard, + .rep_outs = hvmemul_rep_outs_discard, + .rep_movs = hvmemul_rep_movs_discard, + .read_segment = hvmemul_read_segment, + .write_segment = hvmemul_write_segment, + .read_io = hvmemul_read_io_discard, + .write_io = hvmemul_write_io_discard, + .read_cr = hvmemul_read_cr, + .write_cr = hvmemul_write_cr, + .read_msr = hvmemul_read_msr, + .write_msr = hvmemul_write_msr_discard, + .wbinvd = hvmemul_wbinvd_discard, + .cpuid = hvmemul_cpuid, + .inject_hw_exception = hvmemul_inject_hw_exception, + .inject_sw_interrupt = hvmemul_inject_sw_interrupt, + .get_fpu = hvmemul_get_fpu, + .put_fpu = hvmemul_put_fpu, + .invlpg = hvmemul_invlpg +}; + +static int _hvm_emulate_one(struct hvm_emulate_ctxt *hvmemul_ctxt, + const struct x86_emulate_ops *ops) { struct cpu_user_regs *regs = hvmemul_ctxt->ctxt.regs; struct vcpu *curr = current; @@ -1193,7 +1306,7 @@ int hvm_emulate_one( vio->mmio_retrying = vio->mmio_retry; vio->mmio_retry = 0; - rc = x86_emulate(&hvmemul_ctxt->ctxt, &hvm_emulate_ops); + rc = x86_emulate(&hvmemul_ctxt->ctxt, ops); if ( rc == X86EMUL_OKAY && vio->mmio_retry ) rc = X86EMUL_RETRY; @@ -1241,6 +1354,62 @@ int hvm_emulate_one( return X86EMUL_OKAY; } +int hvm_emulate_one( + struct hvm_emulate_ctxt *hvmemul_ctxt) +{ + return _hvm_emulate_one(hvmemul_ctxt, &hvm_emulate_ops); +} + +int hvm_emulate_one_no_write( + struct hvm_emulate_ctxt *hvmemul_ctxt) +{ + return _hvm_emulate_one(hvmemul_ctxt, &hvm_emulate_ops_no_write); +} + +void hvm_mem_event_emulate_one(bool_t nowrite, unsigned int trapnr, + unsigned int errcode) +{ + struct hvm_emulate_ctxt ctx = {{ 0 }}; + int rc; + + hvm_emulate_prepare(&ctx, guest_cpu_user_regs()); + + if ( nowrite ) + rc = hvm_emulate_one_no_write(&ctx); + else + rc = hvm_emulate_one(&ctx); + + switch ( rc ) + { + case X86EMUL_RETRY: + /* + * This function is called when handling an EPT-related mem_event + * reply. As such, nothing else needs to be done here, since simply + * returning makes the current instruction cause a page fault again, + * consistent with X86EMUL_RETRY. + */ + return; + case X86EMUL_UNHANDLEABLE: + gdprintk(XENLOG_DEBUG, "Emulation failed @ %04x:%lx: " + "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + hvmemul_get_seg_reg(x86_seg_cs, &ctx)->sel, + ctx.insn_buf_eip, + ctx.insn_buf[0], ctx.insn_buf[1], + ctx.insn_buf[2], ctx.insn_buf[3], + ctx.insn_buf[4], ctx.insn_buf[5], + ctx.insn_buf[6], ctx.insn_buf[7], + ctx.insn_buf[8], ctx.insn_buf[9]); + hvm_inject_hw_exception(trapnr, errcode); + break; + case X86EMUL_EXCEPTION: + if ( ctx.exn_pending ) + hvm_inject_hw_exception(ctx.exn_vector, ctx.exn_error_code); + break; + } + + hvm_emulate_writeback(&ctx); +} + void hvm_emulate_prepare( struct hvm_emulate_ctxt *hvmemul_ctxt, struct cpu_user_regs *regs) diff --git a/xen/include/asm-x86/hvm/emulate.h b/xen/include/asm-x86/hvm/emulate.h index 00a06cc..efff97e 100644 --- a/xen/include/asm-x86/hvm/emulate.h +++ b/xen/include/asm-x86/hvm/emulate.h @@ -37,6 +37,11 @@ struct hvm_emulate_ctxt { int hvm_emulate_one( struct hvm_emulate_ctxt *hvmemul_ctxt); +int hvm_emulate_one_no_write( + struct hvm_emulate_ctxt *hvmemul_ctxt); +void hvm_mem_event_emulate_one(bool_t nowrite, + unsigned int trapnr, + unsigned int errcode); void hvm_emulate_prepare( struct hvm_emulate_ctxt *hvmemul_ctxt, struct cpu_user_regs *regs); -- 1.7.9.5 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |