cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

misc.c (10007B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright 2022, Athira Rajeev, IBM Corp.
      4 * Copyright 2022, Madhavan Srinivasan, IBM Corp.
      5 * Copyright 2022, Kajol Jain, IBM Corp.
      6 */
      7
      8#include <unistd.h>
      9#include <sys/syscall.h>
     10#include <string.h>
     11#include <stdio.h>
     12#include <sys/ioctl.h>
     13#include <sys/mman.h>
     14#include <stdlib.h>
     15#include <ctype.h>
     16
     17#include "misc.h"
     18
     19#define PAGE_SIZE               sysconf(_SC_PAGESIZE)
     20
     21/* Storage for platform version */
     22int pvr;
     23u64 platform_extended_mask;
     24
     25/* Mask and Shift for Event code fields */
     26int ev_mask_pmcxsel, ev_shift_pmcxsel;		//pmcxsel field
     27int ev_mask_marked, ev_shift_marked;		//marked filed
     28int ev_mask_comb, ev_shift_comb;		//combine field
     29int ev_mask_unit, ev_shift_unit;		//unit field
     30int ev_mask_pmc, ev_shift_pmc;			//pmc field
     31int ev_mask_cache, ev_shift_cache;		//Cache sel field
     32int ev_mask_sample, ev_shift_sample;		//Random sampling field
     33int ev_mask_thd_sel, ev_shift_thd_sel;		//thresh_sel field
     34int ev_mask_thd_start, ev_shift_thd_start;	//thresh_start field
     35int ev_mask_thd_stop, ev_shift_thd_stop;	//thresh_stop field
     36int ev_mask_thd_cmp, ev_shift_thd_cmp;		//thresh cmp field
     37int ev_mask_sm, ev_shift_sm;			//SDAR mode field
     38int ev_mask_rsq, ev_shift_rsq;			//radix scope qual field
     39int ev_mask_l2l3, ev_shift_l2l3;		//l2l3 sel field
     40int ev_mask_mmcr3_src, ev_shift_mmcr3_src;	//mmcr3 field
     41
     42static void init_ev_encodes(void)
     43{
     44	ev_mask_pmcxsel = 0xff;
     45	ev_shift_pmcxsel = 0;
     46	ev_mask_marked = 1;
     47	ev_shift_marked = 8;
     48	ev_mask_unit = 0xf;
     49	ev_shift_unit = 12;
     50	ev_mask_pmc = 0xf;
     51	ev_shift_pmc = 16;
     52	ev_mask_sample	= 0x1f;
     53	ev_shift_sample = 24;
     54	ev_mask_thd_sel = 0x7;
     55	ev_shift_thd_sel = 29;
     56	ev_mask_thd_start = 0xf;
     57	ev_shift_thd_start = 36;
     58	ev_mask_thd_stop = 0xf;
     59	ev_shift_thd_stop = 32;
     60
     61	switch (pvr) {
     62	case POWER10:
     63		ev_mask_rsq = 1;
     64		ev_shift_rsq = 9;
     65		ev_mask_comb = 3;
     66		ev_shift_comb = 10;
     67		ev_mask_cache = 3;
     68		ev_shift_cache = 20;
     69		ev_mask_sm = 0x3;
     70		ev_shift_sm = 22;
     71		ev_mask_l2l3 = 0x1f;
     72		ev_shift_l2l3 = 40;
     73		ev_mask_mmcr3_src = 0x7fff;
     74		ev_shift_mmcr3_src = 45;
     75		break;
     76	case POWER9:
     77		ev_mask_comb = 3;
     78		ev_shift_comb = 10;
     79		ev_mask_cache = 0xf;
     80		ev_shift_cache = 20;
     81		ev_mask_thd_cmp = 0x3ff;
     82		ev_shift_thd_cmp = 40;
     83		ev_mask_sm = 0x3;
     84		ev_shift_sm = 50;
     85		break;
     86	default:
     87		FAIL_IF_EXIT(1);
     88	}
     89}
     90
     91/* Return the extended regs mask value */
     92static u64 perf_get_platform_reg_mask(void)
     93{
     94	if (have_hwcap2(PPC_FEATURE2_ARCH_3_1))
     95		return PERF_POWER10_MASK;
     96	if (have_hwcap2(PPC_FEATURE2_ARCH_3_00))
     97		return PERF_POWER9_MASK;
     98
     99	return -1;
    100}
    101
    102int check_extended_regs_support(void)
    103{
    104	int fd;
    105	struct event event;
    106
    107	event_init(&event, 0x1001e);
    108
    109	event.attr.type = 4;
    110	event.attr.sample_period = 1;
    111	event.attr.disabled = 1;
    112	event.attr.sample_type = PERF_SAMPLE_REGS_INTR;
    113	event.attr.sample_regs_intr = platform_extended_mask;
    114
    115	fd = event_open(&event);
    116	if (fd != -1)
    117		return 0;
    118
    119	return -1;
    120}
    121
    122int check_pvr_for_sampling_tests(void)
    123{
    124	pvr = PVR_VER(mfspr(SPRN_PVR));
    125
    126	platform_extended_mask = perf_get_platform_reg_mask();
    127
    128	/*
    129	 * Check for supported platforms
    130	 * for sampling test
    131	 */
    132	if ((pvr != POWER10) && (pvr != POWER9))
    133		goto out;
    134
    135	/*
    136	 * Check PMU driver registered by looking for
    137	 * PPC_FEATURE2_EBB bit in AT_HWCAP2
    138	 */
    139	if (!have_hwcap2(PPC_FEATURE2_EBB))
    140		goto out;
    141
    142	/* check if platform supports extended regs */
    143	if (check_extended_regs_support())
    144		goto out;
    145
    146	init_ev_encodes();
    147	return 0;
    148out:
    149	printf("%s: Sampling tests un-supported\n", __func__);
    150	return -1;
    151}
    152/*
    153 * Allocate mmap buffer of "mmap_pages" number of
    154 * pages.
    155 */
    156void *event_sample_buf_mmap(int fd, int mmap_pages)
    157{
    158	size_t page_size = sysconf(_SC_PAGESIZE);
    159	size_t mmap_size;
    160	void *buff;
    161
    162	if (mmap_pages <= 0)
    163		return NULL;
    164
    165	if (fd <= 0)
    166		return NULL;
    167
    168	mmap_size =  page_size * (1 + mmap_pages);
    169	buff = mmap(NULL, mmap_size,
    170		PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    171
    172	if (buff == MAP_FAILED) {
    173		perror("mmap() failed.");
    174		return NULL;
    175	}
    176	return buff;
    177}
    178
    179/*
    180 * Post process the mmap buffer.
    181 * - If sample_count != NULL then return count of total
    182 *   number of samples present in the mmap buffer.
    183 * - If sample_count == NULL then return the address
    184 *   of first sample from the mmap buffer
    185 */
    186void *__event_read_samples(void *sample_buff, size_t *size, u64 *sample_count)
    187{
    188	size_t page_size = sysconf(_SC_PAGESIZE);
    189	struct perf_event_header *header = sample_buff + page_size;
    190	struct perf_event_mmap_page *metadata_page = sample_buff;
    191	unsigned long data_head, data_tail;
    192
    193	/*
    194	 * PERF_RECORD_SAMPLE:
    195	 * struct {
    196	 *     struct perf_event_header hdr;
    197	 *     u64 data[];
    198	 * };
    199	 */
    200
    201	data_head = metadata_page->data_head;
    202	/* sync memory before reading sample */
    203	mb();
    204	data_tail = metadata_page->data_tail;
    205
    206	/* Check for sample_count */
    207	if (sample_count)
    208		*sample_count = 0;
    209
    210	while (1) {
    211		/*
    212		 * Reads the mmap data buffer by moving
    213		 * the data_tail to know the last read data.
    214		 * data_head points to head in data buffer.
    215		 * refer "struct perf_event_mmap_page" in
    216		 * "include/uapi/linux/perf_event.h".
    217		 */
    218		if (data_head - data_tail < sizeof(header))
    219			return NULL;
    220
    221		data_tail += sizeof(header);
    222		if (header->type == PERF_RECORD_SAMPLE) {
    223			*size = (header->size - sizeof(header));
    224			if (!sample_count)
    225				return sample_buff + page_size + data_tail;
    226			data_tail += *size;
    227			*sample_count += 1;
    228		} else {
    229			*size = (header->size - sizeof(header));
    230			if ((metadata_page->data_tail + *size) > metadata_page->data_head)
    231				data_tail = metadata_page->data_head;
    232			else
    233				data_tail += *size;
    234		}
    235		header = (struct perf_event_header *)((void *)header + header->size);
    236	}
    237	return NULL;
    238}
    239
    240int collect_samples(void *sample_buff)
    241{
    242	u64 sample_count;
    243	size_t size = 0;
    244
    245	__event_read_samples(sample_buff, &size, &sample_count);
    246	return sample_count;
    247}
    248
    249static void *perf_read_first_sample(void *sample_buff, size_t *size)
    250{
    251	return __event_read_samples(sample_buff, size, NULL);
    252}
    253
    254u64 *get_intr_regs(struct event *event, void *sample_buff)
    255{
    256	u64 type = event->attr.sample_type;
    257	u64 *intr_regs;
    258	size_t size = 0;
    259
    260	if ((type ^ PERF_SAMPLE_REGS_INTR))
    261		return NULL;
    262
    263	intr_regs = (u64 *)perf_read_first_sample(sample_buff, &size);
    264	if (!intr_regs)
    265		return NULL;
    266
    267	/*
    268	 * First entry in the sample buffer used to specify
    269	 * PERF_SAMPLE_REGS_ABI_64, skip perf regs abi to access
    270	 * interrupt registers.
    271	 */
    272	++intr_regs;
    273
    274	return intr_regs;
    275}
    276
    277static const int __perf_reg_mask(const char *register_name)
    278{
    279	if (!strcmp(register_name, "R0"))
    280		return 0;
    281	else if (!strcmp(register_name, "R1"))
    282		return 1;
    283	else if (!strcmp(register_name, "R2"))
    284		return 2;
    285	else if (!strcmp(register_name, "R3"))
    286		return 3;
    287	else if (!strcmp(register_name, "R4"))
    288		return 4;
    289	else if (!strcmp(register_name, "R5"))
    290		return 5;
    291	else if (!strcmp(register_name, "R6"))
    292		return 6;
    293	else if (!strcmp(register_name, "R7"))
    294		return 7;
    295	else if (!strcmp(register_name, "R8"))
    296		return 8;
    297	else if (!strcmp(register_name, "R9"))
    298		return 9;
    299	else if (!strcmp(register_name, "R10"))
    300		return 10;
    301	else if (!strcmp(register_name, "R11"))
    302		return 11;
    303	else if (!strcmp(register_name, "R12"))
    304		return 12;
    305	else if (!strcmp(register_name, "R13"))
    306		return 13;
    307	else if (!strcmp(register_name, "R14"))
    308		return 14;
    309	else if (!strcmp(register_name, "R15"))
    310		return 15;
    311	else if (!strcmp(register_name, "R16"))
    312		return 16;
    313	else if (!strcmp(register_name, "R17"))
    314		return 17;
    315	else if (!strcmp(register_name, "R18"))
    316		return 18;
    317	else if (!strcmp(register_name, "R19"))
    318		return 19;
    319	else if (!strcmp(register_name, "R20"))
    320		return 20;
    321	else if (!strcmp(register_name, "R21"))
    322		return 21;
    323	else if (!strcmp(register_name, "R22"))
    324		return 22;
    325	else if (!strcmp(register_name, "R23"))
    326		return 23;
    327	else if (!strcmp(register_name, "R24"))
    328		return 24;
    329	else if (!strcmp(register_name, "R25"))
    330		return 25;
    331	else if (!strcmp(register_name, "R26"))
    332		return 26;
    333	else if (!strcmp(register_name, "R27"))
    334		return 27;
    335	else if (!strcmp(register_name, "R28"))
    336		return 28;
    337	else if (!strcmp(register_name, "R29"))
    338		return 29;
    339	else if (!strcmp(register_name, "R30"))
    340		return 30;
    341	else if (!strcmp(register_name, "R31"))
    342		return 31;
    343	else if (!strcmp(register_name, "NIP"))
    344		return 32;
    345	else if (!strcmp(register_name, "MSR"))
    346		return 33;
    347	else if (!strcmp(register_name, "ORIG_R3"))
    348		return 34;
    349	else if (!strcmp(register_name, "CTR"))
    350		return 35;
    351	else if (!strcmp(register_name, "LINK"))
    352		return 36;
    353	else if (!strcmp(register_name, "XER"))
    354		return 37;
    355	else if (!strcmp(register_name, "CCR"))
    356		return 38;
    357	else if (!strcmp(register_name, "SOFTE"))
    358		return 39;
    359	else if (!strcmp(register_name, "TRAP"))
    360		return 40;
    361	else if (!strcmp(register_name, "DAR"))
    362		return 41;
    363	else if (!strcmp(register_name, "DSISR"))
    364		return 42;
    365	else if (!strcmp(register_name, "SIER"))
    366		return 43;
    367	else if (!strcmp(register_name, "MMCRA"))
    368		return 44;
    369	else if (!strcmp(register_name, "MMCR0"))
    370		return 45;
    371	else if (!strcmp(register_name, "MMCR1"))
    372		return 46;
    373	else if (!strcmp(register_name, "MMCR2"))
    374		return 47;
    375	else if (!strcmp(register_name, "MMCR3"))
    376		return 48;
    377	else if (!strcmp(register_name, "SIER2"))
    378		return 49;
    379	else if (!strcmp(register_name, "SIER3"))
    380		return 50;
    381	else if (!strcmp(register_name, "PMC1"))
    382		return 51;
    383	else if (!strcmp(register_name, "PMC2"))
    384		return 52;
    385	else if (!strcmp(register_name, "PMC3"))
    386		return 53;
    387	else if (!strcmp(register_name, "PMC4"))
    388		return 54;
    389	else if (!strcmp(register_name, "PMC5"))
    390		return 55;
    391	else if (!strcmp(register_name, "PMC6"))
    392		return 56;
    393	else if (!strcmp(register_name, "SDAR"))
    394		return 57;
    395	else if (!strcmp(register_name, "SIAR"))
    396		return 58;
    397	else
    398		return -1;
    399}
    400
    401u64 get_reg_value(u64 *intr_regs, char *register_name)
    402{
    403	int register_bit_position;
    404
    405	register_bit_position = __perf_reg_mask(register_name);
    406
    407	if (register_bit_position < 0 || (!((platform_extended_mask >>
    408			(register_bit_position - 1)) & 1)))
    409		return -1;
    410
    411	return *(intr_regs + register_bit_position);
    412}