[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH RFC v2 2/2] x86/emulate: Send vm_event from emulate
On Fri, Jan 11, 2019 at 03:37:45PM +0000, Alexandru Stefan ISAILA wrote: > This patch aims to have mem access vm events sent from the emulator. > This is useful in the case of page-walks that have to emulate > instructions in access denied pages. > > We use hvmemul_map_linear_addr() ro intercept r/w access and > hvmemul_insn_fetch() to intercept exec access. > > First we try to send a vm event and if the event is sent then emulation > returns X86EMUL_ACCESS_EXCEPTION. If the event is not sent then the > emulation goes on as expected. > > Signed-off-by: Alexandru Isaila <aisaila@xxxxxxxxxxxxxxx> > > --- > Changes since V1: > - Add newlines in hvmemul_send_vm_event() > - Dropped p2m->get_entry() for p2m_get_mem_access() > - Use a simplified return for hvmemul_send_vm_event. > --- > xen/arch/x86/hvm/emulate.c | 104 ++++++++++++++++++++++++- > xen/arch/x86/hvm/vm_event.c | 2 +- > xen/arch/x86/mm/mem_access.c | 3 +- > xen/arch/x86/x86_emulate/x86_emulate.h | 1 + > xen/include/asm-x86/hvm/emulate.h | 4 +- > 5 files changed, 109 insertions(+), 5 deletions(-) > > diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c > index a766eecc8e..3a6bca32fe 100644 > --- a/xen/arch/x86/hvm/emulate.c > +++ b/xen/arch/x86/hvm/emulate.c > @@ -15,6 +15,7 @@ > #include <xen/paging.h> > #include <xen/trace.h> > #include <xen/vm_event.h> > +#include <xen/monitor.h> > #include <asm/event.h> > #include <asm/i387.h> > #include <asm/xstate.h> > @@ -26,6 +27,7 @@ > #include <asm/hvm/support.h> > #include <asm/hvm/svm/svm.h> > #include <asm/vm_event.h> > +#include <asm/altp2m.h> > > static void hvmtrace_io_assist(const ioreq_t *p) > { > @@ -530,6 +532,56 @@ static int hvmemul_do_mmio_addr(paddr_t mmio_gpa, > return hvmemul_do_io_addr(1, mmio_gpa, reps, size, dir, df, ram_gpa); > } > > +static bool hvmemul_send_vm_event(paddr_t gpa, unsigned long gla, gfn_t gfn, > + uint32_t pfec, struct hvm_emulate_ctxt > *ctxt) > +{ > + xenmem_access_t access; > + vm_event_request_t req = {}; > + > + if ( !ctxt->send_event || !pfec ) > + return false; > + > + if ( p2m_get_mem_access(current->domain, gfn, &access, > + altp2m_vcpu_idx(current)) != 0 ) You can join the ifs: if ( !ctxt->send_event || !pfec || p2m_get_mem_access(current->domain, gfn, &access, altp2m_vcpu_idx(current)) ) return false; > + return false; > + > + switch ( access ) { The braces should be on a newline. > + case XENMEM_access_x: > + case XENMEM_access_rx: > + if ( pfec & PFEC_write_access ) > + req.u.mem_access.flags = MEM_ACCESS_R | MEM_ACCESS_W; > + break; > + > + case XENMEM_access_w: > + case XENMEM_access_rw: > + if ( pfec & PFEC_insn_fetch ) > + req.u.mem_access.flags = MEM_ACCESS_X; > + break; > + > + case XENMEM_access_r: > + case XENMEM_access_n: > + if ( pfec & PFEC_write_access ) > + req.u.mem_access.flags |= MEM_ACCESS_R | MEM_ACCESS_W; > + if ( pfec & PFEC_insn_fetch ) > + req.u.mem_access.flags |= MEM_ACCESS_X; > + break; > + > + default: > + return false; > + } > + > + if ( !req.u.mem_access.flags ) > + return false; /* No violation. */ > + > + req.reason = VM_EVENT_REASON_MEM_ACCESS; > + req.u.mem_access.gfn = gfn_x(gfn); > + req.u.mem_access.flags |= MEM_ACCESS_FAULT_WITH_GLA | > MEM_ACCESS_GLA_VALID; > + req.u.mem_access.gla = gla; > + req.u.mem_access.offset = gpa & ((1 << PAGE_SHIFT) - 1); > + > + return monitor_traps(current, true, &req) >= 0; > +} > + > /* > * Convert addr from linear to physical form, valid over the range > * [addr, addr + *reps * bytes_per_rep]. *reps is adjusted according to > @@ -636,6 +688,7 @@ static void *hvmemul_map_linear_addr( > unsigned int nr_frames = ((linear + bytes - !!bytes) >> PAGE_SHIFT) - > (linear >> PAGE_SHIFT) + 1; > unsigned int i; > + gfn_t gfn; > > /* > * mfn points to the next free slot. All used slots have a page > reference > @@ -674,7 +727,7 @@ static void *hvmemul_map_linear_addr( > ASSERT(mfn_x(*mfn) == 0); > > res = hvm_translate_get_page(curr, addr, true, pfec, > - &pfinfo, &page, NULL, &p2mt); > + &pfinfo, &page, &gfn, &p2mt); > > switch ( res ) > { > @@ -704,6 +757,23 @@ static void *hvmemul_map_linear_addr( > > if ( pfec & PFEC_write_access ) > { > + unsigned long reps = 1; > + struct hvm_emulate_ctxt old; > + int rc = 0; > + paddr_t gpa; > + > + old = *hvmemul_ctxt; > + rc = hvmemul_linear_to_phys( > + addr, &gpa, bytes, &reps, pfec, hvmemul_ctxt); The indentation is weird here, it should be: rc = hvmemul_linear_to_phys(addr, &gpa, bytes, &reps, pfec, hvmemul_ctxt); > + if ( rc == X86EMUL_EXCEPTION ) > + *hvmemul_ctxt = old; > + > + if ( hvmemul_send_vm_event(gpa, addr, gfn, pfec, hvmemul_ctxt) ) > + { > + err = ERR_PTR(~X86EMUL_ACCESS_EXCEPTION); > + goto out; > + } > + > if ( p2m_is_discard_write(p2mt) ) > { > err = ERR_PTR(~X86EMUL_OKAY); > @@ -1224,7 +1294,36 @@ int hvmemul_insn_fetch( > container_of(ctxt, struct hvm_emulate_ctxt, ctxt); > /* Careful, as offset can wrap or truncate WRT insn_buf_eip. */ > uint8_t insn_off = offset - hvmemul_ctxt->insn_buf_eip; > + paddr_t gpa; > + uint32_t pfec = PFEC_page_present | PFEC_insn_fetch; > + unsigned long addr, reps = 1; > + int rc =0; ^ missing space And I don't see the need to initialize rc to 0, since you are assigning it to the return value of hvmemul_virtual_to_linear just below. > + struct hvm_emulate_ctxt old; > + > + rc = hvmemul_virtual_to_linear( > + seg, offset, bytes, &reps, hvm_access_insn_fetch, hvmemul_ctxt, > &addr); Weird indentation, see above. > + if ( rc == X86EMUL_EXCEPTION ) What about other errors returned from hvmemul_virtual_to_linear apart from X86EMUL_EXCEPTION? Are you sure you should continue execution here if an error different than EXCEPTION is returned? > + { > + x86_emul_reset_event(ctxt); Indentation is wrong here, you are missing one space. > + rc = X86EMUL_OKAY; > + } > + > + if ( hvmemul_ctxt->seg_reg[x86_seg_ss].dpl == 3 ) > + pfec |= PFEC_user_mode; > + > + old = *hvmemul_ctxt; > + rc = hvmemul_linear_to_phys( > + addr, &gpa, bytes, &reps, pfec, hvmemul_ctxt); Same here regarding indentation of function parameters. > + if ( rc == X86EMUL_EXCEPTION ) > + { > + *hvmemul_ctxt = old; > + rc = X86EMUL_OKAY; > + } > > + if ( gpa ) > + if ( hvmemul_send_vm_event(gpa, addr, gaddr_to_gfn(gpa), > + pfec, hvmemul_ctxt) ) > + return X86EMUL_ACCESS_EXCEPTION; You can join the ifs: if ( gpa && hvmemul_send_vm_event(...) ) return X86EMUL_ACCESS_EXCEPTION; > /* > * Fall back if requested bytes are not in the prefetch cache. > * But always perform the (fake) read when bytes == 0. There's an inner rc variable declared below which you can now remove. > @@ -2492,12 +2591,13 @@ int hvm_emulate_one_mmio(unsigned long mfn, unsigned > long gla) > } > > void hvm_emulate_one_vm_event(enum emul_kind kind, unsigned int trapnr, > - unsigned int errcode) > + unsigned int errcode, bool send_event) > { > struct hvm_emulate_ctxt ctx = {{ 0 }}; > int rc; > > hvm_emulate_init_once(&ctx, NULL, guest_cpu_user_regs()); > + ctx.send_event = send_event; > > switch ( kind ) > { > diff --git a/xen/arch/x86/hvm/vm_event.c b/xen/arch/x86/hvm/vm_event.c > index 0df8ab40e6..bdc65da3ed 100644 > --- a/xen/arch/x86/hvm/vm_event.c > +++ b/xen/arch/x86/hvm/vm_event.c > @@ -87,7 +87,7 @@ void hvm_vm_event_do_resume(struct vcpu *v) > kind = EMUL_KIND_SET_CONTEXT_INSN; > > hvm_emulate_one_vm_event(kind, TRAP_invalid_op, > - X86_EVENT_NO_EC); > + X86_EVENT_NO_EC, false); > > v->arch.vm_event->emulate_flags = 0; > } > diff --git a/xen/arch/x86/mm/mem_access.c b/xen/arch/x86/mm/mem_access.c > index 56c06a4fc6..536ad6367b 100644 > --- a/xen/arch/x86/mm/mem_access.c > +++ b/xen/arch/x86/mm/mem_access.c > @@ -214,7 +214,8 @@ bool p2m_mem_access_check(paddr_t gpa, unsigned long gla, > d->arch.monitor.inguest_pagefault_disabled && > npfec.kind != npfec_kind_with_gla ) /* don't send a mem_event */ > { > - hvm_emulate_one_vm_event(EMUL_KIND_NORMAL, TRAP_invalid_op, > X86_EVENT_NO_EC); > + hvm_emulate_one_vm_event(EMUL_KIND_NORMAL, TRAP_invalid_op, > + X86_EVENT_NO_EC, true); > > return true; > } > diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h > b/xen/arch/x86/x86_emulate/x86_emulate.h > index 55a9e0ed51..a9829913a4 100644 > --- a/xen/arch/x86/x86_emulate/x86_emulate.h > +++ b/xen/arch/x86/x86_emulate/x86_emulate.h > @@ -162,6 +162,7 @@ struct x86_emul_fpu_aux { > #define X86EMUL_UNRECOGNIZED X86EMUL_UNIMPLEMENTED > /* (cmpxchg accessor): CMPXCHG failed. */ > #define X86EMUL_CMPXCHG_FAILED 7 > +#define X86EMUL_ACCESS_EXCEPTION 8 > > /* FPU sub-types which may be requested via ->get_fpu(). */ > enum x86_emulate_fpu_type { > diff --git a/xen/include/asm-x86/hvm/emulate.h > b/xen/include/asm-x86/hvm/emulate.h > index 26a01e83a4..721e175b04 100644 > --- a/xen/include/asm-x86/hvm/emulate.h > +++ b/xen/include/asm-x86/hvm/emulate.h > @@ -47,6 +47,7 @@ struct hvm_emulate_ctxt { > uint32_t intr_shadow; > > bool_t set_context; > + bool send_event; I'm not sure I see why a send_event field needs to be added to the ctxt struct, isn't is possible to pass this parameter to the relevant functions that care about it? Thanks, Roger. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |