From 53a388d723c82f8cd089381ebb1da52c8ac45a91 Mon Sep 17 00:00:00 2001
From: Bruce Rogers <brogers@suse.com>
Date: Mon, 22 Jan 2018 15:17:08 -0700
Subject: [PATCH] qemu-i386-kvm-MSR_IA32_SPEC_CTRL-and-MSR_IA32_PRED_CMD

---
 target-i386/cpu.h     |  7 ++++++-
 target-i386/helper.c  | 15 +++++++++++++++
 target-i386/kvm.c     | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++
 target-i386/machine.c |  1 +
 4 files changed, 74 insertions(+), 1 deletion(-)

diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 0df6f1d6cf..5990d91427 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -282,6 +282,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
@@ -421,6 +422,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" */
@@ -728,6 +732,7 @@ typedef struct CPUX86State {
     uint64 mce_banks[MCE_BANKS_DEF*4];
 
     uint64_t tsc_aux;
+    uint64_t spec_ctrl;
 
     /* vmstate */
     uint16_t fpus_vmstate;
@@ -895,7 +900,7 @@ uint64_t cpu_get_tsc(CPUX86State *env);
 #define cpu_signal_handler cpu_x86_signal_handler
 #define cpu_list x86_cpu_list
 
-#define CPU_SAVE_VERSION 12
+#define CPU_SAVE_VERSION 13
 
 /* MMU modes definitions */
 #define MMU_MODE0_SUFFIX _kernel
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 1cbe8d6e18..d44507cd1a 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1753,6 +1753,21 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         *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;
+            *ebx = 0;
+            *ecx = 0;
+            *edx &= CPUID_7_0_EDX_SPEC_CTRL | CPUID_7_0_EDX_PRED_CMD;
+        } 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 */
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 0376cc58c9..5b69c9412b 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -281,6 +281,51 @@ static int kvm_has_msr_star(CPUState *env)
     return 0;
 }
 
+static int kvm_has_msr_spec_ctrl(CPUState *env)
+{
+    static int has_msr_spec_ctrl;
+    int ret;
+
+    /* first time */
+    if (has_msr_spec_ctrl == 0) {
+        struct kvm_msr_list msr_list, *kvm_msr_list;
+
+        has_msr_spec_ctrl = -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 && ret != -E2BIG) {
+            return 0;
+        }
+        /* Old kernel modules had a bug and could write beyond the provided
+           memory. Allocate at least a safe amount of 1K. */
+        kvm_msr_list = qemu_mallocz(MAX(1024, 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_IA32_SPEC_CTRL) {
+                    has_msr_spec_ctrl = 1;
+                    break;
+                }
+            }
+        }
+
+        free(kvm_msr_list);
+    }
+
+    if (has_msr_spec_ctrl == 1)
+        return 1;
+    return 0;
+}
+
 int kvm_arch_init(KVMState *s, int smp_cpus)
 {
     int ret;
@@ -493,6 +538,8 @@ static int kvm_put_msrs(CPUState *env)
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_EIP, env->sysenter_eip);
     if (kvm_has_msr_star(env))
 	kvm_msr_entry_set(&msrs[n++], MSR_STAR, env->star);
+    if (kvm_has_msr_spec_ctrl(env))
+	kvm_msr_entry_set(&msrs[n++], MSR_STAR, env->spec_ctrl);
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_TSC, env->tsc);
     kvm_msr_entry_set(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave);
 #ifdef TARGET_X86_64
@@ -637,6 +684,8 @@ static int kvm_get_msrs(CPUState *env)
     msrs[n++].index = MSR_IA32_SYSENTER_EIP;
     if (kvm_has_msr_star(env))
 	msrs[n++].index = MSR_STAR;
+    if (kvm_has_msr_spec_ctrl(env))
+	msrs[n++].index = MSR_IA32_SPEC_CTRL;
     msrs[n++].index = MSR_IA32_TSC;
     msrs[n++].index = MSR_VM_HSAVE_PA;
 #ifdef TARGET_X86_64
@@ -668,6 +717,9 @@ static int kvm_get_msrs(CPUState *env)
         case MSR_STAR:
             env->star = msrs[i].data;
             break;
+        case MSR_IA32_SPEC_CTRL:
+            env->spec_ctrl = msrs[i].data;
+            break;
 #ifdef TARGET_X86_64
         case MSR_CSTAR:
             env->cstar = msrs[i].data;
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 0b8a33afdd..b9e76cfc4d 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -480,6 +480,7 @@ static const VMStateDescription vmstate_cpu = {
         /* KVM pvclock msr */
         VMSTATE_UINT64_V(system_time_msr, CPUState, 11),
         VMSTATE_UINT64_V(wall_clock_msr, CPUState, 11),
+        VMSTATE_UINT64_V(spec_ctrl, CPUState, 13),
         VMSTATE_END_OF_LIST()
         /* The above list is not sorted /wrt version numbers, watch out! */
     }
