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