[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 1/3] xen/arm: io: Distinguish unhandled IO from aborted one



On Tue, 30 Jan 2018, Julien Grall wrote:
> Currently, Xen is considering that an IO could either be handled or
> unhandled. When unhandled, the stage-2 abort function will try another
> way to resolve the abort.
> 
> However, the MMIO emulation may return unhandled when the address
> belongs to an emulated range but was not correct. In that case, Xen
> should avodi to try another way and directly inject a guest data abort.
         ^ avoid


> Introduce a tri-state return to distinguish the following state:
>     * IO_ABORT: The IO was handled but resulted to an abort
                                                  ^ in an abort


>     * IO_HANDLED: The IO was handled
>     * IO_UNHANDLED: The IO was unhandled
> 
> For now, it is considered that an IO belonging to an emulated range
> could either be handled or inject an abort. This could be revisit in the
> future if overlapped region exist (or we want to try another way to
> resolve the abort).
> 
> Signed-off-by: Julien Grall <julien.grall@xxxxxxx>
> ---
>  xen/arch/arm/io.c          | 24 ++++++++++++++----------
>  xen/arch/arm/traps.c       | 34 +++++++++++++++++++++++-----------
>  xen/include/asm-arm/mmio.h |  9 ++++++++-
>  3 files changed, 45 insertions(+), 22 deletions(-)
> 
> diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c
> index c748d8f5bf..a74ec21b86 100644
> --- a/xen/arch/arm/io.c
> +++ b/xen/arch/arm/io.c
> @@ -23,8 +23,9 @@
>  #include <asm/current.h>
>  #include <asm/mmio.h>
>  
> -static int handle_read(const struct mmio_handler *handler, struct vcpu *v,
> -                       mmio_info_t *info)
> +static enum io_state handle_read(const struct mmio_handler *handler,
> +                                 struct vcpu *v,
> +                                 mmio_info_t *info)
>  {
>      const struct hsr_dabt dabt = info->dabt;
>      struct cpu_user_regs *regs = guest_cpu_user_regs();
> @@ -37,7 +38,7 @@ static int handle_read(const struct mmio_handler *handler, 
> struct vcpu *v,
>      uint8_t size = (1 << dabt.size) * 8;
>  
>      if ( !handler->ops->read(v, info, &r, handler->priv) )
> -        return 0;
> +        return IO_ABORT;
>  
>      /*
>       * Sign extend if required.
> @@ -57,17 +58,20 @@ static int handle_read(const struct mmio_handler 
> *handler, struct vcpu *v,
>  
>      set_user_reg(regs, dabt.reg, r);
>  
> -    return 1;
> +    return IO_HANDLED;
>  }
>  
> -static int handle_write(const struct mmio_handler *handler, struct vcpu *v,
> -                        mmio_info_t *info)
> +static enum io_state handle_write(const struct mmio_handler *handler,
> +                                  struct vcpu *v,
> +                                  mmio_info_t *info)
>  {
>      const struct hsr_dabt dabt = info->dabt;
>      struct cpu_user_regs *regs = guest_cpu_user_regs();
> +    int ret;
>  
> -    return handler->ops->write(v, info, get_user_reg(regs, dabt.reg),
> -                               handler->priv);
> +    ret = handler->ops->write(v, info, get_user_reg(regs, dabt.reg),
> +                              handler->priv);
> +    return ( ret ) ? IO_HANDLED : IO_ABORT;
>  }
>  
>  /* This function assumes that mmio regions are not overlapped */
> @@ -100,14 +104,14 @@ static const struct mmio_handler 
> *find_mmio_handler(struct domain *d,
>      return handler;
>  }
>  
> -int handle_mmio(mmio_info_t *info)
> +enum io_state handle_mmio(mmio_info_t *info)
>  {
>      struct vcpu *v = current;
>      const struct mmio_handler *handler = NULL;
>  
>      handler = find_mmio_handler(v->domain, info->gpa);
>      if ( !handler )
> -        return 0;
> +        return IO_UNHANDLED;
>  
>      if ( info->dabt.write )
>          return handle_write(handler, v, info);
> diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
> index c8534d6cff..843adf4959 100644
> --- a/xen/arch/arm/traps.c
> +++ b/xen/arch/arm/traps.c
> @@ -1864,10 +1864,10 @@ static inline bool hpfar_is_valid(bool s1ptw, uint8_t 
> fsc)
>      return s1ptw || (fsc == FSC_FLT_TRANS && !check_workaround_834220());
>  }
>  
> -static bool try_handle_mmio(struct cpu_user_regs *regs,
> -                            const union hsr hsr,
> -                            paddr_t gpa)
> -{
> +static enum io_state try_handle_mmio(struct cpu_user_regs *regs,
> +                                     const union hsr hsr,
> +                                     paddr_t gpa)
> + {
>      const struct hsr_dabt dabt = hsr.dabt;
>      mmio_info_t info = {
>          .gpa = gpa,
> @@ -1879,11 +1879,11 @@ static bool try_handle_mmio(struct cpu_user_regs 
> *regs,
>  
>      /* stage-1 page table should never live in an emulated MMIO region */
>      if ( dabt.s1ptw )
> -        return false;
> +        return IO_UNHANDLED;
>  
>      /* All the instructions used on emulated MMIO region should be valid */
>      if ( !dabt.valid )
> -        return false;
> +        return IO_UNHANDLED;
>  
>      /*
>       * Erratum 766422: Thumb store translation fault to Hypervisor may
> @@ -1896,11 +1896,11 @@ static bool try_handle_mmio(struct cpu_user_regs 
> *regs,
>          if ( rc )
>          {
>              gprintk(XENLOG_DEBUG, "Unable to decode instruction\n");
> -            return false;
> +            return IO_ABORT;
>          }
>      }

Why do the first two error checks result in IO_UNHANDLED, while the
third result in IO_ABORT? Specifically in relation to pagetable walk
failures due to someone else changing stage-2 entry simultaneously (see
comment toward the end of do_trap_stage2_abort_guest)?


> -    return !!handle_mmio(&info);
> +    return handle_mmio(&info);
>  }
>  
>  /*
> @@ -2005,10 +2005,21 @@ static void do_trap_stage2_abort_guest(struct 
> cpu_user_regs *regs,
>           *
>           * Note that emulated region cannot be executed
>           */
> -        if ( is_data && try_handle_mmio(regs, hsr, gpa) )
> +        if ( is_data )
>          {
> -            advance_pc(regs, hsr);
> -            return;
> +            enum io_state state = try_handle_mmio(regs, hsr, gpa);
> +
> +            switch ( state )
> +            {
> +            case IO_ABORT:
> +                goto inject_abt;
> +            case IO_HANDLED:
> +                advance_pc(regs, hsr);
> +                return;
> +            case IO_UNHANDLED:
> +                /* Nothing to do */
> +                break;
> +            }
>          }
>  
>          /*
> @@ -2029,6 +2040,7 @@ static void do_trap_stage2_abort_guest(struct 
> cpu_user_regs *regs,
>                  hsr.bits, xabt.fsc);
>      }
>  
> +inject_abt:
>      gdprintk(XENLOG_DEBUG, "HSR=0x%x pc=%#"PRIregister" gva=%#"PRIvaddr
>               " gpa=%#"PRIpaddr"\n", hsr.bits, regs->pc, gva, gpa);
>      if ( is_data )
> diff --git a/xen/include/asm-arm/mmio.h b/xen/include/asm-arm/mmio.h
> index 37e2b7a707..baaecf6931 100644
> --- a/xen/include/asm-arm/mmio.h
> +++ b/xen/include/asm-arm/mmio.h
> @@ -32,6 +32,13 @@ typedef struct
>      paddr_t gpa;
>  } mmio_info_t;
>  
> +enum io_state
> +{
> +    IO_ABORT,       /* The IO was handled by the helper and lead to an 
> abort. */
                                                                ^ led

> +    IO_HANDLED,     /* The IO was successfully handled by the helper. */
> +    IO_UNHANDLED,   /* The IO was not handled by the helper. */
> +};
> +
>  typedef int (*mmio_read_t)(struct vcpu *v, mmio_info_t *info,
>                             register_t *r, void *priv);
>  typedef int (*mmio_write_t)(struct vcpu *v, mmio_info_t *info,
> @@ -56,7 +63,7 @@ struct vmmio {
>      struct mmio_handler *handlers;
>  };
>  
> -extern int handle_mmio(mmio_info_t *info);
> +extern enum io_state handle_mmio(mmio_info_t *info);
>  void register_mmio_handler(struct domain *d,
>                             const struct mmio_handler_ops *ops,
>                             paddr_t addr, paddr_t size, void *priv);
> -- 
> 2.11.0
> 

_______________________________________________
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®.