KVM: x86 emulator: add get_cached_segment_base() callback to x86_emulate_ops
[deliverable/linux.git] / arch / x86 / kvm / emulate.c
index 5ac0bb465ed67fd725881ccacfeb22e44597f4cf..8228778ace38111b31561886335f1273e30fc765 100644 (file)
@@ -67,6 +67,8 @@
 #define SrcImmUByte (8<<4)      /* 8-bit unsigned immediate operand. */
 #define SrcImmU     (9<<4)      /* Immediate operand, unsigned */
 #define SrcSI       (0xa<<4)   /* Source is in the DS:RSI */
+#define SrcImmFAddr (0xb<<4)   /* Source is immediate far address */
+#define SrcMemFAddr (0xc<<4)   /* Source is far address in memory */
 #define SrcMask     (0xf<<4)
 /* Generic ModRM decode. */
 #define ModRM       (1<<8)
 #define Src2CL      (1<<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 {
@@ -171,11 +169,11 @@ static u32 opcode_table[256] = {
        ByteOp | DstMem | SrcReg | ModRM | Mov, DstMem | SrcReg | ModRM | Mov,
        ByteOp | DstReg | SrcMem | ModRM | Mov, DstReg | SrcMem | ModRM | Mov,
        DstMem | SrcReg | ModRM | Mov, ModRM | DstReg,
-       DstReg | SrcMem | ModRM | Mov, Group | Group1A,
+       ImplicitOps | SrcMem | ModRM, Group | Group1A,
        /* 0x90 - 0x97 */
        DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg, DstReg,
        /* 0x98 - 0x9F */
-       0, 0, SrcImm | Src2Imm16 | No64, 0,
+       0, 0, SrcImmFAddr | No64, 0,
        ImplicitOps | Stack, ImplicitOps | Stack, 0, 0,
        /* 0xA0 - 0xA7 */
        ByteOp | DstReg | SrcMem | Mov | MemAbs, DstReg | SrcMem | Mov | MemAbs,
@@ -215,7 +213,7 @@ static u32 opcode_table[256] = {
        ByteOp | SrcImmUByte | DstAcc, SrcImmUByte | DstAcc,
        /* 0xE8 - 0xEF */
        SrcImm | Stack, SrcImm | ImplicitOps,
-       SrcImmU | Src2Imm16 | No64, SrcImmByte | ImplicitOps,
+       SrcImmFAddr | No64, SrcImmByte | ImplicitOps,
        SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
        SrcNone | ByteOp | DstAcc, SrcNone | DstAcc,
        /* 0xF0 - 0xF7 */
@@ -350,7 +348,7 @@ static u32 group_table[] = {
        [Group5*8] =
        DstMem | SrcNone | ModRM, DstMem | SrcNone | ModRM,
        SrcMem | ModRM | Stack, 0,
-       SrcMem | ModRM | Stack, SrcMem | ModRM | Src2Mem16 | ImplicitOps,
+       SrcMem | ModRM | Stack, SrcMemFAddr | ModRM | ImplicitOps,
        SrcMem | ModRM | Stack, 0,
        [Group7*8] =
        0, 0, ModRM | SrcMem | Priv, ModRM | SrcMem | Priv,
@@ -576,6 +574,13 @@ static u32 group2_table[] = {
        (_type)_x;                                                      \
 })
 
+#define insn_fetch_arr(_arr, _size, _eip)                                \
+({     rc = do_insn_fetch(ctxt, ops, (_eip), _arr, (_size));           \
+       if (rc != X86EMUL_CONTINUE)                                     \
+               goto done;                                              \
+       (_eip) += (_size);                                              \
+})
+
 static inline unsigned long ad_mask(struct decode_cache *c)
 {
        return (1UL << (c->ad_bytes << 3)) - 1;
@@ -1160,6 +1165,17 @@ done_prefixes:
                                         c->regs[VCPU_REGS_RSI]);
                c->src.val = 0;
                break;
+       case SrcImmFAddr:
+               c->src.type = OP_IMM;
+               c->src.ptr = (unsigned long *)c->eip;
+               c->src.bytes = c->op_bytes + 2;
+               insn_fetch_arr(c->src.valptr, c->src.bytes, c->eip);
+               break;
+       case SrcMemFAddr:
+               c->src.type = OP_MEM;
+               c->src.ptr = (unsigned long *)c->modrm_ea;
+               c->src.bytes = c->op_bytes + 2;
+               break;
        }
 
        /*
@@ -1179,22 +1195,10 @@ done_prefixes:
                c->src2.bytes = 1;
                c->src2.val = insn_fetch(u8, 1, c->eip);
                break;
-       case Src2Imm16:
-               c->src2.type = OP_IMM;
-               c->src2.ptr = (unsigned long *)c->eip;
-               c->src2.bytes = 2;
-               c->src2.val = insn_fetch(u16, 2, c->eip);
-               break;
        case Src2One:
                c->src2.bytes = 1;
                c->src2.val = 1;
                break;
-       case Src2Mem16:
-               c->src2.type = OP_MEM;
-               c->src2.bytes = 2;
-               c->src2.ptr = (unsigned long *)(c->modrm_ea + c->src.bytes);
-               c->src2.val = 0;
-               break;
        }
 
        /* Decode and fetch the destination operand: register or memory. */
@@ -1263,6 +1267,33 @@ done:
        return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0;
 }
 
+static int read_emulated(struct x86_emulate_ctxt *ctxt,
+                        struct x86_emulate_ops *ops,
+                        unsigned long addr, void *dest, unsigned size)
+{
+       int rc;
+       struct read_cache *mc = &ctxt->decode.mem_read;
+
+       while (size) {
+               int n = min(size, 8u);
+               size -= n;
+               if (mc->pos < mc->end)
+                       goto read_cached;
+
+               rc = ops->read_emulated(addr, mc->data + mc->end, n, ctxt->vcpu);
+               if (rc != X86EMUL_CONTINUE)
+                       return rc;
+               mc->end += n;
+
+       read_cached:
+               memcpy(dest, mc->data + mc->pos, n);
+               mc->pos += n;
+               dest += n;
+               addr += n;
+       }
+       return X86EMUL_CONTINUE;
+}
+
 static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
                           struct x86_emulate_ops *ops,
                           unsigned int size, unsigned short port,
@@ -1504,9 +1535,9 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
        struct decode_cache *c = &ctxt->decode;
        int rc;
 
-       rc = ops->read_emulated(register_address(c, ss_base(ctxt),
-                                                c->regs[VCPU_REGS_RSP]),
-                               dest, len, ctxt->vcpu);
+       rc = read_emulated(ctxt, ops, register_address(c, ss_base(ctxt),
+                                                      c->regs[VCPU_REGS_RSP]),
+                          dest, len);
        if (rc != X86EMUL_CONTINUE)
                return rc;
 
@@ -1844,7 +1875,7 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
 }
 
 static int
-emulate_syscall(struct x86_emulate_ctxt *ctxt)
+emulate_syscall(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
        struct kvm_segment cs, ss;
@@ -1859,7 +1890,7 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
 
        setup_syscalls_segments(ctxt, &cs, &ss);
 
-       kvm_x86_ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
+       ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
        msr_data >>= 32;
        cs.selector = (u16)(msr_data & 0xfffc);
        ss.selector = (u16)(msr_data + 8);
@@ -1876,17 +1907,17 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
 #ifdef CONFIG_X86_64
                c->regs[VCPU_REGS_R11] = ctxt->eflags & ~EFLG_RF;
 
-               kvm_x86_ops->get_msr(ctxt->vcpu,
-                       ctxt->mode == X86EMUL_MODE_PROT64 ?
-                       MSR_LSTAR : MSR_CSTAR, &msr_data);
+               ops->get_msr(ctxt->vcpu,
+                            ctxt->mode == X86EMUL_MODE_PROT64 ?
+                            MSR_LSTAR : MSR_CSTAR, &msr_data);
                c->eip = msr_data;
 
-               kvm_x86_ops->get_msr(ctxt->vcpu, MSR_SYSCALL_MASK, &msr_data);
+               ops->get_msr(ctxt->vcpu, MSR_SYSCALL_MASK, &msr_data);
                ctxt->eflags &= ~(msr_data | EFLG_RF);
 #endif
        } else {
                /* legacy mode */
-               kvm_x86_ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
+               ops->get_msr(ctxt->vcpu, MSR_STAR, &msr_data);
                c->eip = (u32)msr_data;
 
                ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
@@ -1896,7 +1927,7 @@ emulate_syscall(struct x86_emulate_ctxt *ctxt)
 }
 
 static int
-emulate_sysenter(struct x86_emulate_ctxt *ctxt)
+emulate_sysenter(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
        struct kvm_segment cs, ss;
@@ -1918,7 +1949,7 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
 
        setup_syscalls_segments(ctxt, &cs, &ss);
 
-       kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
+       ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
        switch (ctxt->mode) {
        case X86EMUL_MODE_PROT32:
                if ((msr_data & 0xfffc) == 0x0) {
@@ -1948,17 +1979,17 @@ emulate_sysenter(struct x86_emulate_ctxt *ctxt)
        kvm_x86_ops->set_segment(ctxt->vcpu, &cs, VCPU_SREG_CS);
        kvm_x86_ops->set_segment(ctxt->vcpu, &ss, VCPU_SREG_SS);
 
-       kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_EIP, &msr_data);
+       ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_EIP, &msr_data);
        c->eip = msr_data;
 
-       kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data);
+       ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_ESP, &msr_data);
        c->regs[VCPU_REGS_RSP] = msr_data;
 
        return X86EMUL_CONTINUE;
 }
 
 static int
-emulate_sysexit(struct x86_emulate_ctxt *ctxt)
+emulate_sysexit(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 {
        struct decode_cache *c = &ctxt->decode;
        struct kvm_segment cs, ss;
@@ -1981,7 +2012,7 @@ emulate_sysexit(struct x86_emulate_ctxt *ctxt)
 
        cs.dpl = 3;
        ss.dpl = 3;
-       kvm_x86_ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
+       ops->get_msr(ctxt->vcpu, MSR_IA32_SYSENTER_CS, &msr_data);
        switch (usermode) {
        case X86EMUL_MODE_PROT32:
                cs.selector = (u16)(msr_data + 16);
@@ -2066,17 +2097,6 @@ static bool emulator_io_permited(struct x86_emulate_ctxt *ctxt,
        return true;
 }
 
-static u32 get_cached_descriptor_base(struct x86_emulate_ctxt *ctxt,
-                                     struct x86_emulate_ops *ops,
-                                     int seg)
-{
-       struct desc_struct desc;
-       if (ops->get_cached_descriptor(&desc, seg, ctxt->vcpu))
-               return get_desc_base(&desc);
-       else
-               return ~0;
-}
-
 static void save_state_to_tss16(struct x86_emulate_ctxt *ctxt,
                                struct x86_emulate_ops *ops,
                                struct tss_segment_16 *tss)
@@ -2352,7 +2372,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
        int ret;
        u16 old_tss_sel = ops->get_segment_selector(VCPU_SREG_TR, ctxt->vcpu);
        ulong old_tss_base =
-               get_cached_descriptor_base(ctxt, ops, VCPU_SREG_TR);
+               ops->get_cached_segment_base(VCPU_SREG_TR, ctxt->vcpu);
        u32 desc_limit;
 
        /* FIXME: old_tss_base == ~0 ? */
@@ -2475,6 +2495,7 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
        int saved_dst_type = c->dst.type;
 
        ctxt->interruptibility = 0;
+       ctxt->decode.mem_read.pos = 0;
 
        /* Shadow copy of register state. Committed on successful emulation.
         * NOTE: we can copy them from vcpu as x86_decode_insn() doesn't
@@ -2529,20 +2550,16 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
        }
 
        if (c->src.type == OP_MEM) {
-               rc = ops->read_emulated((unsigned long)c->src.ptr,
-                                       &c->src.val,
-                                       c->src.bytes,
-                                       ctxt->vcpu);
+               rc = read_emulated(ctxt, ops, (unsigned long)c->src.ptr,
+                                       c->src.valptr, c->src.bytes);
                if (rc != X86EMUL_CONTINUE)
                        goto done;
                c->src.orig_val = c->src.val;
        }
 
        if (c->src2.type == OP_MEM) {
-               rc = ops->read_emulated((unsigned long)c->src2.ptr,
-                                       &c->src2.val,
-                                       c->src2.bytes,
-                                       ctxt->vcpu);
+               rc = read_emulated(ctxt, ops, (unsigned long)c->src2.ptr,
+                                       &c->src2.val, c->src2.bytes);
                if (rc != X86EMUL_CONTINUE)
                        goto done;
        }
@@ -2553,8 +2570,8 @@ x86_emulate_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
 
        if ((c->dst.type == OP_MEM) && !(c->d & Mov)) {
                /* optimisation - avoid slow emulated read if Mov */
-               rc = ops->read_emulated((unsigned long)c->dst.ptr, &c->dst.val,
-                                       c->dst.bytes, ctxt->vcpu);
+               rc = read_emulated(ctxt, ops, (unsigned long)c->dst.ptr,
+                                  &c->dst.val, c->dst.bytes);
                if (rc != X86EMUL_CONTINUE)
                        goto done;
        }
@@ -2775,13 +2792,13 @@ special_insn:
                        goto done;
                break;
        case 0x90: /* nop / xchg r8,rax */
-               if (!(c->rex_prefix & 1)) { /* nop */
-                       c->dst.type = OP_NONE;
+               if (c->dst.ptr == (unsigned long *)&c->regs[VCPU_REGS_RAX]) {
+                       c->dst.type = OP_NONE;  /* nop */
                        break;
                }
        case 0x91 ... 0x97: /* xchg reg,rax */
-               c->src.type = c->dst.type = OP_REG;
-               c->src.bytes = c->dst.bytes = c->op_bytes;
+               c->src.type = OP_REG;
+               c->src.bytes = c->op_bytes;
                c->src.ptr = (unsigned long *) &c->regs[VCPU_REGS_RAX];
                c->src.val = *(c->src.ptr);
                goto xchg;
@@ -2860,14 +2877,18 @@ special_insn:
        }
        case 0xe9: /* jmp rel */
                goto jmp;
-       case 0xea: /* jmp far */
+       case 0xea: { /* jmp far */
+               unsigned short sel;
        jump_far:
-               if (load_segment_descriptor(ctxt, ops, c->src2.val,
-                                           VCPU_SREG_CS))
+               memcpy(&sel, c->src.valptr + c->op_bytes, 2);
+
+               if (load_segment_descriptor(ctxt, ops, sel, VCPU_SREG_CS))
                        goto done;
 
-               c->eip = c->src.val;
+               c->eip = 0;
+               memcpy(&c->eip, c->src.valptr, c->op_bytes);
                break;
+       }
        case 0xeb:
              jmp:              /* jmp rel short */
                jmp_rel(c, c->src.val);
@@ -2981,7 +3002,11 @@ writeback:
                    (rc->end != 0 && rc->end == rc->pos))
                        ctxt->restart = false;
        }
-
+       /*
+        * reset read cache here in case string instruction is restared
+        * without decoding
+        */
+       ctxt->decode.mem_read.end = 0;
        /* Commit shadow register state. */
        memcpy(ctxt->vcpu->arch.regs, c->regs, sizeof c->regs);
        kvm_rip_write(ctxt->vcpu, c->eip);
@@ -3063,7 +3088,7 @@ twobyte_insn:
                }
                break;
        case 0x05:              /* syscall */
-               rc = emulate_syscall(ctxt);
+               rc = emulate_syscall(ctxt, ops);
                if (rc != X86EMUL_CONTINUE)
                        goto done;
                else
@@ -3096,7 +3121,7 @@ twobyte_insn:
                        kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
                        goto done;
                }
-               emulator_get_dr(ctxt, c->modrm_reg, &c->regs[c->modrm_rm]);
+               ops->get_dr(c->modrm_reg, &c->regs[c->modrm_rm], ctxt->vcpu);
                c->dst.type = OP_NONE;  /* no writeback */
                break;
        case 0x22: /* mov reg, cr */
@@ -3109,14 +3134,17 @@ twobyte_insn:
                        kvm_queue_exception(ctxt->vcpu, UD_VECTOR);
                        goto done;
                }
-               emulator_set_dr(ctxt, c->modrm_reg, c->regs[c->modrm_rm]);
+
+               ops->set_dr(c->modrm_reg,c->regs[c->modrm_rm] &
+                           ((ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U),
+                       ctxt->vcpu);
                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);
-               if (kvm_set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) {
+               if (ops->set_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], msr_data)) {
                        kvm_inject_gp(ctxt->vcpu, 0);
                        goto done;
                }
@@ -3125,7 +3153,7 @@ twobyte_insn:
                break;
        case 0x32:
                /* rdmsr */
-               if (kvm_get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) {
+               if (ops->get_msr(ctxt->vcpu, c->regs[VCPU_REGS_RCX], &msr_data)) {
                        kvm_inject_gp(ctxt->vcpu, 0);
                        goto done;
                } else {
@@ -3136,14 +3164,14 @@ twobyte_insn:
                c->dst.type = OP_NONE;
                break;
        case 0x34:              /* sysenter */
-               rc = emulate_sysenter(ctxt);
+               rc = emulate_sysenter(ctxt, ops);
                if (rc != X86EMUL_CONTINUE)
                        goto done;
                else
                        goto writeback;
                break;
        case 0x35:              /* sysexit */
-               rc = emulate_sysexit(ctxt);
+               rc = emulate_sysexit(ctxt, ops);
                if (rc != X86EMUL_CONTINUE)
                        goto done;
                else
This page took 0.050433 seconds and 5 git commands to generate.