KVM: emulate: avoid per-byte copying in instruction fetches
[pandora-kernel.git] / arch / x86 / kvm / emulate.c
index 27f677e..02c668a 100644 (file)
@@ -514,12 +514,6 @@ static u32 desc_limit_scaled(struct desc_struct *desc)
        return desc->g ? (limit << 12) | 0xfff : limit;
 }
 
-static void set_seg_override(struct x86_emulate_ctxt *ctxt, int seg)
-{
-       ctxt->has_seg_override = true;
-       ctxt->seg_override = seg;
-}
-
 static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
 {
        if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS)
@@ -528,14 +522,6 @@ static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
        return ctxt->ops->get_cached_segment_base(ctxt, seg);
 }
 
-static unsigned seg_override(struct x86_emulate_ctxt *ctxt)
-{
-       if (!ctxt->has_seg_override)
-               return 0;
-
-       return ctxt->seg_override;
-}
-
 static int emulate_exception(struct x86_emulate_ctxt *ctxt, int vec,
                             u32 error, bool valid)
 {
@@ -719,68 +705,74 @@ static int segmented_read_std(struct x86_emulate_ctxt *ctxt,
 }
 
 /*
- * Fetch the next byte of the instruction being emulated which is pointed to
- * by ctxt->_eip, then increment ctxt->_eip.
- *
- * Also prefetch the remaining bytes of the instruction without crossing page
+ * Prefetch the remaining bytes of the instruction without crossing page
  * boundary if they are not in fetch_cache yet.
  */
-static int do_insn_fetch_byte(struct x86_emulate_ctxt *ctxt, u8 *dest)
+static int __do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt, int op_size)
 {
        struct fetch_cache *fc = &ctxt->fetch;
        int rc;
        int size, cur_size;
+       unsigned long linear;
 
-       if (ctxt->_eip == fc->end) {
-               unsigned long linear;
-               struct segmented_address addr = { .seg = VCPU_SREG_CS,
-                                                 .ea  = ctxt->_eip };
-               cur_size = fc->end - fc->start;
-               size = min(15UL - cur_size,
-                          PAGE_SIZE - offset_in_page(ctxt->_eip));
-               rc = __linearize(ctxt, addr, size, false, true, &linear);
-               if (unlikely(rc != X86EMUL_CONTINUE))
-                       return rc;
-               rc = ctxt->ops->fetch(ctxt, linear, fc->data + cur_size,
-                                     size, &ctxt->exception);
-               if (unlikely(rc != X86EMUL_CONTINUE))
-                       return rc;
-               fc->end += size;
-       }
-       *dest = fc->data[ctxt->_eip - fc->start];
-       ctxt->_eip++;
+       struct segmented_address addr = { .seg = VCPU_SREG_CS,
+                                         .ea  = fc->end };
+       cur_size = fc->end - fc->start;
+       size = min(15UL - cur_size,
+                  PAGE_SIZE - offset_in_page(fc->end));
+
+       /*
+        * One instruction can only straddle two pages,
+        * and one has been loaded at the beginning of
+        * x86_decode_insn.  So, if not enough bytes
+        * still, we must have hit the 15-byte boundary.
+        */
+       if (unlikely(size < op_size))
+               return X86EMUL_UNHANDLEABLE;
+       rc = __linearize(ctxt, addr, size, false, true, &linear);
+       if (unlikely(rc != X86EMUL_CONTINUE))
+               return rc;
+       rc = ctxt->ops->fetch(ctxt, linear, fc->data + cur_size,
+                             size, &ctxt->exception);
+       if (unlikely(rc != X86EMUL_CONTINUE))
+               return rc;
+       fc->end += size;
        return X86EMUL_CONTINUE;
 }
 
-static int do_insn_fetch(struct x86_emulate_ctxt *ctxt,
-                        void *dest, unsigned size)
+static __always_inline int do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt,
+                                              unsigned size)
 {
-       int rc;
-
-       /* x86 instructions are limited to 15 bytes. */
-       if (unlikely(ctxt->_eip + size - ctxt->eip > 15))
-               return X86EMUL_UNHANDLEABLE;
-       while (size--) {
-               rc = do_insn_fetch_byte(ctxt, dest++);
-               if (rc != X86EMUL_CONTINUE)
-                       return rc;
-       }
-       return X86EMUL_CONTINUE;
+       /* We have to be careful about overflow! */
+       if (unlikely(ctxt->_eip > ctxt->fetch.end - size))
+               return __do_insn_fetch_bytes(ctxt, size);
+       else
+               return X86EMUL_CONTINUE;
 }
 
 /* Fetch next part of the instruction being emulated. */
 #define insn_fetch(_type, _ctxt)                                       \
-({     unsigned long _x;                                               \
-       rc = do_insn_fetch(_ctxt, &_x, sizeof(_type));                  \
+({     _type _x;                                                       \
+       struct fetch_cache *_fc;                                        \
+                                                                       \
+       rc = do_insn_fetch_bytes(_ctxt, sizeof(_type));                 \
        if (rc != X86EMUL_CONTINUE)                                     \
                goto done;                                              \
-       (_type)_x;                                                      \
+       _fc = &ctxt->fetch;                                             \
+       _x = *(_type __aligned(1) *) &_fc->data[ctxt->_eip - _fc->start]; \
+       ctxt->_eip += sizeof(_type);                                    \
+       _x;                                                             \
 })
 
 #define insn_fetch_arr(_arr, _size, _ctxt)                             \
-({     rc = do_insn_fetch(_ctxt, _arr, (_size));                       \
+({                                                                     \
+       struct fetch_cache *_fc;                                        \
+       rc = do_insn_fetch_bytes(_ctxt, _size);                         \
        if (rc != X86EMUL_CONTINUE)                                     \
                goto done;                                              \
+       _fc = &ctxt->fetch;                                             \
+       memcpy(_arr, &_fc->data[ctxt->_eip - _fc->start], _size);       \
+       ctxt->_eip += (_size);                                          \
 })
 
 /*
@@ -1066,19 +1058,17 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
                        struct operand *op)
 {
        u8 sib;
-       int index_reg = 0, base_reg = 0, scale;
+       int index_reg, base_reg, scale;
        int rc = X86EMUL_CONTINUE;
        ulong modrm_ea = 0;
 
-       if (ctxt->rex_prefix) {
-               ctxt->modrm_reg = (ctxt->rex_prefix & 4) << 1;  /* REX.R */
-               index_reg = (ctxt->rex_prefix & 2) << 2; /* REX.X */
-               ctxt->modrm_rm = base_reg = (ctxt->rex_prefix & 1) << 3; /* REG.B */
-       }
+       ctxt->modrm_reg = ((ctxt->rex_prefix << 1) & 8); /* REX.R */
+       index_reg = (ctxt->rex_prefix << 2) & 8; /* REX.X */
+       base_reg = (ctxt->rex_prefix << 3) & 8; /* REX.B */
 
-       ctxt->modrm_mod |= (ctxt->modrm & 0xc0) >> 6;
+       ctxt->modrm_mod = (ctxt->modrm & 0xc0) >> 6;
        ctxt->modrm_reg |= (ctxt->modrm & 0x38) >> 3;
-       ctxt->modrm_rm |= (ctxt->modrm & 0x07);
+       ctxt->modrm_rm = base_reg | (ctxt->modrm & 0x07);
        ctxt->modrm_seg = VCPU_SREG_DS;
 
        if (ctxt->modrm_mod == 3 || (ctxt->d & NoMod)) {
@@ -1193,6 +1183,9 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
                }
        }
        op->addr.mem.ea = modrm_ea;
+       if (ctxt->ad_bytes != 8)
+               ctxt->memop.addr.mem.ea = (u32)ctxt->memop.addr.mem.ea;
+
 done:
        return rc;
 }
@@ -1588,34 +1581,28 @@ static void write_register_operand(struct operand *op)
 
 static int writeback(struct x86_emulate_ctxt *ctxt, struct operand *op)
 {
-       int rc;
-
        switch (op->type) {
        case OP_REG:
                write_register_operand(op);
                break;
        case OP_MEM:
                if (ctxt->lock_prefix)
-                       rc = segmented_cmpxchg(ctxt,
+                       return segmented_cmpxchg(ctxt,
+                                                op->addr.mem,
+                                                &op->orig_val,
+                                                &op->val,
+                                                op->bytes);
+               else
+                       return segmented_write(ctxt,
                                               op->addr.mem,
-                                              &op->orig_val,
                                               &op->val,
                                               op->bytes);
-               else
-                       rc = segmented_write(ctxt,
-                                            op->addr.mem,
-                                            &op->val,
-                                            op->bytes);
-               if (rc != X86EMUL_CONTINUE)
-                       return rc;
                break;
        case OP_MEM_STR:
-               rc = segmented_write(ctxt,
-                               op->addr.mem,
-                               op->data,
-                               op->bytes * op->count);
-               if (rc != X86EMUL_CONTINUE)
-                       return rc;
+               return segmented_write(ctxt,
+                                      op->addr.mem,
+                                      op->data,
+                                      op->bytes * op->count);
                break;
        case OP_XMM:
                write_sse_reg(ctxt, &op->vec_val, op->addr.xmm);
@@ -4177,7 +4164,7 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op,
                op->bytes = (ctxt->d & ByteOp) ? 1 : ctxt->op_bytes;
                op->addr.mem.ea =
                        register_address(ctxt, reg_read(ctxt, VCPU_REGS_RSI));
-               op->addr.mem.seg = seg_override(ctxt);
+               op->addr.mem.seg = ctxt->seg_override;
                op->val = 0;
                op->count = 1;
                break;
@@ -4188,7 +4175,7 @@ static int decode_operand(struct x86_emulate_ctxt *ctxt, struct operand *op,
                        register_address(ctxt,
                                reg_read(ctxt, VCPU_REGS_RBX) +
                                (reg_read(ctxt, VCPU_REGS_RAX) & 0xff));
-               op->addr.mem.seg = seg_override(ctxt);
+               op->addr.mem.seg = ctxt->seg_override;
                op->val = 0;
                break;
        case OpImmFAddr:
@@ -4235,6 +4222,7 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
        int mode = ctxt->mode;
        int def_op_bytes, def_ad_bytes, goffset, simd_prefix;
        bool op_prefix = false;
+       bool has_seg_override = false;
        struct opcode opcode;
 
        ctxt->memop.type = OP_NONE;
@@ -4245,6 +4233,11 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
        ctxt->opcode_len = 1;
        if (insn_len > 0)
                memcpy(ctxt->fetch.data, insn, insn_len);
+       else {
+               rc = __do_insn_fetch_bytes(ctxt, 1);
+               if (rc != X86EMUL_CONTINUE)
+                       return rc;
+       }
 
        switch (mode) {
        case X86EMUL_MODE_REAL:
@@ -4288,11 +4281,13 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
                case 0x2e:      /* CS override */
                case 0x36:      /* SS override */
                case 0x3e:      /* DS override */
-                       set_seg_override(ctxt, (ctxt->b >> 3) & 3);
+                       has_seg_override = true;
+                       ctxt->seg_override = (ctxt->b >> 3) & 3;
                        break;
                case 0x64:      /* FS override */
                case 0x65:      /* GS override */
-                       set_seg_override(ctxt, ctxt->b & 7);
+                       has_seg_override = true;
+                       ctxt->seg_override = ctxt->b & 7;
                        break;
                case 0x40 ... 0x4f: /* REX */
                        if (mode != X86EMUL_MODE_PROT64)
@@ -4430,20 +4425,19 @@ done_prefixes:
        /* ModRM and SIB bytes. */
        if (ctxt->d & ModRM) {
                rc = decode_modrm(ctxt, &ctxt->memop);
-               if (!ctxt->has_seg_override)
-                       set_seg_override(ctxt, ctxt->modrm_seg);
+               if (!has_seg_override) {
+                       has_seg_override = true;
+                       ctxt->seg_override = ctxt->modrm_seg;
+               }
        } else if (ctxt->d & MemAbs)
                rc = decode_abs(ctxt, &ctxt->memop);
        if (rc != X86EMUL_CONTINUE)
                goto done;
 
-       if (!ctxt->has_seg_override)
-               set_seg_override(ctxt, VCPU_SREG_DS);
+       if (!has_seg_override)
+               ctxt->seg_override = VCPU_SREG_DS;
 
-       ctxt->memop.addr.mem.seg = seg_override(ctxt);
-
-       if (ctxt->memop.type == OP_MEM && ctxt->ad_bytes != 8)
-               ctxt->memop.addr.mem.ea = (u32)ctxt->memop.addr.mem.ea;
+       ctxt->memop.addr.mem.seg = ctxt->seg_override;
 
        /*
         * Decode and fetch the source operand: register, memory
@@ -4465,7 +4459,7 @@ done_prefixes:
        rc = decode_operand(ctxt, &ctxt->dst, (ctxt->d >> DstShift) & OpMask);
 
 done:
-       if (ctxt->memopp && ctxt->memopp->type == OP_MEM && ctxt->rip_relative)
+       if (ctxt->rip_relative)
                ctxt->memopp->addr.mem.ea += ctxt->_eip;
 
        return (rc != X86EMUL_CONTINUE) ? EMULATION_FAILED : EMULATION_OK;
@@ -4540,6 +4534,16 @@ static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *))
        return X86EMUL_CONTINUE;
 }
 
+void init_decode_cache(struct x86_emulate_ctxt *ctxt)
+{
+       memset(&ctxt->rip_relative, 0,
+              (void *)&ctxt->modrm - (void *)&ctxt->rip_relative);
+
+       ctxt->io_read.pos = 0;
+       ctxt->io_read.end = 0;
+       ctxt->mem_read.end = 0;
+}
+
 int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
 {
        const struct x86_emulate_ops *ops = ctxt->ops;
@@ -4592,7 +4596,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
                                fetch_possible_mmx_operand(ctxt, &ctxt->dst);
                }
 
-               if (unlikely(ctxt->guest_mode) && ctxt->intercept) {
+               if (unlikely(ctxt->guest_mode) && (ctxt->d & Intercept)) {
                        rc = emulator_check_intercept(ctxt, ctxt->intercept,
                                                      X86_ICPT_PRE_EXCEPT);
                        if (rc != X86EMUL_CONTINUE)
@@ -4612,13 +4616,13 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
                }
 
                /* Do instruction specific permission checks */
-               if (ctxt->check_perm) {
+               if (ctxt->d & CheckPerm) {
                        rc = ctxt->check_perm(ctxt);
                        if (rc != X86EMUL_CONTINUE)
                                goto done;
                }
 
-               if (unlikely(ctxt->guest_mode) && ctxt->intercept) {
+               if (unlikely(ctxt->guest_mode) && (ctxt->d & Intercept)) {
                        rc = emulator_check_intercept(ctxt, ctxt->intercept,
                                                      X86_ICPT_POST_EXCEPT);
                        if (rc != X86EMUL_CONTINUE)
@@ -4664,7 +4668,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
 
 special_insn:
 
-       if (unlikely(ctxt->guest_mode) && ctxt->intercept) {
+       if (unlikely(ctxt->guest_mode) && (ctxt->d & Intercept)) {
                rc = emulator_check_intercept(ctxt, ctxt->intercept,
                                              X86_ICPT_POST_MEMACCESS);
                if (rc != X86EMUL_CONTINUE)