x86: KVM: add xsetbv to the emulator
authorVitaly Kuznetsov <vkuznets@redhat.com>
Tue, 13 Aug 2019 13:53:32 +0000 (15:53 +0200)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 22 Aug 2019 08:09:20 +0000 (10:09 +0200)
To avoid hardcoding xsetbv length to '3' we need to support decoding it in
the emulator.

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_emulate.h
arch/x86/kvm/emulate.c
arch/x86/kvm/svm.c
arch/x86/kvm/x86.c

index feab24c..77cf6c1 100644 (file)
@@ -229,7 +229,7 @@ struct x86_emulate_ops {
        int (*pre_leave_smm)(struct x86_emulate_ctxt *ctxt,
                             const char *smstate);
        void (*post_leave_smm)(struct x86_emulate_ctxt *ctxt);
-
+       int (*set_xcr)(struct x86_emulate_ctxt *ctxt, u32 index, u64 xcr);
 };
 
 typedef u32 __attribute__((vector_size(16))) sse128_t;
@@ -429,6 +429,7 @@ enum x86_intercept {
        x86_intercept_ins,
        x86_intercept_out,
        x86_intercept_outs,
+       x86_intercept_xsetbv,
 
        nr_x86_intercepts
 };
index 6170ddf..bef3c3c 100644 (file)
@@ -4156,6 +4156,20 @@ out:
        return rc;
 }
 
+static int em_xsetbv(struct x86_emulate_ctxt *ctxt)
+{
+       u32 eax, ecx, edx;
+
+       eax = reg_read(ctxt, VCPU_REGS_RAX);
+       edx = reg_read(ctxt, VCPU_REGS_RDX);
+       ecx = reg_read(ctxt, VCPU_REGS_RCX);
+
+       if (ctxt->ops->set_xcr(ctxt, ecx, ((u64)edx << 32) | eax))
+               return emulate_gp(ctxt, 0);
+
+       return X86EMUL_CONTINUE;
+}
+
 static bool valid_cr(int nr)
 {
        switch (nr) {
@@ -4409,6 +4423,12 @@ static const struct opcode group7_rm1[] = {
        N, N, N, N, N, N,
 };
 
+static const struct opcode group7_rm2[] = {
+       N,
+       II(ImplicitOps | Priv,                  em_xsetbv,      xsetbv),
+       N, N, N, N, N, N,
+};
+
 static const struct opcode group7_rm3[] = {
        DIP(SrcNone | Prot | Priv,              vmrun,          check_svme_pa),
        II(SrcNone  | Prot | EmulateOnUD,       em_hypercall,   vmmcall),
@@ -4498,7 +4518,8 @@ static const struct group_dual group7 = { {
 }, {
        EXT(0, group7_rm0),
        EXT(0, group7_rm1),
-       N, EXT(0, group7_rm3),
+       EXT(0, group7_rm2),
+       EXT(0, group7_rm3),
        II(SrcNone | DstMem | Mov,              em_smsw, smsw), N,
        II(SrcMem16 | Mov | Priv,               em_lmsw, lmsw),
        EXT(0, group7_rm7),
index 1ff786d..6aba0a0 100644 (file)
@@ -6076,6 +6076,7 @@ static const struct __x86_intercept {
        [x86_intercept_ins]             = POST_EX(SVM_EXIT_IOIO),
        [x86_intercept_out]             = POST_EX(SVM_EXIT_IOIO),
        [x86_intercept_outs]            = POST_EX(SVM_EXIT_IOIO),
+       [x86_intercept_xsetbv]          = PRE_EX(SVM_EXIT_XSETBV),
 };
 
 #undef PRE_EX
index 90a895d..9f46b04 100644 (file)
@@ -6075,6 +6075,11 @@ static void emulator_post_leave_smm(struct x86_emulate_ctxt *ctxt)
        kvm_smm_changed(emul_to_vcpu(ctxt));
 }
 
+static int emulator_set_xcr(struct x86_emulate_ctxt *ctxt, u32 index, u64 xcr)
+{
+       return __kvm_set_xcr(emul_to_vcpu(ctxt), index, xcr);
+}
+
 static const struct x86_emulate_ops emulate_ops = {
        .read_gpr            = emulator_read_gpr,
        .write_gpr           = emulator_write_gpr,
@@ -6116,6 +6121,7 @@ static const struct x86_emulate_ops emulate_ops = {
        .set_hflags          = emulator_set_hflags,
        .pre_leave_smm       = emulator_pre_leave_smm,
        .post_leave_smm      = emulator_post_leave_smm,
+       .set_xcr             = emulator_set_xcr,
 };
 
 static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask)