Merge branch 'x86-cpufeature-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[cascardo/linux.git] / arch / x86 / kvm / emulate.c
index 390400a..56657b0 100644 (file)
 #define NoMod      ((u64)1 << 47)  /* Mod field is ignored */
 #define Intercept   ((u64)1 << 48)  /* Has valid intercept field */
 #define CheckPerm   ((u64)1 << 49)  /* Has valid check_perm field */
+#define NoBigReal   ((u64)1 << 50)  /* No big real mode */
+#define PrivUD      ((u64)1 << 51)  /* #UD instead of #GP on CPL > 0 */
 
 #define DstXacc     (DstAccLo | SrcAccHi | SrcWrite)
 
@@ -640,7 +642,12 @@ static int __linearize(struct x86_emulate_ctxt *ctxt,
                if (!fetch && (desc.type & 8) && !(desc.type & 2))
                        goto bad;
                lim = desc_limit_scaled(&desc);
-               if ((desc.type & 8) || !(desc.type & 4)) {
+               if ((ctxt->mode == X86EMUL_MODE_REAL) && !fetch &&
+                   (ctxt->d & NoBigReal)) {
+                       /* la is between zero and 0xffff */
+                       if (la > 0xffff || (u32)(la + size - 1) > 0xffff)
+                               goto bad;
+               } else if ((desc.type & 8) || !(desc.type & 4)) {
                        /* expand-up segment */
                        if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
                                goto bad;
@@ -705,68 +712,71 @@ 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;
-
-       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++;
-       return X86EMUL_CONTINUE;
-}
+       unsigned size;
+       unsigned long linear;
+       int cur_size = ctxt->fetch.end - ctxt->fetch.data;
+       struct segmented_address addr = { .seg = VCPU_SREG_CS,
+                                          .ea = ctxt->eip + cur_size };
+
+       size = 15UL ^ cur_size;
+       rc = __linearize(ctxt, addr, size, false, true, &linear);
+       if (unlikely(rc != X86EMUL_CONTINUE))
+               return rc;
 
-static int do_insn_fetch(struct x86_emulate_ctxt *ctxt,
-                        void *dest, unsigned size)
-{
-       int rc;
+       size = min_t(unsigned, size, PAGE_SIZE - offset_in_page(linear));
 
-       /* x86 instructions are limited to 15 bytes. */
-       if (unlikely(ctxt->_eip + size - ctxt->eip > 15))
+       /*
+        * 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;
-       while (size--) {
-               rc = do_insn_fetch_byte(ctxt, dest++);
-               if (rc != X86EMUL_CONTINUE)
-                       return rc;
-       }
+       rc = ctxt->ops->fetch(ctxt, linear, ctxt->fetch.end,
+                             size, &ctxt->exception);
+       if (unlikely(rc != X86EMUL_CONTINUE))
+               return rc;
+       ctxt->fetch.end += size;
        return X86EMUL_CONTINUE;
 }
 
+static __always_inline int do_insn_fetch_bytes(struct x86_emulate_ctxt *ctxt,
+                                              unsigned size)
+{
+       if (unlikely(ctxt->fetch.end - ctxt->fetch.ptr < 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;                                                       \
+                                                                       \
+       rc = do_insn_fetch_bytes(_ctxt, sizeof(_type));                 \
        if (rc != X86EMUL_CONTINUE)                                     \
                goto done;                                              \
-       (_type)_x;                                                      \
+       ctxt->_eip += sizeof(_type);                                    \
+       _x = *(_type __aligned(1) *) ctxt->fetch.ptr;                   \
+       ctxt->fetch.ptr += sizeof(_type);                               \
+       _x;                                                             \
 })
 
 #define insn_fetch_arr(_arr, _size, _ctxt)                             \
-({     rc = do_insn_fetch(_ctxt, _arr, (_size));                       \
+({                                                                     \
+       rc = do_insn_fetch_bytes(_ctxt, _size);                         \
        if (rc != X86EMUL_CONTINUE)                                     \
                goto done;                                              \
+       ctxt->_eip += (_size);                                          \
+       memcpy(_arr, ctxt->fetch.ptr, _size);                           \
+       ctxt->fetch.ptr += (_size);                                     \
 })
 
 /*
@@ -1307,8 +1317,7 @@ static int pio_in_emulated(struct x86_emulate_ctxt *ctxt,
                in_page = (ctxt->eflags & EFLG_DF) ?
                        offset_in_page(reg_read(ctxt, VCPU_REGS_RDI)) :
                        PAGE_SIZE - offset_in_page(reg_read(ctxt, VCPU_REGS_RDI));
-               n = min(min(in_page, (unsigned int)sizeof(rc->data)) / size,
-                       count);
+               n = min3(in_page, (unsigned int)sizeof(rc->data) / size, count);
                if (n == 0)
                        n = 1;
                rc->pos = rc->end = 0;
@@ -1665,7 +1674,7 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt,
                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;
+               | EFLG_TF | EFLG_DF | EFLG_NT | EFLG_AC | EFLG_ID;
 
        switch(ctxt->mode) {
        case X86EMUL_MODE_PROT64:
@@ -2201,7 +2210,7 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
        *reg_write(ctxt, VCPU_REGS_RCX) = ctxt->_eip;
        if (efer & EFER_LMA) {
 #ifdef CONFIG_X86_64
-               *reg_write(ctxt, VCPU_REGS_R11) = ctxt->eflags & ~EFLG_RF;
+               *reg_write(ctxt, VCPU_REGS_R11) = ctxt->eflags;
 
                ops->get_msr(ctxt,
                             ctxt->mode == X86EMUL_MODE_PROT64 ?
@@ -2209,14 +2218,14 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
                ctxt->_eip = msr_data;
 
                ops->get_msr(ctxt, MSR_SYSCALL_MASK, &msr_data);
-               ctxt->eflags &= ~(msr_data | EFLG_RF);
+               ctxt->eflags &= ~msr_data;
 #endif
        } else {
                /* legacy mode */
                ops->get_msr(ctxt, MSR_STAR, &msr_data);
                ctxt->_eip = (u32)msr_data;
 
-               ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
+               ctxt->eflags &= ~(EFLG_VM | EFLG_IF);
        }
 
        return X86EMUL_CONTINUE;
@@ -2265,7 +2274,7 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt)
                break;
        }
 
-       ctxt->eflags &= ~(EFLG_VM | EFLG_IF | EFLG_RF);
+       ctxt->eflags &= ~(EFLG_VM | EFLG_IF);
        cs_sel = (u16)msr_data;
        cs_sel &= ~SELECTOR_RPL_MASK;
        ss_sel = cs_sel + 8;
@@ -4222,11 +4231,16 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
        ctxt->memop.type = OP_NONE;
        ctxt->memopp = NULL;
        ctxt->_eip = ctxt->eip;
-       ctxt->fetch.start = ctxt->_eip;
-       ctxt->fetch.end = ctxt->fetch.start + insn_len;
+       ctxt->fetch.ptr = ctxt->fetch.data;
+       ctxt->fetch.end = ctxt->fetch.data + 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:
@@ -4594,7 +4608,10 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
 
                /* Privileged instruction can be executed only in CPL=0 */
                if ((ctxt->d & Priv) && ops->cpl(ctxt)) {
-                       rc = emulate_gp(ctxt, 0);
+                       if (ctxt->d & PrivUD)
+                               rc = emulate_ud(ctxt);
+                       else
+                               rc = emulate_gp(ctxt, 0);
                        goto done;
                }
 
@@ -4622,6 +4639,7 @@ int x86_emulate_insn(struct x86_emulate_ctxt *ctxt)
                        /* All REP prefixes have the same first termination condition */
                        if (address_mask(ctxt, reg_read(ctxt, VCPU_REGS_RCX)) == 0) {
                                ctxt->eip = ctxt->_eip;
+                               ctxt->eflags &= ~EFLG_RF;
                                goto done;
                        }
                }
@@ -4664,6 +4682,11 @@ special_insn:
                        goto done;
        }
 
+       if (ctxt->rep_prefix && (ctxt->d & String))
+               ctxt->eflags |= EFLG_RF;
+       else
+               ctxt->eflags &= ~EFLG_RF;
+
        if (ctxt->execute) {
                if (ctxt->d & Fastop) {
                        void (*fop)(struct fastop *) = (void *)ctxt->execute;
@@ -4803,6 +4826,7 @@ writeback:
                        }
                        goto done; /* skip rip writeback */
                }
+               ctxt->eflags &= ~EFLG_RF;
        }
 
        ctxt->eip = ctxt->_eip;