xref: /kvm-unit-tests/x86/pmu_pebs.c (revision dca3f4c041143c8e8dc70c6890a19a5730310230)
12ae41f5dSLike Xu #include "x86/msr.h"
22ae41f5dSLike Xu #include "x86/processor.h"
32ae41f5dSLike Xu #include "x86/pmu.h"
42ae41f5dSLike Xu #include "x86/isr.h"
52ae41f5dSLike Xu #include "x86/apic.h"
62ae41f5dSLike Xu #include "x86/apic-defs.h"
72ae41f5dSLike Xu #include "x86/desc.h"
82ae41f5dSLike Xu #include "alloc.h"
92ae41f5dSLike Xu 
102ae41f5dSLike Xu #include "vm.h"
112ae41f5dSLike Xu #include "processor.h"
122ae41f5dSLike Xu #include "vmalloc.h"
132ae41f5dSLike Xu #include "alloc_page.h"
142ae41f5dSLike Xu 
152ae41f5dSLike Xu /* bits [63:48] provides the size of the current record in bytes */
162ae41f5dSLike Xu #define	RECORD_SIZE_OFFSET	48
172ae41f5dSLike Xu 
182ae41f5dSLike Xu static unsigned int max_nr_gp_events;
192ae41f5dSLike Xu static unsigned long *ds_bufer;
202ae41f5dSLike Xu static unsigned long *pebs_buffer;
212ae41f5dSLike Xu static u64 ctr_start_val;
222ae41f5dSLike Xu static bool has_baseline;
232ae41f5dSLike Xu 
242ae41f5dSLike Xu struct debug_store {
252ae41f5dSLike Xu 	u64	bts_buffer_base;
262ae41f5dSLike Xu 	u64	bts_index;
272ae41f5dSLike Xu 	u64	bts_absolute_maximum;
282ae41f5dSLike Xu 	u64	bts_interrupt_threshold;
292ae41f5dSLike Xu 	u64	pebs_buffer_base;
302ae41f5dSLike Xu 	u64	pebs_index;
312ae41f5dSLike Xu 	u64	pebs_absolute_maximum;
322ae41f5dSLike Xu 	u64	pebs_interrupt_threshold;
332ae41f5dSLike Xu 	u64	pebs_event_reset[64];
342ae41f5dSLike Xu };
352ae41f5dSLike Xu 
362ae41f5dSLike Xu struct pebs_basic {
372ae41f5dSLike Xu 	u64 format_size;
382ae41f5dSLike Xu 	u64 ip;
392ae41f5dSLike Xu 	u64 applicable_counters;
402ae41f5dSLike Xu 	u64 tsc;
412ae41f5dSLike Xu };
422ae41f5dSLike Xu 
432ae41f5dSLike Xu struct pebs_meminfo {
442ae41f5dSLike Xu 	u64 address;
452ae41f5dSLike Xu 	u64 aux;
462ae41f5dSLike Xu 	u64 latency;
472ae41f5dSLike Xu 	u64 tsx_tuning;
482ae41f5dSLike Xu };
492ae41f5dSLike Xu 
502ae41f5dSLike Xu struct pebs_gprs {
512ae41f5dSLike Xu 	u64 flags, ip, ax, cx, dx, bx, sp, bp, si, di;
522ae41f5dSLike Xu 	u64 r8, r9, r10, r11, r12, r13, r14, r15;
532ae41f5dSLike Xu };
542ae41f5dSLike Xu 
552ae41f5dSLike Xu struct pebs_xmm {
562ae41f5dSLike Xu 	u64 xmm[16*2];	/* two entries for each register */
572ae41f5dSLike Xu };
582ae41f5dSLike Xu 
592ae41f5dSLike Xu struct lbr_entry {
602ae41f5dSLike Xu 	u64 from;
612ae41f5dSLike Xu 	u64 to;
622ae41f5dSLike Xu 	u64 info;
632ae41f5dSLike Xu };
642ae41f5dSLike Xu 
652ae41f5dSLike Xu enum pmc_type {
662ae41f5dSLike Xu 	GP = 0,
672ae41f5dSLike Xu 	FIXED,
682ae41f5dSLike Xu };
692ae41f5dSLike Xu 
702ae41f5dSLike Xu static uint32_t intel_arch_events[] = {
712ae41f5dSLike Xu 	0x00c4, /* PERF_COUNT_HW_BRANCH_INSTRUCTIONS */
722ae41f5dSLike Xu 	0x00c5, /* PERF_COUNT_HW_BRANCH_MISSES */
732ae41f5dSLike Xu 	0x0300, /* PERF_COUNT_HW_REF_CPU_CYCLES */
742ae41f5dSLike Xu 	0x003c, /* PERF_COUNT_HW_CPU_CYCLES */
752ae41f5dSLike Xu 	0x00c0, /* PERF_COUNT_HW_INSTRUCTIONS */
762ae41f5dSLike Xu 	0x013c, /* PERF_COUNT_HW_BUS_CYCLES */
772ae41f5dSLike Xu 	0x4f2e, /* PERF_COUNT_HW_CACHE_REFERENCES */
782ae41f5dSLike Xu 	0x412e, /* PERF_COUNT_HW_CACHE_MISSES */
792ae41f5dSLike Xu };
802ae41f5dSLike Xu 
812ae41f5dSLike Xu /* Iterating each counter value is a waste of time, pick a few typical values. */
822ae41f5dSLike Xu static u64 counter_start_values[] = {
832ae41f5dSLike Xu 	/* if PEBS counter doesn't overflow at all */
842ae41f5dSLike Xu 	0,
852ae41f5dSLike Xu 	0xfffffffffff0,
862ae41f5dSLike Xu 	/* normal counter overflow to have PEBS records */
872ae41f5dSLike Xu 	0xfffffffffffe,
882ae41f5dSLike Xu 	/* test whether emulated instructions should trigger PEBS */
892ae41f5dSLike Xu 	0xffffffffffff,
902ae41f5dSLike Xu };
912ae41f5dSLike Xu 
get_pebs_record_size(u64 pebs_data_cfg,bool use_adaptive)922cb2af7fSSean Christopherson static unsigned int get_pebs_record_size(u64 pebs_data_cfg, bool use_adaptive)
932ae41f5dSLike Xu {
942ae41f5dSLike Xu 	unsigned int sz = sizeof(struct pebs_basic);
952ae41f5dSLike Xu 
962cb2af7fSSean Christopherson 	if (!use_adaptive)
972ae41f5dSLike Xu 		return sz;
982ae41f5dSLike Xu 
992ae41f5dSLike Xu 	if (pebs_data_cfg & PEBS_DATACFG_MEMINFO)
1002ae41f5dSLike Xu 		sz += sizeof(struct pebs_meminfo);
101fc17d527SSean Christopherson 	if (pebs_data_cfg & PEBS_DATACFG_GPRS)
1022ae41f5dSLike Xu 		sz += sizeof(struct pebs_gprs);
1032ae41f5dSLike Xu 	if (pebs_data_cfg & PEBS_DATACFG_XMMS)
1042ae41f5dSLike Xu 		sz += sizeof(struct pebs_xmm);
1052ae41f5dSLike Xu 	if (pebs_data_cfg & PEBS_DATACFG_LBRS)
1062ae41f5dSLike Xu 		sz += MAX_NUM_LBR_ENTRY * sizeof(struct lbr_entry);
1072ae41f5dSLike Xu 
1082ae41f5dSLike Xu 	return sz;
1092ae41f5dSLike Xu }
1102ae41f5dSLike Xu 
cnt_overflow(isr_regs_t * regs)1112ae41f5dSLike Xu static void cnt_overflow(isr_regs_t *regs)
1122ae41f5dSLike Xu {
113c595c361SMingwei Zhang 	apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
1142ae41f5dSLike Xu 	apic_write(APIC_EOI, 0);
1152ae41f5dSLike Xu }
1162ae41f5dSLike Xu 
workload(void)1172ae41f5dSLike Xu static inline void workload(void)
1182ae41f5dSLike Xu {
1192ae41f5dSLike Xu 	asm volatile(
1202ae41f5dSLike Xu 		"mov $0x0, %%eax\n"
1212ae41f5dSLike Xu 		"cmp $0x0, %%eax\n"
1222ae41f5dSLike Xu 		"jne label2\n"
1232ae41f5dSLike Xu 		"jne label2\n"
1242ae41f5dSLike Xu 		"jne label2\n"
1252ae41f5dSLike Xu 		"jne label2\n"
1262ae41f5dSLike Xu 		"mov $0x0, %%eax\n"
1272ae41f5dSLike Xu 		"cmp $0x0, %%eax\n"
1282ae41f5dSLike Xu 		"jne label2\n"
1292ae41f5dSLike Xu 		"jne label2\n"
1302ae41f5dSLike Xu 		"jne label2\n"
1312ae41f5dSLike Xu 		"jne label2\n"
1322ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
1332ae41f5dSLike Xu 		"cpuid\n"
1342ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
1352ae41f5dSLike Xu 		"cpuid\n"
1362ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
1372ae41f5dSLike Xu 		"cpuid\n"
1382ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
1392ae41f5dSLike Xu 		"cpuid\n"
1402ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
1412ae41f5dSLike Xu 		"cpuid\n"
1422ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
1432ae41f5dSLike Xu 		"cpuid\n"
1442ae41f5dSLike Xu 		"label2:\n"
1452ae41f5dSLike Xu 		:
1462ae41f5dSLike Xu 		:
1472ae41f5dSLike Xu 		: "eax", "ebx", "ecx", "edx");
1482ae41f5dSLike Xu }
1492ae41f5dSLike Xu 
workload2(void)1502ae41f5dSLike Xu static inline void workload2(void)
1512ae41f5dSLike Xu {
1522ae41f5dSLike Xu 	asm volatile(
1532ae41f5dSLike Xu 		"mov $0x0, %%eax\n"
1542ae41f5dSLike Xu 		"cmp $0x0, %%eax\n"
1552ae41f5dSLike Xu 		"jne label3\n"
1562ae41f5dSLike Xu 		"jne label3\n"
1572ae41f5dSLike Xu 		"jne label3\n"
1582ae41f5dSLike Xu 		"jne label3\n"
1592ae41f5dSLike Xu 		"mov $0x0, %%eax\n"
1602ae41f5dSLike Xu 		"cmp $0x0, %%eax\n"
1612ae41f5dSLike Xu 		"jne label3\n"
1622ae41f5dSLike Xu 		"jne label3\n"
1632ae41f5dSLike Xu 		"jne label3\n"
1642ae41f5dSLike Xu 		"jne label3\n"
1652ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
1662ae41f5dSLike Xu 		"cpuid\n"
1672ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
1682ae41f5dSLike Xu 		"cpuid\n"
1692ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
1702ae41f5dSLike Xu 		"cpuid\n"
1712ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
1722ae41f5dSLike Xu 		"cpuid\n"
1732ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
1742ae41f5dSLike Xu 		"cpuid\n"
1752ae41f5dSLike Xu 		"mov $0xa, %%eax\n"
1762ae41f5dSLike Xu 		"cpuid\n"
1772ae41f5dSLike Xu 		"label3:\n"
1782ae41f5dSLike Xu 		:
1792ae41f5dSLike Xu 		:
1802ae41f5dSLike Xu 		: "eax", "ebx", "ecx", "edx");
1812ae41f5dSLike Xu }
1822ae41f5dSLike Xu 
alloc_buffers(void)1832ae41f5dSLike Xu static void alloc_buffers(void)
1842ae41f5dSLike Xu {
1852ae41f5dSLike Xu 	ds_bufer = alloc_page();
1862ae41f5dSLike Xu 	force_4k_page(ds_bufer);
1872ae41f5dSLike Xu 	memset(ds_bufer, 0x0, PAGE_SIZE);
1882ae41f5dSLike Xu 
1892ae41f5dSLike Xu 	pebs_buffer = alloc_page();
1902ae41f5dSLike Xu 	force_4k_page(pebs_buffer);
1912ae41f5dSLike Xu 	memset(pebs_buffer, 0x0, PAGE_SIZE);
1922ae41f5dSLike Xu }
1932ae41f5dSLike Xu 
free_buffers(void)1942ae41f5dSLike Xu static void free_buffers(void)
1952ae41f5dSLike Xu {
1962ae41f5dSLike Xu 	if (ds_bufer)
1972ae41f5dSLike Xu 		free_page(ds_bufer);
1982ae41f5dSLike Xu 
1992ae41f5dSLike Xu 	if (pebs_buffer)
2002ae41f5dSLike Xu 		free_page(pebs_buffer);
2012ae41f5dSLike Xu }
2022ae41f5dSLike Xu 
pebs_enable(u64 bitmask,u64 pebs_data_cfg,bool use_adaptive)2032cb2af7fSSean Christopherson static void pebs_enable(u64 bitmask, u64 pebs_data_cfg, bool use_adaptive)
2042ae41f5dSLike Xu {
2052ae41f5dSLike Xu 	static struct debug_store *ds;
2062cb2af7fSSean Christopherson 	u64 adaptive_ctrl = 0, fixed_ctr_ctrl = 0;
2072ae41f5dSLike Xu 	unsigned int idx;
2082ae41f5dSLike Xu 
2092ae41f5dSLike Xu 	if (has_baseline)
2102ae41f5dSLike Xu 		wrmsr(MSR_PEBS_DATA_CFG, pebs_data_cfg);
2112ae41f5dSLike Xu 
2122ae41f5dSLike Xu 	ds = (struct debug_store *)ds_bufer;
2132ae41f5dSLike Xu 	ds->pebs_index = ds->pebs_buffer_base = (unsigned long)pebs_buffer;
2142ae41f5dSLike Xu 	ds->pebs_absolute_maximum = (unsigned long)pebs_buffer + PAGE_SIZE;
2152ae41f5dSLike Xu 	ds->pebs_interrupt_threshold = ds->pebs_buffer_base +
2162cb2af7fSSean Christopherson 		get_pebs_record_size(pebs_data_cfg, use_adaptive);
2172ae41f5dSLike Xu 
2182ae41f5dSLike Xu 	for (idx = 0; idx < pmu.nr_fixed_counters; idx++) {
2192ae41f5dSLike Xu 		if (!(BIT_ULL(FIXED_CNT_INDEX + idx) & bitmask))
2202ae41f5dSLike Xu 			continue;
2212cb2af7fSSean Christopherson 		if (use_adaptive)
2222cb2af7fSSean Christopherson 			adaptive_ctrl = BIT(FIXED_CNT_INDEX + idx * 4);
2232ae41f5dSLike Xu 		wrmsr(MSR_PERF_FIXED_CTRx(idx), ctr_start_val);
2242cb2af7fSSean Christopherson 		fixed_ctr_ctrl |= (0xbULL << (idx * 4) | adaptive_ctrl);
2252ae41f5dSLike Xu 	}
2262ae41f5dSLike Xu 	if (fixed_ctr_ctrl)
2272ae41f5dSLike Xu 		wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, fixed_ctr_ctrl);
2282ae41f5dSLike Xu 
2292ae41f5dSLike Xu 	for (idx = 0; idx < max_nr_gp_events; idx++) {
2302ae41f5dSLike Xu 		if (!(BIT_ULL(idx) & bitmask))
2312ae41f5dSLike Xu 			continue;
2322cb2af7fSSean Christopherson 		if (use_adaptive)
2332cb2af7fSSean Christopherson 			adaptive_ctrl = ICL_EVENTSEL_ADAPTIVE;
2342ae41f5dSLike Xu 		wrmsr(MSR_GP_EVENT_SELECTx(idx), EVNTSEL_EN | EVNTSEL_OS | EVNTSEL_USR |
2352cb2af7fSSean Christopherson 						 intel_arch_events[idx] | adaptive_ctrl);
2362ae41f5dSLike Xu 		wrmsr(MSR_GP_COUNTERx(idx), ctr_start_val);
2372ae41f5dSLike Xu 	}
2382ae41f5dSLike Xu 
2392ae41f5dSLike Xu 	wrmsr(MSR_IA32_DS_AREA,  (unsigned long)ds_bufer);
2402ae41f5dSLike Xu 	wrmsr(MSR_IA32_PEBS_ENABLE, bitmask);
2412ae41f5dSLike Xu 	wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, bitmask);
2422ae41f5dSLike Xu }
2432ae41f5dSLike Xu 
reset_pebs(void)2442ae41f5dSLike Xu static void reset_pebs(void)
2452ae41f5dSLike Xu {
2462ae41f5dSLike Xu 	memset(ds_bufer, 0x0, PAGE_SIZE);
2472ae41f5dSLike Xu 	memset(pebs_buffer, 0x0, PAGE_SIZE);
2482ae41f5dSLike Xu 	wrmsr(MSR_IA32_PEBS_ENABLE, 0);
2492ae41f5dSLike Xu 	wrmsr(MSR_IA32_DS_AREA,  0);
2502ae41f5dSLike Xu 	if (has_baseline)
2512ae41f5dSLike Xu 		wrmsr(MSR_PEBS_DATA_CFG, 0);
2522ae41f5dSLike Xu 
2532ae41f5dSLike Xu 	wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
2542ae41f5dSLike Xu 	wrmsr(MSR_CORE_PERF_GLOBAL_OVF_CTRL, rdmsr(MSR_CORE_PERF_GLOBAL_STATUS));
2552ae41f5dSLike Xu 
2562ae41f5dSLike Xu 	pmu_reset_all_counters();
2572ae41f5dSLike Xu }
2582ae41f5dSLike Xu 
pebs_disable(unsigned int idx)2592ae41f5dSLike Xu static void pebs_disable(unsigned int idx)
2602ae41f5dSLike Xu {
2612ae41f5dSLike Xu 	/*
2622ae41f5dSLike Xu 	* If we only clear the PEBS_ENABLE bit, the counter will continue to increment.
2632ae41f5dSLike Xu 	* In this very tiny time window, if the counter overflows no pebs record will be generated,
2642ae41f5dSLike Xu 	* but a normal counter irq. Test this fully with two ways.
2652ae41f5dSLike Xu 	*/
2662ae41f5dSLike Xu 	if (idx % 2)
2672ae41f5dSLike Xu 		wrmsr(MSR_IA32_PEBS_ENABLE, 0);
2682ae41f5dSLike Xu 
2692ae41f5dSLike Xu 	wrmsr(MSR_CORE_PERF_GLOBAL_CTRL, 0);
2702ae41f5dSLike Xu }
2712ae41f5dSLike Xu 
check_pebs_records(u64 bitmask,u64 pebs_data_cfg,bool use_adaptive)2722cb2af7fSSean Christopherson static void check_pebs_records(u64 bitmask, u64 pebs_data_cfg, bool use_adaptive)
2732ae41f5dSLike Xu {
2742ae41f5dSLike Xu 	struct pebs_basic *pebs_rec = (struct pebs_basic *)pebs_buffer;
2752ae41f5dSLike Xu 	struct debug_store *ds = (struct debug_store *)ds_bufer;
2762cb2af7fSSean Christopherson 	unsigned int pebs_record_size;
2772ae41f5dSLike Xu 	unsigned int count = 0;
2782ae41f5dSLike Xu 	bool expected, pebs_idx_match, pebs_size_match, data_cfg_match;
2792ae41f5dSLike Xu 	void *cur_record;
2802ae41f5dSLike Xu 
2812ae41f5dSLike Xu 	expected = (ds->pebs_index == ds->pebs_buffer_base) && !pebs_rec->format_size;
2822ae41f5dSLike Xu 	if (!(rdmsr(MSR_CORE_PERF_GLOBAL_STATUS) & GLOBAL_STATUS_BUFFER_OVF)) {
2832ae41f5dSLike Xu 		report(expected, "No OVF irq, none PEBS records.");
2842ae41f5dSLike Xu 		return;
2852ae41f5dSLike Xu 	}
2862ae41f5dSLike Xu 
2872ae41f5dSLike Xu 	if (expected) {
2882ae41f5dSLike Xu 		report(!expected, "A OVF irq, but none PEBS records.");
2892ae41f5dSLike Xu 		return;
2902ae41f5dSLike Xu 	}
2912ae41f5dSLike Xu 
2922ae41f5dSLike Xu 	expected = ds->pebs_index >= ds->pebs_interrupt_threshold;
2932ae41f5dSLike Xu 	cur_record = (void *)pebs_buffer;
2942ae41f5dSLike Xu 	do {
2952ae41f5dSLike Xu 		pebs_rec = (struct pebs_basic *)cur_record;
2962ae41f5dSLike Xu 		pebs_record_size = pebs_rec->format_size >> RECORD_SIZE_OFFSET;
2972cb2af7fSSean Christopherson 		pebs_idx_match = pebs_rec->applicable_counters & bitmask;
2982cb2af7fSSean Christopherson 		pebs_size_match = pebs_record_size == get_pebs_record_size(pebs_data_cfg, use_adaptive);
2992cb2af7fSSean Christopherson 		data_cfg_match = (pebs_rec->format_size & GENMASK_ULL(47, 0)) == pebs_data_cfg;
3001006feddSZide Chen 		data_cfg_match = (pebs_rec->format_size & GENMASK_ULL(47, 0)) ==
3011006feddSZide Chen 				 (use_adaptive ? pebs_data_cfg : 0);
3022ae41f5dSLike Xu 		expected = pebs_idx_match && pebs_size_match && data_cfg_match;
3032ae41f5dSLike Xu 		report(expected,
304d4ae0a71SThomas Huth 		       "PEBS record (written seq %d) is verified (including size, counters and cfg).", count);
3058d0f574fSSean Christopherson 		if (use_adaptive && (pebs_data_cfg & PEBS_DATACFG_LBRS)) {
3068d0f574fSSean Christopherson 			unsigned int lbrs_offset = get_pebs_record_size(pebs_data_cfg & ~PEBS_DATACFG_LBRS, true);
3078d0f574fSSean Christopherson 			struct lbr_entry *pebs_lbrs = cur_record + lbrs_offset;
3088d0f574fSSean Christopherson 			int i;
3098d0f574fSSean Christopherson 
3108d0f574fSSean Christopherson 			for (i = 0; i < MAX_NUM_LBR_ENTRY; i++) {
3118d0f574fSSean Christopherson 				if (!pebs_lbrs[i].from && !pebs_lbrs[i].to)
3128d0f574fSSean Christopherson 					continue;
3138d0f574fSSean Christopherson 
3148d0f574fSSean Christopherson 				report_fail("PEBS LBR record %u isn't empty, got from = '%lx', to = '%lx', info = '%lx'",
3158d0f574fSSean Christopherson 					    i, pebs_lbrs[i].from, pebs_lbrs[i].to, pebs_lbrs[i].info);
3168d0f574fSSean Christopherson 			}
3178d0f574fSSean Christopherson 		}
3182ae41f5dSLike Xu 		cur_record = cur_record + pebs_record_size;
3192ae41f5dSLike Xu 		count++;
3202ae41f5dSLike Xu 	} while (expected && (void *)cur_record < (void *)ds->pebs_index);
3212ae41f5dSLike Xu 
3222ae41f5dSLike Xu 	if (!expected) {
3232ae41f5dSLike Xu 		if (!pebs_idx_match)
3242ae41f5dSLike Xu 			printf("FAIL: The applicable_counters (0x%lx) doesn't match with pmc_bitmask (0x%lx).\n",
3252ae41f5dSLike Xu 			       pebs_rec->applicable_counters, bitmask);
3262ae41f5dSLike Xu 		if (!pebs_size_match)
3272cb2af7fSSean Christopherson 			printf("FAIL: The pebs_record_size (%d) doesn't match with expected record size (%d).\n",
3282cb2af7fSSean Christopherson 			       pebs_record_size, get_pebs_record_size(pebs_data_cfg, use_adaptive));
3292ae41f5dSLike Xu 		if (!data_cfg_match)
3302cb2af7fSSean Christopherson 			printf("FAIL: The pebs_data_cfg (0x%lx) doesn't match with the effective MSR_PEBS_DATA_CFG (0x%lx).\n",
3312cb2af7fSSean Christopherson 			       pebs_rec->format_size & 0xffffffffffff, use_adaptive ? pebs_data_cfg : 0);
3322ae41f5dSLike Xu 	}
3332ae41f5dSLike Xu }
3342ae41f5dSLike Xu 
check_one_counter(enum pmc_type type,unsigned int idx,u64 pebs_data_cfg,bool use_adaptive)3352cb2af7fSSean Christopherson static void check_one_counter(enum pmc_type type, unsigned int idx,
3362cb2af7fSSean Christopherson 			      u64 pebs_data_cfg, bool use_adaptive)
3372ae41f5dSLike Xu {
3382ae41f5dSLike Xu 	int pebs_bit = BIT_ULL(type == FIXED ? FIXED_CNT_INDEX + idx : idx);
3392ae41f5dSLike Xu 
3402ae41f5dSLike Xu 	report_prefix_pushf("%s counter %d (0x%lx)",
3412ae41f5dSLike Xu 			    type == FIXED ? "Extended Fixed" : "GP", idx, ctr_start_val);
3422ae41f5dSLike Xu 	reset_pebs();
3432cb2af7fSSean Christopherson 	pebs_enable(pebs_bit, pebs_data_cfg, use_adaptive);
3442ae41f5dSLike Xu 	workload();
3452ae41f5dSLike Xu 	pebs_disable(idx);
3462cb2af7fSSean Christopherson 	check_pebs_records(pebs_bit, pebs_data_cfg, use_adaptive);
3472ae41f5dSLike Xu 	report_prefix_pop();
3482ae41f5dSLike Xu }
3492ae41f5dSLike Xu 
3502ae41f5dSLike Xu /* more than one PEBS records will be generated. */
check_multiple_counters(u64 bitmask,u64 pebs_data_cfg,bool use_adaptive)3512cb2af7fSSean Christopherson static void check_multiple_counters(u64 bitmask, u64 pebs_data_cfg,
3522cb2af7fSSean Christopherson 				    bool use_adaptive)
3532ae41f5dSLike Xu {
3542ae41f5dSLike Xu 	reset_pebs();
3552cb2af7fSSean Christopherson 	pebs_enable(bitmask, pebs_data_cfg, use_adaptive);
3562ae41f5dSLike Xu 	workload2();
3572ae41f5dSLike Xu 	pebs_disable(0);
3582cb2af7fSSean Christopherson 	check_pebs_records(bitmask, pebs_data_cfg, use_adaptive);
3592ae41f5dSLike Xu }
3602ae41f5dSLike Xu 
check_pebs_counters(u64 pebs_data_cfg,bool use_adaptive)3612cb2af7fSSean Christopherson static void check_pebs_counters(u64 pebs_data_cfg, bool use_adaptive)
3622ae41f5dSLike Xu {
3632ae41f5dSLike Xu 	unsigned int idx;
3642ae41f5dSLike Xu 	u64 bitmask = 0;
3652ae41f5dSLike Xu 
36679aa106cSSean Christopherson 	for (idx = 0; has_baseline && idx < pmu.nr_fixed_counters; idx++)
3672cb2af7fSSean Christopherson 		check_one_counter(FIXED, idx, pebs_data_cfg, use_adaptive);
3682ae41f5dSLike Xu 
3692ae41f5dSLike Xu 	for (idx = 0; idx < max_nr_gp_events; idx++)
3702cb2af7fSSean Christopherson 		check_one_counter(GP, idx, pebs_data_cfg, use_adaptive);
3712ae41f5dSLike Xu 
37279aa106cSSean Christopherson 	for (idx = 0; has_baseline && idx < pmu.nr_fixed_counters; idx++)
3732ae41f5dSLike Xu 		bitmask |= BIT_ULL(FIXED_CNT_INDEX + idx);
3742ae41f5dSLike Xu 	for (idx = 0; idx < max_nr_gp_events; idx += 2)
3752ae41f5dSLike Xu 		bitmask |= BIT_ULL(idx);
3762ae41f5dSLike Xu 	report_prefix_pushf("Multiple (0x%lx)", bitmask);
3772cb2af7fSSean Christopherson 	check_multiple_counters(bitmask, pebs_data_cfg, use_adaptive);
3782ae41f5dSLike Xu 	report_prefix_pop();
3792ae41f5dSLike Xu }
3802ae41f5dSLike Xu 
3812ae41f5dSLike Xu /*
3822ae41f5dSLike Xu  * Known reasons for none PEBS records:
3832ae41f5dSLike Xu  *	1. The selected event does not support PEBS;
3842ae41f5dSLike Xu  *	2. From a core pmu perspective, the vCPU and pCPU models are not same;
3852ae41f5dSLike Xu  * 	3. Guest counter has not yet overflowed or been cross-mapped by the host;
3862ae41f5dSLike Xu  */
main(int ac,char ** av)3872ae41f5dSLike Xu int main(int ac, char **av)
3882ae41f5dSLike Xu {
3892ae41f5dSLike Xu 	unsigned int i, j;
3902ae41f5dSLike Xu 
3912ae41f5dSLike Xu 	setup_vm();
3922ae41f5dSLike Xu 
3932ae41f5dSLike Xu 	max_nr_gp_events = MIN(pmu.nr_gp_counters, ARRAY_SIZE(intel_arch_events));
3942ae41f5dSLike Xu 
3952ae41f5dSLike Xu 	printf("PMU version: %d\n", pmu.version);
3962ae41f5dSLike Xu 
3972ae41f5dSLike Xu 	has_baseline = pmu_has_pebs_baseline();
3982ae41f5dSLike Xu 	if (pmu_has_full_writes())
3992ae41f5dSLike Xu 		pmu_activate_full_writes();
4002ae41f5dSLike Xu 
401dd602b6fSSean Christopherson 	if (!pmu.is_intel) {
4022ae41f5dSLike Xu 		report_skip("PEBS requires Intel ICX or later, non-Intel detected");
4032ae41f5dSLike Xu 		return report_summary();
4042ae41f5dSLike Xu 	} else if (!pmu_has_pebs()) {
4052ae41f5dSLike Xu 		report_skip("PEBS required PMU version 2, reported version is %d", pmu.version);
4062ae41f5dSLike Xu 		return report_summary();
407*e67ba872SZide Chen 	} else if (pmu_pebs_format() < 4) {
408*e67ba872SZide Chen 		report_skip("This test supports PEBS_Record_Format >= 4 only");
4092ae41f5dSLike Xu 		return report_summary();
4102ae41f5dSLike Xu 	} else if (rdmsr(MSR_IA32_MISC_ENABLE) & MSR_IA32_MISC_ENABLE_PEBS_UNAVAIL) {
4112ae41f5dSLike Xu 		report_skip("PEBS unavailable according to MISC_ENABLE");
4122ae41f5dSLike Xu 		return report_summary();
4132ae41f5dSLike Xu 	}
4142ae41f5dSLike Xu 
4152ae41f5dSLike Xu 	printf("PEBS format: %d\n", pmu_pebs_format());
4162ae41f5dSLike Xu 	printf("PEBS GP counters: %d\n", pmu.nr_gp_counters);
4172ae41f5dSLike Xu 	printf("PEBS Fixed counters: %d\n", pmu.nr_fixed_counters);
4182ae41f5dSLike Xu 	printf("PEBS baseline (Adaptive PEBS): %d\n", has_baseline);
4192ae41f5dSLike Xu 
4202ae41f5dSLike Xu 	handle_irq(PMI_VECTOR, cnt_overflow);
4212ae41f5dSLike Xu 	alloc_buffers();
4222ae41f5dSLike Xu 
4232ae41f5dSLike Xu 	for (i = 0; i < ARRAY_SIZE(counter_start_values); i++) {
4242ae41f5dSLike Xu 		ctr_start_val = counter_start_values[i];
4252cb2af7fSSean Christopherson 		check_pebs_counters(0, false);
4262ae41f5dSLike Xu 		if (!has_baseline)
4272ae41f5dSLike Xu 			continue;
4282ae41f5dSLike Xu 
429fc17d527SSean Christopherson 		for (j = 0; j <= PEBS_DATACFG_MASK; j++) {
430fc17d527SSean Christopherson 			u64 pebs_data_cfg = j;
431fc17d527SSean Christopherson 
432fc17d527SSean Christopherson 			if (pebs_data_cfg & PEBS_DATACFG_LBRS)
433fc17d527SSean Christopherson 				pebs_data_cfg |= ((MAX_NUM_LBR_ENTRY -1) << PEBS_DATACFG_LBR_SHIFT);
434fc17d527SSean Christopherson 
435fc17d527SSean Christopherson 			report_prefix_pushf("Adaptive (0x%lx)", pebs_data_cfg);
4362cb2af7fSSean Christopherson 			check_pebs_counters(pebs_data_cfg, true);
4372cb2af7fSSean Christopherson 			report_prefix_pop();
4382cb2af7fSSean Christopherson 
4392cb2af7fSSean Christopherson 			report_prefix_pushf("Ignored Adaptive (0x%lx)", pebs_data_cfg);
4402cb2af7fSSean Christopherson 			check_pebs_counters(pebs_data_cfg, false);
4412ae41f5dSLike Xu 			report_prefix_pop();
4422ae41f5dSLike Xu 		}
4432ae41f5dSLike Xu 	}
4442ae41f5dSLike Xu 
4452ae41f5dSLike Xu 	free_buffers();
4462ae41f5dSLike Xu 
4472ae41f5dSLike Xu 	return report_summary();
4482ae41f5dSLike Xu }
449