ia64/xen-unstable

changeset 16413:81aa410fa662

i386: adjustment to segment fixup code.

Clean up and support more instructions.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Nov 21 11:49:41 2007 +0000 (2007-11-21)
parents 8c305873f2b8
children 6301c3b6e1ba
files xen/arch/x86/x86_32/seg_fixup.c
line diff
     1.1 --- a/xen/arch/x86/x86_32/seg_fixup.c	Wed Nov 21 11:38:51 2007 +0000
     1.2 +++ b/xen/arch/x86/x86_32/seg_fixup.c	Wed Nov 21 11:49:41 2007 +0000
     1.3 @@ -42,7 +42,7 @@
     1.4  #define O  OPCODE_BYTE
     1.5  #define M  HAS_MODRM
     1.6  
     1.7 -static unsigned char insn_decode[256] = {
     1.8 +static const unsigned char insn_decode[256] = {
     1.9      /* 0x00 - 0x0F */
    1.10      O|M, O|M, O|M, O|M, X, X, X, X,
    1.11      O|M, O|M, O|M, O|M, X, X, X, X,
    1.12 @@ -69,7 +69,7 @@ static unsigned char insn_decode[256] = 
    1.13      X, X, X, X, X, X, X, X,
    1.14      /* 0x80 - 0x8F */
    1.15      O|M|1, O|M|4, O|M|1, O|M|1, O|M, O|M, O|M, O|M,
    1.16 -    O|M, O|M, O|M, O|M, O|M, O|M, O|M, X,
    1.17 +    O|M, O|M, O|M, O|M, O|M, X|M, O|M, O|M,
    1.18      /* 0x90 - 0x9F */
    1.19      X, X, X, X, X, X, X, X,
    1.20      X, X, X, X, X, X, X, X,
    1.21 @@ -89,17 +89,17 @@ static unsigned char insn_decode[256] = 
    1.22      X, X, X, X, X, X, X, X,
    1.23      X, X, X, X, X, X, X, X,
    1.24      /* 0xF0 - 0xFF */
    1.25 -    X, X, X, X, X, X, X, X,
    1.26 +    X, X, X, X, X, X, O|M, O|M,
    1.27      X, X, X, X, X, X, O|M, O|M
    1.28  };
    1.29  
    1.30 -static unsigned char twobyte_decode[256] = {
    1.31 +static const unsigned char twobyte_decode[256] = {
    1.32      /* 0x00 - 0x0F */
    1.33      X, X, X, X, X, X, X, X,
    1.34      X, X, X, X, X, X, X, X,
    1.35      /* 0x10 - 0x1F */
    1.36      X, X, X, X, X, X, X, X,
    1.37 -    X, X, X, X, X, X, X, X,
    1.38 +    O|M, X, X, X, X, X, X, X,
    1.39      /* 0x20 - 0x2F */
    1.40      X, X, X, X, X, X, X, X,
    1.41      X, X, X, X, X, X, X, X,
    1.42 @@ -122,16 +122,16 @@ static unsigned char twobyte_decode[256]
    1.43      X, X, X, X, X, X, X, X,
    1.44      X, X, X, X, X, X, X, X,
    1.45      /* 0x90 - 0x9F */
    1.46 -    X, X, X, X, X, X, X, X,
    1.47 -    X, X, X, X, X, X, X, X,
    1.48 +    O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M,
    1.49 +    O|M, O|M, O|M, O|M, O|M, O|M, O|M, O|M,
    1.50      /* 0xA0 - 0xAF */
    1.51 -    X, X, X, X, X, X, X, X,
    1.52 -    X, X, X, X, X, X, X, X,
    1.53 +    X, X, X, O|M, O|M|1, O|M, O|M, X,
    1.54 +    X, X, X, O|M, O|M|1, O|M, X, O|M,
    1.55      /* 0xB0 - 0xBF */
    1.56 -    X, X, X, X, X, X, X, X,
    1.57 -    X, X, X, X, X, X, X, X,
    1.58 +    X, X, X, O|M, X, X, O|M, O|M,
    1.59 +    X, X, O|M|1, O|M, O|M, O|M, O|M, O|M,
    1.60      /* 0xC0 - 0xCF */
    1.61 -    X, X, X, X, X, X, X, X,
    1.62 +    O|M, O|M, X, O|M, X, X, X, O|M,
    1.63      X, X, X, X, X, X, X, X,
    1.64      /* 0xD0 - 0xDF */
    1.65      X, X, X, X, X, X, X, X,
    1.66 @@ -155,22 +155,22 @@ static unsigned char twobyte_decode[256]
    1.67   */
    1.68  static int get_baselimit(u16 seg, unsigned long *base, unsigned long *limit)
    1.69  {
    1.70 -    struct vcpu *d = current;
    1.71 -    unsigned long *table, a, b;
    1.72 -    int            ldt = !!(seg & 4);
    1.73 -    int            idx = (seg >> 3) & 8191;
    1.74 +    struct vcpu *curr = current;
    1.75 +    uint32_t    *table, a, b;
    1.76 +    int          ldt = !!(seg & 4);
    1.77 +    int          idx = (seg >> 3) & 8191;
    1.78  
    1.79      /* Get base and check limit. */
    1.80      if ( ldt )
    1.81      {
    1.82 -        table = (unsigned long *)LDT_VIRT_START(d);
    1.83 -        if ( idx >= d->arch.guest_context.ldt_ents )
    1.84 +        table = (uint32_t *)LDT_VIRT_START(curr);
    1.85 +        if ( idx >= curr->arch.guest_context.ldt_ents )
    1.86              goto fail;
    1.87      }
    1.88      else /* gdt */
    1.89      {
    1.90 -        table = (unsigned long *)GDT_VIRT_START(d);
    1.91 -        if ( idx >= d->arch.guest_context.gdt_ents )
    1.92 +        table = (uint32_t *)GDT_VIRT_START(curr);
    1.93 +        if ( idx >= curr->arch.guest_context.gdt_ents )
    1.94              goto fail;
    1.95      }
    1.96  
    1.97 @@ -225,29 +225,29 @@ static int linearise_address(u16 seg, un
    1.98  
    1.99  static int fixup_seg(u16 seg, unsigned long offset)
   1.100  {
   1.101 -    struct vcpu *d = current;
   1.102 -    unsigned long *table, a, b, base, limit;
   1.103 -    int            ldt = !!(seg & 4);
   1.104 -    int            idx = (seg >> 3) & 8191;
   1.105 +    struct vcpu *curr = current;
   1.106 +    uint32_t    *table, a, b, base, limit;
   1.107 +    int          ldt = !!(seg & 4);
   1.108 +    int          idx = (seg >> 3) & 8191;
   1.109  
   1.110      /* Get base and check limit. */
   1.111      if ( ldt )
   1.112      {
   1.113 -        table = (unsigned long *)LDT_VIRT_START(d);
   1.114 -        if ( idx >= d->arch.guest_context.ldt_ents )
   1.115 +        table = (uint32_t *)LDT_VIRT_START(curr);
   1.116 +        if ( idx >= curr->arch.guest_context.ldt_ents )
   1.117          {
   1.118              dprintk(XENLOG_DEBUG, "Segment %04x out of LDT range (%ld)\n",
   1.119 -                    seg, d->arch.guest_context.ldt_ents);
   1.120 +                    seg, curr->arch.guest_context.ldt_ents);
   1.121              goto fail;
   1.122          }
   1.123      }
   1.124      else /* gdt */
   1.125      {
   1.126 -        table = (unsigned long *)GDT_VIRT_START(d);
   1.127 -        if ( idx >= d->arch.guest_context.gdt_ents )
   1.128 +        table = (uint32_t *)GDT_VIRT_START(curr);
   1.129 +        if ( idx >= curr->arch.guest_context.gdt_ents )
   1.130          {
   1.131              dprintk(XENLOG_DEBUG, "Segment %04x out of GDT range (%ld)\n",
   1.132 -                    seg, d->arch.guest_context.gdt_ents);
   1.133 +                    seg, curr->arch.guest_context.gdt_ents);
   1.134              goto fail;
   1.135          }
   1.136      }
   1.137 @@ -265,7 +265,7 @@ static int fixup_seg(u16 seg, unsigned l
   1.138                 _SEGMENT_G|_SEGMENT_CODE|_SEGMENT_DPL)) != 
   1.139           (_SEGMENT_P|_SEGMENT_S|_SEGMENT_DB|_SEGMENT_G|_SEGMENT_DPL) )
   1.140      {
   1.141 -        dprintk(XENLOG_DEBUG, "Bad segment %08lx:%08lx\n", a, b);
   1.142 +        dprintk(XENLOG_DEBUG, "Bad segment %08x:%08x\n", a, b);
   1.143          goto fail;
   1.144      }
   1.145  
   1.146 @@ -295,8 +295,7 @@ static int fixup_seg(u16 seg, unsigned l
   1.147          }
   1.148      }
   1.149  
   1.150 -    dprintk(XENLOG_DEBUG, "None of the above! "
   1.151 -            "(%08lx:%08lx, %08lx, %08lx, %08lx)\n",
   1.152 +    dprintk(XENLOG_DEBUG, "None of the above! (%08x:%08x, %08x, %08x, %08x)\n",
   1.153              a, b, base, limit, base+limit);
   1.154  
   1.155   fail:
   1.156 @@ -318,18 +317,15 @@ static int fixup_seg(u16 seg, unsigned l
   1.157   */
   1.158  int gpf_emulate_4gb(struct cpu_user_regs *regs)
   1.159  {
   1.160 -    struct vcpu *d = current;
   1.161 -    struct trap_info   *ti;
   1.162 -    struct trap_bounce *tb;
   1.163 -    u8            modrm, mod, reg, rm, decode;
   1.164 -    void         *memreg;
   1.165 -    unsigned long offset;
   1.166 -    u8            disp8;
   1.167 -    u32           disp32 = 0;
   1.168 +    struct vcpu   *curr = current;
   1.169 +    u8             modrm, mod, rm, decode;
   1.170 +    const u32     *base, *index = NULL;
   1.171 +    unsigned long  offset;
   1.172 +    s8             disp8;
   1.173 +    s32            disp32 = 0;
   1.174      u8            *eip;         /* ptr to instruction start */
   1.175      u8            *pb, b;       /* ptr into instr. / current instr. byte */
   1.176 -    int            gs_override = 0;
   1.177 -    int            twobyte = 0;
   1.178 +    int            gs_override = 0, scale = 0, twobyte = 0;
   1.179  
   1.180      /* WARNING: We only work for ring-3 segments. */
   1.181      if ( unlikely(vm86_mode(regs)) || unlikely(!ring_3(regs)) )
   1.182 @@ -360,6 +356,9 @@ int gpf_emulate_4gb(struct cpu_user_regs
   1.183              goto fail;
   1.184          }
   1.185  
   1.186 +        if ( twobyte )
   1.187 +            break;
   1.188 +
   1.189          switch ( b )
   1.190          {
   1.191          case 0x67: /* Address-size override */
   1.192 @@ -378,6 +377,9 @@ int gpf_emulate_4gb(struct cpu_user_regs
   1.193          case 0x65: /* GS override */
   1.194              gs_override = 1;
   1.195              break;
   1.196 +        case 0x0f: /* Not really a prefix byte */
   1.197 +            twobyte = 1;
   1.198 +            break;
   1.199          default: /* Not a prefix byte */
   1.200              goto done_prefix;
   1.201          }
   1.202 @@ -390,32 +392,10 @@ int gpf_emulate_4gb(struct cpu_user_regs
   1.203          goto fail;
   1.204      }
   1.205  
   1.206 -    decode = insn_decode[b]; /* opcode byte */
   1.207 +    decode = (!twobyte ? insn_decode : twobyte_decode)[b];
   1.208      pb++;
   1.209 -    if ( decode == 0 && b == 0x0f )
   1.210 -    {
   1.211 -        twobyte = 1;
   1.212  
   1.213 -        if ( get_user(b, pb) )
   1.214 -        {
   1.215 -            dprintk(XENLOG_DEBUG,
   1.216 -                    "Fault while accessing byte %ld of instruction\n",
   1.217 -                    (long)(pb-eip));
   1.218 -            goto page_fault;
   1.219 -        }
   1.220 -
   1.221 -        if ( (pb - eip) >= 15 )
   1.222 -        {
   1.223 -            dprintk(XENLOG_DEBUG, "Too many opcode bytes for a "
   1.224 -                    "legal instruction\n");
   1.225 -            goto fail;
   1.226 -        }
   1.227 -
   1.228 -        decode = twobyte_decode[b];
   1.229 -        pb++;
   1.230 -    }
   1.231 -
   1.232 -    if ( decode == 0 )
   1.233 +    if ( !(decode & OPCODE_BYTE) )
   1.234      {
   1.235          dprintk(XENLOG_DEBUG, "Unsupported %sopcode %02x\n",
   1.236                  twobyte ? "two byte " : "", b);
   1.237 @@ -425,12 +405,12 @@ int gpf_emulate_4gb(struct cpu_user_regs
   1.238      if ( !(decode & HAS_MODRM) )
   1.239      {
   1.240          /* Must be a <disp32>, or bail. */
   1.241 -        if ( (decode & 7) != 4 )
   1.242 +        if ( (decode & INSN_SUFFIX_BYTES) != 4 )
   1.243              goto fail;
   1.244  
   1.245          if ( get_user(offset, (u32 *)pb) )
   1.246          {
   1.247 -            dprintk(XENLOG_DEBUG, "Fault while extracting <disp32>.\n");
   1.248 +            dprintk(XENLOG_DEBUG, "Fault while extracting <moffs32>.\n");
   1.249              goto page_fault;
   1.250          }
   1.251          pb += 4;
   1.252 @@ -451,29 +431,39 @@ int gpf_emulate_4gb(struct cpu_user_regs
   1.253      pb++;
   1.254  
   1.255      mod = (modrm >> 6) & 3;
   1.256 -    reg = (modrm >> 3) & 7;
   1.257      rm  = (modrm >> 0) & 7;
   1.258  
   1.259      if ( rm == 4 )
   1.260      {
   1.261 -        dprintk(XENLOG_DEBUG, "FIXME: Add decoding for the SIB byte.\n");
   1.262 -        goto fixme;
   1.263 +        u8 sib;
   1.264 +
   1.265 +        if ( get_user(sib, pb) )
   1.266 +        {
   1.267 +            dprintk(XENLOG_DEBUG, "Fault while extracting sib byte\n");
   1.268 +            goto page_fault;
   1.269 +        }
   1.270 +
   1.271 +        pb++;
   1.272 +
   1.273 +        rm = sib & 7;
   1.274 +        if ( (sib & 0x38) != 0x20 )
   1.275 +            index = decode_register((sib >> 3) & 7, regs, 0);
   1.276 +        scale = sib >> 6;
   1.277      }
   1.278  
   1.279      /* Decode R/M field. */
   1.280 -    memreg = decode_register(rm,  regs, 0);
   1.281 +    base = decode_register(rm, regs, 0);
   1.282  
   1.283      /* Decode Mod field. */
   1.284 -    switch ( modrm >> 6 )
   1.285 +    switch ( mod )
   1.286      {
   1.287      case 0:
   1.288 -        disp32 = 0;
   1.289          if ( rm == 5 ) /* disp32 rather than (EBP) */
   1.290          {
   1.291 -            memreg = NULL;
   1.292 +            base = NULL;
   1.293              if ( get_user(disp32, (u32 *)pb) )
   1.294              {
   1.295 -                dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n");
   1.296 +                dprintk(XENLOG_DEBUG, "Fault while extracting <base32>.\n");
   1.297                  goto page_fault;
   1.298              }
   1.299              pb += 4;
   1.300 @@ -487,13 +477,13 @@ int gpf_emulate_4gb(struct cpu_user_regs
   1.301              goto page_fault;
   1.302          }
   1.303          pb++;
   1.304 -        disp32 = (disp8 & 0x80) ? (disp8 | ~0xff) : disp8;;
   1.305 +        disp32 = disp8;
   1.306          break;
   1.307  
   1.308      case 2:
   1.309          if ( get_user(disp32, (u32 *)pb) )
   1.310          {
   1.311 -            dprintk(XENLOG_DEBUG, "Fault while extracting <disp8>.\n");
   1.312 +            dprintk(XENLOG_DEBUG, "Fault while extracting <disp32>.\n");
   1.313              goto page_fault;
   1.314          }
   1.315          pb += 4;
   1.316 @@ -505,8 +495,10 @@ int gpf_emulate_4gb(struct cpu_user_regs
   1.317      }
   1.318  
   1.319      offset = disp32;
   1.320 -    if ( memreg != NULL )
   1.321 -        offset += *(u32 *)memreg;
   1.322 +    if ( base != NULL )
   1.323 +        offset += *base;
   1.324 +    if ( index != NULL )
   1.325 +        offset += *index << scale;
   1.326  
   1.327   skip_modrm:
   1.328      if ( !fixup_seg((u16)regs->gs, offset) )
   1.329 @@ -516,10 +508,11 @@ int gpf_emulate_4gb(struct cpu_user_regs
   1.330      perfc_incr(seg_fixups);
   1.331  
   1.332      /* If requested, give a callback on otherwise unused vector 15. */
   1.333 -    if ( VM_ASSIST(d->domain, VMASST_TYPE_4gb_segments_notify) )
   1.334 +    if ( VM_ASSIST(curr->domain, VMASST_TYPE_4gb_segments_notify) )
   1.335      {
   1.336 -        ti  = &d->arch.guest_context.trap_ctxt[15];
   1.337 -        tb  = &d->arch.trap_bounce;
   1.338 +        struct trap_info   *ti  = &curr->arch.guest_context.trap_ctxt[15];
   1.339 +        struct trap_bounce *tb  = &curr->arch.trap_bounce;
   1.340 +
   1.341          tb->flags      = TBF_EXCEPTION | TBF_EXCEPTION_ERRCODE;
   1.342          tb->error_code = pb - eip;
   1.343          tb->cs         = ti->cs;
   1.344 @@ -530,13 +523,6 @@ int gpf_emulate_4gb(struct cpu_user_regs
   1.345  
   1.346      return EXCRET_fault_fixed;
   1.347  
   1.348 - fixme:
   1.349 -    dprintk(XENLOG_DEBUG, "Undecodable instruction "
   1.350 -            "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x "
   1.351 -            "caused GPF(0) at %04x:%08x\n",
   1.352 -            eip[0], eip[1], eip[2], eip[3],
   1.353 -            eip[4], eip[5], eip[6], eip[7],
   1.354 -            regs->cs, regs->eip);
   1.355   fail:
   1.356      return 0;
   1.357