ia64/xen-unstable

changeset 13426:eb19c2745b80

[XEN] Emulate MUL/DIV. Tweak test suite build.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@localhost.localdomain
date Sun Jan 14 12:03:31 2007 +0000 (2007-01-14)
parents e079f1ff6744
children 328deec3febf
files tools/tests/Makefile 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/Makefile	Sat Jan 13 21:36:31 2007 +0000
     1.2 +++ b/tools/tests/Makefile	Sun Jan 14 12:03:31 2007 +0000
     1.3 @@ -7,6 +7,7 @@ TARGET := test_x86_emulator
     1.4  .PHONY: all
     1.5  all: $(TARGET)
     1.6  
     1.7 +.PHONY: blowfish.bin
     1.8  blowfish.bin:
     1.9  	make -f blowfish.mk all
    1.10  
     2.1 --- a/tools/tests/test_x86_emulator.c	Sat Jan 13 21:36:31 2007 +0000
     2.2 +++ b/tools/tests/test_x86_emulator.c	Sun Jan 14 12:03:31 2007 +0000
     2.3 @@ -501,7 +501,10 @@ int main(int argc, char **argv)
     2.4              printf(".");
     2.5          rc = x86_emulate(&ctxt, &emulops);
     2.6          if ( rc != 0 )
     2.7 -            goto fail;
     2.8 +        {
     2.9 +            printf("failed at %%eip == %08x\n", (unsigned int)regs.eip);
    2.10 +            return 1;
    2.11 +        }
    2.12      }
    2.13      if ( (regs.esp != ((unsigned long)res + MMAP_SZ)) ||
    2.14           (regs.eax != 2) || (regs.edx != 1) )
     3.1 --- a/xen/arch/x86/x86_emulate.c	Sat Jan 13 21:36:31 2007 +0000
     3.2 +++ b/xen/arch/x86/x86_emulate.c	Sun Jan 14 12:03:31 2007 +0000
     3.3 @@ -3,7 +3,21 @@
     3.4   * 
     3.5   * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
     3.6   * 
     3.7 - * Copyright (c) 2005 Keir Fraser
     3.8 + * Copyright (c) 2005-2007 Keir Fraser
     3.9 + * 
    3.10 + * This program is free software; you can redistribute it and/or modify
    3.11 + * it under the terms of the GNU General Public License as published by
    3.12 + * the Free Software Foundation; either version 2 of the License, or
    3.13 + * (at your option) any later version.
    3.14 + * 
    3.15 + * This program is distributed in the hope that it will be useful,
    3.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.18 + * GNU General Public License for more details.
    3.19 + * 
    3.20 + * You should have received a copy of the GNU General Public License
    3.21 + * along with this program; if not, write to the Free Software
    3.22 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    3.23   */
    3.24  
    3.25  #ifndef __XEN__
    3.26 @@ -89,7 +103,9 @@ static uint8_t opcode_table[256] = {
    3.27      0, 0, 0, DstReg|SrcMem32|ModRM|Mov /* movsxd (x86/64) */,
    3.28      0, 0, 0, 0,
    3.29      /* 0x68 - 0x6F */
    3.30 -    ImplicitOps|Mov, 0, ImplicitOps|Mov, 0, 0, 0, 0, 0,
    3.31 +    ImplicitOps|Mov, DstMem|SrcImm|ModRM|Mov,
    3.32 +    ImplicitOps|Mov, DstMem|SrcImmByte|ModRM|Mov,
    3.33 +    0, 0, 0, 0,
    3.34      /* 0x70 - 0x77 */
    3.35      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    3.36      ImplicitOps, ImplicitOps, ImplicitOps, ImplicitOps,
    3.37 @@ -194,7 +210,7 @@ static uint8_t twobyte_table[256] = {
    3.38      /* 0xA0 - 0xA7 */
    3.39      0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0, 
    3.40      /* 0xA8 - 0xAF */
    3.41 -    0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, 0,
    3.42 +    0, 0, 0, DstBitBase|SrcReg|ModRM, 0, 0, 0, DstReg|SrcMem|ModRM,
    3.43      /* 0xB0 - 0xB7 */
    3.44      ByteOp|DstMem|SrcReg|ModRM, DstMem|SrcReg|ModRM,
    3.45      0, DstBitBase|SrcReg|ModRM,
    3.46 @@ -467,6 +483,92 @@ do {                                    
    3.47                       ? (uint16_t)_regs.eip : (uint32_t)_regs.eip);      \
    3.48  } while (0)
    3.49  
    3.50 +/*
    3.51 + * Unsigned multiplication with double-word result.
    3.52 + * IN:  Multiplicand=m[0], Multiplier=m[1]
    3.53 + * OUT: Return CF/OF (overflow status); Result=m[1]:m[0]
    3.54 + */
    3.55 +static int mul_dbl(unsigned long m[2])
    3.56 +{
    3.57 +    int rc;
    3.58 +    asm ( "mul %4; seto %b2"
    3.59 +          : "=a" (m[0]), "=d" (m[1]), "=q" (rc)
    3.60 +          : "0" (m[0]), "1" (m[1]), "2" (0) );
    3.61 +    return rc;
    3.62 +}
    3.63 +
    3.64 +/*
    3.65 + * Signed multiplication with double-word result.
    3.66 + * IN:  Multiplicand=m[0], Multiplier=m[1]
    3.67 + * OUT: Return CF/OF (overflow status); Result=m[1]:m[0]
    3.68 + */
    3.69 +static int imul_dbl(unsigned long m[2])
    3.70 +{
    3.71 +    int rc;
    3.72 +    asm ( "imul %4; seto %b2"
    3.73 +          : "=a" (m[0]), "=d" (m[1]), "=q" (rc)
    3.74 +          : "0" (m[0]), "1" (m[1]), "2" (0) );
    3.75 +    return rc;
    3.76 +}
    3.77 +
    3.78 +/*
    3.79 + * Unsigned division of double-word dividend.
    3.80 + * IN:  Dividend=u[1]:u[0], Divisor=v
    3.81 + * OUT: Return 1: #DE
    3.82 + *      Return 0: Quotient=u[0], Remainder=u[1]
    3.83 + */
    3.84 +static int div_dbl(unsigned long u[2], unsigned long v)
    3.85 +{
    3.86 +    if ( (v == 0) || (u[1] > v) || ((u[1] == v) && (u[0] != 0)) )
    3.87 +        return 1;
    3.88 +    asm ( "div %4"
    3.89 +          : "=a" (u[0]), "=d" (u[1])
    3.90 +          : "0" (u[0]), "1" (u[1]), "r" (v) );
    3.91 +    return 0;
    3.92 +}
    3.93 +
    3.94 +/*
    3.95 + * Signed division of double-word dividend.
    3.96 + * IN:  Dividend=u[1]:u[0], Divisor=v
    3.97 + * OUT: Return 1: #DE
    3.98 + *      Return 0: Quotient=u[0], Remainder=u[1]
    3.99 + * NB. We don't use idiv directly as it's moderately hard to work out
   3.100 + *     ahead of time whether it will #DE, which we cannot allow to happen.
   3.101 + */
   3.102 +static int idiv_dbl(unsigned long u[2], unsigned long v)
   3.103 +{
   3.104 +    int negu = (long)u[1] < 0, negv = (long)v < 0;
   3.105 +
   3.106 +    /* u = abs(u) */
   3.107 +    if ( negu )
   3.108 +    {
   3.109 +        u[1] = ~u[1];
   3.110 +        if ( (u[0] = -u[0]) == 0 )
   3.111 +            u[1]++;
   3.112 +    }
   3.113 +
   3.114 +    /* abs(u) / abs(v) */
   3.115 +    if ( div_dbl(u, negv ? -v : v) )
   3.116 +        return 1;
   3.117 +
   3.118 +    /* Remainder has same sign as dividend. It cannot overflow. */
   3.119 +    if ( negu )
   3.120 +        u[1] = -u[1];
   3.121 +
   3.122 +    /* Quotient is overflowed if sign bit is set. */
   3.123 +    if ( negu ^ negv )
   3.124 +    {
   3.125 +        if ( (long)u[0] >= 0 )
   3.126 +            u[0] = -u[0];
   3.127 +        else if ( (u[0] << 1) != 0 ) /* == 0x80...0 is okay */
   3.128 +            return 1;
   3.129 +    }
   3.130 +    else if ( (long)u[0] < 0 )
   3.131 +        return 1;
   3.132 +
   3.133 +    return 0;
   3.134 +}
   3.135 +
   3.136  static int
   3.137  test_cc(
   3.138      unsigned int condition, unsigned int flags)
   3.139 @@ -969,6 +1071,39 @@ x86_emulate(
   3.140          dst.val = (int32_t)src.val;
   3.141          break;
   3.142  
   3.143 +    case 0x69: /* imul imm16/32 */
   3.144 +    case 0x6b: /* imul imm8 */ {
   3.145 +        unsigned long reg = *(long *)decode_register(modrm_reg, &_regs, 0);
   3.146 +        _regs.eflags &= ~(EFLG_OF|EFLG_CF);
   3.147 +        switch ( dst.bytes )
   3.148 +        {
   3.149 +        case 2:
   3.150 +            dst.val = ((uint32_t)(int16_t)src.val *
   3.151 +                       (uint32_t)(int16_t)reg);
   3.152 +            if ( (int16_t)dst.val != (uint32_t)dst.val )
   3.153 +                _regs.eflags |= EFLG_OF|EFLG_CF;
   3.154 +            break;
   3.155 +#ifdef __x86_64__
   3.156 +        case 4:
   3.157 +            dst.val = ((uint64_t)(int32_t)src.val *
   3.158 +                       (uint64_t)(int32_t)reg);
   3.159 +            if ( (int32_t)dst.val != dst.val )
   3.160 +                _regs.eflags |= EFLG_OF|EFLG_CF;
   3.161 +            break;
   3.162 +#endif
   3.163 +        default: {
   3.164 +            unsigned long m[2] = { src.val, reg };
   3.165 +            if ( imul_dbl(m) )
   3.166 +                _regs.eflags |= EFLG_OF|EFLG_CF;
   3.167 +            dst.val = m[0];
   3.168 +            break;
   3.169 +        }
   3.170 +        }
   3.171 +        dst.type = OP_REG;
   3.172 +        dst.reg  = decode_register(modrm_reg, &_regs, 0);
   3.173 +        break;
   3.174 +    }
   3.175 +
   3.176      case 0x80 ... 0x83: /* Grp1 */
   3.177          switch ( modrm_reg & 7 )
   3.178          {
   3.179 @@ -1097,6 +1232,183 @@ x86_emulate(
   3.180          case 3: /* neg */
   3.181              emulate_1op("neg", dst, _regs.eflags);
   3.182              break;
   3.183 +        case 4: /* mul */
   3.184 +            src = dst;
   3.185 +            dst.type = OP_REG;
   3.186 +            dst.reg  = (unsigned long *)&_regs.eax;
   3.187 +            dst.val  = *dst.reg;
   3.188 +            _regs.eflags &= ~(EFLG_OF|EFLG_CF);
   3.189 +            switch ( src.bytes )
   3.190 +            {
   3.191 +            case 1:
   3.192 +                dst.val *= src.val;
   3.193 +                if ( (uint8_t)dst.val != (uint16_t)dst.val )
   3.194 +                    _regs.eflags |= EFLG_OF|EFLG_CF;
   3.195 +                break;
   3.196 +            case 2:
   3.197 +                dst.val *= src.val;
   3.198 +                if ( (uint16_t)dst.val != (uint32_t)dst.val )
   3.199 +                    _regs.eflags |= EFLG_OF|EFLG_CF;
   3.200 +                *(uint16_t *)&_regs.edx = dst.val >> 16;
   3.201 +                break;
   3.202 +#ifdef __x86_64__
   3.203 +            case 4:
   3.204 +                dst.val *= src.val;
   3.205 +                if ( (uint32_t)dst.val != dst.val )
   3.206 +                    _regs.eflags |= EFLG_OF|EFLG_CF;
   3.207 +                _regs.edx = (uint32_t)(dst.val >> 32);
   3.208 +                break;
   3.209 +#endif
   3.210 +            default: {
   3.211 +                unsigned long m[2] = { src.val, dst.val };
   3.212 +                if ( mul_dbl(m) )
   3.213 +                    _regs.eflags |= EFLG_OF|EFLG_CF;
   3.214 +                _regs.edx = m[1];
   3.215 +                dst.val  = m[0];
   3.216 +                break;
   3.217 +            }
   3.218 +            }
   3.219 +            break;
   3.220 +        case 5: /* imul */
   3.221 +            src = dst;
   3.222 +            dst.type = OP_REG;
   3.223 +            dst.reg  = (unsigned long *)&_regs.eax;
   3.224 +            dst.val  = *dst.reg;
   3.225 +            _regs.eflags &= ~(EFLG_OF|EFLG_CF);
   3.226 +            switch ( src.bytes )
   3.227 +            {
   3.228 +            case 1:
   3.229 +                dst.val = ((uint16_t)(int8_t)src.val *
   3.230 +                           (uint16_t)(int8_t)dst.val);
   3.231 +                if ( (int8_t)dst.val != (uint16_t)dst.val )
   3.232 +                    _regs.eflags |= EFLG_OF|EFLG_CF;
   3.233 +                break;
   3.234 +            case 2:
   3.235 +                dst.val = ((uint32_t)(int16_t)src.val *
   3.236 +                           (uint32_t)(int16_t)dst.val);
   3.237 +                if ( (int16_t)dst.val != (uint32_t)dst.val )
   3.238 +                    _regs.eflags |= EFLG_OF|EFLG_CF;
   3.239 +                *(uint16_t *)&_regs.edx = dst.val >> 16;
   3.240 +                break;
   3.241 +#ifdef __x86_64__
   3.242 +            case 4:
   3.243 +                dst.val = ((uint64_t)(int32_t)src.val *
   3.244 +                           (uint64_t)(int32_t)dst.val);
   3.245 +                if ( (int32_t)dst.val != dst.val )
   3.246 +                    _regs.eflags |= EFLG_OF|EFLG_CF;
   3.247 +                _regs.edx = (uint32_t)(dst.val >> 32);
   3.248 +                break;
   3.249 +#endif
   3.250 +            default: {
   3.251 +                unsigned long m[2] = { src.val, dst.val };
   3.252 +                if ( imul_dbl(m) )
   3.253 +                    _regs.eflags |= EFLG_OF|EFLG_CF;
   3.254 +                _regs.edx = m[1];
   3.255 +                dst.val  = m[0];
   3.256 +                break;
   3.257 +            }
   3.258 +            }
   3.259 +            break;
   3.260 +        case 6: /* div */ {
   3.261 +            unsigned long u[2], v;
   3.262 +            src = dst;
   3.263 +            dst.type = OP_REG;
   3.264 +            dst.reg  = (unsigned long *)&_regs.eax;
   3.265 +            switch ( src.bytes )
   3.266 +            {
   3.267 +            case 1:
   3.268 +                u[0] = (uint16_t)_regs.eax;
   3.269 +                u[1] = 0;
   3.270 +                v    = (uint8_t)src.val;
   3.271 +                generate_exception_if(
   3.272 +                    div_dbl(u, v) || ((uint8_t)u[0] != (uint16_t)u[0]),
   3.273 +                    EXC_DE);
   3.274 +                dst.val = (uint8_t)u[0];
   3.275 +                ((uint8_t *)&_regs.eax)[1] = u[1];
   3.276 +                break;
   3.277 +            case 2:
   3.278 +                u[0] = ((uint32_t)_regs.edx << 16) | (uint16_t)_regs.eax;
   3.279 +                u[1] = 0;
   3.280 +                v    = (uint16_t)src.val;
   3.281 +                generate_exception_if(
   3.282 +                    div_dbl(u, v) || ((uint16_t)u[0] != (uint32_t)u[0]),
   3.283 +                    EXC_DE);
   3.284 +                dst.val = (uint16_t)u[0];
   3.285 +                *(uint16_t *)&_regs.edx = u[1];
   3.286 +                break;
   3.287 +#ifdef __x86_64__
   3.288 +            case 4:
   3.289 +                u[0] = (_regs.edx << 32) | (uint32_t)_regs.eax;
   3.290 +                u[1] = 0;
   3.291 +                v    = (uint32_t)src.val;
   3.292 +                generate_exception_if(
   3.293 +                    div_dbl(u, v) || ((uint32_t)u[0] != u[0]),
   3.294 +                    EXC_DE);
   3.295 +                dst.val   = (uint32_t)u[0];
   3.296 +                _regs.edx = (uint32_t)u[1];
   3.297 +                break;
   3.298 +#endif
   3.299 +            default:
   3.300 +                u[0] = _regs.eax;
   3.301 +                u[1] = _regs.edx;
   3.302 +                v    = src.val;
   3.303 +                generate_exception_if(div_dbl(u, v), EXC_DE);
   3.304 +                dst.val   = u[0];
   3.305 +                _regs.edx = u[1];
   3.306 +                break;
   3.307 +            }
   3.308 +            break;
   3.309 +        }
   3.310 +        case 7: /* idiv */ {
   3.311 +            unsigned long u[2], v;
   3.312 +            src = dst;
   3.313 +            dst.type = OP_REG;
   3.314 +            dst.reg  = (unsigned long *)&_regs.eax;
   3.315 +            switch ( src.bytes )
   3.316 +            {
   3.317 +            case 1:
   3.318 +                u[0] = (int16_t)_regs.eax;
   3.319 +                u[1] = ((long)u[0] < 0) ? ~0UL : 0UL;
   3.320 +                v    = (int8_t)src.val;
   3.321 +                generate_exception_if(
   3.322 +                    idiv_dbl(u, v) || ((int8_t)u[0] != (int16_t)u[0]),
   3.323 +                    EXC_DE);
   3.324 +                dst.val = (int8_t)u[0];
   3.325 +                ((int8_t *)&_regs.eax)[1] = u[1];
   3.326 +                break;
   3.327 +            case 2:
   3.328 +                u[0] = (int32_t)((_regs.edx << 16) | (uint16_t)_regs.eax);
   3.329 +                u[1] = ((long)u[0] < 0) ? ~0UL : 0UL;
   3.330 +                v    = (int16_t)src.val;
   3.331 +                generate_exception_if(
   3.332 +                    idiv_dbl(u, v) || ((int16_t)u[0] != (int32_t)u[0]),
   3.333 +                    EXC_DE);
   3.334 +                dst.val = (int16_t)u[0];
   3.335 +                *(int16_t *)&_regs.edx = u[1];
   3.336 +                break;
   3.337 +#ifdef __x86_64__
   3.338 +            case 4:
   3.339 +                u[0] = (_regs.edx << 32) | (uint32_t)_regs.eax;
   3.340 +                u[1] = ((long)u[0] < 0) ? ~0UL : 0UL;
   3.341 +                v    = (int32_t)src.val;
   3.342 +                generate_exception_if(
   3.343 +                    idiv_dbl(u, v) || ((int32_t)u[0] != u[0]),
   3.344 +                    EXC_DE);
   3.345 +                dst.val   = (int32_t)u[0];
   3.346 +                _regs.edx = (uint32_t)u[1];
   3.347 +                break;
   3.348 +#endif
   3.349 +            default:
   3.350 +                u[0] = _regs.eax;
   3.351 +                u[1] = _regs.edx;
   3.352 +                v    = src.val;
   3.353 +                generate_exception_if(idiv_dbl(u, v), EXC_DE);
   3.354 +                dst.val   = u[0];
   3.355 +                _regs.edx = u[1];
   3.356 +                break;
   3.357 +            }
   3.358 +            break;
   3.359 +        }
   3.360          default:
   3.361              goto cannot_emulate;
   3.362          }
   3.363 @@ -1598,6 +1910,34 @@ x86_emulate(
   3.364          emulate_2op_SrcV_nobyte("bts", src, dst, _regs.eflags);
   3.365          break;
   3.366  
   3.367 +    case 0xaf: /* imul */
   3.368 +        _regs.eflags &= ~(EFLG_OF|EFLG_CF);
   3.369 +        switch ( dst.bytes )
   3.370 +        {
   3.371 +        case 2:
   3.372 +            dst.val = ((uint32_t)(int16_t)src.val *
   3.373 +                       (uint32_t)(int16_t)dst.val);
   3.374 +            if ( (int16_t)dst.val != (uint32_t)dst.val )
   3.375 +                _regs.eflags |= EFLG_OF|EFLG_CF;
   3.376 +            break;
   3.377 +#ifdef __x86_64__
   3.378 +        case 4:
   3.379 +            dst.val = ((uint64_t)(int32_t)src.val *
   3.380 +                       (uint64_t)(int32_t)dst.val);
   3.381 +            if ( (int32_t)dst.val != dst.val )
   3.382 +                _regs.eflags |= EFLG_OF|EFLG_CF;
   3.383 +            break;
   3.384 +#endif
   3.385 +        default: {
   3.386 +            unsigned long m[2] = { src.val, dst.val };
   3.387 +            if ( imul_dbl(m) )
   3.388 +                _regs.eflags |= EFLG_OF|EFLG_CF;
   3.389 +            dst.val = m[0];
   3.390 +            break;
   3.391 +        }
   3.392 +        }
   3.393 +        break;
   3.394 +
   3.395      case 0xb6: /* movzx rm8,r{16,32,64} */
   3.396          /* Recompute DstReg as we may have decoded AH/BH/CH/DH. */
   3.397          dst.reg   = decode_register(modrm_reg, &_regs, 0);
     4.1 --- a/xen/include/asm-x86/x86_emulate.h	Sat Jan 13 21:36:31 2007 +0000
     4.2 +++ b/xen/include/asm-x86/x86_emulate.h	Sun Jan 14 12:03:31 2007 +0000
     4.3 @@ -3,7 +3,21 @@
     4.4   * 
     4.5   * Generic x86 (32-bit and 64-bit) instruction decoder and emulator.
     4.6   * 
     4.7 - * Copyright (c) 2005 Keir Fraser
     4.8 + * Copyright (c) 2005-2007 Keir Fraser
     4.9 + * 
    4.10 + * This program is free software; you can redistribute it and/or modify
    4.11 + * it under the terms of the GNU General Public License as published by
    4.12 + * the Free Software Foundation; either version 2 of the License, or
    4.13 + * (at your option) any later version.
    4.14 + * 
    4.15 + * This program is distributed in the hope that it will be useful,
    4.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    4.18 + * GNU General Public License for more details.
    4.19 + * 
    4.20 + * You should have received a copy of the GNU General Public License
    4.21 + * along with this program; if not, write to the Free Software
    4.22 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    4.23   */
    4.24  
    4.25  #ifndef __X86_EMULATE_H__