From a416721754c759656c6535be8790859f44c08afd Mon Sep 17 00:00:00 2001
From: Gleb Natapov <gleb@redhat.com>
Date: Thu, 8 Mar 2012 09:23:25 +0100
Subject: [PATCH] enable architectural PMU cpuid leaf for kvm

RH-Author: Gleb Natapov <gleb@redhat.com>
Message-id: <20120308092324.GJ20128@redhat.com>
Patchwork-id: 38399
O-Subject: [PATCH RHEL6.3 v3 qemu-kvm] enable architectural PMU cpuid leaf for kvm
Bugzilla: 798936
RH-Acked-by: Avi Kivity <avi@redhat.com>
RH-Acked-by: Eduardo Habkost <ehabkost@redhat.com>
RH-Acked-by: Marcelo Tosatti <mtosatti@redhat.com>

Upstream: a0fa82085e175bf8ce6d69a3f83695f81af2a649
BZ: 798936

Signed-off-by: Gleb Natapov <gleb@redhat.com>
---

v1->v2
 - enable PMU reporting only on machine type rhel6.3

v2->v3
 - fix compile warning
 - pass correct parameter to kvm_arch_get_supported_cpuid()

--
			Gleb.

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 hw/pc.c             |    6 ++++++
 hw/pc.h             |    1 +
 target-i386/cpuid.c |   28 ++++++++++++++++++++++++----
 3 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/hw/pc.c b/hw/pc.c
index 4489579..fe78c00 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1627,6 +1627,7 @@ static void pc_init_rhel620(ram_addr_t ram_size,
                             const char *cpu_model)
 {
     rhel_common_init("RHEL 6.2.0 PC", 0);
+    disable_cpuid_leaf10();
     pc_init_pci(ram_size, boot_device, kernel_filename, kernel_cmdline,
                 initrd_filename, setdef_cpu_model(cpu_model, "cpu64-rhel6"));
 }
@@ -1646,6 +1647,7 @@ static void pc_init_rhel610(ram_addr_t ram_size,
                             const char *cpu_model)
 {
     rhel_common_init("RHEL 6.1.0 PC", 0);
+    disable_cpuid_leaf10();
     pc_init_pci(ram_size, boot_device, kernel_filename, kernel_cmdline,
                 initrd_filename, setdef_cpu_model(cpu_model, "cpu64-rhel6"));
 }
@@ -1669,6 +1671,7 @@ static void pc_init_rhel600(ram_addr_t ram_size,
                             const char *cpu_model)
 {
     rhel_common_init("RHEL 6.0.0 PC", 0);
+    disable_cpuid_leaf10();
     pc_init_pci(ram_size, boot_device, kernel_filename, kernel_cmdline,
                 initrd_filename, setdef_cpu_model(cpu_model, "cpu64-rhel6"));
 }
@@ -1739,6 +1742,7 @@ static void pc_init_rhel550(ram_addr_t ram_size,
                             const char *cpu_model)
 {
     rhel_common_init("RHEL 5.5.0 PC", 1);
+    disable_cpuid_leaf10();
     pc_init_pci(ram_size, boot_device, kernel_filename, kernel_cmdline,
                 initrd_filename, setdef_cpu_model(cpu_model, "cpu64-rhel5"));
 }
@@ -1759,6 +1763,7 @@ static void pc_init_rhel544(ram_addr_t ram_size,
                             const char *cpu_model)
 {
     rhel_common_init("RHEL 5.4.4 PC", 1);
+    disable_cpuid_leaf10();
     pc_init_pci(ram_size, boot_device, kernel_filename, kernel_cmdline,
                 initrd_filename, setdef_cpu_model(cpu_model, "cpu64-rhel5"));
 }
@@ -1779,6 +1784,7 @@ static void pc_init_rhel540(ram_addr_t ram_size,
                             const char *cpu_model)
 {
     rhel_common_init("RHEL 5.4.0 PC", 1);
+    disable_cpuid_leaf10();
     pc_init_pci(ram_size, boot_device, kernel_filename, kernel_cmdline,
                 initrd_filename, setdef_cpu_model(cpu_model, "cpu64-rhel5"));
 }
diff --git a/hw/pc.h b/hw/pc.h
index 916a595..aa9dc6d 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -178,4 +178,5 @@ void extboot_init(BlockDriverState *bs, int cmd);
 
 int cpu_is_bsp(CPUState *env);
 
+void disable_cpuid_leaf10(void);
 #endif
diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c
index 77da1db..146dde3 100644
--- a/target-i386/cpuid.c
+++ b/target-i386/cpuid.c
@@ -984,6 +984,8 @@ static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx,
     }
 }
 
+static bool cpuid_leaf10_disabled;
+
 void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
                    uint32_t *eax, uint32_t *ebx,
                    uint32_t *ecx, uint32_t *edx)
@@ -1092,10 +1094,17 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         break;
     case 0xA:
         /* Architectural Performance Monitoring Leaf */
-        *eax = 0;
-        *ebx = 0;
-        *ecx = 0;
-        *edx = 0;
+        if (kvm_enabled() && !cpuid_leaf10_disabled) {
+            *eax = kvm_arch_get_supported_cpuid(env, 0xA, count, R_EAX);
+            *ebx = kvm_arch_get_supported_cpuid(env, 0xA, count, R_EBX);
+            *ecx = kvm_arch_get_supported_cpuid(env, 0xA, count, R_ECX);
+            *edx = kvm_arch_get_supported_cpuid(env, 0xA, count, R_EDX);
+        } else {
+            *eax = 0;
+            *ebx = 0;
+            *ecx = 0;
+            *edx = 0;
+        }
         break;
     case 0xD:
         /* Processor Extended State */
@@ -1236,3 +1245,14 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
         break;
     }
 }
+
+/* Called from hw/pc.c but there is no header
+ * both files include to put this into.
+ * Put it here to silence compiler warning.
+ */
+void disable_cpuid_leaf10(void);
+
+void disable_cpuid_leaf10(void)
+{
+	cpuid_leaf10_disabled = true;
+}
-- 
1.7.7.6

