KVM: x86 emulator: move x86_decode_insn() downwards
authorAvi Kivity <avi@redhat.com>
Thu, 29 Jul 2010 12:11:52 +0000 (15:11 +0300)
committerAvi Kivity <avi@redhat.com>
Sun, 24 Oct 2010 08:50:24 +0000 (10:50 +0200)
No code changes.

Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
arch/x86/kvm/emulate.c

index 799e895fb08e72dbd333c717d50e95c96e08dd68..c6f435917538c8297c4d328ca9dfe79ef9ba2b34 100644 (file)
@@ -945,917 +945,545 @@ done:
        return rc;
 }
 
-int
-x86_decode_insn(struct x86_emulate_ctxt *ctxt)
+static int read_emulated(struct x86_emulate_ctxt *ctxt,
+                        struct x86_emulate_ops *ops,
+                        unsigned long addr, void *dest, unsigned size)
 {
-       struct x86_emulate_ops *ops = ctxt->ops;
-       struct decode_cache *c = &ctxt->decode;
-       int rc = X86EMUL_CONTINUE;
-       int mode = ctxt->mode;
-       int def_op_bytes, def_ad_bytes, dual, goffset;
-       struct opcode opcode, *g_mod012, *g_mod3;
+       int rc;
+       struct read_cache *mc = &ctxt->decode.mem_read;
+       u32 err;
 
-       /* we cannot decode insn before we complete previous rep insn */
-       WARN_ON(ctxt->restart);
+       while (size) {
+               int n = min(size, 8u);
+               size -= n;
+               if (mc->pos < mc->end)
+                       goto read_cached;
 
-       c->eip = ctxt->eip;
-       c->fetch.start = c->fetch.end = c->eip;
-       ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS);
+               rc = ops->read_emulated(addr, mc->data + mc->end, n, &err,
+                                       ctxt->vcpu);
+               if (rc == X86EMUL_PROPAGATE_FAULT)
+                       emulate_pf(ctxt, addr, err);
+               if (rc != X86EMUL_CONTINUE)
+                       return rc;
+               mc->end += n;
 
-       switch (mode) {
-       case X86EMUL_MODE_REAL:
-       case X86EMUL_MODE_VM86:
-       case X86EMUL_MODE_PROT16:
-               def_op_bytes = def_ad_bytes = 2;
-               break;
-       case X86EMUL_MODE_PROT32:
-               def_op_bytes = def_ad_bytes = 4;
-               break;
-#ifdef CONFIG_X86_64
-       case X86EMUL_MODE_PROT64:
-               def_op_bytes = 4;
-               def_ad_bytes = 8;
-               break;
-#endif
-       default:
-               return -1;
+       read_cached:
+               memcpy(dest, mc->data + mc->pos, n);
+               mc->pos += n;
+               dest += n;
+               addr += n;
        }
+       return X86EMUL_CONTINUE;
+}
 
-       c->op_bytes = def_op_bytes;
-       c->ad_bytes = def_ad_bytes;
-
-       /* Legacy prefixes. */
-       for (;;) {
-               switch (c->b = insn_fetch(u8, 1, c->eip)) {
-               case 0x66:      /* operand-size override */
-                       /* switch between 2/4 bytes */
-                       c->op_bytes = def_op_bytes ^ 6;
-                       break;
-               case 0x67:      /* address-size override */
-                       if (mode == X86EMUL_MODE_PROT64)
-                               /* switch between 4/8 bytes */
-                               c->ad_bytes = def_ad_bytes ^ 12;
-                       else
-                               /* switch between 2/4 bytes */
-                               c->ad_bytes = def_ad_bytes ^ 6;
-                       break;
-               case 0x26:      /* ES override */
-               case 0x2e:      /* CS override */
-               case 0x36:      /* SS override */
-               case 0x3e:      /* DS override */
-                       set_seg_override(c, (c->b >> 3) & 3);
-                       break;
-               case 0x64:      /* FS override */
-               case 0x65:      /* GS override */
-                       set_seg_override(c, c->b & 7);
-                       break;
-               case 0x40 ... 0x4f: /* REX */
-                       if (mode != X86EMUL_MODE_PROT64)
-                               goto done_prefixes;
-                       c->rex_prefix = c->b;
-                       continue;
-               case 0xf0:      /* LOCK */
-                       c->lock_prefix = 1;
-                       break;
-               case 0xf2:      /* REPNE/REPNZ */
-                       c->rep_prefix = REPNE_PREFIX;
-                       break;
-               case 0xf3:      /* REP/REPE/REPZ */
-                       c->rep_prefix = REPE_PREFIX;
-                       break;
-               default:
-                       goto done_prefixes;
-               }
-
-               /* Any legacy prefix after a REX prefix nullifies its effect. */
+static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
+                          struct x86_emulate_ops *ops,
+                          unsigned int size, unsigned short port,
+                          void *dest)
+{
+       struct read_cache *rc = &ctxt->decode.io_read;
 
-               c->rex_prefix = 0;
+       if (rc->pos == rc->end) { /* refill pio read ahead */
+               struct decode_cache *c = &ctxt->decode;
+               unsigned int in_page, n;
+               unsigned int count = c->rep_prefix ?
+                       address_mask(c, c->regs[VCPU_REGS_RCX]) : 1;
+               in_page = (ctxt->eflags & EFLG_DF) ?
+                       offset_in_page(c->regs[VCPU_REGS_RDI]) :
+                       PAGE_SIZE - offset_in_page(c->regs[VCPU_REGS_RDI]);
+               n = min(min(in_page, (unsigned int)sizeof(rc->data)) / size,
+                       count);
+               if (n == 0)
+                       n = 1;
+               rc->pos = rc->end = 0;
+               if (!ops->pio_in_emulated(size, port, rc->data, n, ctxt->vcpu))
+                       return 0;
+               rc->end = n * size;
        }
 
-done_prefixes:
+       memcpy(dest, rc->data + rc->pos, size);
+       rc->pos += size;
+       return 1;
+}
 
-       /* REX prefix. */
-       if (c->rex_prefix)
-               if (c->rex_prefix & 8)
-                       c->op_bytes = 8;        /* REX.W */
+static u32 desc_limit_scaled(struct desc_struct *desc)
+{
+       u32 limit = get_desc_limit(desc);
 
-       /* Opcode byte(s). */
-       opcode = opcode_table[c->b];
-       if (opcode.flags == 0) {
-               /* Two-byte opcode? */
-               if (c->b == 0x0f) {
-                       c->twobyte = 1;
-                       c->b = insn_fetch(u8, 1, c->eip);
-                       opcode = twobyte_table[c->b];
-               }
-       }
-       c->d = opcode.flags;
+       return desc->g ? (limit << 12) | 0xfff : limit;
+}
 
-       if (c->d & Group) {
-               dual = c->d & GroupDual;
-               c->modrm = insn_fetch(u8, 1, c->eip);
-               --c->eip;
+static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt,
+                                    struct x86_emulate_ops *ops,
+                                    u16 selector, struct desc_ptr *dt)
+{
+       if (selector & 1 << 2) {
+               struct desc_struct desc;
+               memset (dt, 0, sizeof *dt);
+               if (!ops->get_cached_descriptor(&desc, VCPU_SREG_LDTR, ctxt->vcpu))
+                       return;
 
-               if (c->d & GroupDual) {
-                       g_mod012 = opcode.u.gdual->mod012;
-                       g_mod3 = opcode.u.gdual->mod3;
-               } else
-                       g_mod012 = g_mod3 = opcode.u.group;
+               dt->size = desc_limit_scaled(&desc); /* what if limit > 65535? */
+               dt->address = get_desc_base(&desc);
+       } else
+               ops->get_gdt(dt, ctxt->vcpu);
+}
 
-               c->d &= ~(Group | GroupDual);
+/* allowed just for 8 bytes segments */
+static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt,
+                                  struct x86_emulate_ops *ops,
+                                  u16 selector, struct desc_struct *desc)
+{
+       struct desc_ptr dt;
+       u16 index = selector >> 3;
+       int ret;
+       u32 err;
+       ulong addr;
 
-               goffset = (c->modrm >> 3) & 7;
+       get_descriptor_table_ptr(ctxt, ops, selector, &dt);
 
-               if ((c->modrm >> 6) == 3)
-                       opcode = g_mod3[goffset];
-               else
-                       opcode = g_mod012[goffset];
-               c->d |= opcode.flags;
+       if (dt.size < index * 8 + 7) {
+               emulate_gp(ctxt, selector & 0xfffc);
+               return X86EMUL_PROPAGATE_FAULT;
        }
+       addr = dt.address + index * 8;
+       ret = ops->read_std(addr, desc, sizeof *desc, ctxt->vcpu,  &err);
+       if (ret == X86EMUL_PROPAGATE_FAULT)
+               emulate_pf(ctxt, addr, err);
 
-       c->execute = opcode.u.execute;
+       return ret;
+}
 
-       /* Unrecognised? */
-       if (c->d == 0 || (c->d & Undefined)) {
-               DPRINTF("Cannot emulate %02x\n", c->b);
-               return -1;
-       }
+/* allowed just for 8 bytes segments */
+static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
+                                   struct x86_emulate_ops *ops,
+                                   u16 selector, struct desc_struct *desc)
+{
+       struct desc_ptr dt;
+       u16 index = selector >> 3;
+       u32 err;
+       ulong addr;
+       int ret;
 
-       if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack))
-               c->op_bytes = 8;
+       get_descriptor_table_ptr(ctxt, ops, selector, &dt);
 
-       /* ModRM and SIB bytes. */
-       if (c->d & ModRM)
-               rc = decode_modrm(ctxt, ops);
-       else if (c->d & MemAbs)
-               rc = decode_abs(ctxt, ops);
-       if (rc != X86EMUL_CONTINUE)
-               goto done;
+       if (dt.size < index * 8 + 7) {
+               emulate_gp(ctxt, selector & 0xfffc);
+               return X86EMUL_PROPAGATE_FAULT;
+       }
 
-       if (!c->has_seg_override)
-               set_seg_override(c, VCPU_SREG_DS);
+       addr = dt.address + index * 8;
+       ret = ops->write_std(addr, desc, sizeof *desc, ctxt->vcpu, &err);
+       if (ret == X86EMUL_PROPAGATE_FAULT)
+               emulate_pf(ctxt, addr, err);
 
-       if (!(!c->twobyte && c->b == 0x8d))
-               c->modrm_ea += seg_override_base(ctxt, ops, c);
+       return ret;
+}
 
-       if (c->ad_bytes != 8)
-               c->modrm_ea = (u32)c->modrm_ea;
+static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
+                                  struct x86_emulate_ops *ops,
+                                  u16 selector, int seg)
+{
+       struct desc_struct seg_desc;
+       u8 dpl, rpl, cpl;
+       unsigned err_vec = GP_VECTOR;
+       u32 err_code = 0;
+       bool null_selector = !(selector & ~0x3); /* 0000-0003 are null */
+       int ret;
 
-       if (c->rip_relative)
-               c->modrm_ea += c->eip;
+       memset(&seg_desc, 0, sizeof seg_desc);
 
-       /*
-        * Decode and fetch the source operand: register, memory
-        * or immediate.
-        */
-       switch (c->d & SrcMask) {
-       case SrcNone:
+       if ((seg <= VCPU_SREG_GS && ctxt->mode == X86EMUL_MODE_VM86)
+           || ctxt->mode == X86EMUL_MODE_REAL) {
+               /* set real mode segment descriptor */
+               set_desc_base(&seg_desc, selector << 4);
+               set_desc_limit(&seg_desc, 0xffff);
+               seg_desc.type = 3;
+               seg_desc.p = 1;
+               seg_desc.s = 1;
+               goto load;
+       }
+
+       /* NULL selector is not valid for TR, CS and SS */
+       if ((seg == VCPU_SREG_CS || seg == VCPU_SREG_SS || seg == VCPU_SREG_TR)
+           && null_selector)
+               goto exception;
+
+       /* TR should be in GDT only */
+       if (seg == VCPU_SREG_TR && (selector & (1 << 2)))
+               goto exception;
+
+       if (null_selector) /* for NULL selector skip all following checks */
+               goto load;
+
+       ret = read_segment_descriptor(ctxt, ops, selector, &seg_desc);
+       if (ret != X86EMUL_CONTINUE)
+               return ret;
+
+       err_code = selector & 0xfffc;
+       err_vec = GP_VECTOR;
+
+       /* can't load system descriptor into segment selecor */
+       if (seg <= VCPU_SREG_GS && !seg_desc.s)
+               goto exception;
+
+       if (!seg_desc.p) {
+               err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR;
+               goto exception;
+       }
+
+       rpl = selector & 3;
+       dpl = seg_desc.dpl;
+       cpl = ops->cpl(ctxt->vcpu);
+
+       switch (seg) {
+       case VCPU_SREG_SS:
+               /*
+                * segment is not a writable data segment or segment
+                * selector's RPL != CPL or segment selector's RPL != CPL
+                */
+               if (rpl != cpl || (seg_desc.type & 0xa) != 0x2 || dpl != cpl)
+                       goto exception;
                break;
-       case SrcReg:
-               decode_register_operand(&c->src, c, 0);
+       case VCPU_SREG_CS:
+               if (!(seg_desc.type & 8))
+                       goto exception;
+
+               if (seg_desc.type & 4) {
+                       /* conforming */
+                       if (dpl > cpl)
+                               goto exception;
+               } else {
+                       /* nonconforming */
+                       if (rpl > cpl || dpl != cpl)
+                               goto exception;
+               }
+               /* CS(RPL) <- CPL */
+               selector = (selector & 0xfffc) | cpl;
                break;
-       case SrcMem16:
-               c->src.bytes = 2;
-               goto srcmem_common;
-       case SrcMem32:
-               c->src.bytes = 4;
-               goto srcmem_common;
-       case SrcMem:
-               c->src.bytes = (c->d & ByteOp) ? 1 :
-                                                          c->op_bytes;
-               /* Don't fetch the address for invlpg: it could be unmapped. */
-               if (c->twobyte && c->b == 0x01 && c->modrm_reg == 7)
-                       break;
-       srcmem_common:
+       case VCPU_SREG_TR:
+               if (seg_desc.s || (seg_desc.type != 1 && seg_desc.type != 9))
+                       goto exception;
+               break;
+       case VCPU_SREG_LDTR:
+               if (seg_desc.s || seg_desc.type != 2)
+                       goto exception;
+               break;
+       default: /*  DS, ES, FS, or GS */
                /*
-                * For instructions with a ModR/M byte, switch to register
-                * access if Mod = 3.
+                * segment is not a data or readable code segment or
+                * ((segment is a data or nonconforming code segment)
+                * and (both RPL and CPL > DPL))
                 */
-               if ((c->d & ModRM) && c->modrm_mod == 3) {
-                       c->src.type = OP_REG;
-                       c->src.val = c->modrm_val;
-                       c->src.ptr = c->modrm_ptr;
-                       break;
-               }
-               c->src.type = OP_MEM;
-               c->src.ptr = (unsigned long *)c->modrm_ea;
-               c->src.val = 0;
+               if ((seg_desc.type & 0xa) == 0x8 ||
+                   (((seg_desc.type & 0xc) != 0xc) &&
+                    (rpl > dpl && cpl > dpl)))
+                       goto exception;
                break;
-       case SrcImm:
-       case SrcImmU:
-               c->src.type = OP_IMM;
-               c->src.ptr = (unsigned long *)c->eip;
-               c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               if (c->src.bytes == 8)
-                       c->src.bytes = 4;
-               /* NB. Immediates are sign-extended as necessary. */
-               switch (c->src.bytes) {
+       }
+
+       if (seg_desc.s) {
+               /* mark segment as accessed */
+               seg_desc.type |= 1;
+               ret = write_segment_descriptor(ctxt, ops, selector, &seg_desc);
+               if (ret != X86EMUL_CONTINUE)
+                       return ret;
+       }
+load:
+       ops->set_segment_selector(selector, seg, ctxt->vcpu);
+       ops->set_cached_descriptor(&seg_desc, seg, ctxt->vcpu);
+       return X86EMUL_CONTINUE;
+exception:
+       emulate_exception(ctxt, err_vec, err_code, true);
+       return X86EMUL_PROPAGATE_FAULT;
+}
+
+static inline int writeback(struct x86_emulate_ctxt *ctxt,
+                           struct x86_emulate_ops *ops)
+{
+       int rc;
+       struct decode_cache *c = &ctxt->decode;
+       u32 err;
+
+       switch (c->dst.type) {
+       case OP_REG:
+               /* The 4-byte case *is* correct:
+                * in 64-bit mode we zero-extend.
+                */
+               switch (c->dst.bytes) {
                case 1:
-                       c->src.val = insn_fetch(s8, 1, c->eip);
+                       *(u8 *)c->dst.ptr = (u8)c->dst.val;
                        break;
                case 2:
-                       c->src.val = insn_fetch(s16, 2, c->eip);
+                       *(u16 *)c->dst.ptr = (u16)c->dst.val;
                        break;
                case 4:
-                       c->src.val = insn_fetch(s32, 4, c->eip);
+                       *c->dst.ptr = (u32)c->dst.val;
+                       break;  /* 64b: zero-ext */
+               case 8:
+                       *c->dst.ptr = c->dst.val;
                        break;
                }
-               if ((c->d & SrcMask) == SrcImmU) {
-                       switch (c->src.bytes) {
-                       case 1:
-                               c->src.val &= 0xff;
-                               break;
-                       case 2:
-                               c->src.val &= 0xffff;
-                               break;
-                       case 4:
-                               c->src.val &= 0xffffffff;
-                               break;
-                       }
-               }
                break;
-       case SrcImmByte:
-       case SrcImmUByte:
-               c->src.type = OP_IMM;
-               c->src.ptr = (unsigned long *)c->eip;
-               c->src.bytes = 1;
-               if ((c->d & SrcMask) == SrcImmByte)
-                       c->src.val = insn_fetch(s8, 1, c->eip);
+       case OP_MEM:
+               if (c->lock_prefix)
+                       rc = ops->cmpxchg_emulated(
+                                       (unsigned long)c->dst.ptr,
+                                       &c->dst.orig_val,
+                                       &c->dst.val,
+                                       c->dst.bytes,
+                                       &err,
+                                       ctxt->vcpu);
                else
-                       c->src.val = insn_fetch(u8, 1, c->eip);
-               break;
-       case SrcAcc:
-               c->src.type = OP_REG;
-               c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->src.ptr = &c->regs[VCPU_REGS_RAX];
-               switch (c->src.bytes) {
-                       case 1:
-                               c->src.val = *(u8 *)c->src.ptr;
-                               break;
-                       case 2:
-                               c->src.val = *(u16 *)c->src.ptr;
-                               break;
-                       case 4:
-                               c->src.val = *(u32 *)c->src.ptr;
-                               break;
-                       case 8:
-                               c->src.val = *(u64 *)c->src.ptr;
-                               break;
-               }
-               break;
-       case SrcOne:
-               c->src.bytes = 1;
-               c->src.val = 1;
-               break;
-       case SrcSI:
-               c->src.type = OP_MEM;
-               c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->src.ptr = (unsigned long *)
-                       register_address(c,  seg_override_base(ctxt, ops, c),
-                                        c->regs[VCPU_REGS_RSI]);
-               c->src.val = 0;
+                       rc = ops->write_emulated(
+                                       (unsigned long)c->dst.ptr,
+                                       &c->dst.val,
+                                       c->dst.bytes,
+                                       &err,
+                                       ctxt->vcpu);
+               if (rc == X86EMUL_PROPAGATE_FAULT)
+                       emulate_pf(ctxt,
+                                             (unsigned long)c->dst.ptr, err);
+               if (rc != X86EMUL_CONTINUE)
+                       return rc;
                break;
-       case SrcImmFAddr:
-               c->src.type = OP_IMM;
-               c->src.ptr = (unsigned long *)c->eip;
-               c->src.bytes = c->op_bytes + 2;
-               insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip);
+       case OP_NONE:
+               /* no writeback */
                break;
-       case SrcMemFAddr:
-               c->src.type = OP_MEM;
-               c->src.ptr = (unsigned long *)c->modrm_ea;
-               c->src.bytes = c->op_bytes + 2;
+       default:
                break;
        }
+       return X86EMUL_CONTINUE;
+}
 
-       /*
-        * Decode and fetch the second source operand: register, memory
-        * or immediate.
-        */
-       switch (c->d & Src2Mask) {
-       case Src2None:
-               break;
-       case Src2CL:
-               c->src2.bytes = 1;
-               c->src2.val = c->regs[VCPU_REGS_RCX] & 0x8;
-               break;
-       case Src2ImmByte:
-               c->src2.type = OP_IMM;
-               c->src2.ptr = (unsigned long *)c->eip;
-               c->src2.bytes = 1;
-               c->src2.val = insn_fetch(u8, 1, c->eip);
-               break;
-       case Src2One:
-               c->src2.bytes = 1;
-               c->src2.val = 1;
-               break;
-       }
+static inline void emulate_push(struct x86_emulate_ctxt *ctxt,
+                               struct x86_emulate_ops *ops)
+{
+       struct decode_cache *c = &ctxt->decode;
 
-       /* Decode and fetch the destination operand: register or memory. */
-       switch (c->d & DstMask) {
-       case ImplicitOps:
-               /* Special instructions do their own operand decoding. */
-               return 0;
-       case DstReg:
-               decode_register_operand(&c->dst, c,
-                        c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
-               break;
-       case DstMem:
-       case DstMem64:
-               if ((c->d & ModRM) && c->modrm_mod == 3) {
-                       c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-                       c->dst.type = OP_REG;
-                       c->dst.val = c->dst.orig_val = c->modrm_val;
-                       c->dst.ptr = c->modrm_ptr;
-                       break;
-               }
-               c->dst.type = OP_MEM;
-               c->dst.ptr = (unsigned long *)c->modrm_ea;
-               if ((c->d & DstMask) == DstMem64)
-                       c->dst.bytes = 8;
-               else
-                       c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->dst.val = 0;
-               if (c->d & BitOp) {
-                       unsigned long mask = ~(c->dst.bytes * 8 - 1);
+       c->dst.type  = OP_MEM;
+       c->dst.bytes = c->op_bytes;
+       c->dst.val = c->src.val;
+       register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes);
+       c->dst.ptr = (void *) register_address(c, ss_base(ctxt, ops),
+                                              c->regs[VCPU_REGS_RSP]);
+}
 
-                       c->dst.ptr = (void *)c->dst.ptr +
-                                                  (c->src.val & mask) / 8;
-               }
-               break;
-       case DstAcc:
-               c->dst.type = OP_REG;
-               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->dst.ptr = &c->regs[VCPU_REGS_RAX];
-               switch (c->dst.bytes) {
-                       case 1:
-                               c->dst.val = *(u8 *)c->dst.ptr;
-                               break;
-                       case 2:
-                               c->dst.val = *(u16 *)c->dst.ptr;
-                               break;
-                       case 4:
-                               c->dst.val = *(u32 *)c->dst.ptr;
-                               break;
-                       case 8:
-                               c->dst.val = *(u64 *)c->dst.ptr;
-                               break;
-               }
-               c->dst.orig_val = c->dst.val;
-               break;
-       case DstDI:
-               c->dst.type = OP_MEM;
-               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
-               c->dst.ptr = (unsigned long *)
-                       register_address(c, es_base(ctxt, ops),
-                                        c->regs[VCPU_REGS_RDI]);
-               c->dst.val = 0;
-               break;
-       }
+static int emulate_pop(struct x86_emulate_ctxt *ctxt,
+                      struct x86_emulate_ops *ops,
+                      void *dest, int len)
+{
+       struct decode_cache *c = &ctxt->decode;
+       int rc;
 
-done:
-       return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+       rc = read_emulated(ctxt, ops, register_address(c, ss_base(ctxt, ops),
+                                                      c->regs[VCPU_REGS_RSP]),
+                          dest, len);
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
+
+       register_address_increment(c, &c->regs[VCPU_REGS_RSP], len);
+       return rc;
 }
 
-static int read_emulated(struct x86_emulate_ctxt *ctxt,
-                        struct x86_emulate_ops *ops,
-                        unsigned long addr, void *dest, unsigned size)
+static int emulate_popf(struct x86_emulate_ctxt *ctxt,
+                      struct x86_emulate_ops *ops,
+                      void *dest, int len)
 {
        int rc;
-       struct read_cache *mc = &ctxt->decode.mem_read;
-       u32 err;
+       unsigned long val, change_mask;
+       int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
+       int cpl = ops->cpl(ctxt->vcpu);
 
-       while (size) {
-               int n = min(size, 8u);
-               size -= n;
-               if (mc->pos < mc->end)
-                       goto read_cached;
+       rc = emulate_pop(ctxt, ops, &val, len);
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
 
-               rc = ops->read_emulated(addr, mc->data + mc->end, n, &err,
-                                       ctxt->vcpu);
-               if (rc == X86EMUL_PROPAGATE_FAULT)
-                       emulate_pf(ctxt, addr, err);
-               if (rc != X86EMUL_CONTINUE)
-                       return rc;
-               mc->end += n;
+       change_mask = EFLG_CF | EFLG_PF | EFLG_AF | EFLG_ZF | EFLG_SF | EFLG_OF
+               | EFLG_TF | EFLG_DF | EFLG_NT | EFLG_RF | EFLG_AC | EFLG_ID;
 
-       read_cached:
-               memcpy(dest, mc->data + mc->pos, n);
-               mc->pos += n;
-               dest += n;
-               addr += n;
+       switch(ctxt->mode) {
+       case X86EMUL_MODE_PROT64:
+       case X86EMUL_MODE_PROT32:
+       case X86EMUL_MODE_PROT16:
+               if (cpl == 0)
+                       change_mask |= EFLG_IOPL;
+               if (cpl <= iopl)
+                       change_mask |= EFLG_IF;
+               break;
+       case X86EMUL_MODE_VM86:
+               if (iopl < 3) {
+                       emulate_gp(ctxt, 0);
+                       return X86EMUL_PROPAGATE_FAULT;
+               }
+               change_mask |= EFLG_IF;
+               break;
+       default: /* real mode */
+               change_mask |= (EFLG_IOPL | EFLG_IF);
+               break;
        }
-       return X86EMUL_CONTINUE;
+
+       *(unsigned long *)dest =
+               (ctxt->eflags & ~change_mask) | (val & change_mask);
+
+       return rc;
 }
 
-static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
-                          struct x86_emulate_ops *ops,
-                          unsigned int size, unsigned short port,
-                          void *dest)
+static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt,
+                             struct x86_emulate_ops *ops, int seg)
 {
-       struct read_cache *rc = &ctxt->decode.io_read;
+       struct decode_cache *c = &ctxt->decode;
 
-       if (rc->pos == rc->end) { /* refill pio read ahead */
-               struct decode_cache *c = &ctxt->decode;
-               unsigned int in_page, n;
-               unsigned int count = c->rep_prefix ?
-                       address_mask(c, c->regs[VCPU_REGS_RCX]) : 1;
-               in_page = (ctxt->eflags & EFLG_DF) ?
-                       offset_in_page(c->regs[VCPU_REGS_RDI]) :
-                       PAGE_SIZE - offset_in_page(c->regs[VCPU_REGS_RDI]);
-               n = min(min(in_page, (unsigned int)sizeof(rc->data)) / size,
-                       count);
-               if (n == 0)
-                       n = 1;
-               rc->pos = rc->end = 0;
-               if (!ops->pio_in_emulated(size, port, rc->data, n, ctxt->vcpu))
-                       return 0;
-               rc->end = n * size;
-       }
+       c->src.val = ops->get_segment_selector(seg, ctxt->vcpu);
 
-       memcpy(dest, rc->data + rc->pos, size);
-       rc->pos += size;
-       return 1;
+       emulate_push(ctxt, ops);
 }
 
-static u32 desc_limit_scaled(struct desc_struct *desc)
+static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
+                            struct x86_emulate_ops *ops, int seg)
 {
-       u32 limit = get_desc_limit(desc);
+       struct decode_cache *c = &ctxt->decode;
+       unsigned long selector;
+       int rc;
 
-       return desc->g ? (limit << 12) | 0xfff : limit;
+       rc = emulate_pop(ctxt, ops, &selector, c->op_bytes);
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
+
+       rc = load_segment_descriptor(ctxt, ops, (u16)selector, seg);
+       return rc;
 }
 
-static void get_descriptor_table_ptr(struct x86_emulate_ctxt *ctxt,
-                                    struct x86_emulate_ops *ops,
-                                    u16 selector, struct desc_ptr *dt)
+static int emulate_pusha(struct x86_emulate_ctxt *ctxt,
+                         struct x86_emulate_ops *ops)
 {
-       if (selector & 1 << 2) {
-               struct desc_struct desc;
-               memset (dt, 0, sizeof *dt);
-               if (!ops->get_cached_descriptor(&desc, VCPU_SREG_LDTR, ctxt->vcpu))
-                       return;
+       struct decode_cache *c = &ctxt->decode;
+       unsigned long old_esp = c->regs[VCPU_REGS_RSP];
+       int rc = X86EMUL_CONTINUE;
+       int reg = VCPU_REGS_RAX;
 
-               dt->size = desc_limit_scaled(&desc); /* what if limit > 65535? */
-               dt->address = get_desc_base(&desc);
-       } else
-               ops->get_gdt(dt, ctxt->vcpu);
-}
+       while (reg <= VCPU_REGS_RDI) {
+               (reg == VCPU_REGS_RSP) ?
+               (c->src.val = old_esp) : (c->src.val = c->regs[reg]);
 
-/* allowed just for 8 bytes segments */
-static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt,
-                                  struct x86_emulate_ops *ops,
-                                  u16 selector, struct desc_struct *desc)
-{
-       struct desc_ptr dt;
-       u16 index = selector >> 3;
-       int ret;
-       u32 err;
-       ulong addr;
+               emulate_push(ctxt, ops);
 
-       get_descriptor_table_ptr(ctxt, ops, selector, &dt);
+               rc = writeback(ctxt, ops);
+               if (rc != X86EMUL_CONTINUE)
+                       return rc;
 
-       if (dt.size < index * 8 + 7) {
-               emulate_gp(ctxt, selector & 0xfffc);
-               return X86EMUL_PROPAGATE_FAULT;
+               ++reg;
        }
-       addr = dt.address + index * 8;
-       ret = ops->read_std(addr, desc, sizeof *desc, ctxt->vcpu,  &err);
-       if (ret == X86EMUL_PROPAGATE_FAULT)
-               emulate_pf(ctxt, addr, err);
 
-       return ret;
+       /* Disable writeback. */
+       c->dst.type = OP_NONE;
+
+       return rc;
 }
 
-/* allowed just for 8 bytes segments */
-static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt,
-                                   struct x86_emulate_ops *ops,
-                                   u16 selector, struct desc_struct *desc)
+static int emulate_popa(struct x86_emulate_ctxt *ctxt,
+                       struct x86_emulate_ops *ops)
 {
-       struct desc_ptr dt;
-       u16 index = selector >> 3;
-       u32 err;
-       ulong addr;
-       int ret;
+       struct decode_cache *c = &ctxt->decode;
+       int rc = X86EMUL_CONTINUE;
+       int reg = VCPU_REGS_RDI;
 
-       get_descriptor_table_ptr(ctxt, ops, selector, &dt);
+       while (reg >= VCPU_REGS_RAX) {
+               if (reg == VCPU_REGS_RSP) {
+                       register_address_increment(c, &c->regs[VCPU_REGS_RSP],
+                                                       c->op_bytes);
+                       --reg;
+               }
 
-       if (dt.size < index * 8 + 7) {
-               emulate_gp(ctxt, selector & 0xfffc);
-               return X86EMUL_PROPAGATE_FAULT;
+               rc = emulate_pop(ctxt, ops, &c->regs[reg], c->op_bytes);
+               if (rc != X86EMUL_CONTINUE)
+                       break;
+               --reg;
        }
-
-       addr = dt.address + index * 8;
-       ret = ops->write_std(addr, desc, sizeof *desc, ctxt->vcpu, &err);
-       if (ret == X86EMUL_PROPAGATE_FAULT)
-               emulate_pf(ctxt, addr, err);
-
-       return ret;
+       return rc;
 }
 
-static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
-                                  struct x86_emulate_ops *ops,
-                                  u16 selector, int seg)
+static int emulate_iret_real(struct x86_emulate_ctxt *ctxt,
+                            struct x86_emulate_ops *ops)
 {
-       struct desc_struct seg_desc;
-       u8 dpl, rpl, cpl;
-       unsigned err_vec = GP_VECTOR;
-       u32 err_code = 0;
-       bool null_selector = !(selector & ~0x3); /* 0000-0003 are null */
-       int ret;
+       struct decode_cache *c = &ctxt->decode;
+       int rc = X86EMUL_CONTINUE;
+       unsigned long temp_eip = 0;
+       unsigned long temp_eflags = 0;
+       unsigned long cs = 0;
+       unsigned long mask = EFLG_CF | EFLG_PF | EFLG_AF | EFLG_ZF | EFLG_SF | EFLG_TF |
+                            EFLG_IF | EFLG_DF | EFLG_OF | EFLG_IOPL | EFLG_NT | EFLG_RF |
+                            EFLG_AC | EFLG_ID | (1 << 1); /* Last one is the reserved bit */
+       unsigned long vm86_mask = EFLG_VM | EFLG_VIF | EFLG_VIP;
 
-       memset(&seg_desc, 0, sizeof seg_desc);
+       /* TODO: Add stack limit check */
 
-       if ((seg <= VCPU_SREG_GS && ctxt->mode == X86EMUL_MODE_VM86)
-           || ctxt->mode == X86EMUL_MODE_REAL) {
-               /* set real mode segment descriptor */
-               set_desc_base(&seg_desc, selector << 4);
-               set_desc_limit(&seg_desc, 0xffff);
-               seg_desc.type = 3;
-               seg_desc.p = 1;
-               seg_desc.s = 1;
-               goto load;
-       }
+       rc = emulate_pop(ctxt, ops, &temp_eip, c->op_bytes);
 
-       /* NULL selector is not valid for TR, CS and SS */
-       if ((seg == VCPU_SREG_CS || seg == VCPU_SREG_SS || seg == VCPU_SREG_TR)
-           && null_selector)
-               goto exception;
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
 
-       /* TR should be in GDT only */
-       if (seg == VCPU_SREG_TR && (selector & (1 << 2)))
-               goto exception;
+       if (temp_eip & ~0xffff) {
+               emulate_gp(ctxt, 0);
+               return X86EMUL_PROPAGATE_FAULT;
+       }
 
-       if (null_selector) /* for NULL selector skip all following checks */
-               goto load;
+       rc = emulate_pop(ctxt, ops, &cs, c->op_bytes);
 
-       ret = read_segment_descriptor(ctxt, ops, selector, &seg_desc);
-       if (ret != X86EMUL_CONTINUE)
-               return ret;
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
 
-       err_code = selector & 0xfffc;
-       err_vec = GP_VECTOR;
+       rc = emulate_pop(ctxt, ops, &temp_eflags, c->op_bytes);
 
-       /* can't load system descriptor into segment selecor */
-       if (seg <= VCPU_SREG_GS && !seg_desc.s)
-               goto exception;
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
 
-       if (!seg_desc.p) {
-               err_vec = (seg == VCPU_SREG_SS) ? SS_VECTOR : NP_VECTOR;
-               goto exception;
-       }
+       rc = load_segment_descriptor(ctxt, ops, (u16)cs, VCPU_SREG_CS);
 
-       rpl = selector & 3;
-       dpl = seg_desc.dpl;
-       cpl = ops->cpl(ctxt->vcpu);
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
 
-       switch (seg) {
-       case VCPU_SREG_SS:
-               /*
-                * segment is not a writable data segment or segment
-                * selector's RPL != CPL or segment selector's RPL != CPL
-                */
-               if (rpl != cpl || (seg_desc.type & 0xa) != 0x2 || dpl != cpl)
-                       goto exception;
-               break;
-       case VCPU_SREG_CS:
-               if (!(seg_desc.type & 8))
-                       goto exception;
+       c->eip = temp_eip;
 
-               if (seg_desc.type & 4) {
-                       /* conforming */
-                       if (dpl > cpl)
-                               goto exception;
-               } else {
-                       /* nonconforming */
-                       if (rpl > cpl || dpl != cpl)
-                               goto exception;
-               }
-               /* CS(RPL) <- CPL */
-               selector = (selector & 0xfffc) | cpl;
-               break;
-       case VCPU_SREG_TR:
-               if (seg_desc.s || (seg_desc.type != 1 && seg_desc.type != 9))
-                       goto exception;
-               break;
-       case VCPU_SREG_LDTR:
-               if (seg_desc.s || seg_desc.type != 2)
-                       goto exception;
-               break;
-       default: /*  DS, ES, FS, or GS */
-               /*
-                * segment is not a data or readable code segment or
-                * ((segment is a data or nonconforming code segment)
-                * and (both RPL and CPL > DPL))
-                */
-               if ((seg_desc.type & 0xa) == 0x8 ||
-                   (((seg_desc.type & 0xc) != 0xc) &&
-                    (rpl > dpl && cpl > dpl)))
-                       goto exception;
-               break;
-       }
 
-       if (seg_desc.s) {
-               /* mark segment as accessed */
-               seg_desc.type |= 1;
-               ret = write_segment_descriptor(ctxt, ops, selector, &seg_desc);
-               if (ret != X86EMUL_CONTINUE)
-                       return ret;
+       if (c->op_bytes == 4)
+               ctxt->eflags = ((temp_eflags & mask) | (ctxt->eflags & vm86_mask));
+       else if (c->op_bytes == 2) {
+               ctxt->eflags &= ~0xffff;
+               ctxt->eflags |= temp_eflags;
        }
-load:
-       ops->set_segment_selector(selector, seg, ctxt->vcpu);
-       ops->set_cached_descriptor(&seg_desc, seg, ctxt->vcpu);
-       return X86EMUL_CONTINUE;
-exception:
-       emulate_exception(ctxt, err_vec, err_code, true);
-       return X86EMUL_PROPAGATE_FAULT;
+
+       ctxt->eflags &= ~EFLG_RESERVED_ZEROS_MASK; /* Clear reserved zeros */
+       ctxt->eflags |= EFLG_RESERVED_ONE_MASK;
+
+       return rc;
 }
 
-static inline int writeback(struct x86_emulate_ctxt *ctxt,
-                           struct x86_emulate_ops *ops)
+static inline int emulate_iret(struct x86_emulate_ctxt *ctxt,
+                                   struct x86_emulate_ops* ops)
 {
-       int rc;
-       struct decode_cache *c = &ctxt->decode;
-       u32 err;
-
-       switch (c->dst.type) {
-       case OP_REG:
-               /* The 4-byte case *is* correct:
-                * in 64-bit mode we zero-extend.
-                */
-               switch (c->dst.bytes) {
-               case 1:
-                       *(u8 *)c->dst.ptr = (u8)c->dst.val;
-                       break;
-               case 2:
-                       *(u16 *)c->dst.ptr = (u16)c->dst.val;
-                       break;
-               case 4:
-                       *c->dst.ptr = (u32)c->dst.val;
-                       break;  /* 64b: zero-ext */
-               case 8:
-                       *c->dst.ptr = c->dst.val;
-                       break;
-               }
-               break;
-       case OP_MEM:
-               if (c->lock_prefix)
-                       rc = ops->cmpxchg_emulated(
-                                       (unsigned long)c->dst.ptr,
-                                       &c->dst.orig_val,
-                                       &c->dst.val,
-                                       c->dst.bytes,
-                                       &err,
-                                       ctxt->vcpu);
-               else
-                       rc = ops->write_emulated(
-                                       (unsigned long)c->dst.ptr,
-                                       &c->dst.val,
-                                       c->dst.bytes,
-                                       &err,
-                                       ctxt->vcpu);
-               if (rc == X86EMUL_PROPAGATE_FAULT)
-                       emulate_pf(ctxt,
-                                             (unsigned long)c->dst.ptr, err);
-               if (rc != X86EMUL_CONTINUE)
-                       return rc;
-               break;
-       case OP_NONE:
-               /* no writeback */
-               break;
+       switch(ctxt->mode) {
+       case X86EMUL_MODE_REAL:
+               return emulate_iret_real(ctxt, ops);
+       case X86EMUL_MODE_VM86:
+       case X86EMUL_MODE_PROT16:
+       case X86EMUL_MODE_PROT32:
+       case X86EMUL_MODE_PROT64:
        default:
-               break;
+               /* iret from protected mode unimplemented yet */
+               return X86EMUL_UNHANDLEABLE;
        }
-       return X86EMUL_CONTINUE;
 }
 
-static inline void emulate_push(struct x86_emulate_ctxt *ctxt,
+static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
                                struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
 
-       c->dst.type  = OP_MEM;
-       c->dst.bytes = c->op_bytes;
-       c->dst.val = c->src.val;
-       register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes);
-       c->dst.ptr = (void *) register_address(c, ss_base(ctxt, ops),
-                                              c->regs[VCPU_REGS_RSP]);
+       return emulate_pop(ctxt, ops, &c->dst.val, c->dst.bytes);
 }
 
-static int emulate_pop(struct x86_emulate_ctxt *ctxt,
-                      struct x86_emulate_ops *ops,
-                      void *dest, int len)
-{
-       struct decode_cache *c = &ctxt->decode;
-       int rc;
-
-       rc = read_emulated(ctxt, ops, register_address(c, ss_base(ctxt, ops),
-                                                      c->regs[VCPU_REGS_RSP]),
-                          dest, len);
-       if (rc != X86EMUL_CONTINUE)
-               return rc;
-
-       register_address_increment(c, &c->regs[VCPU_REGS_RSP], len);
-       return rc;
-}
-
-static int emulate_popf(struct x86_emulate_ctxt *ctxt,
-                      struct x86_emulate_ops *ops,
-                      void *dest, int len)
-{
-       int rc;
-       unsigned long val, change_mask;
-       int iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
-       int cpl = ops->cpl(ctxt->vcpu);
-
-       rc = emulate_pop(ctxt, ops, &val, len);
-       if (rc != X86EMUL_CONTINUE)
-               return rc;
-
-       change_mask = EFLG_CF | EFLG_PF | EFLG_AF | EFLG_ZF | EFLG_SF | EFLG_OF
-               | EFLG_TF | EFLG_DF | EFLG_NT | EFLG_RF | EFLG_AC | EFLG_ID;
-
-       switch(ctxt->mode) {
-       case X86EMUL_MODE_PROT64:
-       case X86EMUL_MODE_PROT32:
-       case X86EMUL_MODE_PROT16:
-               if (cpl == 0)
-                       change_mask |= EFLG_IOPL;
-               if (cpl <= iopl)
-                       change_mask |= EFLG_IF;
-               break;
-       case X86EMUL_MODE_VM86:
-               if (iopl < 3) {
-                       emulate_gp(ctxt, 0);
-                       return X86EMUL_PROPAGATE_FAULT;
-               }
-               change_mask |= EFLG_IF;
-               break;
-       default: /* real mode */
-               change_mask |= (EFLG_IOPL | EFLG_IF);
-               break;
-       }
-
-       *(unsigned long *)dest =
-               (ctxt->eflags & ~change_mask) | (val & change_mask);
-
-       return rc;
-}
-
-static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt,
-                             struct x86_emulate_ops *ops, int seg)
-{
-       struct decode_cache *c = &ctxt->decode;
-
-       c->src.val = ops->get_segment_selector(seg, ctxt->vcpu);
-
-       emulate_push(ctxt, ops);
-}
-
-static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
-                            struct x86_emulate_ops *ops, int seg)
-{
-       struct decode_cache *c = &ctxt->decode;
-       unsigned long selector;
-       int rc;
-
-       rc = emulate_pop(ctxt, ops, &selector, c->op_bytes);
-       if (rc != X86EMUL_CONTINUE)
-               return rc;
-
-       rc = load_segment_descriptor(ctxt, ops, (u16)selector, seg);
-       return rc;
-}
-
-static int emulate_pusha(struct x86_emulate_ctxt *ctxt,
-                         struct x86_emulate_ops *ops)
-{
-       struct decode_cache *c = &ctxt->decode;
-       unsigned long old_esp = c->regs[VCPU_REGS_RSP];
-       int rc = X86EMUL_CONTINUE;
-       int reg = VCPU_REGS_RAX;
-
-       while (reg <= VCPU_REGS_RDI) {
-               (reg == VCPU_REGS_RSP) ?
-               (c->src.val = old_esp) : (c->src.val = c->regs[reg]);
-
-               emulate_push(ctxt, ops);
-
-               rc = writeback(ctxt, ops);
-               if (rc != X86EMUL_CONTINUE)
-                       return rc;
-
-               ++reg;
-       }
-
-       /* Disable writeback. */
-       c->dst.type = OP_NONE;
-
-       return rc;
-}
-
-static int emulate_popa(struct x86_emulate_ctxt *ctxt,
-                       struct x86_emulate_ops *ops)
-{
-       struct decode_cache *c = &ctxt->decode;
-       int rc = X86EMUL_CONTINUE;
-       int reg = VCPU_REGS_RDI;
-
-       while (reg >= VCPU_REGS_RAX) {
-               if (reg == VCPU_REGS_RSP) {
-                       register_address_increment(c, &c->regs[VCPU_REGS_RSP],
-                                                       c->op_bytes);
-                       --reg;
-               }
-
-               rc = emulate_pop(ctxt, ops, &c->regs[reg], c->op_bytes);
-               if (rc != X86EMUL_CONTINUE)
-                       break;
-               --reg;
-       }
-       return rc;
-}
-
-static int emulate_iret_real(struct x86_emulate_ctxt *ctxt,
-                            struct x86_emulate_ops *ops)
-{
-       struct decode_cache *c = &ctxt->decode;
-       int rc = X86EMUL_CONTINUE;
-       unsigned long temp_eip = 0;
-       unsigned long temp_eflags = 0;
-       unsigned long cs = 0;
-       unsigned long mask = EFLG_CF | EFLG_PF | EFLG_AF | EFLG_ZF | EFLG_SF | EFLG_TF |
-                            EFLG_IF | EFLG_DF | EFLG_OF | EFLG_IOPL | EFLG_NT | EFLG_RF |
-                            EFLG_AC | EFLG_ID | (1 << 1); /* Last one is the reserved bit */
-       unsigned long vm86_mask = EFLG_VM | EFLG_VIF | EFLG_VIP;
-
-       /* TODO: Add stack limit check */
-
-       rc = emulate_pop(ctxt, ops, &temp_eip, c->op_bytes);
-
-       if (rc != X86EMUL_CONTINUE)
-               return rc;
-
-       if (temp_eip & ~0xffff) {
-               emulate_gp(ctxt, 0);
-               return X86EMUL_PROPAGATE_FAULT;
-       }
-
-       rc = emulate_pop(ctxt, ops, &cs, c->op_bytes);
-
-       if (rc != X86EMUL_CONTINUE)
-               return rc;
-
-       rc = emulate_pop(ctxt, ops, &temp_eflags, c->op_bytes);
-
-       if (rc != X86EMUL_CONTINUE)
-               return rc;
-
-       rc = load_segment_descriptor(ctxt, ops, (u16)cs, VCPU_SREG_CS);
-
-       if (rc != X86EMUL_CONTINUE)
-               return rc;
-
-       c->eip = temp_eip;
-
-
-       if (c->op_bytes == 4)
-               ctxt->eflags = ((temp_eflags & mask) | (ctxt->eflags & vm86_mask));
-       else if (c->op_bytes == 2) {
-               ctxt->eflags &= ~0xffff;
-               ctxt->eflags |= temp_eflags;
-       }
-
-       ctxt->eflags &= ~EFLG_RESERVED_ZEROS_MASK; /* Clear reserved zeros */
-       ctxt->eflags |= EFLG_RESERVED_ONE_MASK;
-
-       return rc;
-}
-
-static inline int emulate_iret(struct x86_emulate_ctxt *ctxt,
-                                   struct x86_emulate_ops* ops)
-{
-       switch(ctxt->mode) {
-       case X86EMUL_MODE_REAL:
-               return emulate_iret_real(ctxt, ops);
-       case X86EMUL_MODE_VM86:
-       case X86EMUL_MODE_PROT16:
-       case X86EMUL_MODE_PROT32:
-       case X86EMUL_MODE_PROT64:
-       default:
-               /* iret from protected mode unimplemented yet */
-               return X86EMUL_UNHANDLEABLE;
-       }
-}
-
-static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
-                               struct x86_emulate_ops *ops)
-{
-       struct decode_cache *c = &ctxt->decode;
-
-       return emulate_pop(ctxt, ops, &c->dst.val, c->dst.bytes);
-}
-
-static inline void emulate_grp2(struct x86_emulate_ctxt *ctxt)
+static inline void emulate_grp2(struct x86_emulate_ctxt *ctxt)
 {
        struct decode_cache *c = &ctxt->decode;
        switch (c->modrm_reg) {
@@ -2624,6 +2252,378 @@ static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned long base,
        op->ptr = (unsigned long *)register_address(c,  base, c->regs[reg]);
 }
 
+int
+x86_decode_insn(struct x86_emulate_ctxt *ctxt)
+{
+       struct x86_emulate_ops *ops = ctxt->ops;
+       struct decode_cache *c = &ctxt->decode;
+       int rc = X86EMUL_CONTINUE;
+       int mode = ctxt->mode;
+       int def_op_bytes, def_ad_bytes, dual, goffset;
+       struct opcode opcode, *g_mod012, *g_mod3;
+
+       /* we cannot decode insn before we complete previous rep insn */
+       WARN_ON(ctxt->restart);
+
+       c->eip = ctxt->eip;
+       c->fetch.start = c->fetch.end = c->eip;
+       ctxt->cs_base = seg_base(ctxt, ops, VCPU_SREG_CS);
+
+       switch (mode) {
+       case X86EMUL_MODE_REAL:
+       case X86EMUL_MODE_VM86:
+       case X86EMUL_MODE_PROT16:
+               def_op_bytes = def_ad_bytes = 2;
+               break;
+       case X86EMUL_MODE_PROT32:
+               def_op_bytes = def_ad_bytes = 4;
+               break;
+#ifdef CONFIG_X86_64
+       case X86EMUL_MODE_PROT64:
+               def_op_bytes = 4;
+               def_ad_bytes = 8;
+               break;
+#endif
+       default:
+               return -1;
+       }
+
+       c->op_bytes = def_op_bytes;
+       c->ad_bytes = def_ad_bytes;
+
+       /* Legacy prefixes. */
+       for (;;) {
+               switch (c->b = insn_fetch(u8, 1, c->eip)) {
+               case 0x66:      /* operand-size override */
+                       /* switch between 2/4 bytes */
+                       c->op_bytes = def_op_bytes ^ 6;
+                       break;
+               case 0x67:      /* address-size override */
+                       if (mode == X86EMUL_MODE_PROT64)
+                               /* switch between 4/8 bytes */
+                               c->ad_bytes = def_ad_bytes ^ 12;
+                       else
+                               /* switch between 2/4 bytes */
+                               c->ad_bytes = def_ad_bytes ^ 6;
+                       break;
+               case 0x26:      /* ES override */
+               case 0x2e:      /* CS override */
+               case 0x36:      /* SS override */
+               case 0x3e:      /* DS override */
+                       set_seg_override(c, (c->b >> 3) & 3);
+                       break;
+               case 0x64:      /* FS override */
+               case 0x65:      /* GS override */
+                       set_seg_override(c, c->b & 7);
+                       break;
+               case 0x40 ... 0x4f: /* REX */
+                       if (mode != X86EMUL_MODE_PROT64)
+                               goto done_prefixes;
+                       c->rex_prefix = c->b;
+                       continue;
+               case 0xf0:      /* LOCK */
+                       c->lock_prefix = 1;
+                       break;
+               case 0xf2:      /* REPNE/REPNZ */
+                       c->rep_prefix = REPNE_PREFIX;
+                       break;
+               case 0xf3:      /* REP/REPE/REPZ */
+                       c->rep_prefix = REPE_PREFIX;
+                       break;
+               default:
+                       goto done_prefixes;
+               }
+
+               /* Any legacy prefix after a REX prefix nullifies its effect. */
+
+               c->rex_prefix = 0;
+       }
+
+done_prefixes:
+
+       /* REX prefix. */
+       if (c->rex_prefix)
+               if (c->rex_prefix & 8)
+                       c->op_bytes = 8;        /* REX.W */
+
+       /* Opcode byte(s). */
+       opcode = opcode_table[c->b];
+       if (opcode.flags == 0) {
+               /* Two-byte opcode? */
+               if (c->b == 0x0f) {
+                       c->twobyte = 1;
+                       c->b = insn_fetch(u8, 1, c->eip);
+                       opcode = twobyte_table[c->b];
+               }
+       }
+       c->d = opcode.flags;
+
+       if (c->d & Group) {
+               dual = c->d & GroupDual;
+               c->modrm = insn_fetch(u8, 1, c->eip);
+               --c->eip;
+
+               if (c->d & GroupDual) {
+                       g_mod012 = opcode.u.gdual->mod012;
+                       g_mod3 = opcode.u.gdual->mod3;
+               } else
+                       g_mod012 = g_mod3 = opcode.u.group;
+
+               c->d &= ~(Group | GroupDual);
+
+               goffset = (c->modrm >> 3) & 7;
+
+               if ((c->modrm >> 6) == 3)
+                       opcode = g_mod3[goffset];
+               else
+                       opcode = g_mod012[goffset];
+               c->d |= opcode.flags;
+       }
+
+       c->execute = opcode.u.execute;
+
+       /* Unrecognised? */
+       if (c->d == 0 || (c->d & Undefined)) {
+               DPRINTF("Cannot emulate %02x\n", c->b);
+               return -1;
+       }
+
+       if (mode == X86EMUL_MODE_PROT64 && (c->d & Stack))
+               c->op_bytes = 8;
+
+       /* ModRM and SIB bytes. */
+       if (c->d & ModRM)
+               rc = decode_modrm(ctxt, ops);
+       else if (c->d & MemAbs)
+               rc = decode_abs(ctxt, ops);
+       if (rc != X86EMUL_CONTINUE)
+               goto done;
+
+       if (!c->has_seg_override)
+               set_seg_override(c, VCPU_SREG_DS);
+
+       if (!(!c->twobyte && c->b == 0x8d))
+               c->modrm_ea += seg_override_base(ctxt, ops, c);
+
+       if (c->ad_bytes != 8)
+               c->modrm_ea = (u32)c->modrm_ea;
+
+       if (c->rip_relative)
+               c->modrm_ea += c->eip;
+
+       /*
+        * Decode and fetch the source operand: register, memory
+        * or immediate.
+        */
+       switch (c->d & SrcMask) {
+       case SrcNone:
+               break;
+       case SrcReg:
+               decode_register_operand(&c->src, c, 0);
+               break;
+       case SrcMem16:
+               c->src.bytes = 2;
+               goto srcmem_common;
+       case SrcMem32:
+               c->src.bytes = 4;
+               goto srcmem_common;
+       case SrcMem:
+               c->src.bytes = (c->d & ByteOp) ? 1 :
+                                                          c->op_bytes;
+               /* Don't fetch the address for invlpg: it could be unmapped. */
+               if (c->twobyte && c->b == 0x01 && c->modrm_reg == 7)
+                       break;
+       srcmem_common:
+               /*
+                * For instructions with a ModR/M byte, switch to register
+                * access if Mod = 3.
+                */
+               if ((c->d & ModRM) && c->modrm_mod == 3) {
+                       c->src.type = OP_REG;
+                       c->src.val = c->modrm_val;
+                       c->src.ptr = c->modrm_ptr;
+                       break;
+               }
+               c->src.type = OP_MEM;
+               c->src.ptr = (unsigned long *)c->modrm_ea;
+               c->src.val = 0;
+               break;
+       case SrcImm:
+       case SrcImmU:
+               c->src.type = OP_IMM;
+               c->src.ptr = (unsigned long *)c->eip;
+               c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+               if (c->src.bytes == 8)
+                       c->src.bytes = 4;
+               /* NB. Immediates are sign-extended as necessary. */
+               switch (c->src.bytes) {
+               case 1:
+                       c->src.val = insn_fetch(s8, 1, c->eip);
+                       break;
+               case 2:
+                       c->src.val = insn_fetch(s16, 2, c->eip);
+                       break;
+               case 4:
+                       c->src.val = insn_fetch(s32, 4, c->eip);
+                       break;
+               }
+               if ((c->d & SrcMask) == SrcImmU) {
+                       switch (c->src.bytes) {
+                       case 1:
+                               c->src.val &= 0xff;
+                               break;
+                       case 2:
+                               c->src.val &= 0xffff;
+                               break;
+                       case 4:
+                               c->src.val &= 0xffffffff;
+                               break;
+                       }
+               }
+               break;
+       case SrcImmByte:
+       case SrcImmUByte:
+               c->src.type = OP_IMM;
+               c->src.ptr = (unsigned long *)c->eip;
+               c->src.bytes = 1;
+               if ((c->d & SrcMask) == SrcImmByte)
+                       c->src.val = insn_fetch(s8, 1, c->eip);
+               else
+                       c->src.val = insn_fetch(u8, 1, c->eip);
+               break;
+       case SrcAcc:
+               c->src.type = OP_REG;
+               c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+               c->src.ptr = &c->regs[VCPU_REGS_RAX];
+               switch (c->src.bytes) {
+                       case 1:
+                               c->src.val = *(u8 *)c->src.ptr;
+                               break;
+                       case 2:
+                               c->src.val = *(u16 *)c->src.ptr;
+                               break;
+                       case 4:
+                               c->src.val = *(u32 *)c->src.ptr;
+                               break;
+                       case 8:
+                               c->src.val = *(u64 *)c->src.ptr;
+                               break;
+               }
+               break;
+       case SrcOne:
+               c->src.bytes = 1;
+               c->src.val = 1;
+               break;
+       case SrcSI:
+               c->src.type = OP_MEM;
+               c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+               c->src.ptr = (unsigned long *)
+                       register_address(c,  seg_override_base(ctxt, ops, c),
+                                        c->regs[VCPU_REGS_RSI]);
+               c->src.val = 0;
+               break;
+       case SrcImmFAddr:
+               c->src.type = OP_IMM;
+               c->src.ptr = (unsigned long *)c->eip;
+               c->src.bytes = c->op_bytes + 2;
+               insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip);
+               break;
+       case SrcMemFAddr:
+               c->src.type = OP_MEM;
+               c->src.ptr = (unsigned long *)c->modrm_ea;
+               c->src.bytes = c->op_bytes + 2;
+               break;
+       }
+
+       /*
+        * Decode and fetch the second source operand: register, memory
+        * or immediate.
+        */
+       switch (c->d & Src2Mask) {
+       case Src2None:
+               break;
+       case Src2CL:
+               c->src2.bytes = 1;
+               c->src2.val = c->regs[VCPU_REGS_RCX] & 0x8;
+               break;
+       case Src2ImmByte:
+               c->src2.type = OP_IMM;
+               c->src2.ptr = (unsigned long *)c->eip;
+               c->src2.bytes = 1;
+               c->src2.val = insn_fetch(u8, 1, c->eip);
+               break;
+       case Src2One:
+               c->src2.bytes = 1;
+               c->src2.val = 1;
+               break;
+       }
+
+       /* Decode and fetch the destination operand: register or memory. */
+       switch (c->d & DstMask) {
+       case ImplicitOps:
+               /* Special instructions do their own operand decoding. */
+               return 0;
+       case DstReg:
+               decode_register_operand(&c->dst, c,
+                        c->twobyte && (c->b == 0xb6 || c->b == 0xb7));
+               break;
+       case DstMem:
+       case DstMem64:
+               if ((c->d & ModRM) && c->modrm_mod == 3) {
+                       c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+                       c->dst.type = OP_REG;
+                       c->dst.val = c->dst.orig_val = c->modrm_val;
+                       c->dst.ptr = c->modrm_ptr;
+                       break;
+               }
+               c->dst.type = OP_MEM;
+               c->dst.ptr = (unsigned long *)c->modrm_ea;
+               if ((c->d & DstMask) == DstMem64)
+                       c->dst.bytes = 8;
+               else
+                       c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+               c->dst.val = 0;
+               if (c->d & BitOp) {
+                       unsigned long mask = ~(c->dst.bytes * 8 - 1);
+
+                       c->dst.ptr = (void *)c->dst.ptr +
+                                                  (c->src.val & mask) / 8;
+               }
+               break;
+       case DstAcc:
+               c->dst.type = OP_REG;
+               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+               c->dst.ptr = &c->regs[VCPU_REGS_RAX];
+               switch (c->dst.bytes) {
+                       case 1:
+                               c->dst.val = *(u8 *)c->dst.ptr;
+                               break;
+                       case 2:
+                               c->dst.val = *(u16 *)c->dst.ptr;
+                               break;
+                       case 4:
+                               c->dst.val = *(u32 *)c->dst.ptr;
+                               break;
+                       case 8:
+                               c->dst.val = *(u64 *)c->dst.ptr;
+                               break;
+               }
+               c->dst.orig_val = c->dst.val;
+               break;
+       case DstDI:
+               c->dst.type = OP_MEM;
+               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
+               c->dst.ptr = (unsigned long *)
+                       register_address(c, es_base(ctxt, ops),
+                                        c->regs[VCPU_REGS_RDI]);
+               c->dst.val = 0;
+               break;
+       }
+
+done:
+       return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
+}
+
 int
 x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
 {