xref: /kvm-unit-tests/x86/pmu_lbr.c (revision d6d3a3bd85095f4554d0ea01fe0c88b99a4413f9)
1 #include "x86/msr.h"
2 #include "x86/processor.h"
3 #include "x86/pmu.h"
4 #include "x86/desc.h"
5 
6 #define N 1000000
7 
8 volatile int count;
9 u32 lbr_from, lbr_to;
10 
11 static noinline int compute_flag(int i)
12 {
13 	if (i % 10 < 4)
14 		return i + 1;
15 	return 0;
16 }
17 
18 static noinline int lbr_test(void)
19 {
20 	int i;
21 	int flag;
22 	volatile double x = 1212121212, y = 121212;
23 
24 	for (i = 0; i < 200000000; i++) {
25 		flag = compute_flag(i);
26 		count++;
27 		if (flag)
28 			x += x / y + y / x;
29 	}
30 	return 0;
31 }
32 
33 static void init_lbr(void *index)
34 {
35 	wrmsr(lbr_from + *(int *) index, 0);
36 	wrmsr(lbr_to + *(int *)index, 0);
37 }
38 
39 static bool test_init_lbr_from_exception(u64 index)
40 {
41 	return test_for_exception(GP_VECTOR, init_lbr, &index);
42 }
43 
44 int main(int ac, char **av)
45 {
46 	u64 perf_cap;
47 	int max, i;
48 
49 	setup_vm();
50 
51 	if (!is_intel()) {
52 		report_skip("PMU_LBR test is for intel CPU's only");
53 		return report_summary();
54 	}
55 
56 	if (!this_cpu_has_pmu()) {
57 		report_skip("No pmu is detected!");
58 		return report_summary();
59 	}
60 
61 	if (!this_cpu_has(X86_FEATURE_PDCM)) {
62 		report_skip("Perfmon/Debug Capabilities MSR isn't supported.");
63 		return report_summary();
64 	}
65 
66 	perf_cap = this_cpu_perf_capabilities();
67 
68 	if (!(perf_cap & PMU_CAP_LBR_FMT)) {
69 		report_skip("(Architectural) LBR is not supported.");
70 		return report_summary();
71 	}
72 
73 	printf("PMU version:		 %d\n", pmu_version());
74 	printf("LBR version:		 %ld\n", perf_cap & PMU_CAP_LBR_FMT);
75 
76 	/* Look for LBR from and to MSRs */
77 	lbr_from = MSR_LBR_CORE_FROM;
78 	lbr_to = MSR_LBR_CORE_TO;
79 	if (test_init_lbr_from_exception(0)) {
80 		lbr_from = MSR_LBR_NHM_FROM;
81 		lbr_to = MSR_LBR_NHM_TO;
82 	}
83 
84 	if (test_init_lbr_from_exception(0)) {
85 		report_skip("LBR on this platform is not supported!");
86 		return report_summary();
87 	}
88 
89 	wrmsr(MSR_LBR_SELECT, 0);
90 	wrmsr(MSR_LBR_TOS, 0);
91 	for (max = 0; max < MAX_NUM_LBR_ENTRY; max++) {
92 		if (test_init_lbr_from_exception(max))
93 			break;
94 	}
95 
96 	report(max > 0, "The number of guest LBR entries is good.");
97 
98 	/* Do some branch instructions. */
99 	wrmsr(MSR_IA32_DEBUGCTLMSR, DEBUGCTLMSR_LBR);
100 	lbr_test();
101 	wrmsr(MSR_IA32_DEBUGCTLMSR, 0);
102 
103 	report(rdmsr(MSR_LBR_TOS) != 0, "The guest LBR MSR_LBR_TOS value is good.");
104 	for (i = 0; i < max; ++i) {
105 		if (!rdmsr(lbr_to + i) || !rdmsr(lbr_from + i))
106 			break;
107 	}
108 	report(i == max, "The guest LBR FROM_IP/TO_IP values are good.");
109 
110 	return report_summary();
111 }
112