[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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.