ia64/xen-unstable

changeset 1820:3d4f8eb89670

bitkeeper revision 1.1106.1.2 (40faa780dekT3E5arFwcbQDu1MbX6g)

Cleaned up Xen's instruction emulator.
author kaf24@scramble.cl.cam.ac.uk
date Sun Jul 18 16:38:24 2004 +0000 (2004-07-18)
parents 0990231d8436
children 1a488e40456a
files xen/arch/x86/x86_32/emulate.c
line diff
     1.1 --- a/xen/arch/x86/x86_32/emulate.c	Sun Jul 18 16:37:38 2004 +0000
     1.2 +++ b/xen/arch/x86/x86_32/emulate.c	Sun Jul 18 16:38:24 2004 +0000
     1.3 @@ -30,6 +30,15 @@
     1.4  #include <xen/perfc.h>
     1.5  #include <asm/processor.h>
     1.6  
     1.7 +/*
     1.8 + * Obtain the base and limit associated with the given segment selector.
     1.9 + * The selector must identify a 32-bit code or data segment. Any segment that
    1.10 + * appears to be truncated to not overlap with Xen is assumed to be a truncated
    1.11 + * 4GB segment, and the returned limit reflects this.
    1.12 + *  @seg   (IN) : Segment selector to decode.
    1.13 + *  @base  (OUT): Decoded linear base address.
    1.14 + *  @limit (OUT): Decoded segment limit, in bytes. 0 == unlimited (4GB).
    1.15 + */
    1.16  int get_baselimit(u16 seg, unsigned long *base, unsigned long *limit)
    1.17  {
    1.18      struct domain *d = current;
    1.19 @@ -80,6 +89,7 @@ int get_baselimit(u16 seg, unsigned long
    1.20      return 0;
    1.21  }
    1.22  
    1.23 +/* Turn a segment+offset into a linear address. */
    1.24  int linearise_address(u16 seg, unsigned long off, unsigned long *linear)
    1.25  {
    1.26      unsigned long base, limit;
    1.27 @@ -95,6 +105,7 @@ int linearise_address(u16 seg, unsigned 
    1.28      return 1;
    1.29  }
    1.30  
    1.31 +/* Decode Reg field of a ModRM byte: return a pointer into a register block. */
    1.32  void *decode_reg(struct pt_regs *regs, u8 b)
    1.33  {
    1.34      switch ( b & 7 )
    1.35 @@ -120,6 +131,9 @@ void *decode_reg(struct pt_regs *regs, u
    1.36   *  @pseg (IN)   : address in pt_regs block of the override segment.
    1.37   *  @regs (IN)   : addrress of the the pt_regs block.
    1.38   */
    1.39 +#define DECODE_EA_FAILED  0
    1.40 +#define DECODE_EA_FIXME   1
    1.41 +#define DECODE_EA_SUCCESS 2
    1.42  int decode_effective_address(u8 **ppb, void **preg, void **pmem,
    1.43                               unsigned int *pseg, struct pt_regs *regs)
    1.44  {
    1.45 @@ -132,7 +146,7 @@ int decode_effective_address(u8 **ppb, v
    1.46      if ( get_user(modrm, pb) )
    1.47      {
    1.48          DPRINTK("Fault while extracting modrm byte\n");
    1.49 -        return 0;
    1.50 +        return DECODE_EA_FAILED;
    1.51      }
    1.52  
    1.53      pb++;
    1.54 @@ -144,7 +158,7 @@ int decode_effective_address(u8 **ppb, v
    1.55      if ( rm == 4 )
    1.56      {
    1.57          DPRINTK("FIXME: Add decoding for the SIB byte.\n");
    1.58 -        return 0;
    1.59 +        return DECODE_EA_FIXME;
    1.60      }
    1.61  
    1.62      /* Decode Reg and R/M fields. */
    1.63 @@ -164,7 +178,7 @@ int decode_effective_address(u8 **ppb, v
    1.64              if ( get_user(disp32, (u32 *)pb) )
    1.65              {
    1.66                  DPRINTK("Fault while extracting <disp8>.\n");
    1.67 -                return 0;
    1.68 +                return DECODE_EA_FAILED;
    1.69              }
    1.70              pb += 4;
    1.71          }
    1.72 @@ -176,7 +190,7 @@ int decode_effective_address(u8 **ppb, v
    1.73          if ( get_user(disp8, pb) )
    1.74          {
    1.75              DPRINTK("Fault while extracting <disp8>.\n");
    1.76 -            return 0;
    1.77 +            return DECODE_EA_FAILED;
    1.78          }
    1.79          pb++;
    1.80          disp32 = (disp8 & 0x80) ? (disp8 | ~0xff) : disp8;;
    1.81 @@ -188,22 +202,22 @@ int decode_effective_address(u8 **ppb, v
    1.82          if ( get_user(disp32, (u32 *)pb) )
    1.83          {
    1.84              DPRINTK("Fault while extracting <disp8>.\n");
    1.85 -            return 0;
    1.86 +            return DECODE_EA_FAILED;
    1.87          }
    1.88          pb += 4;
    1.89          break;
    1.90  
    1.91      case 3:
    1.92          DPRINTK("Not a memory operand!\n");
    1.93 -        return 0;
    1.94 +        return DECODE_EA_FAILED;
    1.95      }
    1.96  
    1.97      if ( !get_baselimit((u16)(*pseg), &ea, &limit) )
    1.98 -        return 0;
    1.99 +        return DECODE_EA_FAILED;
   1.100      if ( limit != 0 )
   1.101      {
   1.102          DPRINTK("Bailing: not a 4GB data segment.\n");
   1.103 -        return 0;
   1.104 +        return DECODE_EA_FAILED;
   1.105      }
   1.106  
   1.107      offset = disp32;
   1.108 @@ -212,23 +226,42 @@ int decode_effective_address(u8 **ppb, v
   1.109      if ( (offset & 0xf0000000) != 0xf0000000 )
   1.110      {
   1.111          DPRINTK("Bailing: not a -ve offset into 4GB segment.\n");
   1.112 -        return 0;
   1.113 +        return DECODE_EA_FAILED;
   1.114      }
   1.115  
   1.116      ea += offset;
   1.117      if ( ea > (PAGE_OFFSET - PAGE_SIZE) )
   1.118      {
   1.119          DPRINTK("!!!! DISALLOWING UNSAFE ACCESS !!!!\n");
   1.120 -        return 0;
   1.121 +        return DECODE_EA_FAILED;
   1.122      }
   1.123  
   1.124      *ppb  = pb;
   1.125      *preg = regreg;
   1.126      *pmem = (void *)ea;
   1.127  
   1.128 -    return 1;
   1.129 +    return DECODE_EA_SUCCESS;
   1.130  }
   1.131  
   1.132 +#define GET_IMM8                                   \
   1.133 +    if ( get_user(ib, (u8 *)pb) ) {                \
   1.134 +        DPRINTK("Fault while extracting imm8\n");  \
   1.135 +        return 0;                                  \
   1.136 +    }                                              \
   1.137 +    pb += 1;
   1.138 +#define GET_IMM16                                  \
   1.139 +    if ( get_user(iw, (u8 *)pb) ) {                \
   1.140 +        DPRINTK("Fault while extracting imm16\n"); \
   1.141 +        return 0;                                  \
   1.142 +    }                                              \
   1.143 +    pb += 2;
   1.144 +#define GET_IMM32                                  \
   1.145 +    if ( get_user(il, (u32 *)pb) ) {               \
   1.146 +        DPRINTK("Fault while extracting imm32\n"); \
   1.147 +        return 0;                                  \
   1.148 +    }                                              \
   1.149 +    pb += 4;
   1.150 +
   1.151  /*
   1.152   * Called from the general-protection fault handler to attempt to decode
   1.153   * and emulate an instruction that depends on 4GB segments. At this point
   1.154 @@ -239,14 +272,17 @@ int gpf_emulate_4gb(struct pt_regs *regs
   1.155  {
   1.156      struct domain *d = current;
   1.157      trap_info_t   *ti;
   1.158 -    u8            *eip, *nextbyte, b, mb, rb;
   1.159 -    u16            mw, rw;
   1.160 -    u32            ml, rl, eflags;
   1.161 -    unsigned int  *pseg = NULL;
   1.162 -    int            i;
   1.163 +    struct guest_trap_bounce *gtb;
   1.164 +
   1.165 +    u8            *eip;         /* ptr to instruction start */
   1.166 +    u8            *pb, b;       /* ptr into instr. / current instr. byte */
   1.167 +    u8             ib, mb, rb;  /* byte operand from imm/register/memory */
   1.168 +    u16            iw, mw, rw;  /* word operand from imm/register/memory */
   1.169 +    u32            il, ml, rl;  /* long operand from imm/register/memory */
   1.170 +    void          *reg, *mem;   /* ptr to register/memory operand */
   1.171 +    unsigned int  *pseg = NULL; /* segment for memory operand (NULL=default) */
   1.172 +    u32            eflags;
   1.173      int            opsz_override = 0;
   1.174 -    void          *reg, *mem;
   1.175 -    struct guest_trap_bounce *gtb;
   1.176  
   1.177      if ( !linearise_address((u16)regs->xcs, regs->eip, (unsigned long *)&eip) )
   1.178      {
   1.179 @@ -255,11 +291,11 @@ int gpf_emulate_4gb(struct pt_regs *regs
   1.180      }
   1.181  
   1.182      /* Parse prefix bytes. We're basically looking for segment override. */
   1.183 -    for ( i = 0; i < 4; i++ )
   1.184 +    for ( pb = eip; (pb - eip) < 4; pb++ )
   1.185      {
   1.186 -        if ( get_user(b, &eip[i]) )
   1.187 +        if ( get_user(b, pb) )
   1.188          {
   1.189 -            DPRINTK("Fault while accessing byte %d of instruction\n", i);
   1.190 +            DPRINTK("Fault while accessing byte %d of instruction\n", pb-eip);
   1.191              return 0;
   1.192          }
   1.193          
   1.194 @@ -298,141 +334,94 @@ int gpf_emulate_4gb(struct pt_regs *regs
   1.195      }
   1.196   done_prefix:
   1.197  
   1.198 -    nextbyte = &eip[i+1];
   1.199 -    if ( !decode_effective_address(&nextbyte, &reg, &mem, pseg, regs) )
   1.200 +    pb++; /* skip opcode byte */
   1.201 +    switch ( decode_effective_address(&pb, &reg, &mem, pseg, regs) )
   1.202 +    {
   1.203 +    case DECODE_EA_FAILED:
   1.204 +        return 0;
   1.205 +    case DECODE_EA_FIXME:
   1.206          goto undecodeable;
   1.207 +    }
   1.208  
   1.209      /* Only handle single-byte opcodes right now. Sufficient for MOV. */
   1.210 -    /*
   1.211 -     * XXX Now I see how this decode routine is panning out, it needs
   1.212 -     * refactoring. Lots of duplicated cruft in here...
   1.213 -     */
   1.214      switch ( b )
   1.215      {
   1.216      case 0x88: /* movb r,r/m */
   1.217          if ( __put_user(*(u8 *)reg, (u8 *)mem) )
   1.218              goto page_fault_w;
   1.219 -        regs->eip += nextbyte - eip;
   1.220          break;
   1.221      case 0x89: /* movl r,r/m */
   1.222 -        if ( opsz_override )
   1.223 -        {
   1.224 -            if ( __put_user(*(u16 *)reg, (u16 *)mem) )
   1.225 -                goto page_fault_w;
   1.226 -        }
   1.227 -        else
   1.228 -        {
   1.229 -            if ( __put_user(*(u32 *)reg, (u32 *)mem) )
   1.230 -                goto page_fault_w;
   1.231 -        }
   1.232 -        regs->eip += nextbyte - eip;
   1.233 +        if ( opsz_override ? __put_user(*(u16 *)reg, (u16 *)mem)
   1.234 +                           : __put_user(*(u32 *)reg, (u32 *)mem) )
   1.235 +            goto page_fault_w;
   1.236          break;
   1.237      case 0x8a: /* movb r/m,r */
   1.238          if ( __get_user(*(u8 *)reg, (u8 *)mem) )
   1.239              goto page_fault_r;
   1.240 -        regs->eip += nextbyte - eip;
   1.241          break;
   1.242      case 0x8b: /* movl r/m,r */
   1.243 -        if ( opsz_override )
   1.244 -        {
   1.245 -            if ( __get_user(*(u16 *)reg, (u16 *)mem) )
   1.246 -                goto page_fault_r;
   1.247 -        }
   1.248 -        else
   1.249 -        {
   1.250 -            if ( __get_user(*(u32 *)reg, (u32 *)mem) )
   1.251 -                goto page_fault_r;
   1.252 -        }
   1.253 -        regs->eip += nextbyte - eip;
   1.254 +        if ( opsz_override ? __get_user(*(u16 *)reg, (u16 *)mem)
   1.255 +                           : __get_user(*(u32 *)reg, (u32 *)mem) )
   1.256 +            goto page_fault_r;
   1.257          break;
   1.258      case 0xc6: /* movb imm,r/m */
   1.259          if ( reg != &regs->eax ) /* Reg == /0 */
   1.260              goto undecodeable;
   1.261 -        if ( get_user(rb, nextbyte) )
   1.262 -        {
   1.263 -            DPRINTK("Fault while extracting immediate byte\n");
   1.264 -            return 0;
   1.265 -        }
   1.266 -        if ( __put_user(rb, (u8 *)mem) )
   1.267 +        GET_IMM8;
   1.268 +        if ( __put_user(ib, (u8 *)mem) )
   1.269              goto page_fault_w;
   1.270 -        regs->eip += nextbyte - eip + 1;
   1.271          break;
   1.272      case 0xc7: /* movl imm,r/m */
   1.273          if ( reg != &regs->eax ) /* Reg == /0 */
   1.274              goto undecodeable;
   1.275          if ( opsz_override )
   1.276          {
   1.277 -            if ( get_user(rw, (u16 *)nextbyte) )
   1.278 -            {
   1.279 -                DPRINTK("Fault while extracting immediate word\n");
   1.280 -                return 0;
   1.281 -            }
   1.282 -            if ( __put_user(rw, (u16 *)mem) )
   1.283 +            GET_IMM16;
   1.284 +            if ( __put_user(iw, (u16 *)mem) )
   1.285                  goto page_fault_w;
   1.286 -            regs->eip += nextbyte - eip + 2;
   1.287          }
   1.288          else
   1.289          {
   1.290 -            if ( get_user(rl, (u32 *)nextbyte) )
   1.291 -            {
   1.292 -                DPRINTK("Fault while extracting immediate longword\n");
   1.293 -                return 0;
   1.294 -            }
   1.295 -            if ( __put_user(rl, (u32 *)mem) )
   1.296 +            GET_IMM32;
   1.297 +            if ( __put_user(il, (u32 *)mem) )
   1.298                  goto page_fault_w;
   1.299 -            regs->eip += nextbyte - eip + 4;
   1.300          }
   1.301          break;
   1.302      case 0x80: /* cmpb imm8,r/m */
   1.303          if ( reg != &regs->edi ) /* Reg == /7 */
   1.304              goto undecodeable;
   1.305 -        if ( get_user(rb, nextbyte) )
   1.306 -        {
   1.307 -            DPRINTK("Fault while extracting immediate byte\n");
   1.308 -            return 0;
   1.309 -        }
   1.310 +        GET_IMM8;
   1.311          if ( __get_user(mb, (u8 *)mem) )
   1.312              goto page_fault_r;
   1.313          __asm__ __volatile__ (
   1.314              "cmpb %b1,%b2 ; pushf ; popl %0"
   1.315              : "=a" (eflags)
   1.316 -            : "0" (rb), "b" (mb) );
   1.317 +            : "0" (ib), "b" (mb) );
   1.318          regs->eflags &= ~0x8d5;     /* OF,SF,ZF,AF,PF,CF */
   1.319          regs->eflags |= eflags & 0x8d5;
   1.320 -        regs->eip += nextbyte - eip + 1;
   1.321          break;
   1.322      case 0x81: /* cmpl imm32,r/m */
   1.323          if ( reg != &regs->edi ) /* Reg == /7 */
   1.324              goto undecodeable;
   1.325          if ( opsz_override )
   1.326          {
   1.327 -            if ( get_user(rw, (u16 *)nextbyte) )
   1.328 -            {
   1.329 -                DPRINTK("Fault while extracting immediate word\n");
   1.330 -                return 0;
   1.331 -            }
   1.332 +            GET_IMM16;
   1.333              if ( __get_user(mw, (u16 *)mem) )
   1.334                  goto page_fault_r;
   1.335              __asm__ __volatile__ (
   1.336                  "cmpw %w1,%w2 ; pushf ; popl %0"
   1.337                  : "=a" (eflags)
   1.338 -                : "0" (rw), "b" (mw) );
   1.339 -            regs->eip += nextbyte - eip + 2;
   1.340 +                : "0" (iw), "b" (mw) );
   1.341          }
   1.342          else
   1.343          {
   1.344 -            if ( get_user(rl, (u32 *)nextbyte) )
   1.345 -            {
   1.346 -                DPRINTK("Fault while extracting immediate longword\n");
   1.347 -                return 0;
   1.348 -            }
   1.349 +            GET_IMM32;
   1.350              if ( __get_user(ml, (u32 *)mem) )
   1.351                  goto page_fault_r;
   1.352              __asm__ __volatile__ (
   1.353                  "cmpl %1,%2 ; pushf ; popl %0"
   1.354                  : "=a" (eflags)
   1.355 -                : "0" (rl), "b" (ml) );
   1.356 -            regs->eip += nextbyte - eip + 4;
   1.357 +                : "0" (il), "b" (ml) );
   1.358          }
   1.359          regs->eflags &= ~0x8d5;     /* OF,SF,ZF,AF,PF,CF */
   1.360          regs->eflags |= eflags & 0x8d5;
   1.361 @@ -440,35 +429,29 @@ int gpf_emulate_4gb(struct pt_regs *regs
   1.362      case 0x83: /* cmpl imm8,r/m */
   1.363          if ( reg != &regs->edi ) /* Reg == /7 */
   1.364              goto undecodeable;
   1.365 -        if ( get_user(rb, nextbyte) )
   1.366 -        {
   1.367 -            DPRINTK("Fault while extracting immediate byte\n");
   1.368 -            return 0;
   1.369 -        }
   1.370 +        GET_IMM8;
   1.371          if ( opsz_override )
   1.372          {
   1.373 -            rw = (rb & 0x80) ? (rb | ~0xff) : rb;
   1.374 +            iw = (u16)(s16)(s8)ib;
   1.375              if ( __get_user(mw, (u16 *)mem) )
   1.376                  goto page_fault_r;
   1.377              __asm__ __volatile__ (
   1.378                  "cmpw %w1,%w2 ; pushf ; popl %0"
   1.379                  : "=a" (eflags)
   1.380 -                : "0" (rw), "b" (mw) );
   1.381 -            regs->eip += nextbyte - eip + 2;
   1.382 +                : "0" (iw), "b" (mw) );
   1.383          }
   1.384          else
   1.385          {
   1.386 -            rl = (rb & 0x80) ? (rb | ~0xff) : rb;
   1.387 +            il = (u32)(s32)(s8)ib;
   1.388              if ( __get_user(ml, (u32 *)mem) )
   1.389                  goto page_fault_r;
   1.390              __asm__ __volatile__ (
   1.391                  "cmpl %1,%2 ; pushf ; popl %0"
   1.392                  : "=a" (eflags)
   1.393 -                : "0" (rl), "b" (ml) );
   1.394 +                : "0" (il), "b" (ml) );
   1.395          }
   1.396          regs->eflags &= ~0x8d5;     /* OF,SF,ZF,AF,PF,CF */
   1.397          regs->eflags |= eflags & 0x8d5;
   1.398 -        regs->eip += nextbyte - eip + 1;
   1.399          break;
   1.400      case 0x38: /* cmpb r,r/m */
   1.401      case 0x3a: /* cmpb r/m,r */
   1.402 @@ -481,7 +464,6 @@ int gpf_emulate_4gb(struct pt_regs *regs
   1.403              : "0" ((b==0x38)?rb:mb), "b" ((b==0x38)?mb:rb) );
   1.404          regs->eflags &= ~0x8d5;     /* OF,SF,ZF,AF,PF,CF */
   1.405          regs->eflags |= eflags & 0x8d5;
   1.406 -        regs->eip += nextbyte - eip;
   1.407          break;
   1.408      case 0x39: /* cmpl r,r/m */
   1.409      case 0x3b: /* cmpl r/m,r */
   1.410 @@ -507,24 +489,23 @@ int gpf_emulate_4gb(struct pt_regs *regs
   1.411          }
   1.412          regs->eflags &= ~0x8d5;     /* OF,SF,ZF,AF,PF,CF */
   1.413          regs->eflags |= eflags & 0x8d5;
   1.414 -        regs->eip += nextbyte - eip;
   1.415          break;
   1.416      default:
   1.417          DPRINTK("Unhandleable opcode byte %02x\n", b);
   1.418          goto undecodeable;
   1.419      }
   1.420  
   1.421 +    /* Success! */
   1.422 +    regs->eip += pb - eip;
   1.423      perfc_incrc(emulations);
   1.424 -
   1.425 -    /* Success! */
   1.426      return 1;
   1.427  
   1.428   undecodeable:
   1.429 -    printk("Undecodable instruction %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x "
   1.430 -           "caused GPF(0) at %04x:%08lx\n",
   1.431 -           eip[0], eip[1], eip[2], eip[3],
   1.432 -           eip[4], eip[5], eip[6], eip[7],
   1.433 -           regs->xcs, regs->eip);
   1.434 +    DPRINTK("Undecodable instruction %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x "
   1.435 +            "caused GPF(0) at %04x:%08lx\n",
   1.436 +            eip[0], eip[1], eip[2], eip[3],
   1.437 +            eip[4], eip[5], eip[6], eip[7],
   1.438 +            regs->xcs, regs->eip);
   1.439      return 0;
   1.440  
   1.441   page_fault_w: