direct-io.hg

changeset 4246:7351314f8d57

bitkeeper revision 1.1236.1.101 (423f0cb4e4UtnlbkQsaMhXYz4hi__w)

Add CMPXCHG8B support to the instruction emulator.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Mon Mar 21 18:04:36 2005 +0000 (2005-03-21)
parents e57dc11820ba
children bc658811e45d
files tools/tests/test_x86_emulator.c xen/arch/x86/x86_emulate.c xen/include/asm-x86/x86_emulate.h
line diff
     1.1 --- a/tools/tests/test_x86_emulator.c	Mon Mar 21 09:52:57 2005 +0000
     1.2 +++ b/tools/tests/test_x86_emulator.c	Mon Mar 21 18:04:36 2005 +0000
     1.3 @@ -60,15 +60,28 @@ static int cmpxchg_any(
     1.4      return X86EMUL_CONTINUE;
     1.5  }
     1.6  
     1.7 +static int cmpxchg8b_any(
     1.8 +    unsigned long addr,
     1.9 +    unsigned long old_lo,
    1.10 +    unsigned long old_hi,
    1.11 +    unsigned long new_lo,
    1.12 +    unsigned long new_hi)
    1.13 +{
    1.14 +    ((unsigned long *)addr)[0] = new_lo;
    1.15 +    ((unsigned long *)addr)[1] = new_hi;
    1.16 +    return X86EMUL_CONTINUE;
    1.17 +}
    1.18 +
    1.19  static struct x86_mem_emulator emulops = {
    1.20 -    read_any, write_any, read_any, write_any, cmpxchg_any
    1.21 +    read_any, write_any, read_any, write_any, cmpxchg_any, cmpxchg8b_any
    1.22  };
    1.23  
    1.24  int main(int argc, char **argv)
    1.25  {
    1.26      struct xen_regs regs;
    1.27 -    char instr[] = { 0x01, 0x08 }; /* add %ecx,(%eax) */
    1.28 +    char instr[20] = { 0x01, 0x08 }; /* add %ecx,(%eax) */
    1.29      unsigned int res = 0x7FFFFFFF;
    1.30 +    u32 cmpxchg8b_res[2] = { 0x12345678, 0x87654321 };
    1.31      unsigned long cr2;
    1.32      int rc;
    1.33  
    1.34 @@ -173,6 +186,41 @@ int main(int argc, char **argv)
    1.35          goto fail;
    1.36      printf("okay\n");
    1.37  
    1.38 +    printf("%-40s", "Testing cmpxchg (%edi) [succeeding]...");
    1.39 +    instr[0] = 0x0f; instr[1] = 0xc7; instr[2] = 0x0f;
    1.40 +    regs.eflags = 0x200;
    1.41 +    regs.eax    = cmpxchg8b_res[0];
    1.42 +    regs.edx    = cmpxchg8b_res[1];
    1.43 +    regs.ebx    = 0x9999AAAA;
    1.44 +    regs.ecx    = 0xCCCCFFFF;
    1.45 +    regs.eip    = (unsigned long)&instr[0];
    1.46 +    regs.edi    = (unsigned long)cmpxchg8b_res;
    1.47 +    cr2         = regs.edi;
    1.48 +    rc = x86_emulate_memop(&regs, cr2, &emulops, 4);
    1.49 +    if ( (rc != 0) || 
    1.50 +         (cmpxchg8b_res[0] != 0x9999AAAA) ||
    1.51 +         (cmpxchg8b_res[1] != 0xCCCCFFFF) ||
    1.52 +         ((regs.eflags&0x240) != 0x240) ||
    1.53 +         (regs.eip != (unsigned long)&instr[3]) )
    1.54 +        goto fail;
    1.55 +    printf("okay\n");
    1.56 +
    1.57 +    printf("%-40s", "Testing cmpxchg (%edi) [failing]...");
    1.58 +    instr[0] = 0x0f; instr[1] = 0xc7; instr[2] = 0x0f;
    1.59 +    regs.eip    = (unsigned long)&instr[0];
    1.60 +    regs.edi    = (unsigned long)cmpxchg8b_res;
    1.61 +    cr2         = regs.edi;
    1.62 +    rc = x86_emulate_memop(&regs, cr2, &emulops, 4);
    1.63 +    if ( (rc != 0) || 
    1.64 +         (cmpxchg8b_res[0] != 0x9999AAAA) ||
    1.65 +         (cmpxchg8b_res[1] != 0xCCCCFFFF) ||
    1.66 +         (regs.eax != 0x9999AAAA) ||
    1.67 +         (regs.edx != 0xCCCCFFFF) ||
    1.68 +         ((regs.eflags&0x240) != 0x200) ||
    1.69 +         (regs.eip != (unsigned long)&instr[3]) )
    1.70 +        goto fail;
    1.71 +    printf("okay\n");
    1.72 +
    1.73      return 0;
    1.74  
    1.75   fail:
     2.1 --- a/xen/arch/x86/x86_emulate.c	Mon Mar 21 09:52:57 2005 +0000
     2.2 +++ b/xen/arch/x86/x86_emulate.c	Mon Mar 21 18:04:36 2005 +0000
     2.3 @@ -181,7 +181,7 @@ static u8 twobyte_table[256] = {
     2.4      /* 0xB8 - 0xBF */
     2.5      0, 0, DstMem|SrcImmByte|ModRM, DstMem|SrcReg|ModRM, 0, 0, 0, 0,
     2.6      /* 0xC0 - 0xCF */
     2.7 -    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
     2.8 +    0, 0, 0, 0, 0, 0, 0, ImplicitOps|ModRM, 0, 0, 0, 0, 0, 0, 0, 0,
     2.9      /* 0xD0 - 0xDF */
    2.10      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    2.11      /* 0xE0 - 0xEF */
    2.12 @@ -963,8 +963,63 @@ x86_emulate_memop(
    2.13      goto writeback;
    2.14  
    2.15   twobyte_special_insn:
    2.16 -    /* Only prefetch instructions get here, so nothing to do. */
    2.17 -    dst.orig_val = dst.val; /* disable writeback */
    2.18 +    /* Disable writeback. */
    2.19 +    dst.orig_val = dst.val;
    2.20 +    switch ( b )
    2.21 +    {
    2.22 +    case 0x0d: /* GrpP (prefetch) */
    2.23 +    case 0x18: /* Grp16 (prefetch/nop) */
    2.24 +        break;
    2.25 +    case 0xc7: /* Grp9 (cmpxchg8b) */
    2.26 +#if defined(__i386__)
    2.27 +    {
    2.28 +        unsigned long old_lo, old_hi;
    2.29 +        if ( ((rc = ops->read_emulated(cr2+0, &old_lo, 4)) != 0) ||
    2.30 +             ((rc = ops->read_emulated(cr2+4, &old_hi, 4)) != 0) )
    2.31 +            goto done;
    2.32 +        if ( (old_lo != _regs.eax) || (old_hi != _regs.edx) )
    2.33 +        {
    2.34 +            _regs.eax = old_lo;
    2.35 +            _regs.edx = old_hi;
    2.36 +            _regs.eflags &= ~EFLG_ZF;
    2.37 +        }
    2.38 +        else if ( ops->cmpxchg8b_emulated == NULL )
    2.39 +        {
    2.40 +            rc = X86EMUL_UNHANDLEABLE;
    2.41 +            goto done;
    2.42 +        }
    2.43 +        else
    2.44 +        {
    2.45 +            if ( (rc = ops->cmpxchg8b_emulated(cr2, old_lo, old_hi,
    2.46 +                                               _regs.ebx, _regs.ecx)) != 0 )
    2.47 +                goto done;
    2.48 +            _regs.eflags |= EFLG_ZF;
    2.49 +        }
    2.50 +        break;
    2.51 +    }
    2.52 +#elif defined(__x86_64__)
    2.53 +    {
    2.54 +        unsigned long old, new;
    2.55 +        if ( (rc = ops->read_emulated(cr2, &old, 8)) != 0 )
    2.56 +            goto done;
    2.57 +        if ( ((u32)(old>>0) != (u32)_regs.eax) ||
    2.58 +             ((u32)(old>>32) != (u32)_regs.edx) )
    2.59 +        {
    2.60 +            _regs.eax = (u32)(old>>0);
    2.61 +            _regs.edx = (u32)(old>>32);
    2.62 +            _regs.eflags &= ~EFLG_ZF;
    2.63 +        }
    2.64 +        else
    2.65 +        {
    2.66 +            new = (_regs.ecx<<32)|(u32)_regs.ebx;
    2.67 +            if ( (rc = ops->cmpxchg_emulated(cr2, old, new, 8)) != 0 )
    2.68 +                goto done;
    2.69 +            _regs.eflags |= EFLG_ZF;
    2.70 +        }
    2.71 +        break;
    2.72 +    }
    2.73 +#endif
    2.74 +    }
    2.75      goto writeback;
    2.76  
    2.77   cannot_emulate:
     3.1 --- a/xen/include/asm-x86/x86_emulate.h	Mon Mar 21 09:52:57 2005 +0000
     3.2 +++ b/xen/include/asm-x86/x86_emulate.h	Mon Mar 21 18:04:36 2005 +0000
     3.3 @@ -34,6 +34,8 @@
     3.4   *     some out-of-band mechanism, unknown to the emulator. The memop signals
     3.5   *     failure by returning X86EMUL_PROPAGATE_FAULT to the emulator, which will
     3.6   *     then immediately bail.
     3.7 + *  3. Valid access sizes are 1, 2, 4 and 8 bytes. On x86/32 systems only
     3.8 + *     cmpxchg8b_emulated need support 8-byte accesses.
     3.9   */
    3.10  /* Access completed successfully: continue emulation as normal. */
    3.11  #define X86EMUL_CONTINUE        0
    3.12 @@ -104,6 +106,25 @@ struct x86_mem_emulator
    3.13          unsigned long old,
    3.14          unsigned long new,
    3.15          unsigned int bytes);
    3.16 +
    3.17 +    /*
    3.18 +     * cmpxchg_emulated: Emulate an atomic (LOCKed) CMPXCHG8B operation on an
    3.19 +     *                   emulated/special memory area.
    3.20 +     *  @addr:  [IN ] Linear address to access.
    3.21 +     *  @old:   [IN ] Value expected to be current at @addr.
    3.22 +     *  @new:   [IN ] Value to write to @addr.
    3.23 +     * NOTES:
    3.24 +     *  1. This function is only ever called when emulating a real CMPXCHG8B.
    3.25 +     *  2. This function is *never* called on x86/64 systems.
    3.26 +     *  2. Not defining this function (i.e., specifying NULL) is equivalent
    3.27 +     *     to defining a function that always returns X86EMUL_UNHANDLEABLE.
    3.28 +     */
    3.29 +    int (*cmpxchg8b_emulated)(
    3.30 +        unsigned long addr,
    3.31 +        unsigned long old_lo,
    3.32 +        unsigned long old_hi,
    3.33 +        unsigned long new_lo,
    3.34 +        unsigned long new_hi);
    3.35  };
    3.36  
    3.37  /* Standard reader/writer functions that callers may wish to use. */