]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/kvm/x86_emulate.c
KVM: Convert vm lock to a mutex
[linux-2.6-omap-h63xx.git] / drivers / kvm / x86_emulate.c
index f60012d626104c45c449cd2c0055468cd835f189..2136da5d69764e8931c3966fba6c6a121d015fb4 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright (c) 2005 Keir Fraser
  *
  * Linux coding style, mod r/m decoder, segment base fixes, real-mode
- * privieged instructions:
+ * privileged instructions:
  *
  * Copyright (C) 2006 Qumranet
  *
@@ -163,7 +163,7 @@ static u16 twobyte_table[256] = {
        ModRM | ImplicitOps, ModRM, ModRM | ImplicitOps, ModRM, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0,
        /* 0x30 - 0x3F */
-       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+       ImplicitOps, 0, ImplicitOps, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        /* 0x40 - 0x47 */
        DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
        DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
@@ -443,8 +443,13 @@ struct operand {
                           (((reg) + _inc) & ((1UL << (ad_bytes << 3)) - 1)); \
        } while (0)
 
-void *decode_register(u8 modrm_reg, unsigned long *regs,
-                     int highbyte_regs)
+/*
+ * Given the 'reg' portion of a ModRM byte, and a register block, return a
+ * pointer into the block that addresses the relevant register.
+ * @highbyte_regs specifies whether to decode AH,CH,DH,BH.
+ */
+static void *decode_register(u8 modrm_reg, unsigned long *regs,
+                            int highbyte_regs)
 {
        void *p;
 
@@ -486,6 +491,7 @@ x86_emulate_memop(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
        unsigned long modrm_ea;
        int use_modrm_ea, index_reg = 0, base_reg = 0, scale, rip_relative = 0;
        int no_wb = 0;
+       u64 msr_data;
 
        /* Shadow copy of register state. Committed on successful emulation. */
        unsigned long _regs[NR_VCPU_REGS];
@@ -813,7 +819,7 @@ done_prefixes:
        case DstReg:
                dst.type = OP_REG;
                if ((d & ByteOp)
-                   && !(twobyte_table && (b == 0xb6 || b == 0xb7))) {
+                   && !(twobyte && (b == 0xb6 || b == 0xb7))) {
                        dst.ptr = decode_register(modrm_reg, _regs,
                                                  (rex_prefix == 0));
                        dst.val = *(u8 *) dst.ptr;
@@ -1177,6 +1183,8 @@ pop_instruction:
 twobyte_insn:
        switch (b) {
        case 0x01: /* lgdt, lidt, lmsw */
+               /* Disable writeback. */
+               no_wb = 1;
                switch (modrm_reg) {
                        u16 size;
                        unsigned long address;
@@ -1214,51 +1222,53 @@ twobyte_insn:
                }
                break;
        case 0x21: /* mov from dr to reg */
+               no_wb = 1;
                if (modrm_mod != 3)
                        goto cannot_emulate;
                rc = emulator_get_dr(ctxt, modrm_reg, &_regs[modrm_rm]);
                break;
        case 0x23: /* mov from reg to dr */
+               no_wb = 1;
                if (modrm_mod != 3)
                        goto cannot_emulate;
                rc = emulator_set_dr(ctxt, modrm_reg, _regs[modrm_rm]);
                break;
        case 0x40 ... 0x4f:     /* cmov */
                dst.val = dst.orig_val = src.val;
-               d &= ~Mov;      /* default to no move */
+               no_wb = 1;
                /*
                 * First, assume we're decoding an even cmov opcode
                 * (lsb == 0).
                 */
                switch ((b & 15) >> 1) {
                case 0: /* cmovo */
-                       d |= (_eflags & EFLG_OF) ? Mov : 0;
+                       no_wb = (_eflags & EFLG_OF) ? 0 : 1;
                        break;
                case 1: /* cmovb/cmovc/cmovnae */
-                       d |= (_eflags & EFLG_CF) ? Mov : 0;
+                       no_wb = (_eflags & EFLG_CF) ? 0 : 1;
                        break;
                case 2: /* cmovz/cmove */
-                       d |= (_eflags & EFLG_ZF) ? Mov : 0;
+                       no_wb = (_eflags & EFLG_ZF) ? 0 : 1;
                        break;
                case 3: /* cmovbe/cmovna */
-                       d |= (_eflags & (EFLG_CF | EFLG_ZF)) ? Mov : 0;
+                       no_wb = (_eflags & (EFLG_CF | EFLG_ZF)) ? 0 : 1;
                        break;
                case 4: /* cmovs */
-                       d |= (_eflags & EFLG_SF) ? Mov : 0;
+                       no_wb = (_eflags & EFLG_SF) ? 0 : 1;
                        break;
                case 5: /* cmovp/cmovpe */
-                       d |= (_eflags & EFLG_PF) ? Mov : 0;
+                       no_wb = (_eflags & EFLG_PF) ? 0 : 1;
                        break;
                case 7: /* cmovle/cmovng */
-                       d |= (_eflags & EFLG_ZF) ? Mov : 0;
+                       no_wb = (_eflags & EFLG_ZF) ? 0 : 1;
                        /* fall through */
                case 6: /* cmovl/cmovnge */
-                       d |= (!(_eflags & EFLG_SF) !=
-                             !(_eflags & EFLG_OF)) ? Mov : 0;
+                       no_wb &= (!(_eflags & EFLG_SF) !=
+                             !(_eflags & EFLG_OF)) ? 0 : 1;
                        break;
                }
                /* Odd cmov opcodes (lsb == 1) have inverted sense. */
-               d ^= (b & 1) ? Mov : 0;
+               no_wb ^= b & 1;
                break;
        case 0xb0 ... 0xb1:     /* cmpxchg */
                /*
@@ -1268,8 +1278,6 @@ twobyte_insn:
                src.orig_val = src.val;
                src.val = _regs[VCPU_REGS_RAX];
                emulate_2op_SrcV("cmp", src, dst, _eflags);
-               /* Always write back. The question is: where to? */
-               d |= Mov;
                if (_eflags & EFLG_ZF) {
                        /* Success: write back to memory. */
                        dst.val = src.orig_val;
@@ -1344,6 +1352,29 @@ twobyte_special_insn:
                        goto cannot_emulate;
                realmode_set_cr(ctxt->vcpu, modrm_reg, modrm_val, &_eflags);
                break;
+       case 0x30:
+               /* wrmsr */
+               msr_data = (u32)_regs[VCPU_REGS_RAX]
+                       | ((u64)_regs[VCPU_REGS_RDX] << 32);
+               rc = kvm_set_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], msr_data);
+               if (rc) {
+                       kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+                       _eip = ctxt->vcpu->rip;
+               }
+               rc = X86EMUL_CONTINUE;
+               break;
+       case 0x32:
+               /* rdmsr */
+               rc = kvm_get_msr(ctxt->vcpu, _regs[VCPU_REGS_RCX], &msr_data);
+               if (rc) {
+                       kvm_arch_ops->inject_gp(ctxt->vcpu, 0);
+                       _eip = ctxt->vcpu->rip;
+               } else {
+                       _regs[VCPU_REGS_RAX] = (u32)msr_data;
+                       _regs[VCPU_REGS_RDX] = msr_data >> 32;
+               }
+               rc = X86EMUL_CONTINUE;
+               break;
        case 0xc7:              /* Grp9 (cmpxchg8b) */
                {
                        u64 old, new;