218e99
From 7bb09ff3360af16599cc2cae834f676a20cdfa88 Mon Sep 17 00:00:00 2001
218e99
From: Paolo Bonzini <pbonzini@redhat.com>
218e99
Date: Wed, 6 Nov 2013 08:27:29 +0100
218e99
Subject: [PATCH 02/29] kvm: migrate vPMU state
218e99
218e99
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
218e99
Message-id: <1379955972-3080-3-git-send-email-pbonzini@redhat.com>
218e99
Patchwork-id: 54487
218e99
O-Subject: [RHEL 7.0 qemu-kvm PATCH 2/2] kvm: migrate vPMU state
218e99
Bugzilla: 928867
218e99
RH-Acked-by: Juan Quintela <quintela@redhat.com>
218e99
RH-Acked-by: Marcelo Tosatti <mtosatti@redhat.com>
218e99
RH-Acked-by: Bandan Das <bsd@redhat.com>
218e99
218e99
Reviewed-by: Gleb Natapov <gnatapov@redhat.com>
218e99
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
218e99
(cherry-picked from commit 0d89436786b02a9e7d561c4d7dc4982e4a2739db)
218e99
218e99
Conflicts:
218e99
	target-i386/machine.c
218e99
        [missing 0779cae, Initialize IA32_FEATURE_CONTROL MSR in reset and migration, 2013-07-07]
218e99
218e99
Signed-of-by: Miroslav Rezanina <mrezanin@redhat.com>
218e99
---
218e99
 target-i386/cpu.h     |   23 ++++++++++++
218e99
 target-i386/kvm.c     |   93 ++++++++++++++++++++++++++++++++++++++++++++++---
218e99
 target-i386/machine.c |   44 +++++++++++++++++++++++
218e99
 3 files changed, 155 insertions(+), 5 deletions(-)
218e99
218e99
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
218e99
index 74c7899..6aebc80 100644
218e99
--- a/target-i386/cpu.h
218e99
+++ b/target-i386/cpu.h
218e99
@@ -304,6 +304,8 @@
218e99
 #define MSR_TSC_ADJUST                  0x0000003b
218e99
 #define MSR_IA32_TSCDEADLINE            0x6e0
218e99
 
218e99
+#define MSR_P6_PERFCTR0                 0xc1
218e99
+
218e99
 #define MSR_MTRRcap                     0xfe
218e99
 #define MSR_MTRRcap_VCNT                8
218e99
 #define MSR_MTRRcap_FIXRANGE_SUPPORT    (1 << 8)
218e99
@@ -317,6 +319,8 @@
218e99
 #define MSR_MCG_STATUS                  0x17a
218e99
 #define MSR_MCG_CTL                     0x17b
218e99
 
218e99
+#define MSR_P6_EVNTSEL0                 0x186
218e99
+
218e99
 #define MSR_IA32_PERF_STATUS            0x198
218e99
 
218e99
 #define MSR_IA32_MISC_ENABLE            0x1a0
218e99
@@ -342,6 +346,14 @@
218e99
 
218e99
 #define MSR_MTRRdefType                 0x2ff
218e99
 
218e99
+#define MSR_CORE_PERF_FIXED_CTR0        0x309
218e99
+#define MSR_CORE_PERF_FIXED_CTR1        0x30a
218e99
+#define MSR_CORE_PERF_FIXED_CTR2        0x30b
218e99
+#define MSR_CORE_PERF_FIXED_CTR_CTRL    0x38d
218e99
+#define MSR_CORE_PERF_GLOBAL_STATUS     0x38e
218e99
+#define MSR_CORE_PERF_GLOBAL_CTRL       0x38f
218e99
+#define MSR_CORE_PERF_GLOBAL_OVF_CTRL   0x390
218e99
+
218e99
 #define MSR_MC0_CTL                     0x400
218e99
 #define MSR_MC0_STATUS                  0x401
218e99
 #define MSR_MC0_ADDR                    0x402
218e99
@@ -720,6 +732,9 @@ typedef struct {
218e99
 #define CPU_NB_REGS CPU_NB_REGS32
218e99
 #endif
218e99
 
218e99
+#define MAX_FIXED_COUNTERS 3
218e99
+#define MAX_GP_COUNTERS    (MSR_IA32_PERF_STATUS - MSR_P6_EVNTSEL0)
218e99
+
218e99
 #define NB_MMU_MODES 3
218e99
 
218e99
 typedef enum TPRAccess {
218e99
@@ -814,6 +829,14 @@ typedef struct CPUX86State {
218e99
     uint64_t mcg_status;
218e99
     uint64_t msr_ia32_misc_enable;
218e99
 
218e99
+    uint64_t msr_fixed_ctr_ctrl;
218e99
+    uint64_t msr_global_ctrl;
218e99
+    uint64_t msr_global_status;
218e99
+    uint64_t msr_global_ovf_ctrl;
218e99
+    uint64_t msr_fixed_counters[MAX_FIXED_COUNTERS];
218e99
+    uint64_t msr_gp_counters[MAX_GP_COUNTERS];
218e99
+    uint64_t msr_gp_evtsel[MAX_GP_COUNTERS];
218e99
+
218e99
     /* exception/interrupt handling */
218e99
     int error_code;
218e99
     int exception_is_int;
218e99
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
218e99
index c5a9416..4b470e4 100644
218e99
--- a/target-i386/kvm.c
218e99
+++ b/target-i386/kvm.c
218e99
@@ -71,6 +71,9 @@ static bool has_msr_misc_enable;
218e99
 static bool has_msr_kvm_steal_time;
218e99
 static int lm_capable_kernel;
218e99
 
218e99
+static bool has_msr_architectural_pmu;
218e99
+static uint32_t num_architectural_pmu_counters;
218e99
+
218e99
 bool kvm_allows_irq0_override(void)
218e99
 {
218e99
     return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
218e99
@@ -579,6 +582,25 @@ int kvm_arch_init_vcpu(CPUState *cs)
218e99
             break;
218e99
         }
218e99
     }
218e99
+
218e99
+    if (limit >= 0x0a) {
218e99
+        uint32_t ver;
218e99
+
218e99
+        cpu_x86_cpuid(env, 0x0a, 0, &ver, &unused, &unused, &unused);
218e99
+        if ((ver & 0xff) > 0) {
218e99
+            has_msr_architectural_pmu = true;
218e99
+            num_architectural_pmu_counters = (ver & 0xff00) >> 8;
218e99
+
218e99
+            /* Shouldn't be more than 32, since that's the number of bits
218e99
+             * available in EBX to tell us _which_ counters are available.
218e99
+             * Play it safe.
218e99
+             */
218e99
+            if (num_architectural_pmu_counters > MAX_GP_COUNTERS) {
218e99
+                num_architectural_pmu_counters = MAX_GP_COUNTERS;
218e99
+            }
218e99
+        }
218e99
+    }
218e99
+
218e99
     cpu_x86_cpuid(env, 0x80000000, 0, &limit, &unused, &unused, &unused);
218e99
 
218e99
     for (i = 0x80000000; i <= limit; i++) {
218e99
@@ -1070,7 +1092,7 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
218e99
         struct kvm_msr_entry entries[100];
218e99
     } msr_data;
218e99
     struct kvm_msr_entry *msrs = msr_data.entries;
218e99
-    int n = 0;
218e99
+    int n = 0, i;
218e99
 
218e99
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_CS, env->sysenter_cs);
218e99
     kvm_msr_entry_set(&msrs[n++], MSR_IA32_SYSENTER_ESP, env->sysenter_esp);
218e99
@@ -1109,9 +1131,8 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
218e99
         }
218e99
     }
218e99
     /*
218e99
-     * The following paravirtual MSRs have side effects on the guest or are
218e99
-     * too heavy for normal writeback. Limit them to reset or full state
218e99
-     * updates.
218e99
+     * The following MSRs have side effects on the guest or are too heavy
218e99
+     * for normal writeback. Limit them to reset or full state updates.
218e99
      */
218e99
     if (level >= KVM_PUT_RESET_STATE) {
218e99
         kvm_msr_entry_set(&msrs[n++], MSR_KVM_SYSTEM_TIME,
218e99
@@ -1129,6 +1150,33 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
218e99
             kvm_msr_entry_set(&msrs[n++], MSR_KVM_STEAL_TIME,
218e99
                               env->steal_time_msr);
218e99
         }
218e99
+        if (has_msr_architectural_pmu) {
218e99
+            /* Stop the counter.  */
218e99
+            kvm_msr_entry_set(&msrs[n++], MSR_CORE_PERF_FIXED_CTR_CTRL, 0);
218e99
+            kvm_msr_entry_set(&msrs[n++], MSR_CORE_PERF_GLOBAL_CTRL, 0);
218e99
+
218e99
+            /* Set the counter values.  */
218e99
+            for (i = 0; i < MAX_FIXED_COUNTERS; i++) {
218e99
+                kvm_msr_entry_set(&msrs[n++], MSR_CORE_PERF_FIXED_CTR0 + i,
218e99
+                                  env->msr_fixed_counters[i]);
218e99
+            }
218e99
+            for (i = 0; i < num_architectural_pmu_counters; i++) {
218e99
+                kvm_msr_entry_set(&msrs[n++], MSR_P6_PERFCTR0 + i,
218e99
+                                  env->msr_gp_counters[i]);
218e99
+                kvm_msr_entry_set(&msrs[n++], MSR_P6_EVNTSEL0 + i,
218e99
+                                  env->msr_gp_evtsel[i]);
218e99
+            }
218e99
+            kvm_msr_entry_set(&msrs[n++], MSR_CORE_PERF_GLOBAL_STATUS,
218e99
+                              env->msr_global_status);
218e99
+            kvm_msr_entry_set(&msrs[n++], MSR_CORE_PERF_GLOBAL_OVF_CTRL,
218e99
+                              env->msr_global_ovf_ctrl);
218e99
+
218e99
+            /* Now start the PMU.  */
218e99
+            kvm_msr_entry_set(&msrs[n++], MSR_CORE_PERF_FIXED_CTR_CTRL,
218e99
+                              env->msr_fixed_ctr_ctrl);
218e99
+            kvm_msr_entry_set(&msrs[n++], MSR_CORE_PERF_GLOBAL_CTRL,
218e99
+                              env->msr_global_ctrl);
218e99
+        }
218e99
         if (hyperv_hypercall_available()) {
218e99
             kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0);
218e99
             kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0);
218e99
@@ -1385,6 +1433,19 @@ static int kvm_get_msrs(X86CPU *cpu)
218e99
     if (has_msr_kvm_steal_time) {
218e99
         msrs[n++].index = MSR_KVM_STEAL_TIME;
218e99
     }
218e99
+    if (has_msr_architectural_pmu) {
218e99
+        msrs[n++].index = MSR_CORE_PERF_FIXED_CTR_CTRL;
218e99
+        msrs[n++].index = MSR_CORE_PERF_GLOBAL_CTRL;
218e99
+        msrs[n++].index = MSR_CORE_PERF_GLOBAL_STATUS;
218e99
+        msrs[n++].index = MSR_CORE_PERF_GLOBAL_OVF_CTRL;
218e99
+        for (i = 0; i < MAX_FIXED_COUNTERS; i++) {
218e99
+            msrs[n++].index = MSR_CORE_PERF_FIXED_CTR0 + i;
218e99
+        }
218e99
+        for (i = 0; i < num_architectural_pmu_counters; i++) {
218e99
+            msrs[n++].index = MSR_P6_PERFCTR0 + i;
218e99
+            msrs[n++].index = MSR_P6_EVNTSEL0 + i;
218e99
+        }
218e99
+    }
218e99
 
218e99
     if (env->mcg_cap) {
218e99
         msrs[n++].index = MSR_MCG_STATUS;
218e99
@@ -1401,7 +1462,8 @@ static int kvm_get_msrs(X86CPU *cpu)
218e99
     }
218e99
 
218e99
     for (i = 0; i < ret; i++) {
218e99
-        switch (msrs[i].index) {
218e99
+        uint32_t index = msrs[i].index;
218e99
+        switch (index) {
218e99
         case MSR_IA32_SYSENTER_CS:
218e99
             env->sysenter_cs = msrs[i].data;
218e99
             break;
218e99
@@ -1473,6 +1535,27 @@ static int kvm_get_msrs(X86CPU *cpu)
218e99
         case MSR_KVM_STEAL_TIME:
218e99
             env->steal_time_msr = msrs[i].data;
218e99
             break;
218e99
+        case MSR_CORE_PERF_FIXED_CTR_CTRL:
218e99
+            env->msr_fixed_ctr_ctrl = msrs[i].data;
218e99
+            break;
218e99
+        case MSR_CORE_PERF_GLOBAL_CTRL:
218e99
+            env->msr_global_ctrl = msrs[i].data;
218e99
+            break;
218e99
+        case MSR_CORE_PERF_GLOBAL_STATUS:
218e99
+            env->msr_global_status = msrs[i].data;
218e99
+            break;
218e99
+        case MSR_CORE_PERF_GLOBAL_OVF_CTRL:
218e99
+            env->msr_global_ovf_ctrl = msrs[i].data;
218e99
+            break;
218e99
+        case MSR_CORE_PERF_FIXED_CTR0 ... MSR_CORE_PERF_FIXED_CTR0 + MAX_FIXED_COUNTERS - 1:
218e99
+            env->msr_fixed_counters[index - MSR_CORE_PERF_FIXED_CTR0] = msrs[i].data;
218e99
+            break;
218e99
+        case MSR_P6_PERFCTR0 ... MSR_P6_PERFCTR0 + MAX_GP_COUNTERS - 1:
218e99
+            env->msr_gp_counters[index - MSR_P6_PERFCTR0] = msrs[i].data;
218e99
+            break;
218e99
+        case MSR_P6_EVNTSEL0 ... MSR_P6_EVNTSEL0 + MAX_GP_COUNTERS - 1:
218e99
+            env->msr_gp_evtsel[index - MSR_P6_EVNTSEL0] = msrs[i].data;
218e99
+            break;
218e99
         }
218e99
     }
218e99
 
218e99
diff --git a/target-i386/machine.c b/target-i386/machine.c
218e99
index 4f30347..08b4ed3 100644
218e99
--- a/target-i386/machine.c
218e99
+++ b/target-i386/machine.c
218e99
@@ -465,6 +465,47 @@ static const VMStateDescription vmstate_xsave ={
218e99
     }
218e99
 };
218e99
 
218e99
+static bool pmu_enable_needed(void *opaque)
218e99
+{
218e99
+    X86CPU *cpu = opaque;
218e99
+    CPUX86State *env = &cpu->env;
218e99
+    int i;
218e99
+
218e99
+    if (env->msr_fixed_ctr_ctrl || env->msr_global_ctrl ||
218e99
+        env->msr_global_status || env->msr_global_ovf_ctrl) {
218e99
+        return true;
218e99
+    }
218e99
+    for (i = 0; i < MAX_FIXED_COUNTERS; i++) {
218e99
+        if (env->msr_fixed_counters[i]) {
218e99
+            return true;
218e99
+        }
218e99
+    }
218e99
+    for (i = 0; i < MAX_GP_COUNTERS; i++) {
218e99
+        if (env->msr_gp_counters[i] || env->msr_gp_evtsel[i]) {
218e99
+            return true;
218e99
+        }
218e99
+    }
218e99
+
218e99
+    return false;
218e99
+}
218e99
+
218e99
+static const VMStateDescription vmstate_msr_architectural_pmu = {
218e99
+    .name = "cpu/msr_architectural_pmu",
218e99
+    .version_id = 1,
218e99
+    .minimum_version_id = 1,
218e99
+    .minimum_version_id_old = 1,
218e99
+    .fields      = (VMStateField []) {
218e99
+        VMSTATE_UINT64(env.msr_fixed_ctr_ctrl, X86CPU),
218e99
+        VMSTATE_UINT64(env.msr_global_ctrl, X86CPU),
218e99
+        VMSTATE_UINT64(env.msr_global_status, X86CPU),
218e99
+        VMSTATE_UINT64(env.msr_global_ovf_ctrl, X86CPU),
218e99
+        VMSTATE_UINT64_ARRAY(env.msr_fixed_counters, X86CPU, MAX_FIXED_COUNTERS),
218e99
+        VMSTATE_UINT64_ARRAY(env.msr_gp_counters, X86CPU, MAX_GP_COUNTERS),
218e99
+        VMSTATE_UINT64_ARRAY(env.msr_gp_evtsel, X86CPU, MAX_GP_COUNTERS),
218e99
+        VMSTATE_END_OF_LIST()
218e99
+    }
218e99
+};
218e99
+
218e99
 const VMStateDescription vmstate_x86_cpu = {
218e99
     .name = "cpu",
218e99
     .version_id = 12,
218e99
@@ -594,6 +635,9 @@ const VMStateDescription vmstate_x86_cpu = {
218e99
             .vmsd = &vmstate_xsave,
218e99
             .needed = vmstate_xsave_needed,
218e99
         }, {
218e99
+            .vmsd = &vmstate_msr_architectural_pmu,
218e99
+            .needed = pmu_enable_needed,
218e99
+        }, {
218e99
             /* empty */
218e99
         }
218e99
     }
218e99
-- 
218e99
1.7.1
218e99