ia64/xen-unstable

changeset 13343:c98f3f3f7099

[XEN] Emulate DAA/DAS the hard way. We cannot execute the instruction
directly within the emulator as it is unavailable if the emulator runs
in x86/64 mode.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Tue Jan 09 16:59:52 2007 +0000 (2007-01-09)
parents de6b5a76d680
children ddea7363fa41 79b5090c791f
files tools/tests/test_x86_emulator.c xen/arch/x86/x86_emulate.c
line diff
     1.1 --- a/tools/tests/test_x86_emulator.c	Tue Jan 09 16:49:16 2007 +0000
     1.2 +++ b/tools/tests/test_x86_emulator.c	Tue Jan 09 16:59:52 2007 +0000
     1.3 @@ -15,6 +15,15 @@ typedef int64_t            s64;
     1.4  #include <asm-x86/x86_emulate.h>
     1.5  #include <sys/mman.h>
     1.6  
     1.7 +/* EFLAGS bit definitions. */
     1.8 +#define EFLG_OF (1<<11)
     1.9 +#define EFLG_DF (1<<10)
    1.10 +#define EFLG_SF (1<<7)
    1.11 +#define EFLG_ZF (1<<6)
    1.12 +#define EFLG_AF (1<<4)
    1.13 +#define EFLG_PF (1<<2)
    1.14 +#define EFLG_CF (1<<0)
    1.15 +
    1.16  static int read(
    1.17      unsigned int seg,
    1.18      unsigned long offset,
    1.19 @@ -98,8 +107,8 @@ int main(int argc, char **argv)
    1.20      struct x86_emulate_ctxt ctxt;
    1.21      struct cpu_user_regs regs;
    1.22      char instr[20] = { 0x01, 0x08 }; /* add %ecx,(%eax) */
    1.23 -    unsigned int *res;
    1.24 -    int rc;
    1.25 +    unsigned int *res, bcdres_native, bcdres_emul;
    1.26 +    int rc, i;
    1.27  
    1.28      ctxt.regs = &regs;
    1.29      ctxt.address_bytes = 4;
    1.30 @@ -399,6 +408,60 @@ int main(int argc, char **argv)
    1.31          goto fail;
    1.32      printf("okay\n");
    1.33  
    1.34 +    printf("%-40s", "Testing daa/das (all inputs)...");
    1.35 +    /* Bits 0-7: AL; Bit 8: EFLG_AF; Bit 9: EFLG_CF; Bit 10: DAA vs. DAS. */
    1.36 +    for ( i = 0; i < 0x800; i++ )
    1.37 +    {
    1.38 +        regs.eflags  = (i & 0x200) ? EFLG_CF : 0;
    1.39 +        regs.eflags |= (i & 0x100) ? EFLG_AF : 0;
    1.40 +        if ( i & 0x400 )
    1.41 +            __asm__ (
    1.42 +                "pushf; and $0xffffffee,(%%esp); or %1,(%%esp); popf; das; "
    1.43 +                "pushf; popl %1"
    1.44 +                : "=a" (bcdres_native), "=r" (regs.eflags)
    1.45 +                : "0" (i & 0xff), "1" (regs.eflags) );
    1.46 +        else
    1.47 +            __asm__ (
    1.48 +                "pushf; and $0xffffffee,(%%esp); or %1,(%%esp); popf; daa; "
    1.49 +                "pushf; popl %1"
    1.50 +                : "=a" (bcdres_native), "=r" (regs.eflags)
    1.51 +                : "0" (i & 0xff), "1" (regs.eflags) );
    1.52 +        bcdres_native |= (regs.eflags & EFLG_CF) ? 0x200 : 0;
    1.53 +        bcdres_native |= (regs.eflags & EFLG_AF) ? 0x100 : 0;
    1.54 +
    1.55 +        instr[0] = (i & 0x400) ? 0x2f: 0x27; /* daa/das */
    1.56 +        regs.eflags  = (i & 0x200) ? EFLG_CF : 0;
    1.57 +        regs.eflags |= (i & 0x100) ? EFLG_AF : 0;
    1.58 +        regs.eip    = (unsigned long)&instr[0];
    1.59 +        regs.eax    = (unsigned char)i;
    1.60 +        rc = x86_emulate(&ctxt, &emulops);
    1.61 +        bcdres_emul  = regs.eax;
    1.62 +        bcdres_emul |= (regs.eflags & EFLG_CF) ? 0x200 : 0;
    1.63 +        bcdres_emul |= (regs.eflags & EFLG_AF) ? 0x100 : 0;
    1.64 +        if ( (rc != 0) || (regs.eax > 255) ||
    1.65 +             (regs.eip != (unsigned long)&instr[1]) )
    1.66 +            goto fail;
    1.67 +
    1.68 +        if ( bcdres_emul != bcdres_native )
    1.69 +        {
    1.70 +            printf("%s:    AL=%02x %s %s\n"
    1.71 +                   "Output: AL=%02x %s %s\n"
    1.72 +                   "Emul.:  AL=%02x %s %s\n",
    1.73 +                   (i & 0x400) ? "DAS" : "DAA",
    1.74 +                   (unsigned char)i,
    1.75 +                   (i & 0x200) ? "CF" : "  ",
    1.76 +                   (i & 0x100) ? "AF" : "  ",
    1.77 +                   (unsigned char)bcdres_native,
    1.78 +                   (bcdres_native & 0x200) ? "CF" : "  ",
    1.79 +                   (bcdres_native & 0x100) ? "AF" : "  ",
    1.80 +                   (unsigned char)bcdres_emul,
    1.81 +                   (bcdres_emul & 0x200) ? "CF" : "  ",
    1.82 +                   (bcdres_emul & 0x100) ? "AF" : "  ");
    1.83 +            goto fail;
    1.84 +        }
    1.85 +    }
    1.86 +    printf("okay\n");
    1.87 +
    1.88      return 0;
    1.89  
    1.90   fail:
     2.1 --- a/xen/arch/x86/x86_emulate.c	Tue Jan 09 16:49:16 2007 +0000
     2.2 +++ b/xen/arch/x86/x86_emulate.c	Tue Jan 09 16:59:52 2007 +0000
     2.3 @@ -1174,25 +1174,47 @@ x86_emulate(
     2.4      {
     2.5      case 0x27: /* daa */ {
     2.6          uint8_t al = _regs.eax;
     2.7 -        unsigned long tmp;
     2.8 +        unsigned long eflags = _regs.eflags;
     2.9          fail_if(mode_64bit());
    2.10 -        __asm__ __volatile__ (
    2.11 -            _PRE_EFLAGS("0","4","2") "daa; " _POST_EFLAGS("0","4","2")
    2.12 -            : "=m" (_regs.eflags), "=a" (al), "=&r" (tmp)
    2.13 -            : "a" (al), "i" (EFLAGS_MASK) );
    2.14 -        *(uint8_t *)_regs.eax = al;
    2.15 +        _regs.eflags &= ~(EFLG_CF|EFLG_AF);
    2.16 +        if ( ((al & 0x0f) > 9) || (eflags & EFLG_AF) )
    2.17 +        {
    2.18 +            *(uint8_t *)&_regs.eax += 6;
    2.19 +            _regs.eflags |= EFLG_AF;
    2.20 +        }
    2.21 +        if ( (al > 0x99) || (eflags & EFLG_CF) )
    2.22 +        {
    2.23 +            *(uint8_t *)&_regs.eax += 0x60;
    2.24 +            _regs.eflags |= EFLG_CF;
    2.25 +        }
    2.26 +        _regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF);
    2.27 +        _regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0;
    2.28 +        _regs.eflags |= (( int8_t)_regs.eax <  0) ? EFLG_SF : 0;
    2.29 +        _regs.eflags |= even_parity(_regs.eax) ? EFLG_PF : 0;
    2.30          break;
    2.31      }
    2.32  
    2.33      case 0x2f: /* das */ {
    2.34          uint8_t al = _regs.eax;
    2.35 -        unsigned long tmp;
    2.36 +        unsigned long eflags = _regs.eflags;
    2.37          fail_if(mode_64bit());
    2.38 -        __asm__ __volatile__ (
    2.39 -            _PRE_EFLAGS("0","4","2") "das; " _POST_EFLAGS("0","4","2")
    2.40 -            : "=m" (_regs.eflags), "=a" (al), "=&r" (tmp)
    2.41 -            : "a" (al), "i" (EFLAGS_MASK) );
    2.42 -        *(uint8_t *)_regs.eax = al;
    2.43 +        _regs.eflags &= ~(EFLG_CF|EFLG_AF);
    2.44 +        if ( ((al & 0x0f) > 9) || (eflags & EFLG_AF) )
    2.45 +        {
    2.46 +            _regs.eflags |= EFLG_AF;
    2.47 +            if ( (al < 6) || (eflags & EFLG_CF) )
    2.48 +                _regs.eflags |= EFLG_CF;
    2.49 +            *(uint8_t *)&_regs.eax -= 6;
    2.50 +        }
    2.51 +        if ( (al > 0x99) || (eflags & EFLG_CF) )
    2.52 +        {
    2.53 +            *(uint8_t *)&_regs.eax -= 0x60;
    2.54 +            _regs.eflags |= EFLG_CF;
    2.55 +        }
    2.56 +        _regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF);
    2.57 +        _regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0;
    2.58 +        _regs.eflags |= (( int8_t)_regs.eax <  0) ? EFLG_SF : 0;
    2.59 +        _regs.eflags |= even_parity(_regs.eax) ? EFLG_PF : 0;
    2.60          break;
    2.61      }
    2.62