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

tracex6_user.c (5630B)


      1// SPDX-License-Identifier: GPL-2.0
      2#define _GNU_SOURCE
      3
      4#include <assert.h>
      5#include <fcntl.h>
      6#include <linux/perf_event.h>
      7#include <sched.h>
      8#include <stdio.h>
      9#include <stdlib.h>
     10#include <sys/ioctl.h>
     11#include <sys/time.h>
     12#include <sys/types.h>
     13#include <sys/wait.h>
     14#include <unistd.h>
     15
     16#include <bpf/bpf.h>
     17#include <bpf/libbpf.h>
     18#include "perf-sys.h"
     19
     20#define SAMPLE_PERIOD  0x7fffffffffffffffULL
     21
     22/* counters, values, values2 */
     23static int map_fd[3];
     24
     25static void check_on_cpu(int cpu, struct perf_event_attr *attr)
     26{
     27	struct bpf_perf_event_value value2;
     28	int pmu_fd, error = 0;
     29	cpu_set_t set;
     30	__u64 value;
     31
     32	/* Move to target CPU */
     33	CPU_ZERO(&set);
     34	CPU_SET(cpu, &set);
     35	assert(sched_setaffinity(0, sizeof(set), &set) == 0);
     36	/* Open perf event and attach to the perf_event_array */
     37	pmu_fd = sys_perf_event_open(attr, -1/*pid*/, cpu/*cpu*/, -1/*group_fd*/, 0);
     38	if (pmu_fd < 0) {
     39		fprintf(stderr, "sys_perf_event_open failed on CPU %d\n", cpu);
     40		error = 1;
     41		goto on_exit;
     42	}
     43	assert(bpf_map_update_elem(map_fd[0], &cpu, &pmu_fd, BPF_ANY) == 0);
     44	assert(ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0) == 0);
     45	/* Trigger the kprobe */
     46	bpf_map_get_next_key(map_fd[1], &cpu, NULL);
     47	/* Check the value */
     48	if (bpf_map_lookup_elem(map_fd[1], &cpu, &value)) {
     49		fprintf(stderr, "Value missing for CPU %d\n", cpu);
     50		error = 1;
     51		goto on_exit;
     52	} else {
     53		fprintf(stderr, "CPU %d: %llu\n", cpu, value);
     54	}
     55	/* The above bpf_map_lookup_elem should trigger the second kprobe */
     56	if (bpf_map_lookup_elem(map_fd[2], &cpu, &value2)) {
     57		fprintf(stderr, "Value2 missing for CPU %d\n", cpu);
     58		error = 1;
     59		goto on_exit;
     60	} else {
     61		fprintf(stderr, "CPU %d: counter: %llu, enabled: %llu, running: %llu\n", cpu,
     62			value2.counter, value2.enabled, value2.running);
     63	}
     64
     65on_exit:
     66	assert(bpf_map_delete_elem(map_fd[0], &cpu) == 0 || error);
     67	assert(ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE, 0) == 0 || error);
     68	assert(close(pmu_fd) == 0 || error);
     69	assert(bpf_map_delete_elem(map_fd[1], &cpu) == 0 || error);
     70	exit(error);
     71}
     72
     73static void test_perf_event_array(struct perf_event_attr *attr,
     74				  const char *name)
     75{
     76	int i, status, nr_cpus = sysconf(_SC_NPROCESSORS_CONF);
     77	pid_t pid[nr_cpus];
     78	int err = 0;
     79
     80	printf("Test reading %s counters\n", name);
     81
     82	for (i = 0; i < nr_cpus; i++) {
     83		pid[i] = fork();
     84		assert(pid[i] >= 0);
     85		if (pid[i] == 0) {
     86			check_on_cpu(i, attr);
     87			exit(1);
     88		}
     89	}
     90
     91	for (i = 0; i < nr_cpus; i++) {
     92		assert(waitpid(pid[i], &status, 0) == pid[i]);
     93		err |= status;
     94	}
     95
     96	if (err)
     97		printf("Test: %s FAILED\n", name);
     98}
     99
    100static void test_bpf_perf_event(void)
    101{
    102	struct perf_event_attr attr_cycles = {
    103		.freq = 0,
    104		.sample_period = SAMPLE_PERIOD,
    105		.inherit = 0,
    106		.type = PERF_TYPE_HARDWARE,
    107		.read_format = 0,
    108		.sample_type = 0,
    109		.config = PERF_COUNT_HW_CPU_CYCLES,
    110	};
    111	struct perf_event_attr attr_clock = {
    112		.freq = 0,
    113		.sample_period = SAMPLE_PERIOD,
    114		.inherit = 0,
    115		.type = PERF_TYPE_SOFTWARE,
    116		.read_format = 0,
    117		.sample_type = 0,
    118		.config = PERF_COUNT_SW_CPU_CLOCK,
    119	};
    120	struct perf_event_attr attr_raw = {
    121		.freq = 0,
    122		.sample_period = SAMPLE_PERIOD,
    123		.inherit = 0,
    124		.type = PERF_TYPE_RAW,
    125		.read_format = 0,
    126		.sample_type = 0,
    127		/* Intel Instruction Retired */
    128		.config = 0xc0,
    129	};
    130	struct perf_event_attr attr_l1d_load = {
    131		.freq = 0,
    132		.sample_period = SAMPLE_PERIOD,
    133		.inherit = 0,
    134		.type = PERF_TYPE_HW_CACHE,
    135		.read_format = 0,
    136		.sample_type = 0,
    137		.config =
    138			PERF_COUNT_HW_CACHE_L1D |
    139			(PERF_COUNT_HW_CACHE_OP_READ << 8) |
    140			(PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16),
    141	};
    142	struct perf_event_attr attr_llc_miss = {
    143		.freq = 0,
    144		.sample_period = SAMPLE_PERIOD,
    145		.inherit = 0,
    146		.type = PERF_TYPE_HW_CACHE,
    147		.read_format = 0,
    148		.sample_type = 0,
    149		.config =
    150			PERF_COUNT_HW_CACHE_LL |
    151			(PERF_COUNT_HW_CACHE_OP_READ << 8) |
    152			(PERF_COUNT_HW_CACHE_RESULT_MISS << 16),
    153	};
    154	struct perf_event_attr attr_msr_tsc = {
    155		.freq = 0,
    156		.sample_period = 0,
    157		.inherit = 0,
    158		/* From /sys/bus/event_source/devices/msr/ */
    159		.type = 7,
    160		.read_format = 0,
    161		.sample_type = 0,
    162		.config = 0,
    163	};
    164
    165	test_perf_event_array(&attr_cycles, "HARDWARE-cycles");
    166	test_perf_event_array(&attr_clock, "SOFTWARE-clock");
    167	test_perf_event_array(&attr_raw, "RAW-instruction-retired");
    168	test_perf_event_array(&attr_l1d_load, "HW_CACHE-L1D-load");
    169
    170	/* below tests may fail in qemu */
    171	test_perf_event_array(&attr_llc_miss, "HW_CACHE-LLC-miss");
    172	test_perf_event_array(&attr_msr_tsc, "Dynamic-msr-tsc");
    173}
    174
    175int main(int argc, char **argv)
    176{
    177	struct bpf_link *links[2];
    178	struct bpf_program *prog;
    179	struct bpf_object *obj;
    180	char filename[256];
    181	int i = 0;
    182
    183	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
    184	obj = bpf_object__open_file(filename, NULL);
    185	if (libbpf_get_error(obj)) {
    186		fprintf(stderr, "ERROR: opening BPF object file failed\n");
    187		return 0;
    188	}
    189
    190	/* load BPF program */
    191	if (bpf_object__load(obj)) {
    192		fprintf(stderr, "ERROR: loading BPF object file failed\n");
    193		goto cleanup;
    194	}
    195
    196	map_fd[0] = bpf_object__find_map_fd_by_name(obj, "counters");
    197	map_fd[1] = bpf_object__find_map_fd_by_name(obj, "values");
    198	map_fd[2] = bpf_object__find_map_fd_by_name(obj, "values2");
    199	if (map_fd[0] < 0 || map_fd[1] < 0 || map_fd[2] < 0) {
    200		fprintf(stderr, "ERROR: finding a map in obj file failed\n");
    201		goto cleanup;
    202	}
    203
    204	bpf_object__for_each_program(prog, obj) {
    205		links[i] = bpf_program__attach(prog);
    206		if (libbpf_get_error(links[i])) {
    207			fprintf(stderr, "ERROR: bpf_program__attach failed\n");
    208			links[i] = NULL;
    209			goto cleanup;
    210		}
    211		i++;
    212	}
    213
    214	test_bpf_perf_event();
    215
    216cleanup:
    217	for (i--; i >= 0; i--)
    218		bpf_link__destroy(links[i]);
    219
    220	bpf_object__close(obj);
    221	return 0;
    222}