KVM: x86 emulator: fix 0f 01 /5 emulation
[safe/jmp/linux-2.6] / arch / x86 / kvm / emulate.c
index 1f0ff4a..7c7debb 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/module.h>
 #include <asm/kvm_emulate.h>
 
-#include "mmu.h"               /* for is_long_mode() */
+#include "x86.h"
 
 /*
  * Opcode effective-address decode tables.
@@ -76,6 +76,8 @@
 #define GroupDual   (1<<15)     /* Alternate decoding of mod == 3 */
 #define GroupMask   0xff        /* Group number stored in bits 0:7 */
 /* Misc flags */
+#define Lock        (1<<26) /* lock prefix is allowed for the instruction */
+#define Priv        (1<<27) /* instruction generates #GP if current CPL != 0 */
 #define No64       (1<<28)
 /* Source 2 operand type */
 #define Src2None    (0<<29)
 #define Src2ImmByte (2<<29)
 #define Src2One     (3<<29)
 #define Src2Imm16   (4<<29)
+#define Src2Mem16   (5<<29) /* Used for Ep encoding. First argument has to be
+                              in memory and second argument is located
+                              immediately after the first one in memory. */
 #define Src2Mask    (7<<29)
 
 enum {
        Group1_80, Group1_81, Group1_82, Group1_83,
        Group1A, Group3_Byte, Group3, Group4, Group5, Group7,
+       Group8, Group9,
 };
 
 static u32 opcode_table[256] = {
        /* 0x00 - 0x07 */
-       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
        ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
        ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
        /* 0x08 - 0x0F */
-       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
-       0, 0, ImplicitOps | Stack | No64, 0,
+       ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
+       ImplicitOps | Stack | No64, 0,
        /* 0x10 - 0x17 */
-       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
        ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
        ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
        /* 0x18 - 0x1F */
-       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
        ByteOp | DstAcc | SrcImm, DstAcc | SrcImm,
        ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
        /* 0x20 - 0x27 */
-       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
        DstAcc | SrcImmByte, DstAcc | SrcImm, 0, 0,
        /* 0x28 - 0x2F */
-       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
        0, 0, 0, 0,
        /* 0x30 - 0x37 */
-       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
        ByteOp | DstReg | SrcMem | ModRM, DstReg | SrcMem | ModRM,
        0, 0, 0, 0,
        /* 0x38 - 0x3F */
@@ -138,7 +145,8 @@ static u32 opcode_table[256] = {
        DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack,
        DstReg | Stack, DstReg | Stack, DstReg | Stack, DstReg | Stack,
        /* 0x60 - 0x67 */
-       0, 0, 0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
+       ImplicitOps | Stack | No64, ImplicitOps | Stack | No64,
+       0, DstReg | SrcMem32 | ModRM | Mov /* movsxd (x86/64) */ ,
        0, 0, 0, 0,
        /* 0x68 - 0x6F */
        SrcImm | Mov | Stack, 0, SrcImmByte | Mov | Stack, 0,
@@ -154,7 +162,7 @@ static u32 opcode_table[256] = {
        Group | Group1_80, Group | Group1_81,
        Group | Group1_82, Group | Group1_83,
        ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
-       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM,
+       ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
        /* 0x88 - 0x8F */
        ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
        ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
@@ -208,7 +216,7 @@ static u32 opcode_table[256] = {
        SrcNone | ByteOp | ImplicitOps, SrcNone | ImplicitOps,
        /* 0xF0 - 0xF7 */
        0, 0, 0, 0,
-       ImplicitOps, ImplicitOps, Group | Group3_Byte, Group | Group3,
+       ImplicitOps | Priv, ImplicitOps, Group | Group3_Byte, Group | Group3,
        /* 0xF8 - 0xFF */
        ImplicitOps, 0, ImplicitOps, ImplicitOps,
        ImplicitOps, ImplicitOps, Group | Group4, Group | Group5,
@@ -216,16 +224,20 @@ static u32 opcode_table[256] = {
 
 static u32 twobyte_table[256] = {
        /* 0x00 - 0x0F */
-       0, Group | GroupDual | Group7, 0, 0, 0, ImplicitOps, ImplicitOps, 0,
-       ImplicitOps, ImplicitOps, 0, 0, 0, ImplicitOps | ModRM, 0, 0,
+       0, Group | GroupDual | Group7, 0, 0,
+       0, ImplicitOps, ImplicitOps | Priv, 0,
+       ImplicitOps | Priv, ImplicitOps | Priv, 0, 0,
+       0, ImplicitOps | ModRM, 0, 0,
        /* 0x10 - 0x1F */
        0, 0, 0, 0, 0, 0, 0, 0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0, 0,
        /* 0x20 - 0x2F */
-       ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
+       ModRM | ImplicitOps | Priv, ModRM | Priv,
+       ModRM | ImplicitOps | Priv, ModRM | Priv,
+       0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        /* 0x30 - 0x3F */
-       ImplicitOps, 0, ImplicitOps, 0,
-       ImplicitOps, ImplicitOps, 0, 0,
+       ImplicitOps | Priv, 0, ImplicitOps | Priv, 0,
+       ImplicitOps, ImplicitOps | Priv, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        /* 0x40 - 0x47 */
        DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
@@ -255,21 +267,23 @@ static u32 twobyte_table[256] = {
        DstMem | SrcReg | Src2CL | ModRM, 0, 0,
        /* 0xA8 - 0xAF */
        ImplicitOps | Stack, ImplicitOps | Stack,
-       0, DstMem | SrcReg | ModRM | BitOp,
+       0, DstMem | SrcReg | ModRM | BitOp | Lock,
        DstMem | SrcReg | Src2ImmByte | ModRM,
        DstMem | SrcReg | Src2CL | ModRM,
        ModRM, 0,
        /* 0xB0 - 0xB7 */
-       ByteOp | DstMem | SrcReg | ModRM, DstMem | SrcReg | ModRM, 0,
-           DstMem | SrcReg | ModRM | BitOp,
+       ByteOp | DstMem | SrcReg | ModRM | Lock, DstMem | SrcReg | ModRM | Lock,
+       0, DstMem | SrcReg | ModRM | BitOp | Lock,
        0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
            DstReg | SrcMem16 | ModRM | Mov,
        /* 0xB8 - 0xBF */
-       0, 0, DstMem | SrcImmByte | ModRM, DstMem | SrcReg | ModRM | BitOp,
+       0, 0,
+       Group | Group8, DstMem | SrcReg | ModRM | BitOp | Lock,
        0, 0, ByteOp | DstReg | SrcMem | ModRM | Mov,
            DstReg | SrcMem16 | ModRM | Mov,
        /* 0xC0 - 0xCF */
-       0, 0, 0, DstMem | SrcReg | ModRM | Mov, 0, 0, 0, ImplicitOps | ModRM,
+       0, 0, 0, DstMem | SrcReg | ModRM | Mov,
+       0, 0, 0, Group | GroupDual | Group9,
        0, 0, 0, 0, 0, 0, 0, 0,
        /* 0xD0 - 0xDF */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -281,25 +295,41 @@ static u32 twobyte_table[256] = {
 
 static u32 group_table[] = {
        [Group1_80*8] =
-       ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
-       ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
-       ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
-       ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
+       ByteOp | DstMem | SrcImm | ModRM | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | Lock,
+       ByteOp | DstMem | SrcImm | ModRM,
        [Group1_81*8] =
-       DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
-       DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
-       DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
-       DstMem | SrcImm | ModRM, DstMem | SrcImm | ModRM,
+       DstMem | SrcImm | ModRM | Lock,
+       DstMem | SrcImm | ModRM | Lock,
+       DstMem | SrcImm | ModRM | Lock,
+       DstMem | SrcImm | ModRM | Lock,
+       DstMem | SrcImm | ModRM | Lock,
+       DstMem | SrcImm | ModRM | Lock,
+       DstMem | SrcImm | ModRM | Lock,
+       DstMem | SrcImm | ModRM,
        [Group1_82*8] =
-       ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
-       ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
-       ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
-       ByteOp | DstMem | SrcImm | ModRM, ByteOp | DstMem | SrcImm | ModRM,
+       ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | No64 | Lock,
+       ByteOp | DstMem | SrcImm | ModRM | No64,
        [Group1_83*8] =
-       DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM,
-       DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM,
-       DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM,
-       DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM,
+       DstMem | SrcImmByte | ModRM | Lock,
+       DstMem | SrcImmByte | ModRM | Lock,
+       DstMem | SrcImmByte | ModRM | Lock,
+       DstMem | SrcImmByte | ModRM | Lock,
+       DstMem | SrcImmByte | ModRM | Lock,
+       DstMem | SrcImmByte | ModRM | Lock,
+       DstMem | SrcImmByte | ModRM | Lock,
+       DstMem | SrcImmByte | ModRM,
        [Group1A*8] =
        DstMem | SrcNone | ModRM | Mov | Stack, 0, 0, 0, 0, 0, 0, 0,
        [Group3_Byte*8] =
@@ -316,26 +346,42 @@ static u32 group_table[] = {
        [Group5*8] =
        DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
        SrcMem | ModRM | Stack, 0,
-       SrcMem | ModRM | Stack, 0, SrcMem | ModRM | Stack, 0,
+       SrcMem | ModRM | Stack, SrcMem | ModRM | Src2Mem16 | ImplicitOps,
+       SrcMem | ModRM | Stack, 0,
        [Group7*8] =
-       0, 0, ModRM | SrcMem, ModRM | SrcMem,
+       0, 0, ModRM | SrcMem | Priv, ModRM | SrcMem | Priv,
        SrcNone | ModRM | DstMem | Mov, 0,
-       SrcMem16 | ModRM | Mov, SrcMem | ModRM | ByteOp,
+       SrcMem16 | ModRM | Mov | Priv, SrcMem | ModRM | ByteOp | Priv,
+       [Group8*8] =
+       0, 0, 0, 0,
+       DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM | Lock,
+       DstMem | SrcImmByte | ModRM | Lock, DstMem | SrcImmByte | ModRM | Lock,
+       [Group9*8] =
+       0, ImplicitOps | ModRM | Lock, 0, 0, 0, 0, 0, 0,
 };
 
 static u32 group2_table[] = {
        [Group7*8] =
-       SrcNone | ModRM, 0, 0, SrcNone | ModRM,
+       SrcNone | ModRM | Priv, 0, 0, SrcNone | ModRM | Priv,
        SrcNone | ModRM | DstMem | Mov, 0,
-       SrcMem16 | ModRM | Mov, 0,
+       SrcMem16 | ModRM | Mov | Priv, 0,
+       [Group9*8] =
+       0, 0, 0, 0, 0, 0, 0, 0,
 };
 
 /* EFLAGS bit definitions. */
+#define EFLG_ID (1<<21)
+#define EFLG_VIP (1<<20)
+#define EFLG_VIF (1<<19)
+#define EFLG_AC (1<<18)
 #define EFLG_VM (1<<17)
 #define EFLG_RF (1<<16)
+#define EFLG_IOPL (3<<12)
+#define EFLG_NT (1<<14)
 #define EFLG_OF (1<<11)
 #define EFLG_DF (1<<10)
 #define EFLG_IF (1<<9)
+#define EFLG_TF (1<<8)
 #define EFLG_SF (1<<7)
 #define EFLG_ZF (1<<6)
 #define EFLG_AF (1<<4)
@@ -520,7 +566,7 @@ static u32 group2_table[] = {
 #define insn_fetch(_type, _size, _eip)                                  \
 ({     unsigned long _x;                                               \
        rc = do_insn_fetch(ctxt, ops, (_eip), &_x, (_size));            \
-       if (rc != 0)                                                    \
+       if (rc != X86EMUL_CONTINUE)                                     \
                goto done;                                              \
        (_eip) += (_size);                                              \
        (_type)_x;                                                      \
@@ -604,29 +650,32 @@ static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
 
        if (linear < fc->start || linear >= fc->end) {
                size = min(15UL, PAGE_SIZE - offset_in_page(linear));
-               rc = ops->read_std(linear, fc->data, size, ctxt->vcpu);
-               if (rc)
+               rc = ops->fetch(linear, fc->data, size, ctxt->vcpu, NULL);
+               if (rc != X86EMUL_CONTINUE)
                        return rc;
                fc->start = linear;
                fc->end = linear + size;
        }
        *dest = fc->data[linear - fc->start];
-       return 0;
+       return X86EMUL_CONTINUE;
 }
 
 static int do_insn_fetch(struct x86_emulate_ctxt *ctxt,
                         struct x86_emulate_ops *ops,
                         unsigned long eip, void *dest, unsigned size)
 {
-       int rc = 0;
+       int rc;
 
+       /* x86 instructions are limited to 15 bytes. */
+       if (eip + size - ctxt->eip > 15)
+               return X86EMUL_UNHANDLEABLE;
        eip += ctxt->cs_base;
        while (size--) {
                rc = do_fetch_insn_byte(ctxt, ops, eip++, dest++);
-               if (rc)
+               if (rc != X86EMUL_CONTINUE)
                        return rc;
        }
-       return 0;
+       return X86EMUL_CONTINUE;
 }
 
 /*
@@ -656,11 +705,11 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt,
                op_bytes = 3;
        *address = 0;
        rc = ops->read_std((unsigned long)ptr, (unsigned long *)size, 2,
-                          ctxt->vcpu);
-       if (rc)
+                          ctxt->vcpu, NULL);
+       if (rc != X86EMUL_CONTINUE)
                return rc;
        rc = ops->read_std((unsigned long)ptr + 2, address, op_bytes,
-                          ctxt->vcpu);
+                          ctxt->vcpu, NULL);
        return rc;
 }
 
@@ -737,7 +786,7 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
        struct decode_cache *c = &ctxt->decode;
        u8 sib;
        int index_reg = 0, base_reg = 0, scale;
-       int rc = 0;
+       int rc = X86EMUL_CONTINUE;
 
        if (c->rex_prefix) {
                c->modrm_reg = (c->rex_prefix & 4) << 1;        /* REX.R */
@@ -850,7 +899,7 @@ static int decode_abs(struct x86_emulate_ctxt *ctxt,
                      struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
-       int rc = 0;
+       int rc = X86EMUL_CONTINUE;
 
        switch (c->ad_bytes) {
        case 2:
@@ -871,19 +920,20 @@ int
 x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
-       int rc = 0;
+       int rc = X86EMUL_CONTINUE;
        int mode = ctxt->mode;
        int def_op_bytes, def_ad_bytes, group;
 
        /* Shadow copy of register state. Committed on successful emulation. */
 
        memset(c, 0, sizeof(struct decode_cache));
-       c->eip = kvm_rip_read(ctxt->vcpu);
+       c->eip = ctxt->eip;
        ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS);
        memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
 
        switch (mode) {
        case X86EMUL_MODE_REAL:
+       case X86EMUL_MODE_VM86:
        case X86EMUL_MODE_PROT16:
                def_op_bytes = def_ad_bytes = 2;
                break;
@@ -969,11 +1019,6 @@ done_prefixes:
                }
        }
 
-       if (mode == X86EMUL_MODE_PROT64 && (c->d & No64)) {
-               kvm_report_emulation_failure(ctxt->vcpu, "invalid x86/64 instruction");;
-               return -1;
-       }
-
        if (c->d & Group) {
                group = c->d & GroupMask;
                c->modrm = insn_fetch(u8, 1, c->eip);
@@ -1000,7 +1045,7 @@ done_prefixes:
                rc = decode_modrm(ctxt, ops);
        else if (c->d & MemAbs)
                rc = decode_abs(ctxt, ops);
-       if (rc)
+       if (rc != X86EMUL_CONTINUE)
                goto done;
 
        if (!c->has_seg_override)
@@ -1122,6 +1167,10 @@ done_prefixes:
                c->src2.bytes = 1;
                c->src2.val = 1;
                break;
+       case Src2Mem16:
+               c->src2.bytes = 2;
+               c->src2.type = OP_MEM;
+               break;
        }
 
        /* Decode and fetch the destination operand: register or memory. */
@@ -1145,9 +1194,9 @@ done_prefixes:
                break;
        case DstAcc:
                c->dst.type = OP_REG;
-               c->dst.bytes = c->op_bytes;
+               c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
                c->dst.ptr = &c->regs[VCPU_REGS_RAX];
-               switch (c->op_bytes) {
+               switch (c->dst.bytes) {
                        case 1:
                                c->dst.val = *(u8 *)c->dst.ptr;
                                break;
@@ -1157,6 +1206,9 @@ done_prefixes:
                        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;
@@ -1191,13 +1243,56 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
        rc = ops->read_emulated(register_address(c, ss_base(ctxt),
                                                 c->regs[VCPU_REGS_RSP]),
                                dest, len, ctxt->vcpu);
-       if (rc != 0)
+       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) {
+                       kvm_inject_gp(ctxt->vcpu, 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, int seg)
 {
        struct decode_cache *c = &ctxt->decode;
@@ -1217,10 +1312,47 @@ static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
        int rc;
 
        rc = emulate_pop(ctxt, ops, &selector, c->op_bytes);
-       if (rc != 0)
+       if (rc != X86EMUL_CONTINUE)
                return rc;
 
-       rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)selector, 1, seg);
+       rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)selector, seg);
+       return rc;
+}
+
+static void emulate_pusha(struct x86_emulate_ctxt *ctxt)
+{
+       struct decode_cache *c = &ctxt->decode;
+       unsigned long old_esp = c->regs[VCPU_REGS_RSP];
+       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);
+               ++reg;
+       }
+}
+
+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;
 }
 
@@ -1228,12 +1360,8 @@ static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
                                struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
-       int rc;
 
-       rc = emulate_pop(ctxt, ops, &c->dst.val, c->dst.bytes);
-       if (rc != 0)
-               return rc;
-       return 0;
+       return emulate_pop(ctxt, ops, &c->dst.val, c->dst.bytes);
 }
 
 static inline void emulate_grp2(struct x86_emulate_ctxt *ctxt)
@@ -1269,7 +1397,7 @@ static inline int emulate_grp3(struct x86_emulate_ctxt *ctxt,
                               struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
-       int rc = 0;
+       int rc = X86EMUL_CONTINUE;
 
        switch (c->modrm_reg) {
        case 0 ... 1:   /* test */
@@ -1316,7 +1444,7 @@ static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt,
                emulate_push(ctxt);
                break;
        }
-       return 0;
+       return X86EMUL_CONTINUE;
 }
 
 static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt,
@@ -1328,7 +1456,7 @@ static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt,
        int rc;
 
        rc = ops->read_emulated(memop, &old, 8, ctxt->vcpu);
-       if (rc != 0)
+       if (rc != X86EMUL_CONTINUE)
                return rc;
 
        if (((u32) (old >> 0) != (u32) c->regs[VCPU_REGS_RAX]) ||
@@ -1343,11 +1471,11 @@ static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt,
                       (u32) c->regs[VCPU_REGS_RBX];
 
                rc = ops->cmpxchg_emulated(memop, &old, &new, 8, ctxt->vcpu);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        return rc;
                ctxt->eflags |= EFLG_ZF;
        }
-       return 0;
+       return X86EMUL_CONTINUE;
 }
 
 static int emulate_ret_far(struct x86_emulate_ctxt *ctxt,
@@ -1358,14 +1486,14 @@ static int emulate_ret_far(struct x86_emulate_ctxt *ctxt,
        unsigned long cs;
 
        rc = emulate_pop(ctxt, ops, &c->eip, c->op_bytes);
-       if (rc)
+       if (rc != X86EMUL_CONTINUE)
                return rc;
        if (c->op_bytes == 4)
                c->eip = (u32)c->eip;
        rc = emulate_pop(ctxt, ops, &cs, c->op_bytes);
-       if (rc)
+       if (rc != X86EMUL_CONTINUE)
                return rc;
-       rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)cs, 1, VCPU_SREG_CS);
+       rc = kvm_load_segment_descriptor(ctxt->vcpu, (u16)cs, VCPU_SREG_CS);
        return rc;
 }
 
@@ -1409,7 +1537,7 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt,
                                        &c->dst.val,
                                        c->dst.bytes,
                                        ctxt->vcpu);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        return rc;
                break;
        case OP_NONE:
@@ -1418,7 +1546,7 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt,
        default:
                break;
        }
-       return 0;
+       return X86EMUL_CONTINUE;
 }
 
 static void toggle_interruptibility(struct x86_emulate_ctxt *ctxt, u32 mask)
@@ -1472,9 +1600,8 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
        u64 msr_data;
 
        /* syscall is not available in real mode */
-       if (c->lock_prefix || ctxt->mode == X86EMUL_MODE_REAL
-               || !(ctxt->vcpu->arch.cr0 & X86_CR0_PE))
-               return -1;
+       if (ctxt->mode == X86EMUL_MODE_REAL || ctxt->mode == X86EMUL_MODE_VM86)
+               return X86EMUL_UNHANDLEABLE;
 
        setup_syscalls_segments(ctxt, &cs, &ss);
 
@@ -1511,7 +1638,7 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
                ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
        }
 
-       return 0;
+       return X86EMUL_CONTINUE;
 }
 
 static int
@@ -1521,22 +1648,17 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
        struct kvm_segment cs, ss;
        u64 msr_data;
 
-       /* inject #UD if LOCK prefix is used */
-       if (c->lock_prefix)
-               return -1;
-
-       /* inject #GP if in real mode or paging is disabled */
-       if (ctxt->mode == X86EMUL_MODE_REAL ||
-               !(ctxt->vcpu->arch.cr0 & X86_CR0_PE)) {
+       /* inject #GP if in real mode */
+       if (ctxt->mode == X86EMUL_MODE_REAL) {
                kvm_inject_gp(ctxt->vcpu, 0);
-               return -1;
+               return X86EMUL_UNHANDLEABLE;
        }
 
        /* XXX sysenter/sysexit have not been tested in 64bit mode.
        * Therefore, we inject an #UD.
        */
        if (ctxt->mode == X86EMUL_MODE_PROT64)
-               return -1;
+               return X86EMUL_UNHANDLEABLE;
 
        setup_syscalls_segments(ctxt, &cs, &ss);
 
@@ -1545,13 +1667,13 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
        case X86EMUL_MODE_PROT32:
                if ((msr_data & 0xfffc) == 0x0) {
                        kvm_inject_gp(ctxt->vcpu, 0);
-                       return -1;
+                       return X86EMUL_PROPAGATE_FAULT;
                }
                break;
        case X86EMUL_MODE_PROT64:
                if (msr_data == 0x0) {
                        kvm_inject_gp(ctxt->vcpu, 0);
-                       return -1;
+                       return X86EMUL_PROPAGATE_FAULT;
                }
                break;
        }
@@ -1576,7 +1698,7 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
        kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data);
        c->regs[VCPU_REGS_RSP] = msr_data;
 
-       return 0;
+       return X86EMUL_CONTINUE;
 }
 
 static int
@@ -1587,21 +1709,11 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
        u64 msr_data;
        int usermode;
 
-       /* inject #UD if LOCK prefix is used */
-       if (c->lock_prefix)
-               return -1;
-
-       /* inject #GP if in real mode or paging is disabled */
-       if (ctxt->mode == X86EMUL_MODE_REAL
-               || !(ctxt->vcpu->arch.cr0 & X86_CR0_PE)) {
-               kvm_inject_gp(ctxt->vcpu, 0);
-               return -1;
-       }
-
-       /* sysexit must be called from CPL 0 */
-       if (kvm_x86_ops->get_cpl(ctxt->vcpu) != 0) {
+       /* inject #GP if in real mode or Virtual 8086 mode */
+       if (ctxt->mode == X86EMUL_MODE_REAL ||
+           ctxt->mode == X86EMUL_MODE_VM86) {
                kvm_inject_gp(ctxt->vcpu, 0);
-               return -1;
+               return X86EMUL_UNHANDLEABLE;
        }
 
        setup_syscalls_segments(ctxt, &cs, &ss);
@@ -1619,7 +1731,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
                cs.selector = (u16)(msr_data + 16);
                if ((msr_data & 0xfffc) == 0x0) {
                        kvm_inject_gp(ctxt->vcpu, 0);
-                       return -1;
+                       return X86EMUL_PROPAGATE_FAULT;
                }
                ss.selector = (u16)(msr_data + 24);
                break;
@@ -1627,7 +1739,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
                cs.selector = (u16)(msr_data + 32);
                if (msr_data == 0x0) {
                        kvm_inject_gp(ctxt->vcpu, 0);
-                       return -1;
+                       return X86EMUL_PROPAGATE_FAULT;
                }
                ss.selector = cs.selector + 8;
                cs.db = 0;
@@ -1643,7 +1755,59 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
        c->eip = ctxt->vcpu->arch.regs[VCPU_REGS_RDX];
        c->regs[VCPU_REGS_RSP] = ctxt->vcpu->arch.regs[VCPU_REGS_RCX];
 
-       return 0;
+       return X86EMUL_CONTINUE;
+}
+
+static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt,
+                             struct x86_emulate_ops *ops)
+{
+       int iopl;
+       if (ctxt->mode == X86EMUL_MODE_REAL)
+               return false;
+       if (ctxt->mode == X86EMUL_MODE_VM86)
+               return true;
+       iopl = (ctxt->eflags & X86_EFLAGS_IOPL) >> IOPL_SHIFT;
+       return ops->cpl(ctxt->vcpu) > iopl;
+}
+
+static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
+                                           struct x86_emulate_ops *ops,
+                                           u16 port, u16 len)
+{
+       struct kvm_segment tr_seg;
+       int r;
+       u16 io_bitmap_ptr;
+       u8 perm, bit_idx = port & 0x7;
+       unsigned mask = (1 << len) - 1;
+
+       kvm_get_segment(ctxt->vcpu, &tr_seg, VCPU_SREG_TR);
+       if (tr_seg.unusable)
+               return false;
+       if (tr_seg.limit < 103)
+               return false;
+       r = ops->read_std(tr_seg.base + 102, &io_bitmap_ptr, 2, ctxt->vcpu,
+                         NULL);
+       if (r != X86EMUL_CONTINUE)
+               return false;
+       if (io_bitmap_ptr + port/8 > tr_seg.limit)
+               return false;
+       r = ops->read_std(tr_seg.base + io_bitmap_ptr + port/8, &perm, 1,
+                         ctxt->vcpu, NULL);
+       if (r != X86EMUL_CONTINUE)
+               return false;
+       if ((perm >> bit_idx) & mask)
+               return false;
+       return true;
+}
+
+static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
+                                struct x86_emulate_ops *ops,
+                                u16 port, u16 len)
+{
+       if (emulator_bad_iopl(ctxt, ops))
+               if (!emulator_io_port_access_allowed(ctxt, ops, port, len))
+                       return false;
+       return true;
 }
 
 int
@@ -1655,7 +1819,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
        struct decode_cache *c = &ctxt->decode;
        unsigned int port;
        int io_dir_in;
-       int rc = 0;
+       int rc = X86EMUL_CONTINUE;
 
        ctxt->interruptibility = 0;
 
@@ -1667,12 +1831,29 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
        memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
        saved_eip = c->eip;
 
+       if (ctxt->mode == X86EMUL_MODE_PROT64 && (c->d & No64)) {
+               kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+               goto done;
+       }
+
+       /* LOCK prefix is allowed only with some instructions */
+       if (c->lock_prefix && !(c->d & Lock)) {
+               kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+               goto done;
+       }
+
+       /* Privileged instruction can be executed only in CPL=0 */
+       if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) {
+               kvm_inject_gp(ctxt->vcpu, 0);
+               goto done;
+       }
+
        if (((c->d & ModRM) && (c->modrm_mod != 3)) || (c->d & MemAbs))
                memop = c->modrm_ea;
 
        if (c->rep_prefix && (c->d & String)) {
                /* All REP prefixes have the same first termination condition */
-               if (c->regs[VCPU_REGS_RCX] == 0) {
+               if (address_mask(c, c->regs[VCPU_REGS_RCX]) == 0) {
                        kvm_rip_write(ctxt->vcpu, c->eip);
                        goto done;
                }
@@ -1696,8 +1877,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
                                goto done;
                        }
                }
-               c->regs[VCPU_REGS_RCX]--;
-               c->eip = kvm_rip_read(ctxt->vcpu);
+               register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
+               c->eip = ctxt->eip;
        }
 
        if (c->src.type == OP_MEM) {
@@ -1707,11 +1888,22 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
                                        &c->src.val,
                                        c->src.bytes,
                                        ctxt->vcpu);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                c->src.orig_val = c->src.val;
        }
 
+       if (c->src2.type == OP_MEM) {
+               c->src2.ptr = (unsigned long *)(memop + c->src.bytes);
+               c->src2.val = 0;
+               rc = ops->read_emulated((unsigned long)c->src2.ptr,
+                                       &c->src2.val,
+                                       c->src2.bytes,
+                                       ctxt->vcpu);
+               if (rc != X86EMUL_CONTINUE)
+                       goto done;
+       }
+
        if ((c->d & DstMask) == ImplicitOps)
                goto special_insn;
 
@@ -1726,12 +1918,15 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
                        c->dst.ptr = (void *)c->dst.ptr +
                                                   (c->src.val & mask) / 8;
                }
-               if (!(c->d & Mov) &&
-                                  /* optimisation - avoid slow emulated read */
-                   ((rc = ops->read_emulated((unsigned long)c->dst.ptr,
-                                          &c->dst.val,
-                                         c->dst.bytes, ctxt->vcpu)) != 0))
-                       goto done;
+               if (!(c->d & Mov)) {
+                       /* optimisation - avoid slow emulated read */
+                       rc = ops->read_emulated((unsigned long)c->dst.ptr,
+                                               &c->dst.val,
+                                               c->dst.bytes,
+                                               ctxt->vcpu);
+                       if (rc != X86EMUL_CONTINUE)
+                               goto done;
+               }
        }
        c->dst.orig_val = c->dst.val;
 
@@ -1750,7 +1945,7 @@ special_insn:
                break;
        case 0x07:              /* pop es */
                rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0x08 ... 0x0d:
@@ -1769,7 +1964,7 @@ special_insn:
                break;
        case 0x17:              /* pop ss */
                rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0x18 ... 0x1d:
@@ -1781,7 +1976,7 @@ special_insn:
                break;
        case 0x1f:              /* pop ds */
                rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0x20 ... 0x25:
@@ -1812,7 +2007,15 @@ special_insn:
        case 0x58 ... 0x5f: /* pop reg */
        pop_instruction:
                rc = emulate_pop(ctxt, ops, &c->dst.val, c->op_bytes);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
+                       goto done;
+               break;
+       case 0x60:      /* pusha */
+               emulate_pusha(ctxt);
+               break;
+       case 0x61:      /* popa */
+               rc = emulate_popa(ctxt, ops);
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0x63:              /* movsxd */
@@ -1826,7 +2029,12 @@ special_insn:
                break;
        case 0x6c:              /* insb */
        case 0x6d:              /* insw/insd */
-                if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+               if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
+                                         (c->d & ByteOp) ? 1 : c->op_bytes)) {
+                       kvm_inject_gp(ctxt->vcpu, 0);
+                       goto done;
+               }
+               if (kvm_emulate_pio_string(ctxt->vcpu,
                                1,
                                (c->d & ByteOp) ? 1 : c->op_bytes,
                                c->rep_prefix ?
@@ -1842,7 +2050,12 @@ special_insn:
                return 0;
        case 0x6e:              /* outsb */
        case 0x6f:              /* outsw/outsd */
-               if (kvm_emulate_pio_string(ctxt->vcpu, NULL,
+               if (!emulator_io_permited(ctxt, ops, c->regs[VCPU_REGS_RDX],
+                                         (c->d & ByteOp) ? 1 : c->op_bytes)) {
+                       kvm_inject_gp(ctxt->vcpu, 0);
+                       goto done;
+               }
+               if (kvm_emulate_pio_string(ctxt->vcpu,
                                0,
                                (c->d & ByteOp) ? 1 : c->op_bytes,
                                c->rep_prefix ?
@@ -1913,12 +2126,11 @@ special_insn:
        case 0x8c: { /* mov r/m, sreg */
                struct kvm_segment segreg;
 
-               if (c->modrm_reg <= 5)
+               if (c->modrm_reg <= VCPU_SREG_GS)
                        kvm_get_segment(ctxt->vcpu, &segreg, c->modrm_reg);
                else {
-                       printk(KERN_INFO "0x8c: Invalid segreg in modrm byte 0x%02x\n",
-                              c->modrm);
-                       goto cannot_emulate;
+                       kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+                       goto done;
                }
                c->dst.val = segreg.selector;
                break;
@@ -1928,32 +2140,26 @@ special_insn:
                break;
        case 0x8e: { /* mov seg, r/m16 */
                uint16_t sel;
-               int type_bits;
-               int err;
 
                sel = c->src.val;
-               if (c->modrm_reg == VCPU_SREG_SS)
-                       toggle_interruptibility(ctxt, X86_SHADOW_INT_MOV_SS);
 
-               if (c->modrm_reg <= 5) {
-                       type_bits = (c->modrm_reg == 1) ? 9 : 1;
-                       err = kvm_load_segment_descriptor(ctxt->vcpu, sel,
-                                                         type_bits, c->modrm_reg);
-               } else {
-                       printk(KERN_INFO "Invalid segreg in modrm byte 0x%02x\n",
-                                       c->modrm);
-                       goto cannot_emulate;
+               if (c->modrm_reg == VCPU_SREG_CS ||
+                   c->modrm_reg > VCPU_SREG_GS) {
+                       kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+                       goto done;
                }
 
-               if (err < 0)
-                       goto cannot_emulate;
+               if (c->modrm_reg == VCPU_SREG_SS)
+                       toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_MOV_SS);
+
+               rc = kvm_load_segment_descriptor(ctxt->vcpu, sel, c->modrm_reg);
 
                c->dst.type = OP_NONE;  /* Disable writeback. */
                break;
        }
        case 0x8f:              /* pop (sole member of Grp1a) */
                rc = emulate_grp1a(ctxt, ops);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0x90: /* nop / xchg r8,rax */
@@ -1975,7 +2181,10 @@ special_insn:
                c->dst.type = OP_REG;
                c->dst.ptr = (unsigned long *) &ctxt->eflags;
                c->dst.bytes = c->op_bytes;
-               goto pop_instruction;
+               rc = emulate_popf(ctxt, ops, &c->dst.val, c->op_bytes);
+               if (rc != X86EMUL_CONTINUE)
+                       goto done;
+               break;
        case 0xa0 ... 0xa1:     /* mov */
                c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
                c->dst.val = c->src.val;
@@ -1989,11 +2198,12 @@ special_insn:
                c->dst.ptr = (unsigned long *)register_address(c,
                                                   es_base(ctxt),
                                                   c->regs[VCPU_REGS_RDI]);
-               if ((rc = ops->read_emulated(register_address(c,
-                                          seg_override_base(ctxt, c),
-                                       c->regs[VCPU_REGS_RSI]),
+               rc = ops->read_emulated(register_address(c,
+                                               seg_override_base(ctxt, c),
+                                               c->regs[VCPU_REGS_RSI]),
                                        &c->dst.val,
-                                       c->dst.bytes, ctxt->vcpu)) != 0)
+                                       c->dst.bytes, ctxt->vcpu);
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                register_address_increment(c, &c->regs[VCPU_REGS_RSI],
                                       (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
@@ -2008,10 +2218,11 @@ special_insn:
                c->src.ptr = (unsigned long *)register_address(c,
                                       seg_override_base(ctxt, c),
                                                   c->regs[VCPU_REGS_RSI]);
-               if ((rc = ops->read_emulated((unsigned long)c->src.ptr,
-                                               &c->src.val,
-                                               c->src.bytes,
-                                               ctxt->vcpu)) != 0)
+               rc = ops->read_emulated((unsigned long)c->src.ptr,
+                                       &c->src.val,
+                                       c->src.bytes,
+                                       ctxt->vcpu);
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
 
                c->dst.type = OP_NONE; /* Disable writeback. */
@@ -2019,10 +2230,11 @@ special_insn:
                c->dst.ptr = (unsigned long *)register_address(c,
                                                   es_base(ctxt),
                                                   c->regs[VCPU_REGS_RDI]);
-               if ((rc = ops->read_emulated((unsigned long)c->dst.ptr,
-                                               &c->dst.val,
-                                               c->dst.bytes,
-                                               ctxt->vcpu)) != 0)
+               rc = ops->read_emulated((unsigned long)c->dst.ptr,
+                                       &c->dst.val,
+                                       c->dst.bytes,
+                                       ctxt->vcpu);
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
 
                DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr);
@@ -2052,12 +2264,13 @@ special_insn:
                c->dst.type = OP_REG;
                c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
                c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
-               if ((rc = ops->read_emulated(register_address(c,
-                                                seg_override_base(ctxt, c),
-                                                c->regs[VCPU_REGS_RSI]),
-                                                &c->dst.val,
-                                                c->dst.bytes,
-                                                ctxt->vcpu)) != 0)
+               rc = ops->read_emulated(register_address(c,
+                                               seg_override_base(ctxt, c),
+                                               c->regs[VCPU_REGS_RSI]),
+                                       &c->dst.val,
+                                       c->dst.bytes,
+                                       ctxt->vcpu);
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                register_address_increment(c, &c->regs[VCPU_REGS_RSI],
                                       (ctxt->eflags & EFLG_DF) ? -c->dst.bytes
@@ -2082,7 +2295,7 @@ special_insn:
                break;
        case 0xcb:              /* ret far */
                rc = emulate_ret_far(ctxt, ops);
-               if (rc)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0xd0 ... 0xd1:     /* Grp2 */
@@ -2113,11 +2326,10 @@ special_insn:
        case 0xe9: /* jmp rel */
                goto jmp;
        case 0xea: /* jmp far */
-               if (kvm_load_segment_descriptor(ctxt->vcpu, c->src2.val, 9,
-                                       VCPU_SREG_CS) < 0) {
-                       DPRINTF("jmp far: Failed to load CS descriptor\n");
-                       goto cannot_emulate;
-               }
+       jump_far:
+               if (kvm_load_segment_descriptor(ctxt->vcpu, c->src2.val,
+                                               VCPU_SREG_CS))
+                       goto done;
 
                c->eip = c->src.val;
                break;
@@ -2135,7 +2347,13 @@ special_insn:
        case 0xef: /* out (e/r)ax,dx */
                port = c->regs[VCPU_REGS_RDX];
                io_dir_in = 0;
-       do_io:  if (kvm_emulate_pio(ctxt->vcpu, NULL, io_dir_in,
+       do_io:
+               if (!emulator_io_permited(ctxt, ops, port,
+                                         (c->d & ByteOp) ? 1 : c->op_bytes)) {
+                       kvm_inject_gp(ctxt->vcpu, 0);
+                       goto done;
+               }
+               if (kvm_emulate_pio(ctxt->vcpu, io_dir_in,
                                   (c->d & ByteOp) ? 1 : c->op_bytes,
                                   port) != 0) {
                        c->eip = saved_eip;
@@ -2152,7 +2370,7 @@ special_insn:
                break;
        case 0xf6 ... 0xf7:     /* Grp3 */
                rc = emulate_grp3(ctxt, ops);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0xf8: /* clc */
@@ -2160,13 +2378,21 @@ special_insn:
                c->dst.type = OP_NONE;  /* Disable writeback. */
                break;
        case 0xfa: /* cli */
-               ctxt->eflags &= ~X86_EFLAGS_IF;
-               c->dst.type = OP_NONE;  /* Disable writeback. */
+               if (emulator_bad_iopl(ctxt, ops))
+                       kvm_inject_gp(ctxt->vcpu, 0);
+               else {
+                       ctxt->eflags &= ~X86_EFLAGS_IF;
+                       c->dst.type = OP_NONE;  /* Disable writeback. */
+               }
                break;
        case 0xfb: /* sti */
-               toggle_interruptibility(ctxt, X86_SHADOW_INT_STI);
-               ctxt->eflags |= X86_EFLAGS_IF;
-               c->dst.type = OP_NONE;  /* Disable writeback. */
+               if (emulator_bad_iopl(ctxt, ops))
+                       kvm_inject_gp(ctxt->vcpu, 0);
+               else {
+                       toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_STI);
+                       ctxt->eflags |= X86_EFLAGS_IF;
+                       c->dst.type = OP_NONE;  /* Disable writeback. */
+               }
                break;
        case 0xfc: /* cld */
                ctxt->eflags &= ~EFLG_DF;
@@ -2176,16 +2402,21 @@ special_insn:
                ctxt->eflags |= EFLG_DF;
                c->dst.type = OP_NONE;  /* Disable writeback. */
                break;
-       case 0xfe ... 0xff:     /* Grp4/Grp5 */
+       case 0xfe: /* Grp4 */
+       grp45:
                rc = emulate_grp45(ctxt, ops);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
+       case 0xff: /* Grp5 */
+               if (c->modrm_reg == 5)
+                       goto jump_far;
+               goto grp45;
        }
 
 writeback:
        rc = writeback(ctxt, ops);
-       if (rc != 0)
+       if (rc != X86EMUL_CONTINUE)
                goto done;
 
        /* Commit shadow register state. */
@@ -2211,18 +2442,18 @@ twobyte_insn:
                                goto cannot_emulate;
 
                        rc = kvm_fix_hypercall(ctxt->vcpu);
-                       if (rc)
+                       if (rc != X86EMUL_CONTINUE)
                                goto done;
 
                        /* Let the processor re-execute the fixed hypercall */
-                       c->eip = kvm_rip_read(ctxt->vcpu);
+                       c->eip = ctxt->eip;
                        /* Disable writeback. */
                        c->dst.type = OP_NONE;
                        break;
                case 2: /* lgdt */
                        rc = read_descriptor(ctxt, ops, c->src.ptr,
                                             &size, &address, c->op_bytes);
-                       if (rc)
+                       if (rc != X86EMUL_CONTINUE)
                                goto done;
                        realmode_lgdt(ctxt->vcpu, size, address);
                        /* Disable writeback. */
@@ -2233,7 +2464,7 @@ twobyte_insn:
                                switch (c->modrm_rm) {
                                case 1:
                                        rc = kvm_fix_hypercall(ctxt->vcpu);
-                                       if (rc)
+                                       if (rc != X86EMUL_CONTINUE)
                                                goto done;
                                        break;
                                default:
@@ -2243,7 +2474,7 @@ twobyte_insn:
                                rc = read_descriptor(ctxt, ops, c->src.ptr,
                                                     &size, &address,
                                                     c->op_bytes);
-                               if (rc)
+                               if (rc != X86EMUL_CONTINUE)
                                        goto done;
                                realmode_lidt(ctxt->vcpu, size, address);
                        }
@@ -2252,13 +2483,16 @@ twobyte_insn:
                        break;
                case 4: /* smsw */
                        c->dst.bytes = 2;
-                       c->dst.val = realmode_get_cr(ctxt->vcpu, 0);
+                       c->dst.val = ops->get_cr(0, ctxt->vcpu);
                        break;
                case 6: /* lmsw */
-                       realmode_lmsw(ctxt->vcpu, (u16)c->src.val,
-                                     &ctxt->eflags);
+                       ops->set_cr(0, (ops->get_cr(0, ctxt->vcpu) & ~0x0ful) |
+                                   (c->src.val & 0x0f), ctxt->vcpu);
                        c->dst.type = OP_NONE;
                        break;
+               case 5: /* not defined */
+                       kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
+                       goto done;
                case 7: /* invlpg*/
                        emulate_invlpg(ctxt->vcpu, memop);
                        /* Disable writeback. */
@@ -2269,8 +2503,9 @@ twobyte_insn:
                }
                break;
        case 0x05:              /* syscall */
-               if (emulate_syscall(ctxt) == -1)
-                       goto cannot_emulate;
+               rc = emulate_syscall(ctxt);
+               if (rc != X86EMUL_CONTINUE)
+                       goto done;
                else
                        goto writeback;
                break;
@@ -2287,52 +2522,47 @@ twobyte_insn:
        case 0x20: /* mov cr, reg */
                if (c->modrm_mod != 3)
                        goto cannot_emulate;
-               c->regs[c->modrm_rm] =
-                               realmode_get_cr(ctxt->vcpu, c->modrm_reg);
+               c->regs[c->modrm_rm] = ops->get_cr(c->modrm_reg, ctxt->vcpu);
                c->dst.type = OP_NONE;  /* no writeback */
                break;
        case 0x21: /* mov from dr to reg */
                if (c->modrm_mod != 3)
                        goto cannot_emulate;
-               rc = emulator_get_dr(ctxt, c->modrm_reg, &c->regs[c->modrm_rm]);
-               if (rc)
+               if (emulator_get_dr(ctxt, c->modrm_reg, &c->regs[c->modrm_rm]))
                        goto cannot_emulate;
+               rc = X86EMUL_CONTINUE;
                c->dst.type = OP_NONE;  /* no writeback */
                break;
        case 0x22: /* mov reg, cr */
                if (c->modrm_mod != 3)
                        goto cannot_emulate;
-               realmode_set_cr(ctxt->vcpu,
-                               c->modrm_reg, c->modrm_val, &ctxt->eflags);
+               ops->set_cr(c->modrm_reg, c->modrm_val, ctxt->vcpu);
                c->dst.type = OP_NONE;
                break;
        case 0x23: /* mov from reg to dr */
                if (c->modrm_mod != 3)
                        goto cannot_emulate;
-               rc = emulator_set_dr(ctxt, c->modrm_reg,
-                                    c->regs[c->modrm_rm]);
-               if (rc)
+               if (emulator_set_dr(ctxt, c->modrm_reg, c->regs[c->modrm_rm]))
                        goto cannot_emulate;
+               rc = X86EMUL_CONTINUE;
                c->dst.type = OP_NONE;  /* no writeback */
                break;
        case 0x30:
                /* wrmsr */
                msr_data = (u32)c->regs[VCPU_REGS_RAX]
                        | ((u64)c->regs[VCPU_REGS_RDX] << 32);
-               rc = kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data);
-               if (rc) {
+               if (kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) {
                        kvm_inject_gp(ctxt->vcpu, 0);
-                       c->eip = kvm_rip_read(ctxt->vcpu);
+                       c->eip = ctxt->eip;
                }
                rc = X86EMUL_CONTINUE;
                c->dst.type = OP_NONE;
                break;
        case 0x32:
                /* rdmsr */
-               rc = kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data);
-               if (rc) {
+               if (kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) {
                        kvm_inject_gp(ctxt->vcpu, 0);
-                       c->eip = kvm_rip_read(ctxt->vcpu);
+                       c->eip = ctxt->eip;
                } else {
                        c->regs[VCPU_REGS_RAX] = (u32)msr_data;
                        c->regs[VCPU_REGS_RDX] = msr_data >> 32;
@@ -2341,14 +2571,16 @@ twobyte_insn:
                c->dst.type = OP_NONE;
                break;
        case 0x34:              /* sysenter */
-               if (emulate_sysenter(ctxt) == -1)
-                       goto cannot_emulate;
+               rc = emulate_sysenter(ctxt);
+               if (rc != X86EMUL_CONTINUE)
+                       goto done;
                else
                        goto writeback;
                break;
        case 0x35:              /* sysexit */
-               if (emulate_sysexit(ctxt) == -1)
-                       goto cannot_emulate;
+               rc = emulate_sysexit(ctxt);
+               if (rc != X86EMUL_CONTINUE)
+                       goto done;
                else
                        goto writeback;
                break;
@@ -2367,7 +2599,7 @@ twobyte_insn:
                break;
        case 0xa1:       /* pop fs */
                rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0xa3:
@@ -2386,7 +2618,7 @@ twobyte_insn:
                break;
        case 0xa9:      /* pop gs */
                rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                break;
        case 0xab:
@@ -2459,7 +2691,7 @@ twobyte_insn:
                break;
        case 0xc7:              /* Grp9 (cmpxchg8b) */
                rc = emulate_grp9(ctxt, ops, memop);
-               if (rc != 0)
+               if (rc != X86EMUL_CONTINUE)
                        goto done;
                c->dst.type = OP_NONE;
                break;