[PATCH] x86emu: Fix more mis-decoding of the data prefix

Julien Cristau jcristau at debian.org
Mon Dec 20 10:41:41 PST 2010


On Fri, Dec 10, 2010 at 14:47:20 -0500, Adam Jackson wrote:

> cc2c73ddcb4370a7c3ad439cda4da825156c26c9's three-cent titanium tax
> doesn't go too far enough.  Fix the rest of the call and jmp
> instructions to handle the data prefix correctly.
> 
> Reference: Intel 64 and IA-32 Architectures Software Developer's Manual
> Volume 2A: Instruction Set Reference, A-M
> 
> http://www.intel.com/Assets/PDF/manual/253666.pdf
> 
> Signed-off-by: Adam Jackson <ajax at redhat.com>
> ---
>  hw/xfree86/x86emu/ops.c |   63 +++++++++++++++++++++++++++++++++-------------
>  1 files changed, 45 insertions(+), 18 deletions(-)
> 
This is the first time I'm looking at x86 low level stuff, so forgive me
if I'm missing something, but I have a question:

> diff --git a/hw/xfree86/x86emu/ops.c b/hw/xfree86/x86emu/ops.c
> index c6b2f0a..5d3cac1 100644
> --- a/hw/xfree86/x86emu/ops.c
> +++ b/hw/xfree86/x86emu/ops.c
> @@ -7065,15 +7065,20 @@ Handles opcode 0x9a
>  ****************************************************************************/
>  static void x86emuOp_call_far_IMM(u8 X86EMU_UNUSED(op1))
>  {
> -    u16 farseg, faroff;
> +    u32 farseg, faroff;
>  
>      START_OF_INSTR();
> -	DECODE_PRINTF("CALL\t");
> +    DECODE_PRINTF("CALL\t");
> +    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
> +	faroff = fetch_long_imm();
> +	farseg = fetch_word_imm();
> +    } else {
>  	faroff = fetch_word_imm();
>  	farseg = fetch_word_imm();
> -	DECODE_PRINTF2("%04x:", farseg);
> -	DECODE_PRINTF2("%04x\n", faroff);
> -	CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, farseg, faroff, "FAR ");
> +    }
> +    DECODE_PRINTF2("%04x:", farseg);
> +    DECODE_PRINTF2("%04x\n", faroff);
> +    CALL_TRACE(M.x86.saved_cs, M.x86.saved_ip, farseg, faroff, "FAR ");
>  
>      /* XXX
>       * 
> @@ -7084,8 +7089,12 @@ static void x86emuOp_call_far_IMM(u8 X86EMU_UNUSED(op1))
>      TRACE_AND_STEP();
>      push_word(M.x86.R_CS);
>      M.x86.R_CS = farseg;
> -    push_word(M.x86.R_IP);
> -    M.x86.R_IP = faroff;
> +    if (M.x86.mode & SYSMODE_PREFIX_DATA) {
> +	push_long(M.x86.R_EIP);
> +    } else {
> +	push_word(M.x86.R_IP);
> +    }
> +    M.x86.R_EIP = faroff & 0xffff;
>      DECODE_CLEAR_SEGOVR();
>      END_OF_INSTR();
>  }

The intel doc says (for far calls in virtual-8086 mode):

IF OperandSize = 32
  THEN
    ...
    EIP ← DEST[31:0]; (* DEST is ptr16:32 or [m16:32] *)
  ELSE
    ...
    EIP ← DEST[15:0]; (* DEST is ptr16:16 or [m16:16]; clear upper 16 bits *)
FI;

which suggests that you don't need the & 0xffff in the last assignment?

Cheers,
Julien


More information about the xorg-devel mailing list