diff -Nurp kvm-kmod-3.10.1/x86/vmx.c kvm-kmod-3.10.1-perfcnt/x86/vmx.c
--- kvm-kmod-3.10.1/x86/vmx.c	2013-08-01 22:04:01.000000000 +0200
+++ kvm-kmod-3.10.1-perfcnt/x86/vmx.c	2014-02-07 12:00:38.000000000 +0100
@@ -510,6 +510,10 @@ struct vcpu_vmx {
 		struct vmx_msr_entry guest[NR_AUTOLOAD_MSRS];
 		struct vmx_msr_entry host[NR_AUTOLOAD_MSRS];
 	} msr_autoload;
+	struct msr_autostore {
+		unsigned nr;
+		struct vmx_msr_entry guest[NR_AUTOLOAD_MSRS];
+	} msr_autostore;
 	struct {
 		int           loaded;
 		u16           fs_sel, gs_sel, ldt_sel;
@@ -1586,6 +1590,28 @@ static void add_atomic_switch_msr(struct
 	m->guest[i].value = guest_val;
 	m->host[i].index = msr;
 	m->host[i].value = host_val;
+
+}
+
+static void add_atomic_store_msr(struct vcpu_vmx *vmx, unsigned msr)
+{
+	unsigned i;
+	struct msr_autostore *m = &vmx->msr_autostore;
+
+	for (i = 0; i < m->nr; ++i)
+		if (m->guest[i].index == msr)
+			break;
+
+	if (i == NR_AUTOLOAD_MSRS) {
+		printk_once(KERN_WARNING"Not enough mst switch entries. "
+				"Can't add msr %x\n", msr);
+		return;
+	} else if (i == m->nr) {
+		++m->nr;
+		vmcs_write32(VM_EXIT_MSR_STORE_COUNT, m->nr);
+	}
+
+	m->guest[i].index = msr;
 }
 
 static void reload_tss(void)
@@ -4366,6 +4392,7 @@ static int vmx_vcpu_setup(struct vcpu_vm
 #endif
 
 	vmcs_write32(VM_EXIT_MSR_STORE_COUNT, 0);
+	vmcs_write64(VM_EXIT_MSR_STORE_ADDR, __pa(vmx->msr_autostore.guest));
 	vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, 0);
 	vmcs_write64(VM_EXIT_MSR_LOAD_ADDR, __pa(vmx->msr_autoload.host));
 	vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, 0);
@@ -4405,6 +4432,90 @@ static int vmx_vcpu_setup(struct vcpu_vm
 	vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
 	set_cr4_guest_host_mask(vmx);
 
+	/* All additions concerning performance counter tracing
+	 * are done here! */
+
+#define MSR_IA32_PERFEVTSEL0    0x00000186
+#define MSR_IA32_PERFEVTSEL1    0x00000187
+
+#define MSR_IA32_PMC0           0x000000c1
+#define MSR_IA32_PMC1           0x000000c2
+
+#define BR_RET_EXEC_EVENT       0x8f
+#define BR_RET_EXEC_UMASK       0x00
+
+#define BR_RET_MISSP_EXEC_EVENT 0x89
+#define BR_RET_MISSP_EXEC_UMASK 0x08
+
+#define INSTR_RET_EVENT         0xc0
+#define INSTR_RET_UMASK         0x00
+
+#define PERFEVTSEL_VALUE(EVENT, UMASK, USR, OS, EDGE, \
+			 PINC, APIC, ENABLE, INV, CMASK) \
+        ((EVENT  & 0xff) <<  0) | \
+        ((UMASK  & 0xff) <<  8) | \
+        ((USR    & 0x01) << 16) | \
+        ((OS     & 0x01) << 17) | \
+        ((EDGE   & 0x01) << 18) | \
+        ((PINC   & 0x01) << 19) | \
+        ((APIC   & 0x01) << 20) | \
+        ((ENABLE & 0x01) << 22) | \
+        ((INV    & 0x01) << 23) | \
+        ((CMASK  & 0xff) << 24)
+
+#define PERF_GLOBAL_CTRL_VALUE(PMC0_ENABLE, PMC1_ENABLE, \
+		FIXED_CTR0_ENABLE, FIXED_CTR1_ENABLE, FIXED_CTR2_ENABLE) \
+	(((unsigned long long)PMC0_ENABLE       & 0xff) <<  0) | \
+	(((unsigned long long)PMC1_ENABLE       & 0xff) <<  1) | \
+	(((unsigned long long)FIXED_CTR0_ENABLE & 0xff) << 32) | \
+	(((unsigned long long)FIXED_CTR1_ENABLE & 0xff) << 33) | \
+	(((unsigned long long)FIXED_CTR2_ENABLE & 0xff) << 34)
+
+
+	add_atomic_switch_msr(vmx, MSR_CORE_PERF_GLOBAL_CTRL,
+			PERF_GLOBAL_CTRL_VALUE(1, 1, 0, 0, 0),
+			read_msr(MSR_CORE_PERF_GLOBAL_CTRL));
+
+	add_atomic_switch_msr(vmx, MSR_IA32_PERFEVTSEL0,
+			PERFEVTSEL_VALUE(
+				INSTR_RET_EVENT,
+				INSTR_RET_UMASK,
+				1, /* User level */
+				1, /* Don't trace the guest kernel */
+				0, /* No edge detect */
+				0, /* PMi on overflow (don't care) */
+				0, /* No APIC interrupt on OV */
+				1, /* Enable counter */
+				0, /* Don't invert the counter */
+				0  /* No mask */
+			),
+			read_msr(MSR_IA32_PERFEVTSEL0));
+
+	add_atomic_switch_msr(vmx, MSR_IA32_PERFEVTSEL1,
+			PERFEVTSEL_VALUE(
+				BR_RET_MISSP_EXEC_EVENT,
+				BR_RET_MISSP_EXEC_UMASK,
+				1, /* User level */
+				1, /* Don't trace the guest kernel */
+				0, /* No edge detect */
+				0, /* PMi on overflow (don't care) */
+				0, /* No APIC interrupt on OV */
+				1, /* Enable counter */
+				0, /* Don't invert the counter */
+				0  /* No mask */
+			),
+			read_msr(MSR_IA32_PERFEVTSEL1));
+
+	add_atomic_switch_msr(vmx, MSR_IA32_PMC0, 0, read_msr(MSR_IA32_PMC0));
+	add_atomic_switch_msr(vmx, MSR_IA32_PMC1, 0, read_msr(MSR_IA32_PMC1));
+
+	add_atomic_store_msr(vmx, MSR_IA32_PMC0);
+	add_atomic_store_msr(vmx, MSR_IA32_PMC1);
+
+	printk(KERN_ALERT"Performance monitoring set up!\n");
+
+	/* Snip */
+
 	return 0;
 }
 
@@ -5025,6 +5136,7 @@ static int handle_cr(struct kvm_vcpu *vc
 			kvm_complete_insn_gp(vcpu, err);
 			return 1;
 		case 3:
+			printk("Switched to cr3 = %lx\n", val);
 			err = kvm_set_cr3(vcpu, val);
 			kvm_complete_insn_gp(vcpu, err);
 			return 1;
@@ -7070,6 +7182,71 @@ static void atomic_switch_perf_msrs(stru
 					msrs[i].host);
 }
 
+
+static u64 __read_autoload_msr(struct kvm_vcpu *vcpu, int index, int guest)
+{
+	int i = 0;
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+	struct msr_autoload *m = &vmx->msr_autoload;
+
+	switch (index) {
+		case MSR_EFER:
+			if (cpu_has_load_ia32_efer) {
+				return (guest ?
+					vmcs_read64(GUEST_IA32_EFER) :
+					vmcs_read64(HOST_IA32_EFER));
+			}
+		break;
+		case MSR_CORE_PERF_GLOBAL_CTRL:
+			if (cpu_has_load_perf_global_ctrl) {
+				return (guest ?
+					vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL) :
+					vmcs_read64(HOST_IA32_PERF_GLOBAL_CTRL));
+			}
+
+		break;
+	}
+
+	if (guest) {
+		for (i = 0; i < m->nr; i++) {
+			if (m->guest[i].index == index)
+				return m->guest[i].value;
+		}
+	} else {
+		for (i = 0; i < m->nr; i++) {
+			if (m->host[i].index == index)
+				return m->host[i].value;
+		}
+	}
+	return -1UL;
+}
+
+static u64 read_autostore_msr(struct kvm_vcpu *vcpu, int index)
+{
+	int i = 0;
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+	struct msr_autostore *m = &vmx->msr_autostore;
+
+	for (i = 0; i < m->nr; i++) {
+		if (m->guest[i].index == index)
+			return m->guest[i].value;
+	}
+	return -1UL;
+}
+
+static u64 read_autoload_msr_guest(struct kvm_vcpu *vcpu, int msr)
+{
+	return __read_autoload_msr(vcpu, msr, 1);
+}
+
+static u64 read_autoload_msr_host(struct kvm_vcpu *vcpu, int msr)
+{
+	return __read_autoload_msr(vcpu, msr, 0);
+}
+
+static u64 old_pmc0;
+static u64 old_pmc1;
+
 static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 {
 	struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -7106,6 +7283,32 @@ static void __noclone vmx_vcpu_run(struc
 	debugctlmsr = get_debugctlmsr();
 
 	vmx->__launched = vmx->loaded_vmcs->launched;
+/*
+	printk("VM_ENTRY_MSR_LOAD_COUNT:              0x%x\n",
+		vmcs_read32(VM_ENTRY_MSR_LOAD_COUNT));
+	printk("VM_EXIT_MSR_LOAD_COUNT:               0x%x\n",
+		vmcs_read32(VM_EXIT_MSR_LOAD_COUNT));
+	printk("MSR_IA32_PMC0 guest:                  0x%llx\n",
+	       read_autoload_msr_guest(vcpu, MSR_IA32_PMC0));
+	printk("MSR_IA32_PMC0 host:                   0x%llx\n",
+	       read_autoload_msr_host(vcpu, MSR_IA32_PMC0));
+	printk("MSR_IA32_PMC1 guest:                  0x%llx\n",
+	       read_autoload_msr_guest(vcpu, MSR_IA32_PMC1));
+	printk("MSR_IA32_PMC1 host:                   0x%llx\n",
+	       read_autoload_msr_host(vcpu, MSR_IA32_PMC1));
+	printk("MSR_IA32_PERFEVTSEL0 guest:           0x%llx\n",
+	       read_autoload_msr_guest(vcpu, MSR_IA32_PERFEVTSEL0));
+	printk("MSR_IA32_PERFEVTSEL0 host:            0x%llx\n",
+	       read_autoload_msr_host(vcpu, MSR_IA32_PERFEVTSEL0));
+	printk("MSR_IA32_PERFEVTSEL1 guest:           0x%llx\n",
+	       read_autoload_msr_guest(vcpu, MSR_IA32_PERFEVTSEL1));
+	printk("MSR_IA32_PERFEVTSEL1 host:            0x%llx\n",
+	       read_autoload_msr_host(vcpu, MSR_IA32_PERFEVTSEL1));
+	printk("MSR_IA32_CORE_PERF_GLOBAL_CTRL guest: 0x%llx\n",
+	       read_autoload_msr_guest(vcpu, MSR_CORE_PERF_GLOBAL_CTRL));
+	printk("MSR_IA32_CORE_PERF_GLOBAL_CTRL host:  0x%llx\n",
+	       read_autoload_msr_host(vcpu, MSR_CORE_PERF_GLOBAL_CTRL));
+*/
 	asm(
 		/* Store host registers */
 		"push %%" _ASM_DX "; push %%" _ASM_BP ";"
@@ -7211,6 +7414,35 @@ static void __noclone vmx_vcpu_run(struc
 #endif
 	      );
 
+	u64 pmc0 = read_autostore_msr(vcpu, MSR_IA32_PMC0);
+	u64 pmc1 = read_autostore_msr(vcpu, MSR_IA32_PMC1);
+/*
+	printk("MSR_IA32_PMC0 stored guest:           0x%llx\n",
+	       pmc0);
+	printk("MSR_IA32_PMC1 stored guest:           0x%llx\n",
+	       pmc1);
+	printk("MSR_IA32_PMC0_OLD guest:              0x%llx\n",
+	       old_pmc0);
+	printk("MSR_IA32_PMC1_OLD guest:              0x%llx\n",
+	       old_pmc1);
+
+	printk("kvm-perf: 0x%llx, 0x%llx, 0x%llx, 0x%llx\n",
+		pmc0, pmc1, old_pmc0, old_pmc1);
+*/
+	/* printk doesn's support floats wtf ... */
+
+	if (pmc1 != old_pmc1)
+		printk("%llu %llu\n", (pmc0 - old_pmc0), (pmc1 - old_pmc1));
+
+	clear_atomic_switch_msr(to_vmx(vcpu), MSR_IA32_PMC0);
+	clear_atomic_switch_msr(to_vmx(vcpu), MSR_IA32_PMC1);
+
+	add_atomic_switch_msr(vmx, MSR_IA32_PMC0, pmc0, read_msr(MSR_IA32_PMC0));
+	add_atomic_switch_msr(vmx, MSR_IA32_PMC1, pmc1, read_msr(MSR_IA32_PMC1));
+
+	old_pmc0 = pmc0;
+	old_pmc1 = pmc1;
+
 	/* MSR_IA32_DEBUGCTLMSR is zeroed on vmexit. Restore it if needed */
 	if (debugctlmsr)
 		update_debugctlmsr(debugctlmsr);
