From: Wei Wang <wei.w.wang@intel.com>
Date: Tue, 7 Nov 2017 16:39:49 +0800
Subject: [PATCH] i386/kvm: MSR_IA32_SPEC_CTRL and MSR_IA32_PRED_CMD

CPUID(EAX=0X7,ECX=0).EDX[26]/[27] indicates the support of
MSR_IA32_SPEC_CTRL and MSR_IA32_PRED_CMD. Expose the CPUID
to the guest. Also add the support of transferring the MSRs during live
migration.

Signed-off-by: Wei Wang <wei.w.wang@intel.com>
---

Index: xen-4.7.4-testing/tools/qemu-xen-traditional-dir-remote/target-i386/helper.c
===================================================================
--- xen-4.7.4-testing.orig/tools/qemu-xen-traditional-dir-remote/target-i386/helper.c
+++ xen-4.7.4-testing/tools/qemu-xen-traditional-dir-remote/target-i386/helper.c
@@ -1528,6 +1528,21 @@ void cpu_x86_cpuid(CPUX86State *env, uin
         *ecx = 0;
         *edx = 0;
         break;
+    case 7:
+        /* Structured Extended Feature Flags Enumeration Leaf */
+        if (count == 0) {
+            host_cpuid(index, 0, eax, ebx, ecx, edx);
+            *eax = 0; /* Maximum ECX value for sub-leaves */
+            *ebx = 0; /* Feature flags */
+            *ecx = 0; /* Reserved */
+            *edx = env->cpuid_features | *edx;
+        } else {
+            *eax = 0;
+            *ebx = 0;
+            *ecx = 0;
+            *edx = 0;
+        }
+        break;
     case 9:
         /* Direct Cache Access Information Leaf */
         *eax = 0; /* Bits 0-31 in DCA_CAP MSR */
Index: xen-4.7.4-testing/tools/qemu-xen-traditional-dir-remote/target-i386/cpu.h
===================================================================
--- xen-4.7.4-testing.orig/tools/qemu-xen-traditional-dir-remote/target-i386/cpu.h
+++ xen-4.7.4-testing/tools/qemu-xen-traditional-dir-remote/target-i386/cpu.h
@@ -250,6 +250,7 @@
 #define MSR_IA32_APICBASE_BSP           (1<<8)
 #define MSR_IA32_APICBASE_ENABLE        (1<<11)
 #define MSR_IA32_APICBASE_BASE          (0xfffff<<12)
+#define MSR_IA32_SPEC_CTRL              0x00000048
 
 #define MSR_MTRRcap			0xfe
 #define MSR_MTRRcap_VCNT		8
@@ -382,6 +383,9 @@
 #define CPUID_EXT3_IBS     (1 << 10)
 #define CPUID_EXT3_SKINIT  (1 << 12)
 
+#define CPUID_7_0_EDX_SPEC_CTRL     (1U << 26)
+#define CPUID_7_0_EDX_PRED_CMD      (1U << 27)
+
 #define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */
 #define CPUID_VENDOR_INTEL_2 0x49656e69 /* "ineI" */
 #define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
@@ -670,6 +674,7 @@ typedef struct CPUX86State {
     /* in order to simplify APIC support, we leave this pointer to the
        user */
     struct APICState *apic_state;
+    uint64_t spec_ctrl;
 } CPUX86State;
 
 CPUX86State *cpu_x86_init(const char *cpu_model);
Index: xen-4.7.4-testing/tools/qemu-xen-traditional-dir-remote/target-i386/kvm.c
===================================================================
--- xen-4.7.4-testing.orig/tools/qemu-xen-traditional-dir-remote/target-i386/kvm.c
+++ xen-4.7.4-testing/tools/qemu-xen-traditional-dir-remote/target-i386/kvm.c
@@ -129,48 +129,73 @@ int kvm_arch_init_vcpu(CPUState *env)
     return kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data);
 }
 
-static int kvm_has_msr_star(CPUState *env)
+static int kvm_has_msr(CPUState *env, int msr)
 {
-    static int has_msr_star;
-    int ret;
+    int ret, has_msr;
+    struct kvm_msr_list msr_list, *kvm_msr_list;
 
-    /* first time */
-    if (has_msr_star == 0) {        
-        struct kvm_msr_list msr_list, *kvm_msr_list;
+    has_msr = -1;
 
-        has_msr_star = -1;
-
-        /* Obtain MSR list from KVM.  These are the MSRs that we must
-         * save/restore */
-        msr_list.nmsrs = 0;
-        ret = kvm_ioctl(env->kvm_state, KVM_GET_MSR_INDEX_LIST, &msr_list);
-        if (ret < 0)
-            return 0;
+    /* Obtain MSR list from KVM.  These are the MSRs that we must
+    * save/restore */
+    msr_list.nmsrs = 0;
+    ret = kvm_ioctl(env->kvm_state, KVM_GET_MSR_INDEX_LIST, &msr_list);
+    if (ret < 0)
+        return 0;
 
-        kvm_msr_list = qemu_mallocz(sizeof(msr_list) +
-                                    msr_list.nmsrs * sizeof(msr_list.indices[0]));
+    kvm_msr_list = qemu_mallocz(sizeof(msr_list) +
+                                msr_list.nmsrs * sizeof(msr_list.indices[0]));
 
-        kvm_msr_list->nmsrs = msr_list.nmsrs;
-        ret = kvm_ioctl(env->kvm_state, KVM_GET_MSR_INDEX_LIST, kvm_msr_list);
-        if (ret >= 0) {
-            int i;
-
-            for (i = 0; i < kvm_msr_list->nmsrs; i++) {
-                if (kvm_msr_list->indices[i] == MSR_STAR) {
-                    has_msr_star = 1;
-                    break;
-                }
+    kvm_msr_list->nmsrs = msr_list.nmsrs;
+    ret = kvm_ioctl(env->kvm_state, KVM_GET_MSR_INDEX_LIST, kvm_msr_list);
+    if (ret >= 0) {
+        int i;
+
+        for (i = 0; i < kvm_msr_list->nmsrs; i++) {
+            if (kvm_msr_list->indices[i] == msr) {
+                has_msr = 1;
+                break;
             }
         }
-
-        free(kvm_msr_list);
     }
 
+    free(kvm_msr_list);
+
+    if (has_msr == 1)
+        return 1;
+    return 0;
+}
+
+static int kvm_has_msr_star(CPUState *env)
+    static int has_msr_star;
+
+    /* first time */
+    if (has_msr_star == 0) {
+        has_msr_star = -1;
+
+        if (kvm_has_msr(env, MSR_STAR))
+            has_msr_star = 1;
+    }
     if (has_msr_star == 1)
         return 1;
     return 0;
 }
 
+static int kvm_has_msr_spec_ctrl(CPUState *env)
+    static int has_msr_spec_ctrl;
+
+    /* first time */
+    if (has_msr_spec_ctrl == 0) {
+        has_msr_spec_ctrl = -1;
+
+        if (kvm_has_msr(env, MSR_IA32_SPEC_CTRL))
+            has_msr_spec_ctrl = 1;
+    }
+    if (has_msr_spec_ctrl == 1)
+        return 1;
+    return 0;
+}
+
 int kvm_arch_init(KVMState *s, int smp_cpus)
 {
     int ret;
@@ -379,8 +404,10 @@ static int kvm_put_msrs(CPUState *env)
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_CS, env->sysenter_cs);
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_ESP, env->sysenter_esp);
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_EIP, env->sysenter_eip);
-    if (kvm_has_msr_star(env))
+    if (kvm_has_msr_star(env, MSR_STAR))
 	kvm_msr_entry_set(&msrs[n++], MSR_STAR, env->star);
+    if (kvm_has_msr_spec_ctrl(env, MSR_IA32_SPEC_CTRL)
+	kvm_msr_entry_set(&msrs[n++], MSR_IA32_SPEC_CTRL, env->spec_ctrl);
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSC, env->tsc);
 #ifdef TARGET_X86_64
     /* FIXME if lm capable */
@@ -515,6 +542,8 @@ static int kvm_get_msrs(CPUState *env)
     if (kvm_has_msr_star(env))
 	msrs[n++].index = MSR_STAR;
     msrs[n++].index = MSR_IA32_TSC;
+    if (kvm_has_msr_spec_ctrl(env))
+	msrs[n++].index = MSR_IA32_SPEC_CTRL;
 #ifdef TARGET_X86_64
     /* FIXME lm_capable_kernel */
     msrs[n++].index = MSR_CSTAR;
@@ -558,6 +587,9 @@ static int kvm_get_msrs(CPUState *env)
         case MSR_IA32_TSC:
             env->tsc = msrs[i].data;
             break;
+        case MSR_IA32_SPEC_CTRL:
+            env->spec_ctrl = msrs[i].data;
+            break;
         }
     }
 
@@ -680,6 +712,9 @@ int kvm_arch_handle_exit(CPUState *env,
         ret = kvm_handle_halt(env);
         break;
     }
+    if (has_msr_spec_ctrl) {
+        kvm_msr_entry_add(cpu, MSR_IA32_SPEC_CTRL, 0);
+    }
 
     return ret;
 }
Index: xen-4.7.4-testing/tools/qemu-xen-traditional-dir-remote/target-i386/machine.c
===================================================================
--- xen-4.7.4-testing.orig/tools/qemu-xen-traditional-dir-remote/target-i386/machine.c
+++ xen-4.7.4-testing/tools/qemu-xen-traditional-dir-remote/target-i386/machine.c
@@ -143,6 +143,7 @@ void cpu_save(QEMUFile *f, void *opaque)
         qemu_put_be64s(f, &env->mtrr_var[i].base);
         qemu_put_be64s(f, &env->mtrr_var[i].mask);
     }
+    qemu_put_be64s(f, &env->spec_ctrl);
 }
 
 #ifdef USE_X86LDOUBLE
@@ -321,6 +322,7 @@ int cpu_load(QEMUFile *f, void *opaque,
             qemu_get_be64s(f, &env->mtrr_var[i].base);
             qemu_get_be64s(f, &env->mtrr_var[i].mask);
         }
+        qemu_get_be64s(f, &env->spec_ctrl);
     }
 
     /* XXX: ensure compatiblity for halted bit ? */
