[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [XEN] Emulate MUL/DIV. Tweak test suite build.
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxxx # Date 1168776211 0 # Node ID eb19c2745b8010ee5ee8700cb36ecd5eef53e656 # Parent e079f1ff6744bbaab19bf3d045efd811144d0403 [XEN] Emulate MUL/DIV. Tweak test suite build. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> --- tools/tests/Makefile | 1 tools/tests/test_x86_emulator.c | 5 xen/arch/x86/x86_emulate.c | 346 +++++++++++++++++++++++++++++++++++++- xen/include/asm-x86/x86_emulate.h | 16 + 4 files changed, 363 insertions(+), 5 deletions(-) diff -r e079f1ff6744 -r eb19c2745b80 tools/tests/Makefile --- a/tools/tests/Makefile Sat Jan 13 21:36:31 2007 +0000 +++ b/tools/tests/Makefile Sun Jan 14 12:03:31 2007 +0000 @@ -7,6 +7,7 @@ TARGET := test_x86_emulator .PHONY: all all: $(TARGET) +.PHONY: blowfish.bin blowfish.bin: make -f blowfish.mk all diff -r e079f1ff6744 -r eb19c2745b80 tools/tests/test_x86_emulator.c --- a/tools/tests/test_x86_emulator.c Sat Jan 13 21:36:31 2007 +0000 +++ b/tools/tests/test_x86_emulator.c Sun Jan 14 12:03:31 2007 +0000 @@ -501,7 +501,10 @@ int main(int argc, char **argv) printf("."); rc = x86_emulate(&ctxt, &emulops); if ( rc != 0 ) - goto fail; + { + printf("failed at %%eip == %08x\n", (unsigned int)regs.eip); + return 1; + } } if ( (regs.esp != ((unsigned long)res + MMAP_SZ)) || (regs.eax != 2) || (regs.edx != 1) ) diff -r e079f1ff6744 -r eb19c2745b80 xen/arch/x86/x86_emulate.c --- a/xen/arch/x86/x86_emulate.c Sat Jan 13 21:36:31 2007 +0000 +++ b/xen/arch/x86/x86_emulate.c Sun Jan 14 12:03:31 2007 +0000 @@ -3,7 +3,21 @@ * * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. * - * Copyright (c) 2005 Keir Fraser + * Copyright (c) 2005-2007 Keir Fraser + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __XEN__ @@ -89,7 +103,9 @@ static uint8_t opcode_table[256] = { 0, 0, 0, DstReg|SrcMem32|ModRM|Mov /* movsxd (x86/64) */, 0, 0, 0, 0, /* 0x68 - 0x6F */ - ImplicitOps|Mov, 0, ImplicitOps|Mov, 0, 0, 0, 0, 0, + ImplicitOps|Mov, DstMem|SrcImm|ModRM|Mov, + ImplicitOps|Mov, DstMem|SrcImmByte|ModRM|Mov, + 0, 0, 0, 0, /* 0x70 - 0x77 */ ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps, @@ -194,7 +210,7 @@ static uint8_t twobyte_table[256] = { /* 0xA0 - 0xA7 */ 0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, /* 0xA8 - 0xAF */ - 0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, + 0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, DstReg|SrcMem|ModRM, /* 0xB0 - 0xB7 */ ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM, 0, DstBitBase|SrcReg|ModRM, @@ -467,6 +483,92 @@ do { ? (uint16_t)_regs.eip : (uint32_t)_regs.eip); \ } while (0) +/* + * Unsigned multiplication with double-word result. + * IN: Multiplicand=m[0], Multiplier=m[1] + * OUT: Return CF/OF (overflow status); Result=m[1]:m[0] + */ +static int mul_dbl(unsigned long m[2]) +{ + int rc; + asm ( "mul %4; seto %b2" + : "=a" (m[0]), "=d" (m[1]), "=q" (rc) + : "0" (m[0]), "1" (m[1]), "2" (0) ); + return rc; +} + +/* + * Signed multiplication with double-word result. + * IN: Multiplicand=m[0], Multiplier=m[1] + * OUT: Return CF/OF (overflow status); Result=m[1]:m[0] + */ +static int imul_dbl(unsigned long m[2]) +{ + int rc; + asm ( "imul %4; seto %b2" + : "=a" (m[0]), "=d" (m[1]), "=q" (rc) + : "0" (m[0]), "1" (m[1]), "2" (0) ); + return rc; +} + +/* + * Unsigned division of double-word dividend. + * IN: Dividend=u[1]:u[0], Divisor=v + * OUT: Return 1: #DE + * Return 0: Quotient=u[0], Remainder=u[1] + */ +static int div_dbl(unsigned long u[2], unsigned long v) +{ + if ( (v == 0) || (u[1] > v) || ((u[1] == v) && (u[0] != 0)) ) + return 1; + asm ( "div %4" + : "=a" (u[0]), "=d" (u[1]) + : "0" (u[0]), "1" (u[1]), "r" (v) ); + return 0; +} + +/* + * Signed division of double-word dividend. + * IN: Dividend=u[1]:u[0], Divisor=v + * OUT: Return 1: #DE + * Return 0: Quotient=u[0], Remainder=u[1] + * NB. We don't use idiv directly as it's moderately hard to work out + * ahead of time whether it will #DE, which we cannot allow to happen. + */ +static int idiv_dbl(unsigned long u[2], unsigned long v) +{ + int negu = (long)u[1] < 0, negv = (long)v < 0; + + /* u = abs(u) */ + if ( negu ) + { + u[1] = ~u[1]; + if ( (u[0] = -u[0]) == 0 ) + u[1]++; + } + + /* abs(u) / abs(v) */ + if ( div_dbl(u, negv ? -v : v) ) + return 1; + + /* Remainder has same sign as dividend. It cannot overflow. */ + if ( negu ) + u[1] = -u[1]; + + /* Quotient is overflowed if sign bit is set. */ + if ( negu ^ negv ) + { + if ( (long)u[0] >= 0 ) + u[0] = -u[0]; + else if ( (u[0] << 1) != 0 ) /* == 0x80...0 is okay */ + return 1; + } + else if ( (long)u[0] < 0 ) + return 1; + + return 0; +} + static int test_cc( unsigned int condition, unsigned int flags) @@ -969,6 +1071,39 @@ x86_emulate( dst.val = (int32_t)src.val; break; + case 0x69: /* imul imm16/32 */ + case 0x6b: /* imul imm8 */ { + unsigned long reg = *(long *)decode_register(modrm_reg, &_regs, 0); + _regs.eflags &= ~(EFLG_OF|EFLG_CF); + switch ( dst.bytes ) + { + case 2: + dst.val = ((uint32_t)(int16_t)src.val * + (uint32_t)(int16_t)reg); + if ( (int16_t)dst.val != (uint32_t)dst.val ) + _regs.eflags |= EFLG_OF|EFLG_CF; + break; +#ifdef __x86_64__ + case 4: + dst.val = ((uint64_t)(int32_t)src.val * + (uint64_t)(int32_t)reg); + if ( (int32_t)dst.val != dst.val ) + _regs.eflags |= EFLG_OF|EFLG_CF; + break; +#endif + default: { + unsigned long m[2] = { src.val, reg }; + if ( imul_dbl(m) ) + _regs.eflags |= EFLG_OF|EFLG_CF; + dst.val = m[0]; + break; + } + } + dst.type = OP_REG; + dst.reg = decode_register(modrm_reg, &_regs, 0); + break; + } + case 0x80 ... 0x83: /* Grp1 */ switch ( modrm_reg & 7 ) { @@ -1097,6 +1232,183 @@ x86_emulate( case 3: /* neg */ emulate_1op("neg", dst, _regs.eflags); break; + case 4: /* mul */ + src = dst; + dst.type = OP_REG; + dst.reg = (unsigned long *)&_regs.eax; + dst.val = *dst.reg; + _regs.eflags &= ~(EFLG_OF|EFLG_CF); + switch ( src.bytes ) + { + case 1: + dst.val *= src.val; + if ( (uint8_t)dst.val != (uint16_t)dst.val ) + _regs.eflags |= EFLG_OF|EFLG_CF; + break; + case 2: + dst.val *= src.val; + if ( (uint16_t)dst.val != (uint32_t)dst.val ) + _regs.eflags |= EFLG_OF|EFLG_CF; + *(uint16_t *)&_regs.edx = dst.val >> 16; + break; +#ifdef __x86_64__ + case 4: + dst.val *= src.val; + if ( (uint32_t)dst.val != dst.val ) + _regs.eflags |= EFLG_OF|EFLG_CF; + _regs.edx = (uint32_t)(dst.val >> 32); + break; +#endif + default: { + unsigned long m[2] = { src.val, dst.val }; + if ( mul_dbl(m) ) + _regs.eflags |= EFLG_OF|EFLG_CF; + _regs.edx = m[1]; + dst.val = m[0]; + break; + } + } + break; + case 5: /* imul */ + src = dst; + dst.type = OP_REG; + dst.reg = (unsigned long *)&_regs.eax; + dst.val = *dst.reg; + _regs.eflags &= ~(EFLG_OF|EFLG_CF); + switch ( src.bytes ) + { + case 1: + dst.val = ((uint16_t)(int8_t)src.val * + (uint16_t)(int8_t)dst.val); + if ( (int8_t)dst.val != (uint16_t)dst.val ) + _regs.eflags |= EFLG_OF|EFLG_CF; + break; + case 2: + dst.val = ((uint32_t)(int16_t)src.val * + (uint32_t)(int16_t)dst.val); + if ( (int16_t)dst.val != (uint32_t)dst.val ) + _regs.eflags |= EFLG_OF|EFLG_CF; + *(uint16_t *)&_regs.edx = dst.val >> 16; + break; +#ifdef __x86_64__ + case 4: + dst.val = ((uint64_t)(int32_t)src.val * + (uint64_t)(int32_t)dst.val); + if ( (int32_t)dst.val != dst.val ) + _regs.eflags |= EFLG_OF|EFLG_CF; + _regs.edx = (uint32_t)(dst.val >> 32); + break; +#endif + default: { + unsigned long m[2] = { src.val, dst.val }; + if ( imul_dbl(m) ) + _regs.eflags |= EFLG_OF|EFLG_CF; + _regs.edx = m[1]; + dst.val = m[0]; + break; + } + } + break; + case 6: /* div */ { + unsigned long u[2], v; + src = dst; + dst.type = OP_REG; + dst.reg = (unsigned long *)&_regs.eax; + switch ( src.bytes ) + { + case 1: + u[0] = (uint16_t)_regs.eax; + u[1] = 0; + v = (uint8_t)src.val; + generate_exception_if( + div_dbl(u, v) || ((uint8_t)u[0] != (uint16_t)u[0]), + EXC_DE); + dst.val = (uint8_t)u[0]; + ((uint8_t *)&_regs.eax)[1] = u[1]; + break; + case 2: + u[0] = ((uint32_t)_regs.edx << 16) | (uint16_t)_regs.eax; + u[1] = 0; + v = (uint16_t)src.val; + generate_exception_if( + div_dbl(u, v) || ((uint16_t)u[0] != (uint32_t)u[0]), + EXC_DE); + dst.val = (uint16_t)u[0]; + *(uint16_t *)&_regs.edx = u[1]; + break; +#ifdef __x86_64__ + case 4: + u[0] = (_regs.edx << 32) | (uint32_t)_regs.eax; + u[1] = 0; + v = (uint32_t)src.val; + generate_exception_if( + div_dbl(u, v) || ((uint32_t)u[0] != u[0]), + EXC_DE); + dst.val = (uint32_t)u[0]; + _regs.edx = (uint32_t)u[1]; + break; +#endif + default: + u[0] = _regs.eax; + u[1] = _regs.edx; + v = src.val; + generate_exception_if(div_dbl(u, v), EXC_DE); + dst.val = u[0]; + _regs.edx = u[1]; + break; + } + break; + } + case 7: /* idiv */ { + unsigned long u[2], v; + src = dst; + dst.type = OP_REG; + dst.reg = (unsigned long *)&_regs.eax; + switch ( src.bytes ) + { + case 1: + u[0] = (int16_t)_regs.eax; + u[1] = ((long)u[0] < 0) ? ~0UL : 0UL; + v = (int8_t)src.val; + generate_exception_if( + idiv_dbl(u, v) || ((int8_t)u[0] != (int16_t)u[0]), + EXC_DE); + dst.val = (int8_t)u[0]; + ((int8_t *)&_regs.eax)[1] = u[1]; + break; + case 2: + u[0] = (int32_t)((_regs.edx << 16) | (uint16_t)_regs.eax); + u[1] = ((long)u[0] < 0) ? ~0UL : 0UL; + v = (int16_t)src.val; + generate_exception_if( + idiv_dbl(u, v) || ((int16_t)u[0] != (int32_t)u[0]), + EXC_DE); + dst.val = (int16_t)u[0]; + *(int16_t *)&_regs.edx = u[1]; + break; +#ifdef __x86_64__ + case 4: + u[0] = (_regs.edx << 32) | (uint32_t)_regs.eax; + u[1] = ((long)u[0] < 0) ? ~0UL : 0UL; + v = (int32_t)src.val; + generate_exception_if( + idiv_dbl(u, v) || ((int32_t)u[0] != u[0]), + EXC_DE); + dst.val = (int32_t)u[0]; + _regs.edx = (uint32_t)u[1]; + break; +#endif + default: + u[0] = _regs.eax; + u[1] = _regs.edx; + v = src.val; + generate_exception_if(idiv_dbl(u, v), EXC_DE); + dst.val = u[0]; + _regs.edx = u[1]; + break; + } + break; + } default: goto cannot_emulate; } @@ -1598,6 +1910,34 @@ x86_emulate( emulate_2op_SrcV_nobyte("bts", src, dst, _regs.eflags); break; + case 0xaf: /* imul */ + _regs.eflags &= ~(EFLG_OF|EFLG_CF); + switch ( dst.bytes ) + { + case 2: + dst.val = ((uint32_t)(int16_t)src.val * + (uint32_t)(int16_t)dst.val); + if ( (int16_t)dst.val != (uint32_t)dst.val ) + _regs.eflags |= EFLG_OF|EFLG_CF; + break; +#ifdef __x86_64__ + case 4: + dst.val = ((uint64_t)(int32_t)src.val * + (uint64_t)(int32_t)dst.val); + if ( (int32_t)dst.val != dst.val ) + _regs.eflags |= EFLG_OF|EFLG_CF; + break; +#endif + default: { + unsigned long m[2] = { src.val, dst.val }; + if ( imul_dbl(m) ) + _regs.eflags |= EFLG_OF|EFLG_CF; + dst.val = m[0]; + break; + } + } + break; + case 0xb6: /* movzx rm8,r{16,32,64} */ /* Recompute DstReg as we may have decoded AH/BH/CH/DH. */ dst.reg = decode_register(modrm_reg, &_regs, 0); diff -r e079f1ff6744 -r eb19c2745b80 xen/include/asm-x86/x86_emulate.h --- a/xen/include/asm-x86/x86_emulate.h Sat Jan 13 21:36:31 2007 +0000 +++ b/xen/include/asm-x86/x86_emulate.h Sun Jan 14 12:03:31 2007 +0000 @@ -3,7 +3,21 @@ * * Generic x86 (32-bit and 64-bit) instruction decoder and emulator. * - * Copyright (c) 2005 Keir Fraser + * Copyright (c) 2005-2007 Keir Fraser + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __X86_EMULATE_H__ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |