xref: /kvm-unit-tests/x86/pmu.c (revision 28437cdbec8b64bd7b761d37da584fbd4378818e)
1a9f8b16fSGleb Natapov 
2a9f8b16fSGleb Natapov #include "x86/msr.h"
3a9f8b16fSGleb Natapov #include "x86/processor.h"
49f17508dSLike Xu #include "x86/pmu.h"
5a9f8b16fSGleb Natapov #include "x86/apic-defs.h"
6a9f8b16fSGleb Natapov #include "x86/apic.h"
7a9f8b16fSGleb Natapov #include "x86/desc.h"
8a9f8b16fSGleb Natapov #include "x86/isr.h"
995a94088SNicholas Piggin #include "vmalloc.h"
10dcda215bSPaolo Bonzini #include "alloc.h"
11a9f8b16fSGleb Natapov 
12a9f8b16fSGleb Natapov #include "libcflat.h"
13a9f8b16fSGleb Natapov #include <stdint.h>
14a9f8b16fSGleb Natapov 
15a9f8b16fSGleb Natapov #define N 1000000
16a9f8b16fSGleb Natapov 
1720cf9147SJim Mattson // These values match the number of instructions and branches in the
1820cf9147SJim Mattson // assembly block in check_emulated_instr().
1920cf9147SJim Mattson #define EXPECTED_INSTR 17
2020cf9147SJim Mattson #define EXPECTED_BRNCH 5
2120cf9147SJim Mattson 
228dbfe326SDapeng Mi #define IBPB_JMP_INSNS		9
238dbfe326SDapeng Mi #define IBPB_JMP_BRANCHES	2
248dbfe326SDapeng Mi 
258dbfe326SDapeng Mi #if defined(__i386__) || defined(_M_IX86) /* i386 */
268dbfe326SDapeng Mi #define IBPB_JMP_ASM(_wrmsr)				\
278dbfe326SDapeng Mi 	"mov $1, %%eax; xor %%edx, %%edx;\n\t"		\
288dbfe326SDapeng Mi 	"mov $73, %%ecx;\n\t"				\
2950f8e27eSDapeng Mi 	_wrmsr "\n\t"					\
308dbfe326SDapeng Mi 	"call 1f\n\t"					\
318dbfe326SDapeng Mi 	"1: pop %%eax\n\t"				\
328dbfe326SDapeng Mi 	"add $(2f-1b), %%eax\n\t"			\
338dbfe326SDapeng Mi 	"jmp *%%eax;\n\t"                               \
348dbfe326SDapeng Mi 	"nop;\n\t"					\
358dbfe326SDapeng Mi 	"2: nop;\n\t"
368dbfe326SDapeng Mi #else /* x86_64 */
378dbfe326SDapeng Mi #define IBPB_JMP_ASM(_wrmsr)				\
388dbfe326SDapeng Mi 	"mov $1, %%eax; xor %%edx, %%edx;\n\t"		\
398dbfe326SDapeng Mi 	"mov $73, %%ecx;\n\t"				\
408dbfe326SDapeng Mi 	_wrmsr "\n\t"					\
418dbfe326SDapeng Mi 	"call 1f\n\t"					\
428dbfe326SDapeng Mi 	"1: pop %%rax\n\t"				\
438dbfe326SDapeng Mi 	"add $(2f-1b), %%rax\n\t"                       \
448dbfe326SDapeng Mi 	"jmp *%%rax;\n\t"                               \
458dbfe326SDapeng Mi 	"nop;\n\t"					\
468dbfe326SDapeng Mi 	"2: nop;\n\t"
478dbfe326SDapeng Mi #endif
488dbfe326SDapeng Mi 
498dbfe326SDapeng Mi /* GLOBAL_CTRL enable + disable + clflush/mfence + IBPB_JMP */
508dbfe326SDapeng Mi #define EXTRA_INSNS  (3 + 3 + 2 + IBPB_JMP_INSNS)
518dbfe326SDapeng Mi #define LOOP_INSNS   (N * 10 + EXTRA_INSNS)
528dbfe326SDapeng Mi #define LOOP_BRANCHES  (N + IBPB_JMP_BRANCHES)
538dbfe326SDapeng Mi #define LOOP_ASM(_wrmsr1, _clflush, _wrmsr2)				\
548dbfe326SDapeng Mi 	_wrmsr1 "\n\t"							\
5550f8e27eSDapeng Mi 	"mov %%ecx, %%edi; mov %%ebx, %%ecx;\n\t"			\
5638b5b426SDapeng Mi 	_clflush "\n\t"                                 		\
5738b5b426SDapeng Mi 	"mfence;\n\t"                                   		\
5850f8e27eSDapeng Mi 	"1: mov (%1), %2; add $64, %1;\n\t"				\
5950f8e27eSDapeng Mi 	"nop; nop; nop; nop; nop; nop; nop;\n\t"			\
6050f8e27eSDapeng Mi 	"loop 1b;\n\t"							\
618dbfe326SDapeng Mi 	IBPB_JMP_ASM(_wrmsr2) 						\
6250f8e27eSDapeng Mi 	"mov %%edi, %%ecx; xor %%eax, %%eax; xor %%edx, %%edx;\n\t"	\
638dbfe326SDapeng Mi 	_wrmsr1 "\n\t"
6450f8e27eSDapeng Mi 
658dbfe326SDapeng Mi #define _loop_asm(_wrmsr1, _clflush, _wrmsr2)			\
6638b5b426SDapeng Mi do {								\
678dbfe326SDapeng Mi 	asm volatile(LOOP_ASM(_wrmsr1, _clflush, _wrmsr2)	\
6838b5b426SDapeng Mi 		     : "=b"(tmp), "=r"(tmp2), "=r"(tmp3)	\
6938b5b426SDapeng Mi 		     : "a"(eax), "d"(edx), "c"(global_ctl),	\
7038b5b426SDapeng Mi 		       "0"(N), "1"(buf)				\
7138b5b426SDapeng Mi 		     : "edi");					\
7238b5b426SDapeng Mi } while (0)
7338b5b426SDapeng Mi 
74a9f8b16fSGleb Natapov typedef struct {
75a9f8b16fSGleb Natapov 	uint32_t ctr;
769720e46cSDapeng Mi 	uint32_t idx;
77006b089dSLike Xu 	uint64_t config;
78a9f8b16fSGleb Natapov 	uint64_t count;
79a9f8b16fSGleb Natapov } pmu_counter_t;
80a9f8b16fSGleb Natapov 
81a9f8b16fSGleb Natapov struct pmu_event {
82797d79a2SThomas Huth 	const char *name;
83a9f8b16fSGleb Natapov 	uint32_t unit_sel;
84a9f8b16fSGleb Natapov 	int min;
85a9f8b16fSGleb Natapov 	int max;
867c648ce2SLike Xu } intel_gp_events[] = {
87a9f8b16fSGleb Natapov 	{"core cycles", 0x003c, 1*N, 50*N},
88a9f8b16fSGleb Natapov 	{"instructions", 0x00c0, 10*N, 10.2*N},
89290f4213SJim Mattson 	{"ref cycles", 0x013c, 1*N, 30*N},
90290f4213SJim Mattson 	{"llc references", 0x4f2e, 1, 2*N},
91a9f8b16fSGleb Natapov 	{"llc misses", 0x412e, 1, 1*N},
92a9f8b16fSGleb Natapov 	{"branches", 0x00c4, 1*N, 1.1*N},
93*28437cdbSDapeng Mi 	{"branch misses", 0x00c5, 1, 0.1*N},
94b883751aSLike Xu }, amd_gp_events[] = {
95b883751aSLike Xu 	{"core cycles", 0x0076, 1*N, 50*N},
96b883751aSLike Xu 	{"instructions", 0x00c0, 10*N, 10.2*N},
97b883751aSLike Xu 	{"branches", 0x00c2, 1*N, 1.1*N},
98*28437cdbSDapeng Mi 	{"branch misses", 0x00c3, 1, 0.1*N},
99a9f8b16fSGleb Natapov }, fixed_events[] = {
1005d6a3a54SDapeng Mi 	{"fixed 0", MSR_CORE_PERF_FIXED_CTR0, 10*N, 10.2*N},
1015d6a3a54SDapeng Mi 	{"fixed 1", MSR_CORE_PERF_FIXED_CTR0 + 1, 1*N, 30*N},
1025d6a3a54SDapeng Mi 	{"fixed 2", MSR_CORE_PERF_FIXED_CTR0 + 2, 0.1*N, 30*N}
103a9f8b16fSGleb Natapov };
104a9f8b16fSGleb Natapov 
105f4e97f59SDapeng Mi /*
106f4e97f59SDapeng Mi  * Events index in intel_gp_events[], ensure consistent with
107f4e97f59SDapeng Mi  * intel_gp_events[].
108f4e97f59SDapeng Mi  */
109f4e97f59SDapeng Mi enum {
11085c75578SDapeng Mi 	INTEL_INSTRUCTIONS_IDX  = 1,
11125cc1ea7SDapeng Mi 	INTEL_REF_CYCLES_IDX	= 2,
112e0d0022fSDapeng Mi 	INTEL_LLC_MISSES_IDX	= 4,
113f4e97f59SDapeng Mi 	INTEL_BRANCHES_IDX	= 5,
114*28437cdbSDapeng Mi 	INTEL_BRANCH_MISS_IDX	= 6,
115f4e97f59SDapeng Mi };
116f4e97f59SDapeng Mi 
117f4e97f59SDapeng Mi /*
118f4e97f59SDapeng Mi  * Events index in amd_gp_events[], ensure consistent with
119f4e97f59SDapeng Mi  * amd_gp_events[].
120f4e97f59SDapeng Mi  */
121f4e97f59SDapeng Mi enum {
12285c75578SDapeng Mi 	AMD_INSTRUCTIONS_IDX    = 1,
123f4e97f59SDapeng Mi 	AMD_BRANCHES_IDX	= 2,
124*28437cdbSDapeng Mi 	AMD_BRANCH_MISS_IDX	= 3,
125f4e97f59SDapeng Mi };
126f4e97f59SDapeng Mi 
127a9f8b16fSGleb Natapov char *buf;
128a9f8b16fSGleb Natapov 
1297c648ce2SLike Xu static struct pmu_event *gp_events;
1307c648ce2SLike Xu static unsigned int gp_events_size;
1319c07c92bSDapeng Mi static unsigned int fixed_counters_num;
1327c648ce2SLike Xu 
1338dbfe326SDapeng Mi static int has_ibpb(void)
1348dbfe326SDapeng Mi {
1358dbfe326SDapeng Mi 	return this_cpu_has(X86_FEATURE_SPEC_CTRL) ||
1368dbfe326SDapeng Mi 	       this_cpu_has(X86_FEATURE_AMD_IBPB);
1378dbfe326SDapeng Mi }
1388dbfe326SDapeng Mi 
13950f8e27eSDapeng Mi static inline void __loop(void)
140a9f8b16fSGleb Natapov {
141a9f8b16fSGleb Natapov 	unsigned long tmp, tmp2, tmp3;
14238b5b426SDapeng Mi 	u32 global_ctl = 0;
14338b5b426SDapeng Mi 	u32 eax = 0;
14438b5b426SDapeng Mi 	u32 edx = 0;
145a9f8b16fSGleb Natapov 
1468dbfe326SDapeng Mi 	if (this_cpu_has(X86_FEATURE_CLFLUSH) && has_ibpb())
1478dbfe326SDapeng Mi 		_loop_asm("nop", "clflush (%1)", "wrmsr");
1488dbfe326SDapeng Mi 	else if (this_cpu_has(X86_FEATURE_CLFLUSH))
1498dbfe326SDapeng Mi 		_loop_asm("nop", "clflush (%1)", "nop");
1508dbfe326SDapeng Mi 	else if (has_ibpb())
1518dbfe326SDapeng Mi 		_loop_asm("nop", "nop", "wrmsr");
15238b5b426SDapeng Mi 	else
1538dbfe326SDapeng Mi 		_loop_asm("nop", "nop", "nop");
15450f8e27eSDapeng Mi }
155a9f8b16fSGleb Natapov 
15650f8e27eSDapeng Mi /*
15750f8e27eSDapeng Mi  * Enable and disable counters in a whole asm blob to ensure
15850f8e27eSDapeng Mi  * no other instructions are counted in the window between
15950f8e27eSDapeng Mi  * counters enabling and really LOOP_ASM code executing.
16050f8e27eSDapeng Mi  * Thus counters can verify instructions and branches events
16150f8e27eSDapeng Mi  * against precise counts instead of a rough valid count range.
16250f8e27eSDapeng Mi  */
16350f8e27eSDapeng Mi static inline void __precise_loop(u64 cntrs)
16450f8e27eSDapeng Mi {
16550f8e27eSDapeng Mi 	unsigned long tmp, tmp2, tmp3;
16638b5b426SDapeng Mi 	u32 global_ctl = pmu.msr_global_ctl;
16750f8e27eSDapeng Mi 	u32 eax = cntrs & (BIT_ULL(32) - 1);
16850f8e27eSDapeng Mi 	u32 edx = cntrs >> 32;
16950f8e27eSDapeng Mi 
1708dbfe326SDapeng Mi 	if (this_cpu_has(X86_FEATURE_CLFLUSH) && has_ibpb())
1718dbfe326SDapeng Mi 		_loop_asm("wrmsr", "clflush (%1)", "wrmsr");
1728dbfe326SDapeng Mi 	else if (this_cpu_has(X86_FEATURE_CLFLUSH))
1738dbfe326SDapeng Mi 		_loop_asm("wrmsr", "clflush (%1)", "nop");
1748dbfe326SDapeng Mi 	else if (has_ibpb())
1758dbfe326SDapeng Mi 		_loop_asm("wrmsr", "nop", "wrmsr");
17638b5b426SDapeng Mi 	else
1778dbfe326SDapeng Mi 		_loop_asm("wrmsr", "nop", "nop");
17850f8e27eSDapeng Mi }
17950f8e27eSDapeng Mi 
18050f8e27eSDapeng Mi static inline void loop(u64 cntrs)
18150f8e27eSDapeng Mi {
18250f8e27eSDapeng Mi 	if (!this_cpu_has_perf_global_ctrl())
18350f8e27eSDapeng Mi 		__loop();
18450f8e27eSDapeng Mi 	else
18550f8e27eSDapeng Mi 		__precise_loop(cntrs);
186a9f8b16fSGleb Natapov }
187a9f8b16fSGleb Natapov 
18889126fa4SDapeng Mi static void adjust_events_range(struct pmu_event *gp_events,
189*28437cdbSDapeng Mi 				int instruction_idx, int branch_idx,
190*28437cdbSDapeng Mi 				int branch_miss_idx)
19189126fa4SDapeng Mi {
19289126fa4SDapeng Mi 	/*
19389126fa4SDapeng Mi 	 * If HW supports GLOBAL_CTRL MSR, enabling and disabling PMCs are
19489126fa4SDapeng Mi 	 * moved in __precise_loop(). Thus, instructions and branches events
19589126fa4SDapeng Mi 	 * can be verified against a precise count instead of a rough range.
19689126fa4SDapeng Mi 	 *
19789126fa4SDapeng Mi 	 * Skip the precise checks on AMD, as AMD CPUs count VMRUN as a branch
19889126fa4SDapeng Mi 	 * instruction in guest context, which* leads to intermittent failures
19989126fa4SDapeng Mi 	 * as the counts will vary depending on how many asynchronous VM-Exits
20089126fa4SDapeng Mi 	 * occur while running the measured code, e.g. if the host takes IRQs.
20189126fa4SDapeng Mi 	 */
20289126fa4SDapeng Mi 	if (pmu.is_intel && this_cpu_has_perf_global_ctrl()) {
20389126fa4SDapeng Mi 		gp_events[instruction_idx].min = LOOP_INSNS;
20489126fa4SDapeng Mi 		gp_events[instruction_idx].max = LOOP_INSNS;
20589126fa4SDapeng Mi 		gp_events[branch_idx].min = LOOP_BRANCHES;
20689126fa4SDapeng Mi 		gp_events[branch_idx].max = LOOP_BRANCHES;
20789126fa4SDapeng Mi 	}
208*28437cdbSDapeng Mi 
209*28437cdbSDapeng Mi 	/*
210*28437cdbSDapeng Mi 	 * For CPUs without IBPB support, no way to force to trigger a branch
211*28437cdbSDapeng Mi 	 * miss and the measured branch misses is possible to be 0.  Thus
212*28437cdbSDapeng Mi 	 * overwrite the lower boundary of branch misses event to 0 to avoid
213*28437cdbSDapeng Mi 	 * false positive.
214*28437cdbSDapeng Mi 	 */
215*28437cdbSDapeng Mi 	if (!has_ibpb())
216*28437cdbSDapeng Mi 		gp_events[branch_miss_idx].min = 0;
21789126fa4SDapeng Mi }
21889126fa4SDapeng Mi 
219a9f8b16fSGleb Natapov volatile uint64_t irq_received;
220a9f8b16fSGleb Natapov 
221a9f8b16fSGleb Natapov static void cnt_overflow(isr_regs_t *regs)
222a9f8b16fSGleb Natapov {
223a9f8b16fSGleb Natapov 	irq_received++;
224c595c361SMingwei Zhang 	apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
225a9f8b16fSGleb Natapov 	apic_write(APIC_EOI, 0);
226a9f8b16fSGleb Natapov }
227a9f8b16fSGleb Natapov 
228a9f8b16fSGleb Natapov static bool check_irq(void)
229a9f8b16fSGleb Natapov {
230a9f8b16fSGleb Natapov 	int i;
231a9f8b16fSGleb Natapov 	irq_received = 0;
232787f0aebSMaxim Levitsky 	sti();
233a9f8b16fSGleb Natapov 	for (i = 0; i < 100000 && !irq_received; i++)
234a9f8b16fSGleb Natapov 		asm volatile("pause");
235787f0aebSMaxim Levitsky 	cli();
236a9f8b16fSGleb Natapov 	return irq_received;
237a9f8b16fSGleb Natapov }
238a9f8b16fSGleb Natapov 
239a9f8b16fSGleb Natapov static bool is_gp(pmu_counter_t *evt)
240a9f8b16fSGleb Natapov {
241b883751aSLike Xu 	if (!pmu.is_intel)
242b883751aSLike Xu 		return true;
243b883751aSLike Xu 
24422f2901aSLike Xu 	return evt->ctr < MSR_CORE_PERF_FIXED_CTR0 ||
24522f2901aSLike Xu 		evt->ctr >= MSR_IA32_PMC0;
246a9f8b16fSGleb Natapov }
247a9f8b16fSGleb Natapov 
248a9f8b16fSGleb Natapov static int event_to_global_idx(pmu_counter_t *cnt)
249a9f8b16fSGleb Natapov {
250b883751aSLike Xu 	if (pmu.is_intel)
251cda64e80SLike Xu 		return cnt->ctr - (is_gp(cnt) ? pmu.msr_gp_counter_base :
252a9f8b16fSGleb Natapov 			(MSR_CORE_PERF_FIXED_CTR0 - FIXED_CNT_INDEX));
253b883751aSLike Xu 
254b883751aSLike Xu 	if (pmu.msr_gp_counter_base == MSR_F15H_PERF_CTR0)
255b883751aSLike Xu 		return (cnt->ctr - pmu.msr_gp_counter_base) / 2;
256b883751aSLike Xu 	else
257b883751aSLike Xu 		return cnt->ctr - pmu.msr_gp_counter_base;
258a9f8b16fSGleb Natapov }
259a9f8b16fSGleb Natapov 
260a9f8b16fSGleb Natapov static struct pmu_event* get_counter_event(pmu_counter_t *cnt)
261a9f8b16fSGleb Natapov {
262a9f8b16fSGleb Natapov 	if (is_gp(cnt)) {
263a9f8b16fSGleb Natapov 		int i;
264a9f8b16fSGleb Natapov 
2657c648ce2SLike Xu 		for (i = 0; i < gp_events_size; i++)
266a9f8b16fSGleb Natapov 			if (gp_events[i].unit_sel == (cnt->config & 0xffff))
267a9f8b16fSGleb Natapov 				return &gp_events[i];
2689c07c92bSDapeng Mi 	} else {
2699c07c92bSDapeng Mi 		unsigned int idx = cnt->ctr - MSR_CORE_PERF_FIXED_CTR0;
2709c07c92bSDapeng Mi 
2719c07c92bSDapeng Mi 		if (idx < ARRAY_SIZE(fixed_events))
2729c07c92bSDapeng Mi 			return &fixed_events[idx];
2739c07c92bSDapeng Mi 	}
274a9f8b16fSGleb Natapov 
275a9f8b16fSGleb Natapov 	return (void*)0;
276a9f8b16fSGleb Natapov }
277a9f8b16fSGleb Natapov 
278a9f8b16fSGleb Natapov static void global_enable(pmu_counter_t *cnt)
279a9f8b16fSGleb Natapov {
28062ba5036SLike Xu 	if (!this_cpu_has_perf_global_ctrl())
28162ba5036SLike Xu 		return;
28262ba5036SLike Xu 
283a9f8b16fSGleb Natapov 	cnt->idx = event_to_global_idx(cnt);
2848a2866d1SLike Xu 	wrmsr(pmu.msr_global_ctl, rdmsr(pmu.msr_global_ctl) | BIT_ULL(cnt->idx));
285a9f8b16fSGleb Natapov }
286a9f8b16fSGleb Natapov 
287a9f8b16fSGleb Natapov static void global_disable(pmu_counter_t *cnt)
288a9f8b16fSGleb Natapov {
28962ba5036SLike Xu 	if (!this_cpu_has_perf_global_ctrl())
29062ba5036SLike Xu 		return;
29162ba5036SLike Xu 
2928a2866d1SLike Xu 	wrmsr(pmu.msr_global_ctl, rdmsr(pmu.msr_global_ctl) & ~BIT_ULL(cnt->idx));
293a9f8b16fSGleb Natapov }
294a9f8b16fSGleb Natapov 
295e9e7577bSLike Xu static void __start_event(pmu_counter_t *evt, uint64_t count)
296a9f8b16fSGleb Natapov {
297e9e7577bSLike Xu     evt->count = count;
298a9f8b16fSGleb Natapov     wrmsr(evt->ctr, evt->count);
299cda64e80SLike Xu     if (is_gp(evt)) {
300cda64e80SLike Xu 	    wrmsr(MSR_GP_EVENT_SELECTx(event_to_global_idx(evt)),
301a9f8b16fSGleb Natapov 		  evt->config | EVNTSEL_EN);
302cda64e80SLike Xu     } else {
303a9f8b16fSGleb Natapov 	    uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL);
304a9f8b16fSGleb Natapov 	    int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4;
305a9f8b16fSGleb Natapov 	    uint32_t usrospmi = 0;
306a9f8b16fSGleb Natapov 
307a9f8b16fSGleb Natapov 	    if (evt->config & EVNTSEL_OS)
308a9f8b16fSGleb Natapov 		    usrospmi |= (1 << 0);
309a9f8b16fSGleb Natapov 	    if (evt->config & EVNTSEL_USR)
310a9f8b16fSGleb Natapov 		    usrospmi |= (1 << 1);
311a9f8b16fSGleb Natapov 	    if (evt->config & EVNTSEL_INT)
312a9f8b16fSGleb Natapov 		    usrospmi |= (1 << 3); // PMI on overflow
313a9f8b16fSGleb Natapov 	    ctrl = (ctrl & ~(0xf << shift)) | (usrospmi << shift);
314a9f8b16fSGleb Natapov 	    wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl);
315a9f8b16fSGleb Natapov     }
3165a2cb3e6SLike Xu     apic_write(APIC_LVTPC, PMI_VECTOR);
317a9f8b16fSGleb Natapov }
318a9f8b16fSGleb Natapov 
319e9e7577bSLike Xu static void start_event(pmu_counter_t *evt)
320e9e7577bSLike Xu {
321e9e7577bSLike Xu 	__start_event(evt, 0);
32250f8e27eSDapeng Mi 	global_enable(evt);
323e9e7577bSLike Xu }
324e9e7577bSLike Xu 
32550f8e27eSDapeng Mi static void __stop_event(pmu_counter_t *evt)
326a9f8b16fSGleb Natapov {
327cda64e80SLike Xu 	if (is_gp(evt)) {
328cda64e80SLike Xu 		wrmsr(MSR_GP_EVENT_SELECTx(event_to_global_idx(evt)),
329a9f8b16fSGleb Natapov 		      evt->config & ~EVNTSEL_EN);
330cda64e80SLike Xu 	} else {
331a9f8b16fSGleb Natapov 		uint32_t ctrl = rdmsr(MSR_CORE_PERF_FIXED_CTR_CTRL);
332a9f8b16fSGleb Natapov 		int shift = (evt->ctr - MSR_CORE_PERF_FIXED_CTR0) * 4;
333a9f8b16fSGleb Natapov 		wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl & ~(0xf << shift));
334a9f8b16fSGleb Natapov 	}
335a9f8b16fSGleb Natapov 	evt->count = rdmsr(evt->ctr);
336a9f8b16fSGleb Natapov }
337a9f8b16fSGleb Natapov 
33850f8e27eSDapeng Mi static void stop_event(pmu_counter_t *evt)
33950f8e27eSDapeng Mi {
34050f8e27eSDapeng Mi 	global_disable(evt);
34150f8e27eSDapeng Mi 	__stop_event(evt);
34250f8e27eSDapeng Mi }
34350f8e27eSDapeng Mi 
3448554261fSLike Xu static noinline void measure_many(pmu_counter_t *evt, int count)
345a9f8b16fSGleb Natapov {
346a9f8b16fSGleb Natapov 	int i;
34750f8e27eSDapeng Mi 	u64 cntrs = 0;
34850f8e27eSDapeng Mi 
34950f8e27eSDapeng Mi 	for (i = 0; i < count; i++) {
35050f8e27eSDapeng Mi 		__start_event(&evt[i], 0);
35150f8e27eSDapeng Mi 		cntrs |= BIT_ULL(event_to_global_idx(&evt[i]));
35250f8e27eSDapeng Mi 	}
35350f8e27eSDapeng Mi 	loop(cntrs);
354a9f8b16fSGleb Natapov 	for (i = 0; i < count; i++)
35550f8e27eSDapeng Mi 		__stop_event(&evt[i]);
356a9f8b16fSGleb Natapov }
357a9f8b16fSGleb Natapov 
3588554261fSLike Xu static void measure_one(pmu_counter_t *evt)
3598554261fSLike Xu {
3608554261fSLike Xu 	measure_many(evt, 1);
3618554261fSLike Xu }
3628554261fSLike Xu 
363e9e7577bSLike Xu static noinline void __measure(pmu_counter_t *evt, uint64_t count)
364e9e7577bSLike Xu {
36550f8e27eSDapeng Mi 	u64 cntrs = BIT_ULL(event_to_global_idx(evt));
36650f8e27eSDapeng Mi 
367e9e7577bSLike Xu 	__start_event(evt, count);
36850f8e27eSDapeng Mi 	loop(cntrs);
36950f8e27eSDapeng Mi 	__stop_event(evt);
370e9e7577bSLike Xu }
371e9e7577bSLike Xu 
372a9f8b16fSGleb Natapov static bool verify_event(uint64_t count, struct pmu_event *e)
373a9f8b16fSGleb Natapov {
3749c07c92bSDapeng Mi 	bool pass;
375d24d3381SDapeng Mi 
3769c07c92bSDapeng Mi 	if (!e)
3779c07c92bSDapeng Mi 		return false;
3789c07c92bSDapeng Mi 
3799c07c92bSDapeng Mi 	pass = count >= e->min && count <= e->max;
380d24d3381SDapeng Mi 	if (!pass)
381d24d3381SDapeng Mi 		printf("FAIL: %d <= %"PRId64" <= %d\n", e->min, count, e->max);
382d24d3381SDapeng Mi 
383d24d3381SDapeng Mi 	return pass;
384a9f8b16fSGleb Natapov }
385a9f8b16fSGleb Natapov 
386a9f8b16fSGleb Natapov static bool verify_counter(pmu_counter_t *cnt)
387a9f8b16fSGleb Natapov {
388a9f8b16fSGleb Natapov 	return verify_event(cnt->count, get_counter_event(cnt));
389a9f8b16fSGleb Natapov }
390a9f8b16fSGleb Natapov 
391a9f8b16fSGleb Natapov static void check_gp_counter(struct pmu_event *evt)
392a9f8b16fSGleb Natapov {
393a9f8b16fSGleb Natapov 	pmu_counter_t cnt = {
394a9f8b16fSGleb Natapov 		.config = EVNTSEL_OS | EVNTSEL_USR | evt->unit_sel,
395a9f8b16fSGleb Natapov 	};
396a9f8b16fSGleb Natapov 	int i;
397a9f8b16fSGleb Natapov 
398cda64e80SLike Xu 	for (i = 0; i < pmu.nr_gp_counters; i++) {
399cda64e80SLike Xu 		cnt.ctr = MSR_GP_COUNTERx(i);
4008554261fSLike Xu 		measure_one(&cnt);
401a299895bSThomas Huth 		report(verify_event(cnt.count, evt), "%s-%d", evt->name, i);
402a9f8b16fSGleb Natapov 	}
403a9f8b16fSGleb Natapov }
404a9f8b16fSGleb Natapov 
405a9f8b16fSGleb Natapov static void check_gp_counters(void)
406a9f8b16fSGleb Natapov {
407a9f8b16fSGleb Natapov 	int i;
408a9f8b16fSGleb Natapov 
4097c648ce2SLike Xu 	for (i = 0; i < gp_events_size; i++)
4102719b92cSYang Weijiang 		if (pmu_gp_counter_is_available(i))
411a9f8b16fSGleb Natapov 			check_gp_counter(&gp_events[i]);
412a9f8b16fSGleb Natapov 		else
413a9f8b16fSGleb Natapov 			printf("GP event '%s' is disabled\n",
414a9f8b16fSGleb Natapov 					gp_events[i].name);
415a9f8b16fSGleb Natapov }
416a9f8b16fSGleb Natapov 
417a9f8b16fSGleb Natapov static void check_fixed_counters(void)
418a9f8b16fSGleb Natapov {
419a9f8b16fSGleb Natapov 	pmu_counter_t cnt = {
420a9f8b16fSGleb Natapov 		.config = EVNTSEL_OS | EVNTSEL_USR,
421a9f8b16fSGleb Natapov 	};
422a9f8b16fSGleb Natapov 	int i;
423a9f8b16fSGleb Natapov 
4249c07c92bSDapeng Mi 	for (i = 0; i < fixed_counters_num; i++) {
425a9f8b16fSGleb Natapov 		cnt.ctr = fixed_events[i].unit_sel;
4268554261fSLike Xu 		measure_one(&cnt);
4272719b92cSYang Weijiang 		report(verify_event(cnt.count, &fixed_events[i]), "fixed-%d", i);
428a9f8b16fSGleb Natapov 	}
429a9f8b16fSGleb Natapov }
430a9f8b16fSGleb Natapov 
431a9f8b16fSGleb Natapov static void check_counters_many(void)
432a9f8b16fSGleb Natapov {
433f21c809eSDapeng Mi 	pmu_counter_t cnt[48];
434a9f8b16fSGleb Natapov 	int i, n;
435a9f8b16fSGleb Natapov 
436414ee7d1SSean Christopherson 	for (i = 0, n = 0; n < pmu.nr_gp_counters; i++) {
4372719b92cSYang Weijiang 		if (!pmu_gp_counter_is_available(i))
438a9f8b16fSGleb Natapov 			continue;
439a9f8b16fSGleb Natapov 
440cda64e80SLike Xu 		cnt[n].ctr = MSR_GP_COUNTERx(n);
4414ac45293SWei Huang 		cnt[n].config = EVNTSEL_OS | EVNTSEL_USR |
4427c648ce2SLike Xu 			gp_events[i % gp_events_size].unit_sel;
443a9f8b16fSGleb Natapov 		n++;
444a9f8b16fSGleb Natapov 	}
4459c07c92bSDapeng Mi 	for (i = 0; i < fixed_counters_num; i++) {
446a9f8b16fSGleb Natapov 		cnt[n].ctr = fixed_events[i].unit_sel;
447a9f8b16fSGleb Natapov 		cnt[n].config = EVNTSEL_OS | EVNTSEL_USR;
448a9f8b16fSGleb Natapov 		n++;
449a9f8b16fSGleb Natapov 	}
450a9f8b16fSGleb Natapov 
451f21c809eSDapeng Mi 	assert(n <= ARRAY_SIZE(cnt));
4528554261fSLike Xu 	measure_many(cnt, n);
453a9f8b16fSGleb Natapov 
454a9f8b16fSGleb Natapov 	for (i = 0; i < n; i++)
455a9f8b16fSGleb Natapov 		if (!verify_counter(&cnt[i]))
456a9f8b16fSGleb Natapov 			break;
457a9f8b16fSGleb Natapov 
458a299895bSThomas Huth 	report(i == n, "all counters");
459a9f8b16fSGleb Natapov }
460a9f8b16fSGleb Natapov 
4617ec3b67aSLike Xu static uint64_t measure_for_overflow(pmu_counter_t *cnt)
4627ec3b67aSLike Xu {
4637ec3b67aSLike Xu 	__measure(cnt, 0);
4647ec3b67aSLike Xu 	/*
4657ec3b67aSLike Xu 	 * To generate overflow, i.e. roll over to '0', the initial count just
4667ec3b67aSLike Xu 	 * needs to be preset to the negative expected count.  However, as per
4677ec3b67aSLike Xu 	 * Intel's SDM, the preset count needs to be incremented by 1 to ensure
4687ec3b67aSLike Xu 	 * the overflow interrupt is generated immediately instead of possibly
4697ec3b67aSLike Xu 	 * waiting for the overflow to propagate through the counter.
4707ec3b67aSLike Xu 	 */
4717ec3b67aSLike Xu 	assert(cnt->count > 1);
4727ec3b67aSLike Xu 	return 1 - cnt->count;
4737ec3b67aSLike Xu }
4747ec3b67aSLike Xu 
475a9f8b16fSGleb Natapov static void check_counter_overflow(void)
476a9f8b16fSGleb Natapov {
477a9f8b16fSGleb Natapov 	int i;
47885c75578SDapeng Mi 	uint64_t overflow_preset;
47985c75578SDapeng Mi 	int instruction_idx = pmu.is_intel ?
48085c75578SDapeng Mi 			      INTEL_INSTRUCTIONS_IDX :
48185c75578SDapeng Mi 			      AMD_INSTRUCTIONS_IDX;
48285c75578SDapeng Mi 
483a9f8b16fSGleb Natapov 	pmu_counter_t cnt = {
484cda64e80SLike Xu 		.ctr = MSR_GP_COUNTERx(0),
48585c75578SDapeng Mi 		.config = EVNTSEL_OS | EVNTSEL_USR |
48685c75578SDapeng Mi 			  gp_events[instruction_idx].unit_sel /* instructions */,
487a9f8b16fSGleb Natapov 	};
4887ec3b67aSLike Xu 	overflow_preset = measure_for_overflow(&cnt);
489a9f8b16fSGleb Natapov 
490a9f8b16fSGleb Natapov 	/* clear status before test */
49162ba5036SLike Xu 	if (this_cpu_has_perf_global_status())
4928a2866d1SLike Xu 		pmu_clear_global_status();
493a9f8b16fSGleb Natapov 
4945bba1769SAndrew Jones 	report_prefix_push("overflow");
4955bba1769SAndrew Jones 
496cda64e80SLike Xu 	for (i = 0; i < pmu.nr_gp_counters + 1; i++) {
497a9f8b16fSGleb Natapov 		uint64_t status;
498a9f8b16fSGleb Natapov 		int idx;
49933cfc1b0SNadav Amit 
5007ec3b67aSLike Xu 		cnt.count = overflow_preset;
501cda64e80SLike Xu 		if (pmu_use_full_writes())
502414ee7d1SSean Christopherson 			cnt.count &= (1ull << pmu.gp_counter_width) - 1;
50333cfc1b0SNadav Amit 
504414ee7d1SSean Christopherson 		if (i == pmu.nr_gp_counters) {
505b883751aSLike Xu 			if (!pmu.is_intel)
506b883751aSLike Xu 				break;
507b883751aSLike Xu 
508a9f8b16fSGleb Natapov 			cnt.ctr = fixed_events[0].unit_sel;
5097ec3b67aSLike Xu 			cnt.count = measure_for_overflow(&cnt);
510cda64e80SLike Xu 			cnt.count &= (1ull << pmu.gp_counter_width) - 1;
511cda64e80SLike Xu 		} else {
512cda64e80SLike Xu 			cnt.ctr = MSR_GP_COUNTERx(i);
51333cfc1b0SNadav Amit 		}
51433cfc1b0SNadav Amit 
515a9f8b16fSGleb Natapov 		if (i % 2)
516a9f8b16fSGleb Natapov 			cnt.config |= EVNTSEL_INT;
517a9f8b16fSGleb Natapov 		else
518a9f8b16fSGleb Natapov 			cnt.config &= ~EVNTSEL_INT;
519a9f8b16fSGleb Natapov 		idx = event_to_global_idx(&cnt);
520e9e7577bSLike Xu 		__measure(&cnt, cnt.count);
521b883751aSLike Xu 		if (pmu.is_intel)
522a299895bSThomas Huth 			report(cnt.count == 1, "cntr-%d", i);
523b883751aSLike Xu 		else
524b883751aSLike Xu 			report(cnt.count == 0xffffffffffff || cnt.count < 7, "cntr-%d", i);
52562ba5036SLike Xu 
52662ba5036SLike Xu 		if (!this_cpu_has_perf_global_status())
52762ba5036SLike Xu 			continue;
52862ba5036SLike Xu 
5298a2866d1SLike Xu 		status = rdmsr(pmu.msr_global_status);
530a299895bSThomas Huth 		report(status & (1ull << idx), "status-%d", i);
5318a2866d1SLike Xu 		wrmsr(pmu.msr_global_status_clr, status);
5328a2866d1SLike Xu 		status = rdmsr(pmu.msr_global_status);
533a299895bSThomas Huth 		report(!(status & (1ull << idx)), "status clear-%d", i);
534a299895bSThomas Huth 		report(check_irq() == (i % 2), "irq-%d", i);
535a9f8b16fSGleb Natapov 	}
5365bba1769SAndrew Jones 
5375bba1769SAndrew Jones 	report_prefix_pop();
538a9f8b16fSGleb Natapov }
539a9f8b16fSGleb Natapov 
540a9f8b16fSGleb Natapov static void check_gp_counter_cmask(void)
541a9f8b16fSGleb Natapov {
54285c75578SDapeng Mi 	int instruction_idx = pmu.is_intel ?
54385c75578SDapeng Mi 			      INTEL_INSTRUCTIONS_IDX :
54485c75578SDapeng Mi 			      AMD_INSTRUCTIONS_IDX;
54585c75578SDapeng Mi 
546a9f8b16fSGleb Natapov 	pmu_counter_t cnt = {
547cda64e80SLike Xu 		.ctr = MSR_GP_COUNTERx(0),
54885c75578SDapeng Mi 		.config = EVNTSEL_OS | EVNTSEL_USR |
54985c75578SDapeng Mi 			  gp_events[instruction_idx].unit_sel /* instructions */,
550a9f8b16fSGleb Natapov 	};
551a9f8b16fSGleb Natapov 	cnt.config |= (0x2 << EVNTSEL_CMASK_SHIFT);
5528554261fSLike Xu 	measure_one(&cnt);
55385c75578SDapeng Mi 	report(cnt.count < gp_events[instruction_idx].min, "cmask");
554a9f8b16fSGleb Natapov }
555a9f8b16fSGleb Natapov 
556ca1b9de9SNadav Amit static void do_rdpmc_fast(void *ptr)
557ca1b9de9SNadav Amit {
558ca1b9de9SNadav Amit 	pmu_counter_t *cnt = ptr;
559ca1b9de9SNadav Amit 	uint32_t idx = (uint32_t)cnt->idx | (1u << 31);
560ca1b9de9SNadav Amit 
561ca1b9de9SNadav Amit 	if (!is_gp(cnt))
562ca1b9de9SNadav Amit 		idx |= 1 << 30;
563ca1b9de9SNadav Amit 
564ca1b9de9SNadav Amit 	cnt->count = rdpmc(idx);
565ca1b9de9SNadav Amit }
566ca1b9de9SNadav Amit 
567ca1b9de9SNadav Amit 
568a9f8b16fSGleb Natapov static void check_rdpmc(void)
569a9f8b16fSGleb Natapov {
57022f2901aSLike Xu 	uint64_t val = 0xff0123456789ull;
571ca1b9de9SNadav Amit 	bool exc;
572a9f8b16fSGleb Natapov 	int i;
573a9f8b16fSGleb Natapov 
5745bba1769SAndrew Jones 	report_prefix_push("rdpmc");
5755bba1769SAndrew Jones 
576414ee7d1SSean Christopherson 	for (i = 0; i < pmu.nr_gp_counters; i++) {
57733cfc1b0SNadav Amit 		uint64_t x;
578ca1b9de9SNadav Amit 		pmu_counter_t cnt = {
579cda64e80SLike Xu 			.ctr = MSR_GP_COUNTERx(i),
580ca1b9de9SNadav Amit 			.idx = i
581ca1b9de9SNadav Amit 		};
58233cfc1b0SNadav Amit 
58333cfc1b0SNadav Amit 	        /*
58422f2901aSLike Xu 	         * Without full-width writes, only the low 32 bits are writable,
58522f2901aSLike Xu 	         * and the value is sign-extended.
58633cfc1b0SNadav Amit 	         */
587cda64e80SLike Xu 		if (pmu.msr_gp_counter_base == MSR_IA32_PERFCTR0)
58833cfc1b0SNadav Amit 			x = (uint64_t)(int64_t)(int32_t)val;
58922f2901aSLike Xu 		else
59022f2901aSLike Xu 			x = (uint64_t)(int64_t)val;
59133cfc1b0SNadav Amit 
59233cfc1b0SNadav Amit 		/* Mask according to the number of supported bits */
593414ee7d1SSean Christopherson 		x &= (1ull << pmu.gp_counter_width) - 1;
59433cfc1b0SNadav Amit 
595cda64e80SLike Xu 		wrmsr(MSR_GP_COUNTERx(i), val);
596a299895bSThomas Huth 		report(rdpmc(i) == x, "cntr-%d", i);
597ca1b9de9SNadav Amit 
598ca1b9de9SNadav Amit 		exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt);
599ca1b9de9SNadav Amit 		if (exc)
600ca1b9de9SNadav Amit 			report_skip("fast-%d", i);
601ca1b9de9SNadav Amit 		else
602a299895bSThomas Huth 			report(cnt.count == (u32)val, "fast-%d", i);
603a9f8b16fSGleb Natapov 	}
6049c07c92bSDapeng Mi 	for (i = 0; i < fixed_counters_num; i++) {
605414ee7d1SSean Christopherson 		uint64_t x = val & ((1ull << pmu.fixed_counter_width) - 1);
606ca1b9de9SNadav Amit 		pmu_counter_t cnt = {
607ca1b9de9SNadav Amit 			.ctr = MSR_CORE_PERF_FIXED_CTR0 + i,
608ca1b9de9SNadav Amit 			.idx = i
609ca1b9de9SNadav Amit 		};
61033cfc1b0SNadav Amit 
6113f914933SLike Xu 		wrmsr(MSR_PERF_FIXED_CTRx(i), x);
612a299895bSThomas Huth 		report(rdpmc(i | (1 << 30)) == x, "fixed cntr-%d", i);
613ca1b9de9SNadav Amit 
614ca1b9de9SNadav Amit 		exc = test_for_exception(GP_VECTOR, do_rdpmc_fast, &cnt);
615ca1b9de9SNadav Amit 		if (exc)
616ca1b9de9SNadav Amit 			report_skip("fixed fast-%d", i);
617ca1b9de9SNadav Amit 		else
618a299895bSThomas Huth 			report(cnt.count == (u32)x, "fixed fast-%d", i);
619a9f8b16fSGleb Natapov 	}
6205bba1769SAndrew Jones 
6215bba1769SAndrew Jones 	report_prefix_pop();
622a9f8b16fSGleb Natapov }
623a9f8b16fSGleb Natapov 
624ddade902SEric Hankland static void check_running_counter_wrmsr(void)
625ddade902SEric Hankland {
62659ca1413SEric Hankland 	uint64_t status;
62722f2901aSLike Xu 	uint64_t count;
62885c75578SDapeng Mi 	unsigned int instruction_idx = pmu.is_intel ?
62985c75578SDapeng Mi 				       INTEL_INSTRUCTIONS_IDX :
63085c75578SDapeng Mi 				       AMD_INSTRUCTIONS_IDX;
63185c75578SDapeng Mi 
632ddade902SEric Hankland 	pmu_counter_t evt = {
633cda64e80SLike Xu 		.ctr = MSR_GP_COUNTERx(0),
63485c75578SDapeng Mi 		.config = EVNTSEL_OS | EVNTSEL_USR |
63585c75578SDapeng Mi 			  gp_events[instruction_idx].unit_sel,
636ddade902SEric Hankland 	};
637ddade902SEric Hankland 
63859ca1413SEric Hankland 	report_prefix_push("running counter wrmsr");
63959ca1413SEric Hankland 
640ddade902SEric Hankland 	start_event(&evt);
64150f8e27eSDapeng Mi 	__loop();
642cda64e80SLike Xu 	wrmsr(MSR_GP_COUNTERx(0), 0);
643ddade902SEric Hankland 	stop_event(&evt);
64485c75578SDapeng Mi 	report(evt.count < gp_events[instruction_idx].min, "cntr");
64559ca1413SEric Hankland 
64659ca1413SEric Hankland 	/* clear status before overflow test */
64762ba5036SLike Xu 	if (this_cpu_has_perf_global_status())
6488a2866d1SLike Xu 		pmu_clear_global_status();
64959ca1413SEric Hankland 
65059ca1413SEric Hankland 	start_event(&evt);
65122f2901aSLike Xu 
65222f2901aSLike Xu 	count = -1;
653cda64e80SLike Xu 	if (pmu_use_full_writes())
654414ee7d1SSean Christopherson 		count &= (1ull << pmu.gp_counter_width) - 1;
65522f2901aSLike Xu 
656cda64e80SLike Xu 	wrmsr(MSR_GP_COUNTERx(0), count);
65722f2901aSLike Xu 
65850f8e27eSDapeng Mi 	__loop();
65959ca1413SEric Hankland 	stop_event(&evt);
66062ba5036SLike Xu 
66162ba5036SLike Xu 	if (this_cpu_has_perf_global_status()) {
6628a2866d1SLike Xu 		status = rdmsr(pmu.msr_global_status);
6638a2866d1SLike Xu 		report(status & 1, "status msr bit");
66462ba5036SLike Xu 	}
66559ca1413SEric Hankland 
66659ca1413SEric Hankland 	report_prefix_pop();
667ddade902SEric Hankland }
668ddade902SEric Hankland 
66920cf9147SJim Mattson static void check_emulated_instr(void)
67020cf9147SJim Mattson {
67120cf9147SJim Mattson 	uint64_t status, instr_start, brnch_start;
6728b547cc2SLike Xu 	uint64_t gp_counter_width = (1ull << pmu.gp_counter_width) - 1;
673f4e97f59SDapeng Mi 	unsigned int branch_idx = pmu.is_intel ?
674f4e97f59SDapeng Mi 				  INTEL_BRANCHES_IDX : AMD_BRANCHES_IDX;
67585c75578SDapeng Mi 	unsigned int instruction_idx = pmu.is_intel ?
67685c75578SDapeng Mi 				       INTEL_INSTRUCTIONS_IDX :
67785c75578SDapeng Mi 				       AMD_INSTRUCTIONS_IDX;
67820cf9147SJim Mattson 	pmu_counter_t brnch_cnt = {
679cda64e80SLike Xu 		.ctr = MSR_GP_COUNTERx(0),
68020cf9147SJim Mattson 		/* branch instructions */
681b883751aSLike Xu 		.config = EVNTSEL_OS | EVNTSEL_USR | gp_events[branch_idx].unit_sel,
68220cf9147SJim Mattson 	};
68320cf9147SJim Mattson 	pmu_counter_t instr_cnt = {
684cda64e80SLike Xu 		.ctr = MSR_GP_COUNTERx(1),
68520cf9147SJim Mattson 		/* instructions */
68685c75578SDapeng Mi 		.config = EVNTSEL_OS | EVNTSEL_USR | gp_events[instruction_idx].unit_sel,
68720cf9147SJim Mattson 	};
68820cf9147SJim Mattson 	report_prefix_push("emulated instruction");
68920cf9147SJim Mattson 
69062ba5036SLike Xu 	if (this_cpu_has_perf_global_status())
6918a2866d1SLike Xu 		pmu_clear_global_status();
69220cf9147SJim Mattson 
69320cf9147SJim Mattson 	start_event(&brnch_cnt);
69420cf9147SJim Mattson 	start_event(&instr_cnt);
69520cf9147SJim Mattson 
69620cf9147SJim Mattson 	brnch_start = -EXPECTED_BRNCH;
69720cf9147SJim Mattson 	instr_start = -EXPECTED_INSTR;
6988b547cc2SLike Xu 	wrmsr(MSR_GP_COUNTERx(0), brnch_start & gp_counter_width);
6998b547cc2SLike Xu 	wrmsr(MSR_GP_COUNTERx(1), instr_start & gp_counter_width);
70020cf9147SJim Mattson 	// KVM_FEP is a magic prefix that forces emulation so
70120cf9147SJim Mattson 	// 'KVM_FEP "jne label\n"' just counts as a single instruction.
70220cf9147SJim Mattson 	asm volatile(
70320cf9147SJim Mattson 		"mov $0x0, %%eax\n"
70420cf9147SJim Mattson 		"cmp $0x0, %%eax\n"
70520cf9147SJim Mattson 		KVM_FEP "jne label\n"
70620cf9147SJim Mattson 		KVM_FEP "jne label\n"
70720cf9147SJim Mattson 		KVM_FEP "jne label\n"
70820cf9147SJim Mattson 		KVM_FEP "jne label\n"
70920cf9147SJim Mattson 		KVM_FEP "jne label\n"
71020cf9147SJim Mattson 		"mov $0xa, %%eax\n"
71120cf9147SJim Mattson 		"cpuid\n"
71220cf9147SJim Mattson 		"mov $0xa, %%eax\n"
71320cf9147SJim Mattson 		"cpuid\n"
71420cf9147SJim Mattson 		"mov $0xa, %%eax\n"
71520cf9147SJim Mattson 		"cpuid\n"
71620cf9147SJim Mattson 		"mov $0xa, %%eax\n"
71720cf9147SJim Mattson 		"cpuid\n"
71820cf9147SJim Mattson 		"mov $0xa, %%eax\n"
71920cf9147SJim Mattson 		"cpuid\n"
72020cf9147SJim Mattson 		"label:\n"
72120cf9147SJim Mattson 		:
72220cf9147SJim Mattson 		:
72320cf9147SJim Mattson 		: "eax", "ebx", "ecx", "edx");
72420cf9147SJim Mattson 
72562ba5036SLike Xu 	if (this_cpu_has_perf_global_ctrl())
7268a2866d1SLike Xu 		wrmsr(pmu.msr_global_ctl, 0);
72720cf9147SJim Mattson 
72820cf9147SJim Mattson 	stop_event(&brnch_cnt);
72920cf9147SJim Mattson 	stop_event(&instr_cnt);
73020cf9147SJim Mattson 
73120cf9147SJim Mattson 	// Check that the end count - start count is at least the expected
73220cf9147SJim Mattson 	// number of instructions and branches.
73320cf9147SJim Mattson 	report(instr_cnt.count - instr_start >= EXPECTED_INSTR,
73420cf9147SJim Mattson 	       "instruction count");
73520cf9147SJim Mattson 	report(brnch_cnt.count - brnch_start >= EXPECTED_BRNCH,
73620cf9147SJim Mattson 	       "branch count");
73762ba5036SLike Xu 	if (this_cpu_has_perf_global_status()) {
73820cf9147SJim Mattson 		// Additionally check that those counters overflowed properly.
7398a2866d1SLike Xu 		status = rdmsr(pmu.msr_global_status);
7404070b9c6SLike Xu 		report(status & 1, "branch counter overflow");
7414070b9c6SLike Xu 		report(status & 2, "instruction counter overflow");
74262ba5036SLike Xu 	}
74320cf9147SJim Mattson 
74420cf9147SJim Mattson 	report_prefix_pop();
74520cf9147SJim Mattson }
74620cf9147SJim Mattson 
747006b089dSLike Xu #define XBEGIN_STARTED (~0u)
748006b089dSLike Xu static void check_tsx_cycles(void)
749006b089dSLike Xu {
750006b089dSLike Xu 	pmu_counter_t cnt;
751006b089dSLike Xu 	unsigned int i, ret = 0;
752006b089dSLike Xu 
753006b089dSLike Xu 	if (!this_cpu_has(X86_FEATURE_RTM))
754006b089dSLike Xu 		return;
755006b089dSLike Xu 
756006b089dSLike Xu 	report_prefix_push("TSX cycles");
757006b089dSLike Xu 
758006b089dSLike Xu 	for (i = 0; i < pmu.nr_gp_counters; i++) {
759006b089dSLike Xu 		cnt.ctr = MSR_GP_COUNTERx(i);
760006b089dSLike Xu 
761006b089dSLike Xu 		if (i == 2) {
762d4ae0a71SThomas Huth 			/* Transactional cycles committed only on gp counter 2 */
763006b089dSLike Xu 			cnt.config = EVNTSEL_OS | EVNTSEL_USR | 0x30000003c;
764006b089dSLike Xu 		} else {
765006b089dSLike Xu 			/* Transactional cycles */
766006b089dSLike Xu 			cnt.config = EVNTSEL_OS | EVNTSEL_USR | 0x10000003c;
767006b089dSLike Xu 		}
768006b089dSLike Xu 
769006b089dSLike Xu 		start_event(&cnt);
770006b089dSLike Xu 
771006b089dSLike Xu 		asm volatile("xbegin 1f\n\t"
772006b089dSLike Xu 				"1:\n\t"
773006b089dSLike Xu 				: "+a" (ret) :: "memory");
774006b089dSLike Xu 
775006b089dSLike Xu 		/* Generate a non-canonical #GP to trigger ABORT. */
776006b089dSLike Xu 		if (ret == XBEGIN_STARTED)
777006b089dSLike Xu 			*(int *)NONCANONICAL = 0;
778006b089dSLike Xu 
779006b089dSLike Xu 		stop_event(&cnt);
780006b089dSLike Xu 
781006b089dSLike Xu 		report(cnt.count > 0, "gp cntr-%d with a value of %" PRId64 "", i, cnt.count);
782006b089dSLike Xu 	}
783006b089dSLike Xu 
784006b089dSLike Xu 	report_prefix_pop();
785006b089dSLike Xu }
786006b089dSLike Xu 
787f2a56148SDapeng Mi static void warm_up(void)
788f2a56148SDapeng Mi {
789f2a56148SDapeng Mi 	int i;
790f2a56148SDapeng Mi 
791f2a56148SDapeng Mi 	/*
792f2a56148SDapeng Mi 	 * Since cycles event is always run as the first event, there would be
793f2a56148SDapeng Mi 	 * a warm-up state to warm up the cache, it leads to the measured cycles
794f2a56148SDapeng Mi 	 * value may exceed the pre-defined cycles upper boundary and cause
795f2a56148SDapeng Mi 	 * false positive. To avoid this, introduce an warm-up state before
796f2a56148SDapeng Mi 	 * the real verification.
797f2a56148SDapeng Mi 	 */
798f2a56148SDapeng Mi 	for (i = 0; i < 10; i++)
79950f8e27eSDapeng Mi 		loop(0);
800f2a56148SDapeng Mi }
801f2a56148SDapeng Mi 
80222f2901aSLike Xu static void check_counters(void)
80322f2901aSLike Xu {
80400dca75cSLike Xu 	if (is_fep_available())
80500dca75cSLike Xu 		check_emulated_instr();
80600dca75cSLike Xu 
807f2a56148SDapeng Mi 	warm_up();
80822f2901aSLike Xu 	check_gp_counters();
80922f2901aSLike Xu 	check_fixed_counters();
81022f2901aSLike Xu 	check_rdpmc();
81122f2901aSLike Xu 	check_counters_many();
81222f2901aSLike Xu 	check_counter_overflow();
81322f2901aSLike Xu 	check_gp_counter_cmask();
81422f2901aSLike Xu 	check_running_counter_wrmsr();
815006b089dSLike Xu 	check_tsx_cycles();
81622f2901aSLike Xu }
81722f2901aSLike Xu 
81822f2901aSLike Xu static void do_unsupported_width_counter_write(void *index)
81922f2901aSLike Xu {
82022f2901aSLike Xu 	wrmsr(MSR_IA32_PMC0 + *((int *) index), 0xffffff0123456789ull);
82122f2901aSLike Xu }
82222f2901aSLike Xu 
82322f2901aSLike Xu static void check_gp_counters_write_width(void)
82422f2901aSLike Xu {
82522f2901aSLike Xu 	u64 val_64 = 0xffffff0123456789ull;
8264b74c718SThomas Huth 	u64 val_32 = val_64 & ((1ull << 32) - 1);
827414ee7d1SSean Christopherson 	u64 val_max_width = val_64 & ((1ull << pmu.gp_counter_width) - 1);
82822f2901aSLike Xu 	int i;
82922f2901aSLike Xu 
83022f2901aSLike Xu 	/*
83122f2901aSLike Xu 	 * MSR_IA32_PERFCTRn supports 64-bit writes,
83222f2901aSLike Xu 	 * but only the lowest 32 bits are valid.
83322f2901aSLike Xu 	 */
834414ee7d1SSean Christopherson 	for (i = 0; i < pmu.nr_gp_counters; i++) {
83522f2901aSLike Xu 		wrmsr(MSR_IA32_PERFCTR0 + i, val_32);
83622f2901aSLike Xu 		assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32);
83722f2901aSLike Xu 		assert(rdmsr(MSR_IA32_PMC0 + i) == val_32);
83822f2901aSLike Xu 
83922f2901aSLike Xu 		wrmsr(MSR_IA32_PERFCTR0 + i, val_max_width);
84022f2901aSLike Xu 		assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32);
84122f2901aSLike Xu 		assert(rdmsr(MSR_IA32_PMC0 + i) == val_32);
84222f2901aSLike Xu 
84322f2901aSLike Xu 		wrmsr(MSR_IA32_PERFCTR0 + i, val_64);
84422f2901aSLike Xu 		assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32);
84522f2901aSLike Xu 		assert(rdmsr(MSR_IA32_PMC0 + i) == val_32);
84622f2901aSLike Xu 	}
84722f2901aSLike Xu 
84822f2901aSLike Xu 	/*
8494340720eSLike Xu 	 * MSR_IA32_PMCn supports writing values up to GP counter width,
85022f2901aSLike Xu 	 * and only the lowest bits of GP counter width are valid.
85122f2901aSLike Xu 	 */
852414ee7d1SSean Christopherson 	for (i = 0; i < pmu.nr_gp_counters; i++) {
85322f2901aSLike Xu 		wrmsr(MSR_IA32_PMC0 + i, val_32);
85422f2901aSLike Xu 		assert(rdmsr(MSR_IA32_PMC0 + i) == val_32);
85522f2901aSLike Xu 		assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_32);
85622f2901aSLike Xu 
85722f2901aSLike Xu 		wrmsr(MSR_IA32_PMC0 + i, val_max_width);
85822f2901aSLike Xu 		assert(rdmsr(MSR_IA32_PMC0 + i) == val_max_width);
85922f2901aSLike Xu 		assert(rdmsr(MSR_IA32_PERFCTR0 + i) == val_max_width);
86022f2901aSLike Xu 
86122f2901aSLike Xu 		report(test_for_exception(GP_VECTOR,
86222f2901aSLike Xu 			do_unsupported_width_counter_write, &i),
86322f2901aSLike Xu 		"writing unsupported width to MSR_IA32_PMC%d raises #GP", i);
86422f2901aSLike Xu 	}
86522f2901aSLike Xu }
86622f2901aSLike Xu 
867290f4213SJim Mattson /*
868290f4213SJim Mattson  * Per the SDM, reference cycles are currently implemented using the
869290f4213SJim Mattson  * core crystal clock, TSC, or bus clock. Calibrate to the TSC
870290f4213SJim Mattson  * frequency to set reasonable expectations.
871290f4213SJim Mattson  */
872290f4213SJim Mattson static void set_ref_cycle_expectations(void)
873290f4213SJim Mattson {
874290f4213SJim Mattson 	pmu_counter_t cnt = {
875290f4213SJim Mattson 		.ctr = MSR_IA32_PERFCTR0,
87625cc1ea7SDapeng Mi 		.config = EVNTSEL_OS | EVNTSEL_USR |
87725cc1ea7SDapeng Mi 			  intel_gp_events[INTEL_REF_CYCLES_IDX].unit_sel,
878290f4213SJim Mattson 	};
879290f4213SJim Mattson 	uint64_t tsc_delta;
880290f4213SJim Mattson 	uint64_t t0, t1, t2, t3;
881290f4213SJim Mattson 
8822719b92cSYang Weijiang 	/* Bit 2 enumerates the availability of reference cycles events. */
883414ee7d1SSean Christopherson 	if (!pmu.nr_gp_counters || !pmu_gp_counter_is_available(2))
884290f4213SJim Mattson 		return;
885290f4213SJim Mattson 
88662ba5036SLike Xu 	if (this_cpu_has_perf_global_ctrl())
8878a2866d1SLike Xu 		wrmsr(pmu.msr_global_ctl, 0);
888290f4213SJim Mattson 
889290f4213SJim Mattson 	t0 = fenced_rdtsc();
890290f4213SJim Mattson 	start_event(&cnt);
891290f4213SJim Mattson 	t1 = fenced_rdtsc();
892290f4213SJim Mattson 
893290f4213SJim Mattson 	/*
894290f4213SJim Mattson 	 * This loop has to run long enough to dominate the VM-exit
895290f4213SJim Mattson 	 * costs for playing with the PMU MSRs on start and stop.
896290f4213SJim Mattson 	 *
897290f4213SJim Mattson 	 * On a 2.6GHz Ice Lake, with the TSC frequency at 104 times
898290f4213SJim Mattson 	 * the core crystal clock, this function calculated a guest
899290f4213SJim Mattson 	 * TSC : ref cycles ratio of around 105 with ECX initialized
900290f4213SJim Mattson 	 * to one billion.
901290f4213SJim Mattson 	 */
902290f4213SJim Mattson 	asm volatile("loop ." : "+c"((int){1000000000ull}));
903290f4213SJim Mattson 
904290f4213SJim Mattson 	t2 = fenced_rdtsc();
905290f4213SJim Mattson 	stop_event(&cnt);
906290f4213SJim Mattson 	t3 = fenced_rdtsc();
907290f4213SJim Mattson 
908290f4213SJim Mattson 	tsc_delta = ((t2 - t1) + (t3 - t0)) / 2;
909290f4213SJim Mattson 
910290f4213SJim Mattson 	if (!tsc_delta)
911290f4213SJim Mattson 		return;
912290f4213SJim Mattson 
91325cc1ea7SDapeng Mi 	intel_gp_events[INTEL_REF_CYCLES_IDX].min =
91425cc1ea7SDapeng Mi 		(intel_gp_events[INTEL_REF_CYCLES_IDX].min * cnt.count) / tsc_delta;
91525cc1ea7SDapeng Mi 	intel_gp_events[INTEL_REF_CYCLES_IDX].max =
91625cc1ea7SDapeng Mi 		(intel_gp_events[INTEL_REF_CYCLES_IDX].max * cnt.count) / tsc_delta;
917290f4213SJim Mattson }
918290f4213SJim Mattson 
91985c21181SLike Xu static void check_invalid_rdpmc_gp(void)
92085c21181SLike Xu {
92185c21181SLike Xu 	uint64_t val;
92285c21181SLike Xu 
92385c21181SLike Xu 	report(rdpmc_safe(64, &val) == GP_VECTOR,
92485c21181SLike Xu 	       "Expected #GP on RDPMC(64)");
92585c21181SLike Xu }
92685c21181SLike Xu 
927a9f8b16fSGleb Natapov int main(int ac, char **av)
928a9f8b16fSGleb Natapov {
92989126fa4SDapeng Mi 	int instruction_idx;
93089126fa4SDapeng Mi 	int branch_idx;
931*28437cdbSDapeng Mi 	int branch_miss_idx;
93289126fa4SDapeng Mi 
933a9f8b16fSGleb Natapov 	setup_vm();
9345a2cb3e6SLike Xu 	handle_irq(PMI_VECTOR, cnt_overflow);
935dcda215bSPaolo Bonzini 	buf = malloc(N*64);
936a9f8b16fSGleb Natapov 
93785c21181SLike Xu 	check_invalid_rdpmc_gp();
93885c21181SLike Xu 
939b883751aSLike Xu 	if (pmu.is_intel) {
940414ee7d1SSean Christopherson 		if (!pmu.version) {
94103041e97SLike Xu 			report_skip("No Intel Arch PMU is detected!");
94232b9603cSRadim Krčmář 			return report_summary();
943a9f8b16fSGleb Natapov 		}
9447c648ce2SLike Xu 		gp_events = (struct pmu_event *)intel_gp_events;
9457c648ce2SLike Xu 		gp_events_size = sizeof(intel_gp_events)/sizeof(intel_gp_events[0]);
94689126fa4SDapeng Mi 		instruction_idx = INTEL_INSTRUCTIONS_IDX;
94789126fa4SDapeng Mi 		branch_idx = INTEL_BRANCHES_IDX;
948*28437cdbSDapeng Mi 		branch_miss_idx = INTEL_BRANCH_MISS_IDX;
949e0d0022fSDapeng Mi 
950e0d0022fSDapeng Mi 		/*
951e0d0022fSDapeng Mi 		 * For legacy Intel CPUS without clflush/clflushopt support,
952e0d0022fSDapeng Mi 		 * there is no way to force to trigger a LLC miss, thus set
953e0d0022fSDapeng Mi 		 * the minimum value to 0 to avoid false positives.
954e0d0022fSDapeng Mi 		 */
955e0d0022fSDapeng Mi 		if (!this_cpu_has(X86_FEATURE_CLFLUSH))
956e0d0022fSDapeng Mi 			gp_events[INTEL_LLC_MISSES_IDX].min = 0;
957e0d0022fSDapeng Mi 
958b883751aSLike Xu 		report_prefix_push("Intel");
959290f4213SJim Mattson 		set_ref_cycle_expectations();
960b883751aSLike Xu 	} else {
961b883751aSLike Xu 		gp_events_size = sizeof(amd_gp_events)/sizeof(amd_gp_events[0]);
962b883751aSLike Xu 		gp_events = (struct pmu_event *)amd_gp_events;
96389126fa4SDapeng Mi 		instruction_idx = AMD_INSTRUCTIONS_IDX;
96489126fa4SDapeng Mi 		branch_idx = AMD_BRANCHES_IDX;
965*28437cdbSDapeng Mi 		branch_miss_idx = AMD_BRANCH_MISS_IDX;
966b883751aSLike Xu 		report_prefix_push("AMD");
967b883751aSLike Xu 	}
968*28437cdbSDapeng Mi 	adjust_events_range(gp_events, instruction_idx, branch_idx, branch_miss_idx);
969290f4213SJim Mattson 
970414ee7d1SSean Christopherson 	printf("PMU version:         %d\n", pmu.version);
971414ee7d1SSean Christopherson 	printf("GP counters:         %d\n", pmu.nr_gp_counters);
972414ee7d1SSean Christopherson 	printf("GP counter width:    %d\n", pmu.gp_counter_width);
973414ee7d1SSean Christopherson 	printf("Mask length:         %d\n", pmu.gp_counter_mask_length);
974414ee7d1SSean Christopherson 	printf("Fixed counters:      %d\n", pmu.nr_fixed_counters);
975414ee7d1SSean Christopherson 	printf("Fixed counter width: %d\n", pmu.fixed_counter_width);
9760ef1f6a8SPaolo Bonzini 
9779c07c92bSDapeng Mi 	fixed_counters_num = MIN(pmu.nr_fixed_counters, ARRAY_SIZE(fixed_events));
9789c07c92bSDapeng Mi 	if (pmu.nr_fixed_counters > ARRAY_SIZE(fixed_events))
9799c07c92bSDapeng Mi 		report_info("Fixed counters number %d > defined fixed events %u.  "
9809c07c92bSDapeng Mi 			    "Please update test case.", pmu.nr_fixed_counters,
9819c07c92bSDapeng Mi 			    (uint32_t)ARRAY_SIZE(fixed_events));
9829c07c92bSDapeng Mi 
9835a2cb3e6SLike Xu 	apic_write(APIC_LVTPC, PMI_VECTOR);
984a9f8b16fSGleb Natapov 
985afa714b2SPaolo Bonzini 	check_counters();
98620cf9147SJim Mattson 
987879e7f07SLike Xu 	if (pmu_has_full_writes()) {
988cda64e80SLike Xu 		pmu.msr_gp_counter_base = MSR_IA32_PMC0;
989cda64e80SLike Xu 
99022f2901aSLike Xu 		report_prefix_push("full-width writes");
99122f2901aSLike Xu 		check_counters();
99222f2901aSLike Xu 		check_gp_counters_write_width();
993d7714e16SLike Xu 		report_prefix_pop();
99422f2901aSLike Xu 	}
995a9f8b16fSGleb Natapov 
996b883751aSLike Xu 	if (!pmu.is_intel) {
997b883751aSLike Xu 		report_prefix_push("K7");
998b883751aSLike Xu 		pmu.nr_gp_counters = AMD64_NUM_COUNTERS;
999b883751aSLike Xu 		pmu.msr_gp_counter_base = MSR_K7_PERFCTR0;
1000b883751aSLike Xu 		pmu.msr_gp_event_select_base = MSR_K7_EVNTSEL0;
1001b883751aSLike Xu 		check_counters();
1002b883751aSLike Xu 		report_prefix_pop();
1003b883751aSLike Xu 	}
1004b883751aSLike Xu 
1005f3cdd159SJan Kiszka 	return report_summary();
1006a9f8b16fSGleb Natapov }
1007