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

Re: [Xen-devel] [PATCH v13 1/3] x86emul: New return code for unimplemented instruction



> -----Original Message-----
> From: Petre Pircalabu [mailto:ppircalabu@xxxxxxxxxxxxxxx]
> Sent: 25 September 2017 13:03
> To: xen-devel@xxxxxxxxxxxxx
> Cc: Ian Jackson <Ian.Jackson@xxxxxxxxxx>; Wei Liu <wei.liu2@xxxxxxxxxx>;
> Andrew Cooper <Andrew.Cooper3@xxxxxxxxxx>; George Dunlap
> <George.Dunlap@xxxxxxxxxx>; jbeulich@xxxxxxxx; konrad.wilk@xxxxxxxxxx;
> sstabellini@xxxxxxxxxx; Tim (Xen.org) <tim@xxxxxxx>; Paul Durrant
> <Paul.Durrant@xxxxxxxxxx>; rcojocaru@xxxxxxxxxxxxxxx;
> tamas@xxxxxxxxxxxxx; jun.nakajima@xxxxxxxxx; Kevin Tian
> <kevin.tian@xxxxxxxxx>; Petre Pircalabu <ppircalabu@xxxxxxxxxxxxxxx>
> Subject: [PATCH v13 1/3] x86emul: New return code for unimplemented
> instruction
> 
> Enforce the distinction between an instruction not implemented by the
> emulator and the failure to emulate that instruction by defining a new
> return code, X86EMUL_UNIMPLEMENTED.
> 
> This value should only be returned by the core emulator only if it fails to
> properly decode the current instruction's opcode, and not by any of other
> functions, such as the x86_emulate_ops or the hvm_io_ops callbacks.
> 
> e.g. hvm_process_io_intercept should not return
> X86EMUL_UNIMPLEMENTED.
> The return value of this function depends on either the return code of
> one of the hvm_io_ops handlers (read/write) or the value returned by
> hvm_copy_guest_from_phys / hvm_copy_to_guest_phys.
> 
> Similary, none of this functions should return X86EMUL_UNIMPLEMENTED.
>  - hvm_io_intercept
>  - hvmemul_do_io
>  - hvm_send_buffered_ioreq
>  - hvm_send_ioreq
>  - hvm_broadcast_ioreq
>  - hvmemul_do_io_buffer
>  - hvmemul_validate
> 
> Also the behavior of hvm_emulate_one_insn and
> vmx_realmode_emulate_one
> was modified to generate an Invalid Opcode trap when
> X86EMUL_UNRECOGNIZED
> is returned by the emulator instead of just crash the domain.
> 
> Signed-off-by: Petre Pircalabu <ppircalabu@xxxxxxxxxxxxxxx>
> 

Reviewed-by: Paul Durrant <paul.durrant@xxxxxxxxxx>

> ---
> Changed since v10:
>     * Added asserts to make sure the return code cannot be
> X86EMUL_UNIMPLEMENTED.
>     * Add new return code (X86EMUL_UNRECOGNIZED) to be used when
> trying
>     to emulate an instruction with an invalid opcode.
> 
> Changed since v11:
>     * Fixed double negative in the patch description.
>     * Move assertion into the switch and use ASSERT_UNREACHABLE() when
>     applicable.
>     * Changed the description of X86EMUL_UNIMPLEMENTED /
> X86EMUL_UNRECOGNIZED
>     to reflect the differences between those 2 return codes.
>     * Changed the returned value to X86EMUL_UNRECOGNIZED in the
>     following cases:
>         X86EMUL_OPC(0x0f, 0x73): /* Group 14 */
>         X86EMUL_OPC_66(0x0f, 0x73):
>         X86EMUL_OPC_VEX_66(0x0f, 0x73):
>                 - All valid opcodes are defined, so it should return
>                 X86EMUL_UNRECOGNIZED if mod R/M bits are not matched.
> 
>         X86EMUL_OPC(0x0f, 0xc7) /* Group 9 */
>                 - For register type instructions all possible opcodes are
>                 defined, so it should return X86EMUL_UNRECOGNIZED if
>                 mod R/M bits are not matched.
> 
>         X86EMUL_OPC_VEX(0x0f38, 0xf3): /* Group 17 */
>                 - All valid opcodes are defined, so it should return
>                 X86EMUL_UNRECOGNIZED if mod R/M bits are not matched.
> 
>         X86EMUL_OPC_XOP(09, 0x01): /* XOP Grp1 */
>         X86EMUL_OPC_XOP(09, 0x02): /* XOP Grp2 */
>                 - All valid opcodes are defined, so it should return
>                 X86EMUL_UNRECOGNIZED if mod R/M bits are not matched.
> 
>         X86EMUL_OPC(0x0f, 0x01): /* Grp7 */
>                 - Not all valid opcodes are defined so it should return
>                 X86EMUL_UNIMPLEMENTED if mod R/M bits are not matched.
>                 (e.g. XGETBV)
> 
>         X86EMUL_OPC_66(0x0f, 0x78):
>                 - All valid opcodes are defined, so it should return
>                 X86EMUL_UNRECOGNIZED if mod R/M bits are not matched.
> 
>         X86EMUL_OPC(0x0f, 0xae):
>         X86EMUL_OPC_66(0x0f, 0xae): /* Grp15 */
>                 - Not all valid opcodes are defined so it should return
>                 X86EMUL_UNIMPLEMENTED if mod R/M bits are not matched.
>                 (e.g. FXSAVE/FXRSTOR )
> 
> Changed since v12:
>     * return X86EMUL_UNIMPLEMENTED if HAVE_GAS_RDRAND is not
> defined
>     * create unrecognized_insn label
>     * return X86EMUL_UNRECOGNIZED in case of failure to decode Group #13
>     instructions.
>     * add a "TODO:" comment to the description of X86EMUL_UNRECOGNIZED
>     stating that for now it can be used interchangeably with
>     X86EMUL_UNIMPLEMENTED.
> ---
>  xen/arch/x86/hvm/emulate.c             | 12 ++++++++
>  xen/arch/x86/hvm/hvm.c                 |  1 +
>  xen/arch/x86/hvm/io.c                  |  5 ++++
>  xen/arch/x86/hvm/vmx/realmode.c        |  9 ++++++
>  xen/arch/x86/mm/shadow/multi.c         |  2 +-
>  xen/arch/x86/x86_emulate/x86_emulate.c | 51 +++++++++++++++++++----
> -----------
>  xen/arch/x86/x86_emulate/x86_emulate.h | 17 ++++++++++++
>  7 files changed, 74 insertions(+), 23 deletions(-)
> 
> diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
> index cc874ce..385fe1e 100644
> --- a/xen/arch/x86/hvm/emulate.c
> +++ b/xen/arch/x86/hvm/emulate.c
> @@ -284,10 +284,15 @@ static int hvmemul_do_io(
>          }
>          break;
>      }
> +    case X86EMUL_UNIMPLEMENTED:
> +        ASSERT_UNREACHABLE();
> +        /* Fall-through */
>      default:
>          BUG();
>      }
> 
> +    ASSERT(rc != X86EMUL_UNIMPLEMENTED);
> +
>      if ( rc != X86EMUL_OKAY )
>          return rc;
> 
> @@ -313,6 +318,9 @@ static int hvmemul_do_io_buffer(
> 
>      rc = hvmemul_do_io(is_mmio, addr, reps, size, dir, df, 0,
>                         (uintptr_t)buffer);
> +
> +    ASSERT(rc != X86EMUL_UNIMPLEMENTED);
> +
>      if ( rc == X86EMUL_UNHANDLEABLE && dir == IOREQ_READ )
>          memset(buffer, 0xff, size);
> 
> @@ -405,6 +413,8 @@ static int hvmemul_do_io_addr(
>      rc = hvmemul_do_io(is_mmio, addr, &count, size, dir, df, 1,
>                         ram_gpa);
> 
> +    ASSERT(rc != X86EMUL_UNIMPLEMENTED);
> +
>      if ( rc == X86EMUL_OKAY )
>          v->arch.hvm_vcpu.hvm_io.mmio_retry = (count < *reps);
> 
> @@ -2045,6 +2055,7 @@ int hvm_emulate_one_mmio(unsigned long mfn,
> unsigned long gla)
>      switch ( rc )
>      {
>      case X86EMUL_UNHANDLEABLE:
> +    case X86EMUL_UNIMPLEMENTED:
>          hvm_dump_emulation_state(XENLOG_G_WARNING, "MMCFG",
> &ctxt);
>          break;
>      case X86EMUL_EXCEPTION:
> @@ -2102,6 +2113,7 @@ void hvm_emulate_one_vm_event(enum
> emul_kind kind, unsigned int trapnr,
>           * consistent with X86EMUL_RETRY.
>           */
>          return;
> +    case X86EMUL_UNIMPLEMENTED:
>      case X86EMUL_UNHANDLEABLE:
>          hvm_dump_emulation_state(XENLOG_G_DEBUG, "Mem event", &ctx);
>          hvm_inject_hw_exception(trapnr, errcode);
> diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
> index d99f4b4..57f3f76 100644
> --- a/xen/arch/x86/hvm/hvm.c
> +++ b/xen/arch/x86/hvm/hvm.c
> @@ -3735,6 +3735,7 @@ void hvm_ud_intercept(struct cpu_user_regs
> *regs)
>      switch ( hvm_emulate_one(&ctxt) )
>      {
>      case X86EMUL_UNHANDLEABLE:
> +    case X86EMUL_UNIMPLEMENTED:
>          hvm_inject_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC);
>          break;
>      case X86EMUL_EXCEPTION:
> diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c
> index bf41954..b8c0ae7 100644
> --- a/xen/arch/x86/hvm/io.c
> +++ b/xen/arch/x86/hvm/io.c
> @@ -99,6 +99,11 @@ bool
> hvm_emulate_one_insn(hvm_emulate_validate_t *validate, const char
> *descr)
>          hvm_dump_emulation_state(XENLOG_G_WARNING, descr, &ctxt);
>          return false;
> 
> +    case X86EMUL_UNRECOGNIZED:
> +        hvm_dump_emulation_state(XENLOG_G_WARNING, descr, &ctxt);
> +        hvm_inject_hw_exception(TRAP_invalid_op, X86_EVENT_NO_EC);
> +        break;
> +
>      case X86EMUL_EXCEPTION:
>          hvm_inject_event(&ctxt.ctxt.event);
>          break;
> diff --git a/xen/arch/x86/hvm/vmx/realmode.c
> b/xen/arch/x86/hvm/vmx/realmode.c
> index 12d43ad..b73fc80 100644
> --- a/xen/arch/x86/hvm/vmx/realmode.c
> +++ b/xen/arch/x86/hvm/vmx/realmode.c
> @@ -112,6 +112,15 @@ void vmx_realmode_emulate_one(struct
> hvm_emulate_ctxt *hvmemul_ctxt)
>          goto fail;
>      }
> 
> +    if ( rc == X86EMUL_UNRECOGNIZED )
> +    {
> +        gdprintk(XENLOG_ERR, "Unrecognized insn.\n");
> +        if ( curr->arch.hvm_vcpu.guest_cr[0] & X86_CR0_PE )
> +            goto fail;
> +
> +        realmode_deliver_exception(TRAP_invalid_op, 0, hvmemul_ctxt);
> +    }
> +
>      if ( rc == X86EMUL_EXCEPTION )
>      {
>          if ( unlikely(curr->domain->debugger_attached) &&
> diff --git a/xen/arch/x86/mm/shadow/multi.c
> b/xen/arch/x86/mm/shadow/multi.c
> index 8d4f244..2557e21 100644
> --- a/xen/arch/x86/mm/shadow/multi.c
> +++ b/xen/arch/x86/mm/shadow/multi.c
> @@ -3488,7 +3488,7 @@ static int sh_page_fault(struct vcpu *v,
>       * would be a good unshadow hint. If we *do* decide to unshadow-on-
> fault
>       * then it must be 'failable': we cannot require the unshadow to succeed.
>       */
> -    if ( r == X86EMUL_UNHANDLEABLE )
> +    if ( r == X86EMUL_UNHANDLEABLE || r == X86EMUL_UNIMPLEMENTED )
>      {
>          perfc_incr(shadow_fault_emulate_failed);
>  #if SHADOW_OPTIMIZATIONS & SHOPT_FAST_EMULATION
> diff --git a/xen/arch/x86/x86_emulate/x86_emulate.c
> b/xen/arch/x86/x86_emulate/x86_emulate.c
> index c1e2300..5be33d8 100644
> --- a/xen/arch/x86/x86_emulate/x86_emulate.c
> +++ b/xen/arch/x86/x86_emulate/x86_emulate.c
> @@ -848,7 +848,8 @@ do{ asm volatile (                                        
>               \
>                  stub.func);                                             \
>          generate_exception_if(res_.fields.trapnr == EXC_UD, EXC_UD);    \
>          domain_crash(current->domain);                                  \
> -        goto cannot_emulate;                                            \
> +        rc = X86EMUL_UNHANDLEABLE;                                      \
> +        goto done;                                                      \
>      }                                                                   \
>  } while (0)
>  #else
> @@ -2585,7 +2586,7 @@ x86_decode(
>                          d = twobyte_table[0x3a].desc;
>                          break;
>                      default:
> -                        rc = X86EMUL_UNHANDLEABLE;
> +                        rc = X86EMUL_UNRECOGNIZED;
>                          goto done;
>                      }
>                  }
> @@ -2599,7 +2600,7 @@ x86_decode(
>                  }
>                  else
>                  {
> -                    rc = X86EMUL_UNHANDLEABLE;
> +                    rc = X86EMUL_UNRECOGNIZED;
>                      goto done;
>                  }
> 
> @@ -2879,7 +2880,7 @@ x86_decode(
> 
>      default:
>          ASSERT_UNREACHABLE();
> -        return X86EMUL_UNHANDLEABLE;
> +        return X86EMUL_UNIMPLEMENTED;
>      }
> 
>      if ( ea.type == OP_MEM )
> @@ -4191,7 +4192,7 @@ x86_emulate(
>                  break;
>              case 4: /* fldenv - TODO */
>                  state->fpu_ctrl = true;
> -                goto cannot_emulate;
> +                goto unimplemented_insn;
>              case 5: /* fldcw m2byte */
>                  state->fpu_ctrl = true;
>                  if ( (rc = ops->read(ea.mem.seg, ea.mem.off, &src.val,
> @@ -4202,7 +4203,7 @@ x86_emulate(
>                  break;
>              case 6: /* fnstenv - TODO */
>                  state->fpu_ctrl = true;
> -                goto cannot_emulate;
> +                goto unimplemented_insn;
>              case 7: /* fnstcw m2byte */
>                  state->fpu_ctrl = true;
>                  emulate_fpu_insn_memdst("fnstcw", dst.val);
> @@ -4438,7 +4439,7 @@ x86_emulate(
>              case 4: /* frstor - TODO */
>              case 6: /* fnsave - TODO */
>                  state->fpu_ctrl = true;
> -                goto cannot_emulate;
> +                goto unimplemented_insn;
>              case 7: /* fnstsw m2byte */
>                  state->fpu_ctrl = true;
>                  emulate_fpu_insn_memdst("fnstsw", dst.val);
> @@ -5197,7 +5198,7 @@ x86_emulate(
>  #undef _GRP7
> 
>          default:
> -            goto cannot_emulate;
> +            goto unimplemented_insn;
>          }
>          break;
>      }
> @@ -6195,7 +6196,7 @@ x86_emulate(
>                  /* vpsll{w,d} $imm8,{x,y}mm,{x,y}mm */
>              break;
>          default:
> -            goto cannot_emulate;
> +            goto unrecognized_insn;
>          }
>      simd_0f_shift_imm:
>          generate_exception_if(ea.type != OP_REG, EXC_UD);
> @@ -6243,7 +6244,7 @@ x86_emulate(
>          case 6: /* psllq $imm8,mm */
>              goto simd_0f_shift_imm;
>          }
> -        goto cannot_emulate;
> +        goto unrecognized_insn;
> 
>      case X86EMUL_OPC_66(0x0f, 0x73):
>      case X86EMUL_OPC_VEX_66(0x0f, 0x73):
> @@ -6259,7 +6260,7 @@ x86_emulate(
>                  /* vpslldq $imm8,{x,y}mm,{x,y}mm */
>              goto simd_0f_shift_imm;
>          }
> -        goto cannot_emulate;
> +        goto unrecognized_insn;
> 
>      case X86EMUL_OPC(0x0f, 0x77):        /* emms */
>      case X86EMUL_OPC_VEX(0x0f, 0x77):    /* vzero{all,upper} */
> @@ -6323,7 +6324,7 @@ x86_emulate(
>          case 0: /* extrq $imm8,$imm8,xmm */
>              break;
>          default:
> -            goto cannot_emulate;
> +            goto unrecognized_insn;
>          }
>          /* fall through */
>      case X86EMUL_OPC_F2(0x0f, 0x78):     /* insertq $imm8,$imm8,xmm,xmm
> */
> @@ -6518,7 +6519,7 @@ x86_emulate(
>                  goto done;
>              break;
>          default:
> -            goto cannot_emulate;
> +            goto unimplemented_insn;
>          }
>          break;
> 
> @@ -6534,7 +6535,7 @@ x86_emulate(
>              vcpu_must_have(avx);
>              goto stmxcsr;
>          }
> -        goto cannot_emulate;
> +        goto unrecognized_insn;
> 
>      case X86EMUL_OPC_F3(0x0f, 0xae): /* Grp15 */
>          fail_if(modrm_mod != 3);
> @@ -6777,10 +6778,10 @@ x86_emulate(
>              switch ( modrm_reg & 7 )
>              {
>              default:
> -                goto cannot_emulate;
> +                goto unrecognized_insn;
> 
> -#ifdef HAVE_GAS_RDRAND
>              case 6: /* rdrand */
> +#ifdef HAVE_GAS_RDRAND
>                  generate_exception_if(rep_prefix(), EXC_UD);
>                  host_and_vcpu_must_have(rdrand);
>                  dst = ea;
> @@ -6805,6 +6806,8 @@ x86_emulate(
>                  if ( carry )
>                      _regs.eflags |= X86_EFLAGS_CF;
>                  break;
> +#else
> +                goto unimplemented_insn;
>  #endif
> 
>              case 7: /* rdseed / rdpid */
> @@ -7359,7 +7362,7 @@ x86_emulate(
>              host_and_vcpu_must_have(bmi1);
>              break;
>          default:
> -            goto cannot_emulate;
> +            goto unrecognized_insn;
>          }
> 
>          generate_exception_if(vex.l, EXC_UD);
> @@ -7670,7 +7673,7 @@ x86_emulate(
>              host_and_vcpu_must_have(tbm);
>              break;
>          default:
> -            goto cannot_emulate;
> +            goto unrecognized_insn;
>          }
> 
>      xop_09_rm_rv:
> @@ -7704,7 +7707,7 @@ x86_emulate(
>              host_and_vcpu_must_have(tbm);
>              goto xop_09_rm_rv;
>          }
> -        goto cannot_emulate;
> +        goto unrecognized_insn;
> 
>      case X86EMUL_OPC_XOP(0a, 0x10): /* bextr imm,r/m,r */
>      {
> @@ -7736,8 +7739,11 @@ x86_emulate(
>      }
> 
>      default:
> -    cannot_emulate:
> -        rc = X86EMUL_UNHANDLEABLE;
> +    unimplemented_insn:
> +        rc = X86EMUL_UNIMPLEMENTED;
> +        goto done;
> +    unrecognized_insn:
> +        rc = X86EMUL_UNRECOGNIZED;
>          goto done;
>      }
> 
> @@ -7789,7 +7795,8 @@ x86_emulate(
>                  if ( (d & DstMask) != DstMem )
>                  {
>                      ASSERT_UNREACHABLE();
> -                    goto cannot_emulate;
> +                    rc = X86EMUL_UNHANDLEABLE;
> +                    goto done;
>                  }
>                  break;
>              }
> diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h
> b/xen/arch/x86/x86_emulate/x86_emulate.h
> index 4ddf111..0c8c80a 100644
> --- a/xen/arch/x86/x86_emulate/x86_emulate.h
> +++ b/xen/arch/x86/x86_emulate/x86_emulate.h
> @@ -133,6 +133,23 @@ struct x86_emul_fpu_aux {
>    * Undefined behavior when used anywhere else.
>    */
>  #define X86EMUL_DONE           4
> + /*
> +  * Current instruction is not implemented by the emulator.
> +  * This value should only be returned by the core emulator when a valid
> +  * opcode is found but the execution logic for that instruction is missing.
> +  * It should NOT be returned by any of the x86_emulate_ops callbacks.
> +  */
> +#define X86EMUL_UNIMPLEMENTED  5
> + /*
> +  * The current instruction's opcode is not valid.
> +  * If this error code is returned by a function, an #UD trap should be
> +  * raised by the final consumer of it.
> +  *
> +  * TODO: For the moment X86EMUL_UNRECOGNIZED and
> X86EMUL_UNIMPLEMENTED
> +  * can be used interchangeably therefore raising an #UD trap is not
> +  * strictly expected for now.
> + */
> +#define X86EMUL_UNRECOGNIZED   X86EMUL_UNIMPLEMENTED
> 
>  /* FPU sub-types which may be requested via ->get_fpu(). */
>  enum x86_emulate_fpu_type {
> --
> 2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

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