Merge branch 'sched-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / arch / x86 / kvm / emulate.c
index c44b460..4dade6a 100644 (file)
@@ -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)
@@ -93,35 +95,35 @@ enum {
 
 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,
        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 */
@@ -157,7 +159,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,
@@ -211,7 +213,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,
@@ -219,16 +221,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,
@@ -258,17 +264,18 @@ 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, Group | Group8, 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 */
@@ -285,25 +292,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] =
@@ -322,20 +345,20 @@ static u32 group_table[] = {
        SrcMem | ModRM | Stack, 0,
        SrcMem | ModRM | Stack, 0, 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,
-       DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM,
+       DstMem | SrcImmByte | ModRM, DstMem | SrcImmByte | ModRM | Lock,
+       DstMem | SrcImmByte | ModRM | Lock, DstMem | SrcImmByte | ModRM | Lock,
        [Group9*8] =
-       0, ImplicitOps | ModRM, 0, 0, 0, 0, 0, 0,
+       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,
        SrcNone | ModRM | DstMem | Mov, 0,
        SrcMem16 | ModRM | Mov, 0,
        [Group9*8] =
@@ -343,11 +366,18 @@ static u32 group2_table[] = {
 };
 
 /* 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)
@@ -986,7 +1016,7 @@ done_prefixes:
        }
 
        if (mode == X86EMUL_MODE_PROT64 && (c->d & No64)) {
-               kvm_report_emulation_failure(ctxt->vcpu, "invalid x86/64 instruction");;
+               kvm_report_emulation_failure(ctxt->vcpu, "invalid x86/64 instruction");
                return -1;
        }
 
@@ -1214,6 +1244,49 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
        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 = kvm_x86_ops->get_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;
@@ -1236,7 +1309,7 @@ static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt,
        if (rc != 0)
                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;
 }
 
@@ -1418,7 +1491,7 @@ static int emulate_ret_far(struct x86_emulate_ctxt *ctxt,
        rc = emulate_pop(ctxt, ops, &cs, c->op_bytes);
        if (rc)
                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;
 }
 
@@ -1525,9 +1598,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->mode == X86EMUL_MODE_VM86)
-               return -1;
+       if (ctxt->mode == X86EMUL_MODE_REAL || ctxt->mode == X86EMUL_MODE_VM86)
+               return X86EMUL_UNHANDLEABLE;
 
        setup_syscalls_segments(ctxt, &cs, &ss);
 
@@ -1564,7 +1636,7 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
                ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
        }
 
-       return 0;
+       return X86EMUL_CONTINUE;
 }
 
 static int
@@ -1574,21 +1646,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 */
        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);
 
@@ -1597,13 +1665,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;
        }
@@ -1628,7 +1696,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
@@ -1639,21 +1707,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 Virtual 8086 mode */
        if (ctxt->mode == X86EMUL_MODE_REAL ||
            ctxt->mode == X86EMUL_MODE_VM86) {
                kvm_inject_gp(ctxt->vcpu, 0);
-               return -1;
-       }
-
-       /* sysexit must be called from CPL 0 */
-       if (kvm_x86_ops->get_cpl(ctxt->vcpu) != 0) {
-               kvm_inject_gp(ctxt->vcpu, 0);
-               return -1;
+               return X86EMUL_UNHANDLEABLE;
        }
 
        setup_syscalls_segments(ctxt, &cs, &ss);
@@ -1671,7 +1729,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;
@@ -1679,7 +1737,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;
@@ -1695,7 +1753,58 @@ 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)
+{
+       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 kvm_x86_ops->get_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))
+               if (!emulator_io_port_access_allowed(ctxt, ops, port, len))
+                       return false;
+       return true;
 }
 
 int
@@ -1719,6 +1828,18 @@ 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;
 
+       /* 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) && kvm_x86_ops->get_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;
 
@@ -1889,7 +2010,12 @@ special_insn:
                break;
        case 0x6c:              /* insb */
        case 0x6d:              /* insw/insd */
-                if (kvm_emulate_pio_string(ctxt->vcpu,
+               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 ?
@@ -1905,6 +2031,11 @@ special_insn:
                return 0;
        case 0x6e:              /* outsb */
        case 0x6f:              /* outsw/outsd */
+               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,
@@ -1991,25 +2122,19 @@ 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, X86_SHADOW_INT_MOV_SS);
+
+               rc = kvm_load_segment_descriptor(ctxt->vcpu, sel, c->modrm_reg);
 
                c->dst.type = OP_NONE;  /* Disable writeback. */
                break;
@@ -2038,7 +2163,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;
@@ -2180,11 +2308,9 @@ 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;
-               }
+               if (kvm_load_segment_descriptor(ctxt->vcpu, c->src2.val,
+                                               VCPU_SREG_CS))
+                       goto done;
 
                c->eip = c->src.val;
                break;
@@ -2202,7 +2328,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, 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;
@@ -2227,13 +2359,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))
+                       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))
+                       kvm_inject_gp(ctxt->vcpu, 0);
+               else {
+                       toggle_interruptibility(ctxt, X86_SHADOW_INT_STI);
+                       ctxt->eflags |= X86_EFLAGS_IF;
+                       c->dst.type = OP_NONE;  /* Disable writeback. */
+               }
                break;
        case 0xfc: /* cld */
                ctxt->eflags &= ~EFLG_DF;
@@ -2336,8 +2476,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;
@@ -2408,14 +2549,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;