|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v3 21/25] x86emul: add read-modify-write hook
On 07/12/17 14:16, Jan Beulich wrote:
> In order to correctly emulate read-modify-write insns, especially
> LOCKed ones, we should not issue reads and writes separately. Use a
> new hook to combine both, and don't uniformly read the memory
> destination anymore. Instead, DstMem opcodes without Mov now need to
> have done so in their respective case blocks.
>
> Also strip bogus _ prefixes from macro parameters when this only affects
> lines which are being changed anyway.
>
> In the test harness, besides some re-ordering to facilitate running a
> few tests twice (one without and a second time with the .rmw hook in
> place), tighten a few EFLAGS checks and add a test for NOT with memory
> operand (in particular to verify EFLAGS don't get altered there).
>
> For now make use of the hook optional for callers; eventually we may
> want to consider making this mandatory.
>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
> ---
> v3: New.
> ---
> TBD: Do we want to also support non-lockable RMW insns in the new hook
> and helper (SHL & friends, SHLD, SHRD)?
What would this achieve? I suppose it would avoid a double pagewalk.
>
>
> --- a/xen/arch/x86/x86_emulate/x86_emulate.c
> +++ b/xen/arch/x86/x86_emulate/x86_emulate.c
> @@ -3356,35 +3388,83 @@ x86_emulate(
> unsigned int i, n;
> unsigned long dummy;
>
> - case 0x00 ... 0x05: add: /* add */
> - emulate_2op_SrcV("add", src, dst, _regs.eflags);
> + case 0x00: case 0x01: add: /* add reg,mem */
> + if ( ops->rmw && dst.type == OP_MEM )
> + state->rmw = rmw_add;
> + else
> + {
> + case 0x02 ... 0x05: /* add */
I think it would help to identify reg,reg specifically in these comments.
> + emulate_2op_SrcV("add", src, dst, _regs.eflags);
> + }
> break;
>
> - case 0x08 ... 0x0d: or: /* or */
> - emulate_2op_SrcV("or", src, dst, _regs.eflags);
> + case 0x08: case 0x09: or: /* or reg,mem */
> + if ( ops->rmw && dst.type == OP_MEM )
> + state->rmw = rmw_or;
> + else
> + {
> + case 0x0a ... 0x0d: /* or */
> + emulate_2op_SrcV("or", src, dst, _regs.eflags);
> + }
> break;
>
> - case 0x10 ... 0x15: adc: /* adc */
> - emulate_2op_SrcV("adc", src, dst, _regs.eflags);
> + case 0x10: case 0x11: adc: /* adc reg,mem */
> + if ( ops->rmw && dst.type == OP_MEM )
> + state->rmw = rmw_adc;
> + else
> + {
> + case 0x12 ... 0x15: /* adc */
> + emulate_2op_SrcV("adc", src, dst, _regs.eflags);
> + }
> break;
>
> - case 0x18 ... 0x1d: sbb: /* sbb */
> - emulate_2op_SrcV("sbb", src, dst, _regs.eflags);
> + case 0x18: case 0x19: sbb: /* sbb reg,mem */
> + if ( ops->rmw && dst.type == OP_MEM )
> + state->rmw = rmw_sbb;
> + else
> + {
> + case 0x1a ... 0x1d: /* sbb */
> + emulate_2op_SrcV("sbb", src, dst, _regs.eflags);
> + }
> break;
>
> - case 0x20 ... 0x25: and: /* and */
> - emulate_2op_SrcV("and", src, dst, _regs.eflags);
> + case 0x20: case 0x21: and: /* and reg,mem */
> + if ( ops->rmw && dst.type == OP_MEM )
> + state->rmw = rmw_and;
> + else
> + {
> + case 0x22 ... 0x25: /* and */
> + emulate_2op_SrcV("and", src, dst, _regs.eflags);
> + }
> break;
>
> - case 0x28 ... 0x2d: sub: /* sub */
> - emulate_2op_SrcV("sub", src, dst, _regs.eflags);
> + case 0x28: case 0x29: sub: /* sub reg,mem */
> + if ( ops->rmw && dst.type == OP_MEM )
> + state->rmw = rmw_sub;
> + else
> + {
> + case 0x2a ... 0x2d: /* sub */
> + emulate_2op_SrcV("sub", src, dst, _regs.eflags);
> + }
> break;
>
> - case 0x30 ... 0x35: xor: /* xor */
> - emulate_2op_SrcV("xor", src, dst, _regs.eflags);
> + case 0x30: case 0x31: xor: /* xor reg,mem */
> + if ( ops->rmw && dst.type == OP_MEM )
> + state->rmw = rmw_xor;
> + else
> + {
> + case 0x32 ... 0x35: /* xor */
> + emulate_2op_SrcV("xor", src, dst, _regs.eflags);
> + }
> break;
>
> - case 0x38 ... 0x3d: cmp: /* cmp */
> + case 0x38: case 0x39: cmp: /* cmp reg,mem */
> + if ( ops->rmw && dst.type == OP_MEM &&
> + (rc = read_ulong(dst.mem.seg, dst.mem.off, &dst.val,
> + dst.bytes, ctxt, ops)) != X86EMUL_OKAY )
Why does rmw matter here? cmp doesn't write to its operands.
> + goto done;
> + /* fall through */
> + case 0x3a ... 0x3d: /* cmp */
> generate_exception_if(lock_prefix, EXC_UD);
> emulate_2op_SrcV("cmp", src, dst, _regs.eflags);
> dst.type = OP_NONE;
> @@ -3700,6 +3780,13 @@ x86_emulate(
> break;
>
> case 0x86 ... 0x87: xchg: /* xchg */
> + /* The lock prefix is implied for this insn. */
> + lock_prefix = 1;
Only for memory. I.e. this should probably be inside an OP_MEM check.
~Andrew
> + if ( ops->rmw && dst.type == OP_MEM )
> + {
> + state->rmw = rmw_xchg;
> + break;
> + }
> /* Write back the register source. */
> switch ( dst.bytes )
> {
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |