[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [XEN] Emulate DAA/DAS the hard way. We cannot execute the instruction
# HG changeset patch # User kfraser@xxxxxxxxxxxxxxxxxxxxx # Date 1168361992 0 # Node ID c98f3f3f7099ec1516354faa34a16be841e4a47c # Parent de6b5a76d680057c7793561c40a9285c613065d1 [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@xxxxxxxxxxxxx> --- tools/tests/test_x86_emulator.c | 67 ++++++++++++++++++++++++++++++++++++++-- xen/arch/x86/x86_emulate.c | 46 ++++++++++++++++++++------- 2 files changed, 99 insertions(+), 14 deletions(-) diff -r de6b5a76d680 -r c98f3f3f7099 tools/tests/test_x86_emulator.c --- a/tools/tests/test_x86_emulator.c Tue Jan 09 16:49:16 2007 +0000 +++ b/tools/tests/test_x86_emulator.c Tue Jan 09 16:59:52 2007 +0000 @@ -15,6 +15,15 @@ typedef int64_t s64; #include <asm-x86/x86_emulate.h> #include <sys/mman.h> +/* EFLAGS bit definitions. */ +#define EFLG_OF (1<<11) +#define EFLG_DF (1<<10) +#define EFLG_SF (1<<7) +#define EFLG_ZF (1<<6) +#define EFLG_AF (1<<4) +#define EFLG_PF (1<<2) +#define EFLG_CF (1<<0) + static int read( unsigned int seg, unsigned long offset, @@ -98,8 +107,8 @@ int main(int argc, char **argv) struct x86_emulate_ctxt ctxt; struct cpu_user_regs regs; char instr[20] = { 0x01, 0x08 }; /* add %ecx,(%eax) */ - unsigned int *res; - int rc; + unsigned int *res, bcdres_native, bcdres_emul; + int rc, i; ctxt.regs = ®s; ctxt.address_bytes = 4; @@ -399,6 +408,60 @@ int main(int argc, char **argv) goto fail; printf("okay\n"); + printf("%-40s", "Testing daa/das (all inputs)..."); + /* Bits 0-7: AL; Bit 8: EFLG_AF; Bit 9: EFLG_CF; Bit 10: DAA vs. DAS. */ + for ( i = 0; i < 0x800; i++ ) + { + regs.eflags = (i & 0x200) ? EFLG_CF : 0; + regs.eflags |= (i & 0x100) ? EFLG_AF : 0; + if ( i & 0x400 ) + __asm__ ( + "pushf; and $0xffffffee,(%%esp); or %1,(%%esp); popf; das; " + "pushf; popl %1" + : "=a" (bcdres_native), "=r" (regs.eflags) + : "0" (i & 0xff), "1" (regs.eflags) ); + else + __asm__ ( + "pushf; and $0xffffffee,(%%esp); or %1,(%%esp); popf; daa; " + "pushf; popl %1" + : "=a" (bcdres_native), "=r" (regs.eflags) + : "0" (i & 0xff), "1" (regs.eflags) ); + bcdres_native |= (regs.eflags & EFLG_CF) ? 0x200 : 0; + bcdres_native |= (regs.eflags & EFLG_AF) ? 0x100 : 0; + + instr[0] = (i & 0x400) ? 0x2f: 0x27; /* daa/das */ + regs.eflags = (i & 0x200) ? EFLG_CF : 0; + regs.eflags |= (i & 0x100) ? EFLG_AF : 0; + regs.eip = (unsigned long)&instr[0]; + regs.eax = (unsigned char)i; + rc = x86_emulate(&ctxt, &emulops); + bcdres_emul = regs.eax; + bcdres_emul |= (regs.eflags & EFLG_CF) ? 0x200 : 0; + bcdres_emul |= (regs.eflags & EFLG_AF) ? 0x100 : 0; + if ( (rc != 0) || (regs.eax > 255) || + (regs.eip != (unsigned long)&instr[1]) ) + goto fail; + + if ( bcdres_emul != bcdres_native ) + { + printf("%s: AL=%02x %s %s\n" + "Output: AL=%02x %s %s\n" + "Emul.: AL=%02x %s %s\n", + (i & 0x400) ? "DAS" : "DAA", + (unsigned char)i, + (i & 0x200) ? "CF" : " ", + (i & 0x100) ? "AF" : " ", + (unsigned char)bcdres_native, + (bcdres_native & 0x200) ? "CF" : " ", + (bcdres_native & 0x100) ? "AF" : " ", + (unsigned char)bcdres_emul, + (bcdres_emul & 0x200) ? "CF" : " ", + (bcdres_emul & 0x100) ? "AF" : " "); + goto fail; + } + } + printf("okay\n"); + return 0; fail: diff -r de6b5a76d680 -r c98f3f3f7099 xen/arch/x86/x86_emulate.c --- a/xen/arch/x86/x86_emulate.c Tue Jan 09 16:49:16 2007 +0000 +++ b/xen/arch/x86/x86_emulate.c Tue Jan 09 16:59:52 2007 +0000 @@ -1174,25 +1174,47 @@ x86_emulate( { case 0x27: /* daa */ { uint8_t al = _regs.eax; - unsigned long tmp; + unsigned long eflags = _regs.eflags; fail_if(mode_64bit()); - __asm__ __volatile__ ( - _PRE_EFLAGS("0","4","2") "daa; " _POST_EFLAGS("0","4","2") - : "=m" (_regs.eflags), "=a" (al), "=&r" (tmp) - : "a" (al), "i" (EFLAGS_MASK) ); - *(uint8_t *)_regs.eax = al; + _regs.eflags &= ~(EFLG_CF|EFLG_AF); + if ( ((al & 0x0f) > 9) || (eflags & EFLG_AF) ) + { + *(uint8_t *)&_regs.eax += 6; + _regs.eflags |= EFLG_AF; + } + if ( (al > 0x99) || (eflags & EFLG_CF) ) + { + *(uint8_t *)&_regs.eax += 0x60; + _regs.eflags |= EFLG_CF; + } + _regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF); + _regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0; + _regs.eflags |= (( int8_t)_regs.eax < 0) ? EFLG_SF : 0; + _regs.eflags |= even_parity(_regs.eax) ? EFLG_PF : 0; break; } case 0x2f: /* das */ { uint8_t al = _regs.eax; - unsigned long tmp; + unsigned long eflags = _regs.eflags; fail_if(mode_64bit()); - __asm__ __volatile__ ( - _PRE_EFLAGS("0","4","2") "das; " _POST_EFLAGS("0","4","2") - : "=m" (_regs.eflags), "=a" (al), "=&r" (tmp) - : "a" (al), "i" (EFLAGS_MASK) ); - *(uint8_t *)_regs.eax = al; + _regs.eflags &= ~(EFLG_CF|EFLG_AF); + if ( ((al & 0x0f) > 9) || (eflags & EFLG_AF) ) + { + _regs.eflags |= EFLG_AF; + if ( (al < 6) || (eflags & EFLG_CF) ) + _regs.eflags |= EFLG_CF; + *(uint8_t *)&_regs.eax -= 6; + } + if ( (al > 0x99) || (eflags & EFLG_CF) ) + { + *(uint8_t *)&_regs.eax -= 0x60; + _regs.eflags |= EFLG_CF; + } + _regs.eflags &= ~(EFLG_SF|EFLG_ZF|EFLG_PF); + _regs.eflags |= ((uint8_t)_regs.eax == 0) ? EFLG_ZF : 0; + _regs.eflags |= (( int8_t)_regs.eax < 0) ? EFLG_SF : 0; + _regs.eflags |= even_parity(_regs.eax) ? EFLG_PF : 0; break; } _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |