]> Git Repo - linux.git/blobdiff - arch/x86/kvm/emulate.c
Merge tag 'v4.15' into x86/pti, to be able to merge dependent changes
[linux.git] / arch / x86 / kvm / emulate.c
index 453d8c99010822222b8a1d9433d0bdfc6dc50fd9..290ecf711aec2d6684fd296d07d7379a88232027 100644 (file)
@@ -1047,7 +1047,6 @@ static void fetch_register_operand(struct operand *op)
 
 static void read_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data, int reg)
 {
-       ctxt->ops->get_fpu(ctxt);
        switch (reg) {
        case 0: asm("movdqa %%xmm0, %0" : "=m"(*data)); break;
        case 1: asm("movdqa %%xmm1, %0" : "=m"(*data)); break;
@@ -1069,13 +1068,11 @@ static void read_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data, int reg)
 #endif
        default: BUG();
        }
-       ctxt->ops->put_fpu(ctxt);
 }
 
 static void write_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data,
                          int reg)
 {
-       ctxt->ops->get_fpu(ctxt);
        switch (reg) {
        case 0: asm("movdqa %0, %%xmm0" : : "m"(*data)); break;
        case 1: asm("movdqa %0, %%xmm1" : : "m"(*data)); break;
@@ -1097,12 +1094,10 @@ static void write_sse_reg(struct x86_emulate_ctxt *ctxt, sse128_t *data,
 #endif
        default: BUG();
        }
-       ctxt->ops->put_fpu(ctxt);
 }
 
 static void read_mmx_reg(struct x86_emulate_ctxt *ctxt, u64 *data, int reg)
 {
-       ctxt->ops->get_fpu(ctxt);
        switch (reg) {
        case 0: asm("movq %%mm0, %0" : "=m"(*data)); break;
        case 1: asm("movq %%mm1, %0" : "=m"(*data)); break;
@@ -1114,12 +1109,10 @@ static void read_mmx_reg(struct x86_emulate_ctxt *ctxt, u64 *data, int reg)
        case 7: asm("movq %%mm7, %0" : "=m"(*data)); break;
        default: BUG();
        }
-       ctxt->ops->put_fpu(ctxt);
 }
 
 static void write_mmx_reg(struct x86_emulate_ctxt *ctxt, u64 *data, int reg)
 {
-       ctxt->ops->get_fpu(ctxt);
        switch (reg) {
        case 0: asm("movq %0, %%mm0" : : "m"(*data)); break;
        case 1: asm("movq %0, %%mm1" : : "m"(*data)); break;
@@ -1131,7 +1124,6 @@ static void write_mmx_reg(struct x86_emulate_ctxt *ctxt, u64 *data, int reg)
        case 7: asm("movq %0, %%mm7" : : "m"(*data)); break;
        default: BUG();
        }
-       ctxt->ops->put_fpu(ctxt);
 }
 
 static int em_fninit(struct x86_emulate_ctxt *ctxt)
@@ -1139,9 +1131,7 @@ static int em_fninit(struct x86_emulate_ctxt *ctxt)
        if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
                return emulate_nm(ctxt);
 
-       ctxt->ops->get_fpu(ctxt);
        asm volatile("fninit");
-       ctxt->ops->put_fpu(ctxt);
        return X86EMUL_CONTINUE;
 }
 
@@ -1152,9 +1142,7 @@ static int em_fnstcw(struct x86_emulate_ctxt *ctxt)
        if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
                return emulate_nm(ctxt);
 
-       ctxt->ops->get_fpu(ctxt);
        asm volatile("fnstcw %0": "+m"(fcw));
-       ctxt->ops->put_fpu(ctxt);
 
        ctxt->dst.val = fcw;
 
@@ -1168,9 +1156,7 @@ static int em_fnstsw(struct x86_emulate_ctxt *ctxt)
        if (ctxt->ops->get_cr(ctxt, 0) & (X86_CR0_TS | X86_CR0_EM))
                return emulate_nm(ctxt);
 
-       ctxt->ops->get_fpu(ctxt);
        asm volatile("fnstsw %0": "+m"(fsw));
-       ctxt->ops->put_fpu(ctxt);
 
        ctxt->dst.val = fsw;
 
@@ -2405,9 +2391,21 @@ static int rsm_load_seg_64(struct x86_emulate_ctxt *ctxt, u64 smbase, int n)
 }
 
 static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt,
-                                    u64 cr0, u64 cr4)
+                                   u64 cr0, u64 cr3, u64 cr4)
 {
        int bad;
+       u64 pcid;
+
+       /* In order to later set CR4.PCIDE, CR3[11:0] must be zero.  */
+       pcid = 0;
+       if (cr4 & X86_CR4_PCIDE) {
+               pcid = cr3 & 0xfff;
+               cr3 &= ~0xfff;
+       }
+
+       bad = ctxt->ops->set_cr(ctxt, 3, cr3);
+       if (bad)
+               return X86EMUL_UNHANDLEABLE;
 
        /*
         * First enable PAE, long mode needs it before CR0.PG = 1 is set.
@@ -2426,6 +2424,12 @@ static int rsm_enter_protected_mode(struct x86_emulate_ctxt *ctxt,
                bad = ctxt->ops->set_cr(ctxt, 4, cr4);
                if (bad)
                        return X86EMUL_UNHANDLEABLE;
+               if (pcid) {
+                       bad = ctxt->ops->set_cr(ctxt, 3, cr3 | pcid);
+                       if (bad)
+                               return X86EMUL_UNHANDLEABLE;
+               }
+
        }
 
        return X86EMUL_CONTINUE;
@@ -2436,11 +2440,11 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase)
        struct desc_struct desc;
        struct desc_ptr dt;
        u16 selector;
-       u32 val, cr0, cr4;
+       u32 val, cr0, cr3, cr4;
        int i;
 
        cr0 =                      GET_SMSTATE(u32, smbase, 0x7ffc);
-       ctxt->ops->set_cr(ctxt, 3, GET_SMSTATE(u32, smbase, 0x7ff8));
+       cr3 =                      GET_SMSTATE(u32, smbase, 0x7ff8);
        ctxt->eflags =             GET_SMSTATE(u32, smbase, 0x7ff4) | X86_EFLAGS_FIXED;
        ctxt->_eip =               GET_SMSTATE(u32, smbase, 0x7ff0);
 
@@ -2482,14 +2486,14 @@ static int rsm_load_state_32(struct x86_emulate_ctxt *ctxt, u64 smbase)
 
        ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7ef8));
 
-       return rsm_enter_protected_mode(ctxt, cr0, cr4);
+       return rsm_enter_protected_mode(ctxt, cr0, cr3, cr4);
 }
 
 static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase)
 {
        struct desc_struct desc;
        struct desc_ptr dt;
-       u64 val, cr0, cr4;
+       u64 val, cr0, cr3, cr4;
        u32 base3;
        u16 selector;
        int i, r;
@@ -2506,7 +2510,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase)
        ctxt->ops->set_dr(ctxt, 7, (val & DR7_VOLATILE) | DR7_FIXED_1);
 
        cr0 =                       GET_SMSTATE(u64, smbase, 0x7f58);
-       ctxt->ops->set_cr(ctxt, 3,  GET_SMSTATE(u64, smbase, 0x7f50));
+       cr3 =                       GET_SMSTATE(u64, smbase, 0x7f50);
        cr4 =                       GET_SMSTATE(u64, smbase, 0x7f48);
        ctxt->ops->set_smbase(ctxt, GET_SMSTATE(u32, smbase, 0x7f00));
        val =                       GET_SMSTATE(u64, smbase, 0x7ed0);
@@ -2534,7 +2538,7 @@ static int rsm_load_state_64(struct x86_emulate_ctxt *ctxt, u64 smbase)
        dt.address =                GET_SMSTATE(u64, smbase, 0x7e68);
        ctxt->ops->set_gdt(ctxt, &dt);
 
-       r = rsm_enter_protected_mode(ctxt, cr0, cr4);
+       r = rsm_enter_protected_mode(ctxt, cr0, cr3, cr4);
        if (r != X86EMUL_CONTINUE)
                return r;
 
@@ -2592,6 +2596,15 @@ static int em_rsm(struct x86_emulate_ctxt *ctxt)
        ctxt->ops->set_msr(ctxt, MSR_EFER, efer);
 
        smbase = ctxt->ops->get_smbase(ctxt);
+
+       /*
+        * Give pre_leave_smm() a chance to make ISA-specific changes to the
+        * vCPU state (e.g. enter guest mode) before loading state from the SMM
+        * state-save area.
+        */
+       if (ctxt->ops->pre_leave_smm(ctxt, smbase))
+               return X86EMUL_UNHANDLEABLE;
+
        if (emulator_has_longmode(ctxt))
                ret = rsm_load_state_64(ctxt, smbase + 0x8000);
        else
@@ -3993,12 +4006,8 @@ static int em_fxsave(struct x86_emulate_ctxt *ctxt)
        if (rc != X86EMUL_CONTINUE)
                return rc;
 
-       ctxt->ops->get_fpu(ctxt);
-
        rc = asm_safe("fxsave %[fx]", , [fx] "+m"(fx_state));
 
-       ctxt->ops->put_fpu(ctxt);
-
        if (rc != X86EMUL_CONTINUE)
                return rc;
 
@@ -4006,6 +4015,26 @@ static int em_fxsave(struct x86_emulate_ctxt *ctxt)
                                   fxstate_size(ctxt));
 }
 
+/*
+ * FXRSTOR might restore XMM registers not provided by the guest. Fill
+ * in the host registers (via FXSAVE) instead, so they won't be modified.
+ * (preemption has to stay disabled until FXRSTOR).
+ *
+ * Use noinline to keep the stack for other functions called by callers small.
+ */
+static noinline int fxregs_fixup(struct fxregs_state *fx_state,
+                                const size_t used_size)
+{
+       struct fxregs_state fx_tmp;
+       int rc;
+
+       rc = asm_safe("fxsave %[fx]", , [fx] "+m"(fx_tmp));
+       memcpy((void *)fx_state + used_size, (void *)&fx_tmp + used_size,
+              __fxstate_size(16) - used_size);
+
+       return rc;
+}
+
 static int em_fxrstor(struct x86_emulate_ctxt *ctxt)
 {
        struct fxregs_state fx_state;
@@ -4016,19 +4045,17 @@ static int em_fxrstor(struct x86_emulate_ctxt *ctxt)
        if (rc != X86EMUL_CONTINUE)
                return rc;
 
-       ctxt->ops->get_fpu(ctxt);
-
        size = fxstate_size(ctxt);
+       rc = segmented_read_std(ctxt, ctxt->memop.addr.mem, &fx_state, size);
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
+
        if (size < __fxstate_size(16)) {
-               rc = asm_safe("fxsave %[fx]", , [fx] "+m"(fx_state));
+               rc = fxregs_fixup(&fx_state, size);
                if (rc != X86EMUL_CONTINUE)
                        goto out;
        }
 
-       rc = segmented_read_std(ctxt, ctxt->memop.addr.mem, &fx_state, size);
-       if (rc != X86EMUL_CONTINUE)
-               goto out;
-
        if (fx_state.mxcsr >> 16) {
                rc = emulate_gp(ctxt, 0);
                goto out;
@@ -4038,8 +4065,6 @@ static int em_fxrstor(struct x86_emulate_ctxt *ctxt)
                rc = asm_safe("fxrstor %[fx]", : [fx] "m"(fx_state));
 
 out:
-       ctxt->ops->put_fpu(ctxt);
-
        return rc;
 }
 
@@ -4992,6 +5017,8 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
        bool op_prefix = false;
        bool has_seg_override = false;
        struct opcode opcode;
+       u16 dummy;
+       struct desc_struct desc;
 
        ctxt->memop.type = OP_NONE;
        ctxt->memopp = NULL;
@@ -5010,6 +5037,11 @@ int x86_decode_insn(struct x86_emulate_ctxt *ctxt, void *insn, int insn_len)
        switch (mode) {
        case X86EMUL_MODE_REAL:
        case X86EMUL_MODE_VM86:
+               def_op_bytes = def_ad_bytes = 2;
+               ctxt->ops->get_segment(ctxt, &dummy, &desc, NULL, VCPU_SREG_CS);
+               if (desc.d)
+                       def_op_bytes = def_ad_bytes = 4;
+               break;
        case X86EMUL_MODE_PROT16:
                def_op_bytes = def_ad_bytes = 2;
                break;
@@ -5282,9 +5314,7 @@ static int flush_pending_x87_faults(struct x86_emulate_ctxt *ctxt)
 {
        int rc;
 
-       ctxt->ops->get_fpu(ctxt);
        rc = asm_safe("fwait");
-       ctxt->ops->put_fpu(ctxt);
 
        if (unlikely(rc != X86EMUL_CONTINUE))
                return emulate_exception(ctxt, MF_VECTOR, 0, false);
This page took 0.038228 seconds and 4 git commands to generate.