diff mbox

[v9,1/2] x86emul: New return code for unimplemented instruction

Message ID 1504119449-7324-2-git-send-email-ppircalabu@bitdefender.com (mailing list archive)
State New, archived
Headers show

Commit Message

Petre Ovidiu PIRCALABU Aug. 30, 2017, 6:57 p.m. UTC
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 used by the core emulator if it fails to decode
the current instruction, and not by any of the x86_emulate_ops
callbacks.

Signed-off-by: Petre Pircalabu <ppircalabu@bitdefender.com>
Reviewed-by: Paul Durrant <paul.durrant@citrix.com>
---
 xen/arch/x86/hvm/emulate.c             |  3 +++
 xen/arch/x86/hvm/hvm.c                 |  1 +
 xen/arch/x86/hvm/io.c                  |  1 +
 xen/arch/x86/hvm/vmx/realmode.c        |  2 +-
 xen/arch/x86/mm/shadow/multi.c         |  2 +-
 xen/arch/x86/x86_emulate/x86_emulate.c | 35 ++++++++++++++++++----------------
 xen/arch/x86/x86_emulate/x86_emulate.h |  6 ++++++
 7 files changed, 32 insertions(+), 18 deletions(-)

Comments

Jan Beulich Sept. 1, 2017, 10:33 a.m. UTC | #1
>>> On 30.08.17 at 20:57, <ppircalabu@bitdefender.com> wrote:
> --- a/xen/arch/x86/hvm/emulate.c
> +++ b/xen/arch/x86/hvm/emulate.c
> @@ -2044,6 +2044,7 @@ int hvm_emulate_one_mmio(unsigned long mfn, unsigned long gla)

Way earlier in this file there are consumers of X86EMUL_UNHANDLEABLE
in hvmemul_do_io() and hvmemul_do_io_buffer(). I'm sure I did
point this out before, and I cannot see why you don't adjust those as
well, and you also don't say anything in this regard in the description.
Similarly there's a consumer in hvm_process_io_intercept() (in a file
you don't touch at all). The use in hvm_broadcast_ioreq() is likely
fine, but I'd still like you to reason about that in the description.

> @@ -5177,7 +5177,7 @@ x86_emulate(
>                  goto done;
>              break;
>          default:
> -            goto cannot_emulate;
> +            goto unimplemented_insn;

While I can see why you do this change, for many/all of the ones
I'll leave in context below I think you rather want to switch to
generate_exception(EXC_UD).

> @@ -6176,7 +6176,7 @@ x86_emulate(
>                  /* vpsll{w,d} $imm8,{x,y}mm,{x,y}mm */
>              break;
>          default:
> -            goto cannot_emulate;
> +            goto unimplemented_insn;
>          }
>      simd_0f_shift_imm:
>          generate_exception_if(ea.type != OP_REG, EXC_UD);
> @@ -6224,7 +6224,7 @@ x86_emulate(
>          case 6: /* psllq $imm8,mm */
>              goto simd_0f_shift_imm;
>          }
> -        goto cannot_emulate;
> +        goto unimplemented_insn;
>  
>      case X86EMUL_OPC_66(0x0f, 0x73):
>      case X86EMUL_OPC_VEX_66(0x0f, 0x73):
> @@ -6240,7 +6240,7 @@ x86_emulate(
>                  /* vpslldq $imm8,{x,y}mm,{x,y}mm */
>              goto simd_0f_shift_imm;
>          }
> -        goto cannot_emulate;
> +        goto unimplemented_insn;
>  
>      case X86EMUL_OPC(0x0f, 0x77):        /* emms */
>      case X86EMUL_OPC_VEX(0x0f, 0x77):    /* vzero{all,upper} */
> @@ -6304,7 +6304,7 @@ x86_emulate(
>          case 0: /* extrq $imm8,$imm8,xmm */
>              break;
>          default:
> -            goto cannot_emulate;
> +            goto unimplemented_insn;
>          }
>          /* fall through */
>      case X86EMUL_OPC_F2(0x0f, 0x78):     /* insertq $imm8,$imm8,xmm,xmm */
> @@ -6515,7 +6515,7 @@ x86_emulate(

A few lines up from here is another instance you appear to have
missed.

> @@ -7341,7 +7341,7 @@ x86_emulate(
>              host_and_vcpu_must_have(bmi1);
>              break;
>          default:
> -            goto cannot_emulate;
> +            goto unimplemented_insn;
>          }
>  
>          generate_exception_if(vex.l, EXC_UD);
> @@ -7650,7 +7650,7 @@ x86_emulate(
>              host_and_vcpu_must_have(tbm);
>              break;
>          default:
> -            goto cannot_emulate;
> +            goto unimplemented_insn;
>          }
>  
>      xop_09_rm_rv:
> @@ -7684,7 +7684,7 @@ x86_emulate(
>              host_and_vcpu_must_have(tbm);
>              goto xop_09_rm_rv;
>          }
> -        goto cannot_emulate;
> +        goto unimplemented_insn;
>  
>      case X86EMUL_OPC_XOP(0a, 0x10): /* bextr imm,r/m,r */
>      {
> @@ -7716,6 +7716,9 @@ x86_emulate(
>      }
>  
>      default:
> +    unimplemented_insn:
> +        rc = X86EMUL_UNIMPLEMENTED;
> +        goto done;
>      cannot_emulate:
>          rc = X86EMUL_UNHANDLEABLE;
>          goto done;

I guess the cannot_emulate label would then better be moved
elsewhere (either out of the switch or to a place where one of
the goto-s to it currently sits).

Jan
Petre Ovidiu PIRCALABU Sept. 4, 2017, 5:20 p.m. UTC | #2
On Vi, 2017-09-01 at 04:33 -0600, Jan Beulich wrote:
> >

> > >

> > > >

> > > > On 30.08.17 at 20:57, <ppircalabu@bitdefender.com> wrote:

> > --- a/xen/arch/x86/hvm/emulate.c

> > +++ b/xen/arch/x86/hvm/emulate.c

> > @@ -2044,6 +2044,7 @@ int hvm_emulate_one_mmio(unsigned long mfn,

> > unsigned long gla)

> Way earlier in this file there are consumers of X86EMUL_UNHANDLEABLE

> in hvmemul_do_io() and hvmemul_do_io_buffer(). I'm sure I did

> point this out before, and I cannot see why you don't adjust those as

> well, and you also don't say anything in this regard in the

> description.

> Similarly there's a consumer in hvm_process_io_intercept() (in a file

> you don't touch at all). The use in hvm_broadcast_ioreq() is likely

> fine, but I'd still like you to reason about that in the description.


My mistake. I have added my comments in the cover letter as I thought
they will be easier to read. I will add them the the patch description
for the next iteration.

In my opinion, hvm_process_io_intercept cannot 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.
In case of the latter, the function crashes the domain and
returns X86EMUL_UNHANDLEABLE if the result is neither HVMCOPY_okay
nor HVMCOPY_bad_gfn_to_mfn.
hvm_op_ops should not return X86EMUL_UNIMPLEMENTED as this return
code's usage should strictly be limited to the core emulator and only
when an instruction opcode is invalid.

hvmemul_do_io - X86EMUL_UNHANDLEABLE is tested against the return code
of hvm_io_intercept which can return X86EMUL_UNHANDLEABLE only if the
IO handler was not found or it was returned by hvm_process_io_intercept
(cannot return X86EMUL_UNIMPLEMENTED).
In this case I think adding the X86EMUL_UNIMPLEMENTED check would mask
a possible misuse of this return code instead of just triggering BUG()
in the early stages of development.

hvm_send_buffered_ioreq - currently returns X86EMUL_UNHANDLEABLE if:
- the buffered iopage is NULL.
- the ioreq size if invalid
- the queue is full.
In none of these cases the function cannot return X86EMUL_UNIMPLEMENTED
because they are not related to the instruction opcode decoding, so
this function cannot return X86EMUL_UNIMPLEMENTED.

hvm_send_ioreq - can return X86EMUL_UNHANDLEABLE only if the current
vcpu in not the hvm_iorec_server's list or the value if returned from
hvm_send_buffered_ioreq, hence this function also cannot return
X86EMUL_UNIMPLEMENTED.

hvm_broadcast_ioreq - calls hvm_send_ioreq and chvemul_do_iohecks the
return code against X86EMUL_UNHANDLEABLE. There is no need to extend
the check to handle X86EMUL_UNIMPLEMENTED because this value cannot be
returned by hvm_send_ioreq.

hvmemul_do_io_buffer - calls hvmemul_do_io and, if the return code is
X86EMUL_UNHANDLEABLE and dir is IOREQ_READ, sets the return buffer to
0xFF.
The return value of hvemul_do_io can be:
- return value of hvm_io_intercept (cannot be X86EMUL_UNIMPLEMENTED),
- return value of hvm_process_io_intercept (cannot be
X86EMUL_UNIMPLEMENTED)
- return value of hvm_send_ioreq(cannot be X86EMUL_UNIMPLEMENTED)
- X86EMUL_RETRY / X86EMUL_OKAY (depending on state)
The condition also should not be extended to take into account
X86EMUL_UNIMPLEMENTED because this value cannot be returned by
hvemul_do_io.

> >

> > @@ -5177,7 +5177,7 @@ x86_emulate(

> >                  goto done;

> >              break;

> >          default:

> > -            goto cannot_emulate;

> > +            goto unimplemented_insn;

> While I can see why you do this change, for many/all of the ones

> I'll leave in context below I think you rather want to switch to

> generate_exception(EXC_UD).

Some of the opcodes are valid but not supported by the emulator. In
this case X86EMUL_UNIMPLEMENTED should be returned to allow the monitor
app to handle this case. Also, in the worst case scenario, when the
opcode doesn't correspond to a valid x86(-64) instruction, if the
monitor app for example tries to single-step it on the real hardware an
UD exception will also be reported.
>

> >

> > @@ -6176,7 +6176,7 @@ x86_emulate(

> >                  /* vpsll{w,d} $imm8,{x,y}mm,{x,y}mm */

> >              break;

> >          default:

> > -            goto cannot_emulate;

> > +            goto unimplemented_insn;

> >          }

> >

> > > >      simd_0f_shift_imm:

> >          generate_exception_if(ea.type != OP_REG, EXC_UD);

> > @@ -6224,7 +6224,7 @@ x86_emulate(

> >          case 6: /* psllq $imm8,mm */

> >              goto simd_0f_shift_imm;

> >          }

> > -        goto cannot_emulate;

> > +        goto unimplemented_insn;

> >

> >      case X86EMUL_OPC_66(0x0f, 0x73):

> >      case X86EMUL_OPC_VEX_66(0x0f, 0x73):

> > @@ -6240,7 +6240,7 @@ x86_emulate(

> >                  /* vpslldq $imm8,{x,y}mm,{x,y}mm */

> >              goto simd_0f_shift_imm;

> >          }

> > -        goto cannot_emulate;

> > +        goto unimplemented_insn;

> >

> >      case X86EMUL_OPC(0x0f, 0x77):        /* emms */

> >      case X86EMUL_OPC_VEX(0x0f, 0x77):    /* vzero{all,upper} */

> > @@ -6304,7 +6304,7 @@ x86_emulate(

> >          case 0: /* extrq $imm8,$imm8,xmm */

> >              break;

> >          default:

> > -            goto cannot_emulate;

> > +            goto unimplemented_insn;

> >          }

> >          /* fall through */

> >      case X86EMUL_OPC_F2(0x0f, 0x78):     /* insertq

> > $imm8,$imm8,xmm,xmm */

> > @@ -6515,7 +6515,7 @@ x86_emulate(

> A few lines up from here is another instance you appear to have

> missed.

>

> >

> > @@ -7341,7 +7341,7 @@ x86_emulate(

> >              host_and_vcpu_must_have(bmi1);

> >              break;

> >          default:

> > -            goto cannot_emulate;

> > +            goto unimplemented_insn;

> >          }

> >

> >          generate_exception_if(vex.l, EXC_UD);

> > @@ -7650,7 +7650,7 @@ x86_emulate(

> >              host_and_vcpu_must_have(tbm);

> >              break;

> >          default:

> > -            goto cannot_emulate;

> > +            goto unimplemented_insn;

> >          }

> >

> >      xop_09_rm_rv:

> > @@ -7684,7 +7684,7 @@ x86_emulate(

> >              host_and_vcpu_must_have(tbm);

> >              goto xop_09_rm_rv;

> >          }

> > -        goto cannot_emulate;

> > +        goto unimplemented_insn;

> >

> >      case X86EMUL_OPC_XOP(0a, 0x10): /* bextr imm,r/m,r */

> >      {

> > @@ -7716,6 +7716,9 @@ x86_emulate(

> >      }

> >

Thanks for noticing it. I will change it back to cannot_emulate as
there are no other valid instructions for this opcodes.

> >      default:

> > +    unimplemented_insn:

> > +        rc = X86EMUL_UNIMPLEMENTED;

> > +        goto done;

> >      cannot_emulate:

> >          rc = X86EMUL_UNHANDLEABLE;

> >          goto done;

> I guess the cannot_emulate label would then better be moved

> elsewhere (either out of the switch or to a place where one of

> the goto-s to it currently sits).

I will change it in the new iteration of the patch.

> Jan

>

>

> ________________________

> This email was scanned by Bitdefender


Many thanks for your patience,
//Petre

________________________
This email was scanned by Bitdefender
Jan Beulich Sept. 5, 2017, 5:42 a.m. UTC | #3
>>> Petre Ovidiu PIRCALABU <ppircalabu@bitdefender.com> 09/04/17 7:20 PM >>>
>On Vi, 2017-09-01 at 04:33 -0600, Jan Beulich wrote:
>> >
>> > >
>> > > >
>> > > > On 30.08.17 at 20:57, <ppircalabu@bitdefender.com> wrote:
>> > --- a/xen/arch/x86/hvm/emulate.c
>> > +++ b/xen/arch/x86/hvm/emulate.c
>> > @@ -2044,6 +2044,7 @@ int hvm_emulate_one_mmio(unsigned long mfn,
>> > unsigned long gla)
>> Way earlier in this file there are consumers of X86EMUL_UNHANDLEABLE
>> in hvmemul_do_io() and hvmemul_do_io_buffer(). I'm sure I did
>> point this out before, and I cannot see why you don't adjust those as
>> well, and you also don't say anything in this regard in the
>> description.
>> Similarly there's a consumer in hvm_process_io_intercept() (in a file
>> you don't touch at all). The use in hvm_broadcast_ioreq() is likely
>> fine, but I'd still like you to reason about that in the description.
>
>My mistake. I have added my comments in the cover letter as I thought
>they will be easier to read. I will add them the the patch description
>for the next iteration.

Thanks, that'll make them stay with the changes once committed. Your
further explanations are too long for a commit message though, imo. Aiui
they all boil down to the uses being in functions sitting behind rather than
in front of x86_emulate(). If that's the case, I would suggest you state just
that fact along with the enumeration of places that don't need touching for
that reason. This will make reviewing (and later viewing/understanding)
quite a bit easier.

>> > @@ -5177,7 +5177,7 @@ x86_emulate(
>> >                  goto done;
>> >              break;
>> >          default:
>> > -            goto cannot_emulate;
>> > +            goto unimplemented_insn;
>> While I can see why you do this change, for many/all of the ones
>> I'll leave in context below I think you rather want to switch to
>> generate_exception(EXC_UD).
>Some of the opcodes are valid but not supported by the emulator. In
>this case X86EMUL_UNIMPLEMENTED should be returned to allow the monitor
>app to handle this case. Also, in the worst case scenario, when the
>opcode doesn't correspond to a valid x86(-64) instruction, if the
>monitor app for example tries to single-step it on the real hardware an
>UD exception will also be reported.

Please be more precise with "some of the opcodes are valid". When I
looked through your change, I don't think I've seen any such case for the
places I meant the comment to apply to. Also, as far as the emulator
changes themselves go, please leave aside considerations of what a
monitor app may or may not do. These changes need to be consistent
all by themselves.

>> > @@ -7716,6 +7716,9 @@ x86_emulate(
>> >      }
>> >
>Thanks for noticing it. I will change it back to cannot_emulate as
>there are no other valid instructions for this opcodes.

I have trouble understanding this comment of yours, not the least
because I don't recall having asked (in particular around here) that
you switch anything back.

Jan
Petre Ovidiu PIRCALABU Sept. 5, 2017, 3:23 p.m. UTC | #4
On Lu, 2017-09-04 at 23:42 -0600, Jan Beulich wrote:
> > >

> > > >

> > > > @@ -5177,7 +5177,7 @@ x86_emulate(

> > > >                  goto done;

> > > >              break;

> > > >          default:

> > > > -            goto cannot_emulate;

> > > > +            goto unimplemented_insn;

> > > While I can see why you do this change, for many/all of the ones

> > > I'll leave in context below I think you rather want to switch to

> > > generate_exception(EXC_UD).

> > Some of the opcodes are valid but not supported by the emulator. In

> > this case X86EMUL_UNIMPLEMENTED should be returned to allow the

> > monitor

> > app to handle this case. Also, in the worst case scenario, when the

> > opcode doesn't correspond to a valid x86(-64) instruction, if the

> > monitor app for example tries to single-step it on the real

> > hardware an

> > UD exception will also be reported.

> Please be more precise with "some of the opcodes are valid". When I

> looked through your change, I don't think I've seen any such case for

> the

> places I meant the comment to apply to. Also, as far as the emulator

> changes themselves go, please leave aside considerations of what a

> monitor app may or may not do. These changes need to be consistent

> all by themselves.

>

Sorry about the poor wording. I was under the impression that you
required the invalid opcodes to be handled differently from the ones
which are valid but unimplemented (directly generate EXC_UD instead of
returning X86EMUL_UNIMPLEMENTED and let the caller handle it).

e.g. for  X86EMUL_OPC_VEX(0x0f38, 0xf3): /* Grp 17 */
the mod R/M possible values are 1,2,3 (source: http://sandpile.org/x86/
opc_grp.htm).
From my perspective I wouldn't differentiate between those 2 cases and
return X86EMUL_UNIMPLEMENTED. The performance penalty is negligible if
the monitor is neither present nor it implements
XEN_DOMCTL_MONITOR_EVENT_EMUL_UNIMPLEMENTED. The monitor can only offer
a "second-chance" re-execution of the faulty instruction and does not
affect the internal logic of x86_decode/x86_emulate.

> > >

> > > >

> > > > @@ -7716,6 +7716,9 @@ x86_emulate(

> > > >      }

> > > >

> > Thanks for noticing it. I will change it back to cannot_emulate as

> > there are no other valid instructions for this opcodes.

> I have trouble understanding this comment of yours, not the least

> because I don't recall having asked (in particular around here) that

> you switch anything back.

>

> Jan

>

>

> ________________________

> This email was scanned by Bitdefender


Many thanks for your support,
//Petre

________________________
This email was scanned by Bitdefender
Jan Beulich Sept. 5, 2017, 3:46 p.m. UTC | #5
>>> On 05.09.17 at 17:23, <ppircalabu@bitdefender.com> wrote:
> On Lu, 2017-09-04 at 23:42 -0600, Jan Beulich wrote:
>> > >
>> > > >
>> > > > @@ -5177,7 +5177,7 @@ x86_emulate(
>> > > >                  goto done;
>> > > >              break;
>> > > >          default:
>> > > > -            goto cannot_emulate;
>> > > > +            goto unimplemented_insn;
>> > > While I can see why you do this change, for many/all of the ones
>> > > I'll leave in context below I think you rather want to switch to
>> > > generate_exception(EXC_UD).
>> > Some of the opcodes are valid but not supported by the emulator. In
>> > this case X86EMUL_UNIMPLEMENTED should be returned to allow the
>> > monitor
>> > app to handle this case. Also, in the worst case scenario, when the
>> > opcode doesn't correspond to a valid x86(-64) instruction, if the
>> > monitor app for example tries to single-step it on the real
>> > hardware an
>> > UD exception will also be reported.
>> Please be more precise with "some of the opcodes are valid". When I
>> looked through your change, I don't think I've seen any such case for
>> the
>> places I meant the comment to apply to. Also, as far as the emulator
>> changes themselves go, please leave aside considerations of what a
>> monitor app may or may not do. These changes need to be consistent
>> all by themselves.
>>
> Sorry about the poor wording. I was under the impression that you
> required the invalid opcodes to be handled differently from the ones
> which are valid but unimplemented (directly generate EXC_UD instead of
> returning X86EMUL_UNIMPLEMENTED and let the caller handle it).

Yes, that's what I think would be best. I admit there is a potential
problem with this, when one or more of them become defined. But
that's something I'd like to also have Andrew's input on.

> e.g. for  X86EMUL_OPC_VEX(0x0f38, 0xf3): /* Grp 17 */
> the mod R/M possible values are 1,2,3 (source: http://sandpile.org/x86/ 
> opc_grp.htm).
> From my perspective I wouldn't differentiate between those 2 cases and
> return X86EMUL_UNIMPLEMENTED.

I must still be missing something: What two cases are you talking
about? The three valid values have an implementation in the
emulator. All others are undefined, i.e. at present would ideally
produce #UD (see above).

Jan
Petre Ovidiu PIRCALABU Sept. 5, 2017, 4:20 p.m. UTC | #6
On Ma, 2017-09-05 at 09:46 -0600, Jan Beulich wrote:
> >

> > >

> > > >

> > > > On 05.09.17 at 17:23, <ppircalabu@bitdefender.com> wrote:

> > On Lu, 2017-09-04 at 23:42 -0600, Jan Beulich wrote:

> > >

> > > >

> > > > >

> > > > >

> > > > > >

> > > > > >

> > > > > > @@ -5177,7 +5177,7 @@ x86_emulate(

> > > > > >                  goto done;

> > > > > >              break;

> > > > > >          default:

> > > > > > -            goto cannot_emulate;

> > > > > > +            goto unimplemented_insn;

> > > > > While I can see why you do this change, for many/all of the

> > > > > ones

> > > > > I'll leave in context below I think you rather want to switch

> > > > > to

> > > > > generate_exception(EXC_UD).

> > > > Some of the opcodes are valid but not supported by the

> > > > emulator. In

> > > > this case X86EMUL_UNIMPLEMENTED should be returned to allow the

> > > > monitor

> > > > app to handle this case. Also, in the worst case scenario, when

> > > > the

> > > > opcode doesn't correspond to a valid x86(-64) instruction, if

> > > > the

> > > > monitor app for example tries to single-step it on the real

> > > > hardware an

> > > > UD exception will also be reported.

> > > Please be more precise with "some of the opcodes are valid". When

> > > I

> > > looked through your change, I don't think I've seen any such case

> > > for

> > > the

> > > places I meant the comment to apply to. Also, as far as the

> > > emulator

> > > changes themselves go, please leave aside considerations of what

> > > a

> > > monitor app may or may not do. These changes need to be

> > > consistent

> > > all by themselves.

> > >

> > Sorry about the poor wording. I was under the impression that you

> > required the invalid opcodes to be handled differently from the

> > ones

> > which are valid but unimplemented (directly generate EXC_UD instead

> > of

> > returning X86EMUL_UNIMPLEMENTED and let the caller handle it).

> Yes, that's what I think would be best. I admit there is a potential

> problem with this, when one or more of them become defined. But

> that's something I'd like to also have Andrew's input on.

>

> >

> > e.g. for  X86EMUL_OPC_VEX(0x0f38, 0xf3): /* Grp 17 */

> > the mod R/M possible values are 1,2,3 (source: http://sandpile.org/

> > x86/

> > opc_grp.htm).

> > From my perspective I wouldn't differentiate between those 2 cases

> > and

> > return X86EMUL_UNIMPLEMENTED.

> I must still be missing something: What two cases are you talking

> about? The three valid values have an implementation in the

> emulator. All others are undefined, i.e. at present would ideally

> produce #UD (see above).


Probably a better example it the handling of Grp7 (after applying
Andrew's patch).
if modrm is 0xd0 the instruction is xgetbv (valid but unimplemented)
if modrm value is corrupted (the encoding doesn't correspond to a valid
instruction it will also jump to emul_unimplemented.
>

> Jan

>

>

> ________________________

> This email was scanned by Bitdefender


Many thanks,
Petre

________________________
This email was scanned by Bitdefender
Jan Beulich Sept. 6, 2017, 9:49 a.m. UTC | #7
>>> On 05.09.17 at 18:20, <ppircalabu@bitdefender.com> wrote:
> On Ma, 2017-09-05 at 09:46 -0600, Jan Beulich wrote:
>> >
>> > >
>> > > >
>> > > > On 05.09.17 at 17:23, <ppircalabu@bitdefender.com> wrote:
>> > On Lu, 2017-09-04 at 23:42 -0600, Jan Beulich wrote:
>> > >
>> > > >
>> > > > >
>> > > > >
>> > > > > >
>> > > > > >
>> > > > > > @@ -5177,7 +5177,7 @@ x86_emulate(
>> > > > > >                  goto done;
>> > > > > >              break;
>> > > > > >          default:
>> > > > > > -            goto cannot_emulate;
>> > > > > > +            goto unimplemented_insn;
>> > > > > While I can see why you do this change, for many/all of the
>> > > > > ones
>> > > > > I'll leave in context below I think you rather want to switch
>> > > > > to
>> > > > > generate_exception(EXC_UD).
>> > > > Some of the opcodes are valid but not supported by the
>> > > > emulator. In
>> > > > this case X86EMUL_UNIMPLEMENTED should be returned to allow the
>> > > > monitor
>> > > > app to handle this case. Also, in the worst case scenario, when
>> > > > the
>> > > > opcode doesn't correspond to a valid x86(-64) instruction, if
>> > > > the
>> > > > monitor app for example tries to single-step it on the real
>> > > > hardware an
>> > > > UD exception will also be reported.
>> > > Please be more precise with "some of the opcodes are valid". When
>> > > I
>> > > looked through your change, I don't think I've seen any such case
>> > > for
>> > > the
>> > > places I meant the comment to apply to. Also, as far as the
>> > > emulator
>> > > changes themselves go, please leave aside considerations of what
>> > > a
>> > > monitor app may or may not do. These changes need to be
>> > > consistent
>> > > all by themselves.
>> > >
>> > Sorry about the poor wording. I was under the impression that you
>> > required the invalid opcodes to be handled differently from the
>> > ones
>> > which are valid but unimplemented (directly generate EXC_UD instead
>> > of
>> > returning X86EMUL_UNIMPLEMENTED and let the caller handle it).
>> Yes, that's what I think would be best. I admit there is a potential
>> problem with this, when one or more of them become defined. But
>> that's something I'd like to also have Andrew's input on.
>>
>> >
>> > e.g. for  X86EMUL_OPC_VEX(0x0f38, 0xf3): /* Grp 17 */
>> > the mod R/M possible values are 1,2,3 (source: http://sandpile.org/ 
>> > x86/
>> > opc_grp.htm).
>> > From my perspective I wouldn't differentiate between those 2 cases
>> > and
>> > return X86EMUL_UNIMPLEMENTED.
>> I must still be missing something: What two cases are you talking
>> about? The three valid values have an implementation in the
>> emulator. All others are undefined, i.e. at present would ideally
>> produce #UD (see above).
> 
> Probably a better example it the handling of Grp7 (after applying
> Andrew's patch).
> if modrm is 0xd0 the instruction is xgetbv (valid but unimplemented)
> if modrm value is corrupted (the encoding doesn't correspond to a valid
> instruction it will also jump to emul_unimplemented.

In cases when there is a mix of missing and undefined opcodes
I would view it as acceptable to go the unimplemented path
without further splitting. In cases where all unhandled cases
are also undefined, I'd prefer #UD to be raised.

Jan
diff mbox

Patch

diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
index 64454c7..f9f8c25 100644
--- a/xen/arch/x86/hvm/emulate.c
+++ b/xen/arch/x86/hvm/emulate.c
@@ -2044,6 +2044,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:
@@ -2101,6 +2102,8 @@  void hvm_emulate_one_vm_event(enum emul_kind kind, unsigned int trapnr,
          * consistent with X86EMUL_RETRY.
          */
         return;
+    case X86EMUL_UNIMPLEMENTED:
+        /* fall-through */
     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 6cb903d..ea2812c 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -3695,6 +3695,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..984db21 100644
--- a/xen/arch/x86/hvm/io.c
+++ b/xen/arch/x86/hvm/io.c
@@ -96,6 +96,7 @@  bool hvm_emulate_one_insn(hvm_emulate_validate_t *validate, const char *descr)
     switch ( rc )
     {
     case X86EMUL_UNHANDLEABLE:
+    case X86EMUL_UNIMPLEMENTED:
         hvm_dump_emulation_state(XENLOG_G_WARNING, descr, &ctxt);
         return false;
 
diff --git a/xen/arch/x86/hvm/vmx/realmode.c b/xen/arch/x86/hvm/vmx/realmode.c
index 11bde58..fdbbee2 100644
--- a/xen/arch/x86/hvm/vmx/realmode.c
+++ b/xen/arch/x86/hvm/vmx/realmode.c
@@ -106,7 +106,7 @@  void vmx_realmode_emulate_one(struct hvm_emulate_ctxt *hvmemul_ctxt)
     if ( hvm_vcpu_io_need_completion(vio) || vio->mmio_retry )
         vio->io_completion = HVMIO_realmode_completion;
 
-    if ( rc == X86EMUL_UNHANDLEABLE )
+    if ( rc == X86EMUL_UNHANDLEABLE || rc == X86EMUL_UNIMPLEMENTED )
     {
         gdprintk(XENLOG_ERR, "Failed to emulate insn.\n");
         goto fail;
diff --git a/xen/arch/x86/mm/shadow/multi.c b/xen/arch/x86/mm/shadow/multi.c
index c5c0af8..15727a2 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 2201852..242b0af 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.c
+++ b/xen/arch/x86/x86_emulate/x86_emulate.c
@@ -2577,7 +2577,7 @@  x86_decode(
                         d = twobyte_table[0x3a].desc;
                         break;
                     default:
-                        rc = X86EMUL_UNHANDLEABLE;
+                        rc = X86EMUL_UNIMPLEMENTED;
                         goto done;
                     }
                 }
@@ -2591,7 +2591,7 @@  x86_decode(
                 }
                 else
                 {
-                    rc = X86EMUL_UNHANDLEABLE;
+                    rc = X86EMUL_UNIMPLEMENTED;
                     goto done;
                 }
 
@@ -2871,7 +2871,7 @@  x86_decode(
 
     default:
         ASSERT_UNREACHABLE();
-        return X86EMUL_UNHANDLEABLE;
+        return X86EMUL_UNIMPLEMENTED;
     }
 
     if ( ea.type == OP_MEM )
@@ -4183,7 +4183,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,
@@ -4194,7 +4194,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);
@@ -4430,7 +4430,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);
@@ -5177,7 +5177,7 @@  x86_emulate(
                 goto done;
             break;
         default:
-            goto cannot_emulate;
+            goto unimplemented_insn;
         }
         break;
     }
@@ -6176,7 +6176,7 @@  x86_emulate(
                 /* vpsll{w,d} $imm8,{x,y}mm,{x,y}mm */
             break;
         default:
-            goto cannot_emulate;
+            goto unimplemented_insn;
         }
     simd_0f_shift_imm:
         generate_exception_if(ea.type != OP_REG, EXC_UD);
@@ -6224,7 +6224,7 @@  x86_emulate(
         case 6: /* psllq $imm8,mm */
             goto simd_0f_shift_imm;
         }
-        goto cannot_emulate;
+        goto unimplemented_insn;
 
     case X86EMUL_OPC_66(0x0f, 0x73):
     case X86EMUL_OPC_VEX_66(0x0f, 0x73):
@@ -6240,7 +6240,7 @@  x86_emulate(
                 /* vpslldq $imm8,{x,y}mm,{x,y}mm */
             goto simd_0f_shift_imm;
         }
-        goto cannot_emulate;
+        goto unimplemented_insn;
 
     case X86EMUL_OPC(0x0f, 0x77):        /* emms */
     case X86EMUL_OPC_VEX(0x0f, 0x77):    /* vzero{all,upper} */
@@ -6304,7 +6304,7 @@  x86_emulate(
         case 0: /* extrq $imm8,$imm8,xmm */
             break;
         default:
-            goto cannot_emulate;
+            goto unimplemented_insn;
         }
         /* fall through */
     case X86EMUL_OPC_F2(0x0f, 0x78):     /* insertq $imm8,$imm8,xmm,xmm */
@@ -6515,7 +6515,7 @@  x86_emulate(
             vcpu_must_have(avx);
             goto stmxcsr;
         }
-        goto cannot_emulate;
+        goto unimplemented_insn;
 
     case X86EMUL_OPC_F3(0x0f, 0xae): /* Grp15 */
         fail_if(modrm_mod != 3);
@@ -6759,7 +6759,7 @@  x86_emulate(
             switch ( modrm_reg & 7 )
             {
             default:
-                goto cannot_emulate;
+                goto unimplemented_insn;
 
 #ifdef HAVE_GAS_RDRAND
             case 6: /* rdrand */
@@ -7341,7 +7341,7 @@  x86_emulate(
             host_and_vcpu_must_have(bmi1);
             break;
         default:
-            goto cannot_emulate;
+            goto unimplemented_insn;
         }
 
         generate_exception_if(vex.l, EXC_UD);
@@ -7650,7 +7650,7 @@  x86_emulate(
             host_and_vcpu_must_have(tbm);
             break;
         default:
-            goto cannot_emulate;
+            goto unimplemented_insn;
         }
 
     xop_09_rm_rv:
@@ -7684,7 +7684,7 @@  x86_emulate(
             host_and_vcpu_must_have(tbm);
             goto xop_09_rm_rv;
         }
-        goto cannot_emulate;
+        goto unimplemented_insn;
 
     case X86EMUL_OPC_XOP(0a, 0x10): /* bextr imm,r/m,r */
     {
@@ -7716,6 +7716,9 @@  x86_emulate(
     }
 
     default:
+    unimplemented_insn:
+        rc = X86EMUL_UNIMPLEMENTED;
+        goto done;
     cannot_emulate:
         rc = X86EMUL_UNHANDLEABLE;
         goto done;
diff --git a/xen/arch/x86/x86_emulate/x86_emulate.h b/xen/arch/x86/x86_emulate/x86_emulate.h
index 4ddf111..82812ca 100644
--- a/xen/arch/x86/x86_emulate/x86_emulate.h
+++ b/xen/arch/x86/x86_emulate/x86_emulate.h
@@ -133,6 +133,12 @@  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 if decode fails
+  * and not by any of the x86_emulate_ops callbacks.
+  */
+#define X86EMUL_UNIMPLEMENTED  5
 
 /* FPU sub-types which may be requested via ->get_fpu(). */
 enum x86_emulate_fpu_type {