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