xref: /kvm-unit-tests/x86/pmu.c (revision a9f8b16f63b04053fea8df756ba55d00adf127be)
1*a9f8b16fSGleb Natapov 
2*a9f8b16fSGleb Natapov #include "x86/msr.h"
3*a9f8b16fSGleb Natapov #include "x86/processor.h"
4*a9f8b16fSGleb Natapov #include "x86/apic-defs.h"
5*a9f8b16fSGleb Natapov #include "x86/apic.h"
6*a9f8b16fSGleb Natapov #include "x86/desc.h"
7*a9f8b16fSGleb Natapov #include "x86/isr.h"
8*a9f8b16fSGleb Natapov #include "x86/vm.h"
9*a9f8b16fSGleb Natapov 
10*a9f8b16fSGleb Natapov #include "libcflat.h"
11*a9f8b16fSGleb Natapov #include <stdint.h>
12*a9f8b16fSGleb Natapov 
13*a9f8b16fSGleb Natapov #define FIXED_CNT_INDEX 32
14*a9f8b16fSGleb Natapov #define PC_VECTOR	32
15*a9f8b16fSGleb Natapov 
16*a9f8b16fSGleb Natapov #define EVNSEL_EVENT_SHIFT	0
17*a9f8b16fSGleb Natapov #define EVNTSEL_UMASK_SHIFT	8
18*a9f8b16fSGleb Natapov #define EVNTSEL_USR_SHIFT	16
19*a9f8b16fSGleb Natapov #define EVNTSEL_OS_SHIFT	17
20*a9f8b16fSGleb Natapov #define EVNTSEL_EDGE_SHIFT	18
21*a9f8b16fSGleb Natapov #define EVNTSEL_PC_SHIFT	19
22*a9f8b16fSGleb Natapov #define EVNTSEL_INT_SHIFT	20
23*a9f8b16fSGleb Natapov #define EVNTSEL_EN_SHIF		22
24*a9f8b16fSGleb Natapov #define EVNTSEL_INV_SHIF	23
25*a9f8b16fSGleb Natapov #define EVNTSEL_CMASK_SHIFT	24
26*a9f8b16fSGleb Natapov 
27*a9f8b16fSGleb Natapov #define EVNTSEL_EN	(1 << EVNTSEL_EN_SHIF)
28*a9f8b16fSGleb Natapov #define EVNTSEL_USR	(1 << EVNTSEL_USR_SHIFT)
29*a9f8b16fSGleb Natapov #define EVNTSEL_OS	(1 << EVNTSEL_OS_SHIFT)
30*a9f8b16fSGleb Natapov #define EVNTSEL_PC	(1 << EVNTSEL_PC_SHIFT)
31*a9f8b16fSGleb Natapov #define EVNTSEL_INT	(1 << EVNTSEL_INT_SHIFT)
32*a9f8b16fSGleb Natapov #define EVNTSEL_INV	(1 << EVNTSEL_INV_SHIF)
33*a9f8b16fSGleb Natapov 
34*a9f8b16fSGleb Natapov #define N 1000000
35*a9f8b16fSGleb Natapov 
36*a9f8b16fSGleb Natapov typedef struct {
37*a9f8b16fSGleb Natapov 	uint32_t ctr;
38*a9f8b16fSGleb Natapov 	uint32_t config;
39*a9f8b16fSGleb Natapov 	uint64_t count;
40*a9f8b16fSGleb Natapov 	int idx;
41*a9f8b16fSGleb Natapov } pmu_counter_t;
42*a9f8b16fSGleb Natapov 
43*a9f8b16fSGleb Natapov union cpuid10_eax {
44*a9f8b16fSGleb Natapov 	struct {
45*a9f8b16fSGleb Natapov 		unsigned int version_id:8;
46*a9f8b16fSGleb Natapov 		unsigned int num_counters:8;
47*a9f8b16fSGleb Natapov 		unsigned int bit_width:8;
48*a9f8b16fSGleb Natapov 		unsigned int mask_length:8;
49*a9f8b16fSGleb Natapov 	} split;
50*a9f8b16fSGleb Natapov 	unsigned int full;
51*a9f8b16fSGleb Natapov } eax;
52*a9f8b16fSGleb Natapov 
53*a9f8b16fSGleb Natapov union cpuid10_ebx {
54*a9f8b16fSGleb Natapov 	struct {
55*a9f8b16fSGleb Natapov 		unsigned int no_unhalted_core_cycles:1;
56*a9f8b16fSGleb Natapov 		unsigned int no_instructions_retired:1;
57*a9f8b16fSGleb Natapov 		unsigned int no_unhalted_reference_cycles:1;
58*a9f8b16fSGleb Natapov 		unsigned int no_llc_reference:1;
59*a9f8b16fSGleb Natapov 		unsigned int no_llc_misses:1;
60*a9f8b16fSGleb Natapov 		unsigned int no_branch_instruction_retired:1;
61*a9f8b16fSGleb Natapov 		unsigned int no_branch_misses_retired:1;
62*a9f8b16fSGleb Natapov 	} split;
63*a9f8b16fSGleb Natapov 	unsigned int full;
64*a9f8b16fSGleb Natapov } ebx;
65*a9f8b16fSGleb Natapov 
66*a9f8b16fSGleb Natapov union cpuid10_edx {
67*a9f8b16fSGleb Natapov 	struct {
68*a9f8b16fSGleb Natapov 		unsigned int num_counters_fixed:5;
69*a9f8b16fSGleb Natapov 		unsigned int bit_width_fixed:8;
70*a9f8b16fSGleb Natapov 		unsigned int reserved:19;
71*a9f8b16fSGleb Natapov 	} split;
72*a9f8b16fSGleb Natapov 	unsigned int full;
73*a9f8b16fSGleb Natapov } edx;
74*a9f8b16fSGleb Natapov 
75*a9f8b16fSGleb Natapov struct pmu_event {
76*a9f8b16fSGleb Natapov 	char *name;
77*a9f8b16fSGleb Natapov 	uint32_t unit_sel;
78*a9f8b16fSGleb Natapov 	int min;
79*a9f8b16fSGleb Natapov 	int max;
80*a9f8b16fSGleb Natapov } gp_events[] = {
81*a9f8b16fSGleb Natapov 	{"core cycles", 0x003c, 1*N, 50*N},
82*a9f8b16fSGleb Natapov 	{"instructions", 0x00c0, 10*N, 10.2*N},
83*a9f8b16fSGleb Natapov 	{"ref cycles", 0x013c, 1*N, 30*N},
84*a9f8b16fSGleb Natapov 	{"llc refference", 0x4f2e, 1, 1*N},
85*a9f8b16fSGleb Natapov 	{"llc misses", 0x412e, 1, 1*N},
86*a9f8b16fSGleb Natapov 	{"branches", 0x00c4, 1*N, 1.1*N},
87*a9f8b16fSGleb Natapov 	{"branch misses", 0x00c5, 0, 0.1*N},
88*a9f8b16fSGleb Natapov }, fixed_events[] = {
89*a9f8b16fSGleb Natapov 	{"fixed 1", MSR_CORE_PERF_FIXED_CTR0, 10*N, 10.2*N},
90*a9f8b16fSGleb Natapov 	{"fixed 2", MSR_CORE_PERF_FIXED_CTR0 + 1, 1*N, 30*N},
91*a9f8b16fSGleb Natapov 	{"fixed 3", MSR_CORE_PERF_FIXED_CTR0 + 2, 1*N, 30*N}
92*a9f8b16fSGleb Natapov };
93*a9f8b16fSGleb Natapov 
94*a9f8b16fSGleb Natapov static int tests, failures;
95*a9f8b16fSGleb Natapov 
96*a9f8b16fSGleb Natapov char *buf;
97*a9f8b16fSGleb Natapov 
98*a9f8b16fSGleb Natapov static inline void loop()
99*a9f8b16fSGleb Natapov {
100*a9f8b16fSGleb Natapov 	unsigned long tmp, tmp2, tmp3;
101*a9f8b16fSGleb Natapov 
102*a9f8b16fSGleb Natapov 	asm volatile("1: mov (%1), %2; add $64, %1; nop; nop; nop; nop; nop; nop; nop; loop 1b"
103*a9f8b16fSGleb Natapov 			: "=c"(tmp), "=r"(tmp2), "=r"(tmp3): "0"(N), "1"(buf));
104*a9f8b16fSGleb Natapov 
105*a9f8b16fSGleb Natapov }
106*a9f8b16fSGleb Natapov 
107*a9f8b16fSGleb Natapov volatile uint64_t irq_received;
108*a9f8b16fSGleb Natapov 
109*a9f8b16fSGleb Natapov static void cnt_overflow(isr_regs_t *regs)
110*a9f8b16fSGleb Natapov {
111*a9f8b16fSGleb Natapov 	irq_received++;
112*a9f8b16fSGleb Natapov 	apic_write(APIC_EOI, 0);
113*a9f8b16fSGleb Natapov }
114*a9f8b16fSGleb Natapov 
115*a9f8b16fSGleb Natapov static bool check_irq(void)
116*a9f8b16fSGleb Natapov {
117*a9f8b16fSGleb Natapov 	int i;
118*a9f8b16fSGleb Natapov 	irq_received = 0;
119*a9f8b16fSGleb Natapov 	irq_enable();
120*a9f8b16fSGleb Natapov 	for (i = 0; i < 100000 && !irq_received; i++)
121*a9f8b16fSGleb Natapov 		asm volatile("pause");
122*a9f8b16fSGleb Natapov 	irq_disable();
123*a9f8b16fSGleb Natapov 	return irq_received;
124*a9f8b16fSGleb Natapov }
125*a9f8b16fSGleb Natapov 
126*a9f8b16fSGleb Natapov static bool is_gp(pmu_counter_t *evt)
127*a9f8b16fSGleb Natapov {
128*a9f8b16fSGleb Natapov 	return evt->ctr < MSR_CORE_PERF_FIXED_CTR0;
129*a9f8b16fSGleb Natapov }
130*a9f8b16fSGleb Natapov 
131*a9f8b16fSGleb Natapov static int event_to_global_idx(pmu_counter_t *cnt)
132*a9f8b16fSGleb Natapov {
133*a9f8b16fSGleb Natapov 	return cnt->ctr - (is_gp(cnt) ? MSR_IA32_PERFCTR0 :
134*a9f8b16fSGleb Natapov 		(MSR_CORE_PERF_FIXED_CTR0 - FIXED_CNT_INDEX));
135*a9f8b16fSGleb Natapov }
136*a9f8b16fSGleb Natapov 
137*a9f8b16fSGleb Natapov static struct pmu_event* get_counter_event(pmu_counter_t *cnt)
138*a9f8b16fSGleb Natapov {
139*a9f8b16fSGleb Natapov 	if (is_gp(cnt)) {
140*a9f8b16fSGleb Natapov 		int i;
141*a9f8b16fSGleb Natapov 
142*a9f8b16fSGleb Natapov 		for (i = 0; i < sizeof(gp_events)/sizeof(gp_events[0]); i++)
143*a9f8b16fSGleb Natapov 			if (gp_events[i].unit_sel == (cnt->config & 0xffff))
144*a9f8b16fSGleb Natapov 				return &gp_events[i];
145*a9f8b16fSGleb Natapov 	} else
146*a9f8b16fSGleb Natapov 		return &fixed_events[cnt->ctr - MSR_CORE_PERF_FIXED_CTR0];
147*a9f8b16fSGleb Natapov 
148*a9f8b16fSGleb Natapov 	return (void*)0;
149*a9f8b16fSGleb Natapov }
150*a9f8b16fSGleb Natapov 
151*a9f8b16fSGleb Natapov static void global_enable(pmu_counter_t *cnt)
152*a9f8b16fSGleb Natapov {
153*a9f8b16fSGleb Natapov 	cnt->idx = event_to_global_idx(cnt);
154*a9f8b16fSGleb Natapov 
155*a9f8b16fSGleb Natapov 	wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_CTRL) |
156*a9f8b16fSGleb Natapov 			(1ull << cnt->idx));
157*a9f8b16fSGleb Natapov }
158*a9f8b16fSGleb Natapov 
159*a9f8b16fSGleb Natapov static void global_disable(pmu_counter_t *cnt)
160*a9f8b16fSGleb Natapov {
161*a9f8b16fSGleb Natapov 	wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_CTRL) &
162*a9f8b16fSGleb Natapov 			~(1ull << cnt->idx));
163*a9f8b16fSGleb Natapov }
164*a9f8b16fSGleb Natapov 
165*a9f8b16fSGleb Natapov 
166*a9f8b16fSGleb Natapov static void start_event(pmu_counter_t *evt)
167*a9f8b16fSGleb Natapov {
168*a9f8b16fSGleb Natapov     wrmsr(evt->ctr, evt->count);
169*a9f8b16fSGleb Natapov     if (is_gp(evt))
170*a9f8b16fSGleb Natapov 	    wrmsr(MSR_P6_EVNTSEL0 + event_to_global_idx(evt),
171*a9f8b16fSGleb Natapov 			    evt->config | EVNTSEL_EN);
172*a9f8b16fSGleb Natapov     else {
173*a9f8b16fSGleb Natapov 	    uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL);
174*a9f8b16fSGleb Natapov 	    int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4;
175*a9f8b16fSGleb Natapov 	    uint32_t usrospmi = 0;
176*a9f8b16fSGleb Natapov 
177*a9f8b16fSGleb Natapov 	    if (evt->config & EVNTSEL_OS)
178*a9f8b16fSGleb Natapov 		    usrospmi |= (1 << 0);
179*a9f8b16fSGleb Natapov 	    if (evt->config & EVNTSEL_USR)
180*a9f8b16fSGleb Natapov 		    usrospmi |= (1 << 1);
181*a9f8b16fSGleb Natapov 	    if (evt->config & EVNTSEL_INT)
182*a9f8b16fSGleb Natapov 		    usrospmi |= (1 << 3); // PMI on overflow
183*a9f8b16fSGleb Natapov 	    ctrl = (ctrl & ~(0xf << shift)) | (usrospmi << shift);
184*a9f8b16fSGleb Natapov 	    wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl);
185*a9f8b16fSGleb Natapov     }
186*a9f8b16fSGleb Natapov     global_enable(evt);
187*a9f8b16fSGleb Natapov }
188*a9f8b16fSGleb Natapov 
189*a9f8b16fSGleb Natapov static void stop_event(pmu_counter_t *evt)
190*a9f8b16fSGleb Natapov {
191*a9f8b16fSGleb Natapov 	global_disable(evt);
192*a9f8b16fSGleb Natapov 	if (is_gp(evt))
193*a9f8b16fSGleb Natapov 		wrmsr(MSR_P6_EVNTSEL0 + event_to_global_idx(evt),
194*a9f8b16fSGleb Natapov 				evt->config & ~EVNTSEL_EN);
195*a9f8b16fSGleb Natapov 	else {
196*a9f8b16fSGleb Natapov 		uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL);
197*a9f8b16fSGleb Natapov 		int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4;
198*a9f8b16fSGleb Natapov 		wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl & ~(0xf << shift));
199*a9f8b16fSGleb Natapov 	}
200*a9f8b16fSGleb Natapov 	evt->count = rdmsr(evt->ctr);
201*a9f8b16fSGleb Natapov }
202*a9f8b16fSGleb Natapov 
203*a9f8b16fSGleb Natapov static void measure(pmu_counter_t *evt, int count)
204*a9f8b16fSGleb Natapov {
205*a9f8b16fSGleb Natapov 	int i;
206*a9f8b16fSGleb Natapov 	for (i = 0; i < count; i++)
207*a9f8b16fSGleb Natapov 		start_event(&evt[i]);
208*a9f8b16fSGleb Natapov 	loop();
209*a9f8b16fSGleb Natapov 	for (i = 0; i < count; i++)
210*a9f8b16fSGleb Natapov 		stop_event(&evt[i]);
211*a9f8b16fSGleb Natapov }
212*a9f8b16fSGleb Natapov 
213*a9f8b16fSGleb Natapov static void report(const char *name, int n, bool pass)
214*a9f8b16fSGleb Natapov {
215*a9f8b16fSGleb Natapov     printf("%s: pmu %s-%d\n", pass ? "PASS" : "FAIL", name, n);
216*a9f8b16fSGleb Natapov     tests += 1;
217*a9f8b16fSGleb Natapov     failures += !pass;
218*a9f8b16fSGleb Natapov }
219*a9f8b16fSGleb Natapov 
220*a9f8b16fSGleb Natapov static bool verify_event(uint64_t count, struct pmu_event *e)
221*a9f8b16fSGleb Natapov {
222*a9f8b16fSGleb Natapov 	// printf("%lld >= %lld <= %lld\n", e->min, count, e->max);
223*a9f8b16fSGleb Natapov 	return count >= e->min  && count <= e->max;
224*a9f8b16fSGleb Natapov 
225*a9f8b16fSGleb Natapov }
226*a9f8b16fSGleb Natapov 
227*a9f8b16fSGleb Natapov static bool verify_counter(pmu_counter_t *cnt)
228*a9f8b16fSGleb Natapov {
229*a9f8b16fSGleb Natapov 	return verify_event(cnt->count, get_counter_event(cnt));
230*a9f8b16fSGleb Natapov }
231*a9f8b16fSGleb Natapov 
232*a9f8b16fSGleb Natapov static void check_gp_counter(struct pmu_event *evt)
233*a9f8b16fSGleb Natapov {
234*a9f8b16fSGleb Natapov 	pmu_counter_t cnt = {
235*a9f8b16fSGleb Natapov 		.ctr = MSR_IA32_PERFCTR0,
236*a9f8b16fSGleb Natapov 		.config = EVNTSEL_OS | EVNTSEL_USR | evt->unit_sel,
237*a9f8b16fSGleb Natapov 	};
238*a9f8b16fSGleb Natapov 	int i;
239*a9f8b16fSGleb Natapov 
240*a9f8b16fSGleb Natapov 	for (i = 0; i < eax.split.num_counters; i++, cnt.ctr++) {
241*a9f8b16fSGleb Natapov 		cnt.count = 0;
242*a9f8b16fSGleb Natapov 		measure(&cnt, 1);
243*a9f8b16fSGleb Natapov 		report(evt->name, i, verify_event(cnt.count, evt));
244*a9f8b16fSGleb Natapov 	}
245*a9f8b16fSGleb Natapov }
246*a9f8b16fSGleb Natapov 
247*a9f8b16fSGleb Natapov static void check_gp_counters(void)
248*a9f8b16fSGleb Natapov {
249*a9f8b16fSGleb Natapov 	int i;
250*a9f8b16fSGleb Natapov 
251*a9f8b16fSGleb Natapov 	for (i = 0; i < sizeof(gp_events)/sizeof(gp_events[0]); i++)
252*a9f8b16fSGleb Natapov 		if (!(ebx.full & (1 << i)))
253*a9f8b16fSGleb Natapov 			check_gp_counter(&gp_events[i]);
254*a9f8b16fSGleb Natapov 		else
255*a9f8b16fSGleb Natapov 			printf("GP event '%s' is disabled\n",
256*a9f8b16fSGleb Natapov 					gp_events[i].name);
257*a9f8b16fSGleb Natapov }
258*a9f8b16fSGleb Natapov 
259*a9f8b16fSGleb Natapov static void check_fixed_counters(void)
260*a9f8b16fSGleb Natapov {
261*a9f8b16fSGleb Natapov 	pmu_counter_t cnt = {
262*a9f8b16fSGleb Natapov 		.config = EVNTSEL_OS | EVNTSEL_USR,
263*a9f8b16fSGleb Natapov 	};
264*a9f8b16fSGleb Natapov 	int i;
265*a9f8b16fSGleb Natapov 
266*a9f8b16fSGleb Natapov 	for (i = 0; i < edx.split.num_counters_fixed; i++) {
267*a9f8b16fSGleb Natapov 		cnt.count = 0;
268*a9f8b16fSGleb Natapov 		cnt.ctr = fixed_events[i].unit_sel;
269*a9f8b16fSGleb Natapov 		measure(&cnt, 1);
270*a9f8b16fSGleb Natapov 		report("fixed", i, verify_event(cnt.count, &fixed_events[i]));
271*a9f8b16fSGleb Natapov 	}
272*a9f8b16fSGleb Natapov }
273*a9f8b16fSGleb Natapov 
274*a9f8b16fSGleb Natapov static void check_counters_many(void)
275*a9f8b16fSGleb Natapov {
276*a9f8b16fSGleb Natapov 	pmu_counter_t cnt[10];
277*a9f8b16fSGleb Natapov 	int i, n;
278*a9f8b16fSGleb Natapov 
279*a9f8b16fSGleb Natapov 	for (i = 0, n = 0; n < eax.split.num_counters; i++) {
280*a9f8b16fSGleb Natapov 		if (ebx.full & (1 << i))
281*a9f8b16fSGleb Natapov 			continue;
282*a9f8b16fSGleb Natapov 
283*a9f8b16fSGleb Natapov 		cnt[n].count = 0;
284*a9f8b16fSGleb Natapov 		cnt[n].ctr = MSR_IA32_PERFCTR0 + n;
285*a9f8b16fSGleb Natapov 		cnt[n].config = EVNTSEL_OS | EVNTSEL_USR | gp_events[i].unit_sel;
286*a9f8b16fSGleb Natapov 		n++;
287*a9f8b16fSGleb Natapov 	}
288*a9f8b16fSGleb Natapov 	for (i = 0; i < edx.split.num_counters_fixed; i++) {
289*a9f8b16fSGleb Natapov 		cnt[n].count = 0;
290*a9f8b16fSGleb Natapov 		cnt[n].ctr = fixed_events[i].unit_sel;
291*a9f8b16fSGleb Natapov 		cnt[n].config = EVNTSEL_OS | EVNTSEL_USR;
292*a9f8b16fSGleb Natapov 		n++;
293*a9f8b16fSGleb Natapov 	}
294*a9f8b16fSGleb Natapov 
295*a9f8b16fSGleb Natapov 	measure(cnt, n);
296*a9f8b16fSGleb Natapov 
297*a9f8b16fSGleb Natapov 	for (i = 0; i < n; i++)
298*a9f8b16fSGleb Natapov 		if (!verify_counter(&cnt[i]))
299*a9f8b16fSGleb Natapov 			break;
300*a9f8b16fSGleb Natapov 
301*a9f8b16fSGleb Natapov 	report("all counters", 0, i == n);
302*a9f8b16fSGleb Natapov }
303*a9f8b16fSGleb Natapov 
304*a9f8b16fSGleb Natapov static void check_counter_overflow(void)
305*a9f8b16fSGleb Natapov {
306*a9f8b16fSGleb Natapov 	uint64_t count;
307*a9f8b16fSGleb Natapov 	int i;
308*a9f8b16fSGleb Natapov 	pmu_counter_t cnt = {
309*a9f8b16fSGleb Natapov 		.ctr = MSR_IA32_PERFCTR0,
310*a9f8b16fSGleb Natapov 		.config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel /* instructions */,
311*a9f8b16fSGleb Natapov 		.count = 0,
312*a9f8b16fSGleb Natapov 	};
313*a9f8b16fSGleb Natapov 	measure(&cnt, 1);
314*a9f8b16fSGleb Natapov 	count = cnt.count;
315*a9f8b16fSGleb Natapov 
316*a9f8b16fSGleb Natapov 	/* clear status before test */
317*a9f8b16fSGleb Natapov 	wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_STATUS));
318*a9f8b16fSGleb Natapov 
319*a9f8b16fSGleb Natapov 	for (i = 0; i < eax.split.num_counters + 1; i++, cnt.ctr++) {
320*a9f8b16fSGleb Natapov 		uint64_t status;
321*a9f8b16fSGleb Natapov 		int idx;
322*a9f8b16fSGleb Natapov 		if (i == eax.split.num_counters)
323*a9f8b16fSGleb Natapov 			cnt.ctr = fixed_events[0].unit_sel;
324*a9f8b16fSGleb Natapov 		if (i % 2)
325*a9f8b16fSGleb Natapov 			cnt.config |= EVNTSEL_INT;
326*a9f8b16fSGleb Natapov 		else
327*a9f8b16fSGleb Natapov 			cnt.config &= ~EVNTSEL_INT;
328*a9f8b16fSGleb Natapov 		idx = event_to_global_idx(&cnt);
329*a9f8b16fSGleb Natapov 		cnt.count = 1 - count;
330*a9f8b16fSGleb Natapov 		measure(&cnt, 1);
331*a9f8b16fSGleb Natapov 		report("overflow", i, cnt.count == 1);
332*a9f8b16fSGleb Natapov 		status = rdmsr(MSR_CORE_PERF_GLOBAL_STATUS);
333*a9f8b16fSGleb Natapov 		report("overflow status", i, status & (1ull << idx));
334*a9f8b16fSGleb Natapov 		wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, status);
335*a9f8b16fSGleb Natapov 		status = rdmsr(MSR_CORE_PERF_GLOBAL_STATUS);
336*a9f8b16fSGleb Natapov 		report("overflow status clear", i, !(status & (1ull << idx)));
337*a9f8b16fSGleb Natapov 		report("overflow irq", i, check_irq() == (i % 2));
338*a9f8b16fSGleb Natapov 	}
339*a9f8b16fSGleb Natapov }
340*a9f8b16fSGleb Natapov 
341*a9f8b16fSGleb Natapov static void check_gp_counter_cmask(void)
342*a9f8b16fSGleb Natapov {
343*a9f8b16fSGleb Natapov 	pmu_counter_t cnt = {
344*a9f8b16fSGleb Natapov 		.ctr = MSR_IA32_PERFCTR0,
345*a9f8b16fSGleb Natapov 		.config = EVNTSEL_OS | EVNTSEL_USR | gp_events[1].unit_sel /* instructions */,
346*a9f8b16fSGleb Natapov 		.count = 0,
347*a9f8b16fSGleb Natapov 	};
348*a9f8b16fSGleb Natapov 	cnt.config |= (0x2 << EVNTSEL_CMASK_SHIFT);
349*a9f8b16fSGleb Natapov 	measure(&cnt, 1);
350*a9f8b16fSGleb Natapov 	report("cmask", 0, cnt.count < gp_events[1].min);
351*a9f8b16fSGleb Natapov }
352*a9f8b16fSGleb Natapov 
353*a9f8b16fSGleb Natapov static void check_rdpmc(void)
354*a9f8b16fSGleb Natapov {
355*a9f8b16fSGleb Natapov 	uint64_t val = 0x1f3456789ull;
356*a9f8b16fSGleb Natapov 	int i;
357*a9f8b16fSGleb Natapov 
358*a9f8b16fSGleb Natapov 	for (i = 0; i < eax.split.num_counters; i++) {
359*a9f8b16fSGleb Natapov 		uint64_t x = (val & 0xffffffff) |
360*a9f8b16fSGleb Natapov 			((1ull << (eax.split.bit_width - 32)) - 1) << 32;
361*a9f8b16fSGleb Natapov 		wrmsr(MSR_IA32_PERFCTR0 + i, val);
362*a9f8b16fSGleb Natapov 		report("rdpmc", i, rdpmc(i) == x);
363*a9f8b16fSGleb Natapov 		report("rdpmc fast", i, rdpmc(i | (1<<31)) == (u32)val);
364*a9f8b16fSGleb Natapov 	}
365*a9f8b16fSGleb Natapov 	for (i = 0; i < edx.split.num_counters_fixed; i++) {
366*a9f8b16fSGleb Natapov 		uint64_t x = (val & 0xffffffff) |
367*a9f8b16fSGleb Natapov 			((1ull << (edx.split.bit_width_fixed - 32)) - 1) << 32;
368*a9f8b16fSGleb Natapov 		wrmsr(MSR_CORE_PERF_FIXED_CTR0 + i, val);
369*a9f8b16fSGleb Natapov 		report("rdpmc fixed", i, rdpmc(i | (1 << 30)) == x);
370*a9f8b16fSGleb Natapov 		report("rdpmc fixed fast", i, rdpmc(i | (3<<30)) == (u32)val);
371*a9f8b16fSGleb Natapov 	}
372*a9f8b16fSGleb Natapov }
373*a9f8b16fSGleb Natapov 
374*a9f8b16fSGleb Natapov int main(int ac, char **av)
375*a9f8b16fSGleb Natapov {
376*a9f8b16fSGleb Natapov 	struct cpuid id = cpuid(10);
377*a9f8b16fSGleb Natapov 
378*a9f8b16fSGleb Natapov 	setup_vm();
379*a9f8b16fSGleb Natapov 	setup_idt();
380*a9f8b16fSGleb Natapov 	handle_irq(PC_VECTOR, cnt_overflow);
381*a9f8b16fSGleb Natapov 	buf = vmalloc(N*64);
382*a9f8b16fSGleb Natapov 
383*a9f8b16fSGleb Natapov 	eax.full = id.a;
384*a9f8b16fSGleb Natapov 	ebx.full = id.b;
385*a9f8b16fSGleb Natapov 	edx.full = id.d;
386*a9f8b16fSGleb Natapov 
387*a9f8b16fSGleb Natapov 	if (!eax.split.version_id) {
388*a9f8b16fSGleb Natapov 		printf("No pmu is detected!\n");
389*a9f8b16fSGleb Natapov 		return 1;
390*a9f8b16fSGleb Natapov 	}
391*a9f8b16fSGleb Natapov 	printf("PMU version:         %d\n", eax.split.version_id);
392*a9f8b16fSGleb Natapov 	printf("GP counters:         %d\n", eax.split.num_counters);
393*a9f8b16fSGleb Natapov 	printf("GP counter width:    %d\n", eax.split.bit_width);
394*a9f8b16fSGleb Natapov 	printf("Mask length:         %d\n", eax.split.mask_length);
395*a9f8b16fSGleb Natapov 	printf("Fixed counters:      %d\n", edx.split.num_counters_fixed);
396*a9f8b16fSGleb Natapov 	printf("Fixed counter width: %d\n", edx.split.bit_width_fixed);
397*a9f8b16fSGleb Natapov 
398*a9f8b16fSGleb Natapov 	apic_write(APIC_LVTPC, PC_VECTOR);
399*a9f8b16fSGleb Natapov 
400*a9f8b16fSGleb Natapov 	check_gp_counters();
401*a9f8b16fSGleb Natapov 	check_fixed_counters();
402*a9f8b16fSGleb Natapov 	check_rdpmc();
403*a9f8b16fSGleb Natapov 	check_counters_many();
404*a9f8b16fSGleb Natapov 	check_counter_overflow();
405*a9f8b16fSGleb Natapov 	check_gp_counter_cmask();
406*a9f8b16fSGleb Natapov 
407*a9f8b16fSGleb Natapov 	printf("\n%d tests, %d failures\n", tests, failures);
408*a9f8b16fSGleb Natapov 	return !failures ? 0 : 1;
409*a9f8b16fSGleb Natapov }
410