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>
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 = ®s; 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