KVM: x86 emulator: fix 0f 01 /5 emulation
[safe/jmp/linux-2.6] / arch / x86 / kvm / emulate.c
index 4dce805..7c7debb 100644 (file)
@@ -566,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;                                                      \
@@ -667,7 +667,7 @@ static int do_insn_fetch(struct x86_emulate_ctxt *ctxt,
        int rc;
 
        /* x86 instructions are limited to 15 bytes. */
-       if (eip + size - ctxt->decode.eip_orig > 15)
+       if (eip + size - ctxt->eip > 15)
                return X86EMUL_UNHANDLEABLE;
        eip += ctxt->cs_base;
        while (size--) {
@@ -927,7 +927,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
        /* Shadow copy of register state. Committed on successful emulation. */
 
        memset(c, 0, sizeof(struct decode_cache));
-       c->eip = c->eip_orig = 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);
 
@@ -1257,7 +1257,7 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt,
        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);
+       int cpl = ops->cpl(ctxt->vcpu);
 
        rc = emulate_pop(ctxt, ops, &val, len);
        if (rc != X86EMUL_CONTINUE)
@@ -1758,7 +1758,8 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
        return X86EMUL_CONTINUE;
 }
 
-static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
+static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt,
+                             struct x86_emulate_ops *ops)
 {
        int iopl;
        if (ctxt->mode == X86EMUL_MODE_REAL)
@@ -1766,7 +1767,7 @@ static bool emulator_bad_iopl(struct x86_emulate_ctxt *ctxt)
        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;
+       return ops->cpl(ctxt->vcpu) > iopl;
 }
 
 static bool emulator_io_port_access_allowed(struct x86_emulate_ctxt *ctxt,
@@ -1803,7 +1804,7 @@ 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_bad_iopl(ctxt, ops))
                if (!emulator_io_port_access_allowed(ctxt, ops, port, len))
                        return false;
        return true;
@@ -1842,7 +1843,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
        }
 
        /* Privileged instruction can be executed only in CPL=0 */
-       if ((c->d & Priv) && kvm_x86_ops->get_cpl(ctxt->vcpu)) {
+       if ((c->d & Priv) && ops->cpl(ctxt->vcpu)) {
                kvm_inject_gp(ctxt->vcpu, 0);
                goto done;
        }
@@ -1877,7 +1878,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
                        }
                }
                register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1);
-               c->eip = kvm_rip_read(ctxt->vcpu);
+               c->eip = ctxt->eip;
        }
 
        if (c->src.type == OP_MEM) {
@@ -2125,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;
@@ -2378,7 +2378,7 @@ special_insn:
                c->dst.type = OP_NONE;  /* Disable writeback. */
                break;
        case 0xfa: /* cli */
-               if (emulator_bad_iopl(ctxt))
+               if (emulator_bad_iopl(ctxt, ops))
                        kvm_inject_gp(ctxt->vcpu, 0);
                else {
                        ctxt->eflags &= ~X86_EFLAGS_IF;
@@ -2386,7 +2386,7 @@ special_insn:
                }
                break;
        case 0xfb: /* sti */
-               if (emulator_bad_iopl(ctxt))
+               if (emulator_bad_iopl(ctxt, ops))
                        kvm_inject_gp(ctxt->vcpu, 0);
                else {
                        toggle_interruptibility(ctxt, KVM_X86_SHADOW_INT_STI);
@@ -2446,7 +2446,7 @@ twobyte_insn:
                                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;
@@ -2483,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. */
@@ -2519,8 +2522,7 @@ 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 */
@@ -2534,8 +2536,7 @@ twobyte_insn:
        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 */
@@ -2552,7 +2553,7 @@ twobyte_insn:
                        | ((u64)c->regs[VCPU_REGS_RDX] << 32);
                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;
@@ -2561,7 +2562,7 @@ twobyte_insn:
                /* rdmsr */
                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;