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

utils.c (5264B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright 2013-2015, Michael Ellerman, IBM Corp.
      4 */
      5
      6#define _GNU_SOURCE	/* For CPU_ZERO etc. */
      7
      8#include <elf.h>
      9#include <errno.h>
     10#include <fcntl.h>
     11#include <link.h>
     12#include <sched.h>
     13#include <stdio.h>
     14#include <stdlib.h>
     15#include <string.h>
     16#include <sys/ioctl.h>
     17#include <sys/stat.h>
     18#include <sys/sysinfo.h>
     19#include <sys/types.h>
     20#include <sys/utsname.h>
     21#include <unistd.h>
     22#include <asm/unistd.h>
     23#include <linux/limits.h>
     24
     25#include "utils.h"
     26
     27static char auxv[4096];
     28
     29int read_auxv(char *buf, ssize_t buf_size)
     30{
     31	ssize_t num;
     32	int rc, fd;
     33
     34	fd = open("/proc/self/auxv", O_RDONLY);
     35	if (fd == -1) {
     36		perror("open");
     37		return -errno;
     38	}
     39
     40	num = read(fd, buf, buf_size);
     41	if (num < 0) {
     42		perror("read");
     43		rc = -EIO;
     44		goto out;
     45	}
     46
     47	if (num > buf_size) {
     48		printf("overflowed auxv buffer\n");
     49		rc = -EOVERFLOW;
     50		goto out;
     51	}
     52
     53	rc = 0;
     54out:
     55	close(fd);
     56	return rc;
     57}
     58
     59void *find_auxv_entry(int type, char *auxv)
     60{
     61	ElfW(auxv_t) *p;
     62
     63	p = (ElfW(auxv_t) *)auxv;
     64
     65	while (p->a_type != AT_NULL) {
     66		if (p->a_type == type)
     67			return p;
     68
     69		p++;
     70	}
     71
     72	return NULL;
     73}
     74
     75void *get_auxv_entry(int type)
     76{
     77	ElfW(auxv_t) *p;
     78
     79	if (read_auxv(auxv, sizeof(auxv)))
     80		return NULL;
     81
     82	p = find_auxv_entry(type, auxv);
     83	if (p)
     84		return (void *)p->a_un.a_val;
     85
     86	return NULL;
     87}
     88
     89int pick_online_cpu(void)
     90{
     91	int ncpus, cpu = -1;
     92	cpu_set_t *mask;
     93	size_t size;
     94
     95	ncpus = get_nprocs_conf();
     96	size = CPU_ALLOC_SIZE(ncpus);
     97	mask = CPU_ALLOC(ncpus);
     98	if (!mask) {
     99		perror("malloc");
    100		return -1;
    101	}
    102
    103	CPU_ZERO_S(size, mask);
    104
    105	if (sched_getaffinity(0, size, mask)) {
    106		perror("sched_getaffinity");
    107		goto done;
    108	}
    109
    110	/* We prefer a primary thread, but skip 0 */
    111	for (cpu = 8; cpu < ncpus; cpu += 8)
    112		if (CPU_ISSET_S(cpu, size, mask))
    113			goto done;
    114
    115	/* Search for anything, but in reverse */
    116	for (cpu = ncpus - 1; cpu >= 0; cpu--)
    117		if (CPU_ISSET_S(cpu, size, mask))
    118			goto done;
    119
    120	printf("No cpus in affinity mask?!\n");
    121
    122done:
    123	CPU_FREE(mask);
    124	return cpu;
    125}
    126
    127bool is_ppc64le(void)
    128{
    129	struct utsname uts;
    130	int rc;
    131
    132	errno = 0;
    133	rc = uname(&uts);
    134	if (rc) {
    135		perror("uname");
    136		return false;
    137	}
    138
    139	return strcmp(uts.machine, "ppc64le") == 0;
    140}
    141
    142int read_sysfs_file(char *fpath, char *result, size_t result_size)
    143{
    144	char path[PATH_MAX] = "/sys/";
    145	int rc = -1, fd;
    146
    147	strncat(path, fpath, PATH_MAX - strlen(path) - 1);
    148
    149	if ((fd = open(path, O_RDONLY)) < 0)
    150		return rc;
    151
    152	rc = read(fd, result, result_size);
    153
    154	close(fd);
    155
    156	if (rc < 0)
    157		return rc;
    158
    159	return 0;
    160}
    161
    162int read_debugfs_file(char *debugfs_file, int *result)
    163{
    164	int rc = -1, fd;
    165	char path[PATH_MAX];
    166	char value[16];
    167
    168	strcpy(path, "/sys/kernel/debug/");
    169	strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
    170
    171	if ((fd = open(path, O_RDONLY)) < 0)
    172		return rc;
    173
    174	if ((rc = read(fd, value, sizeof(value))) < 0)
    175		return rc;
    176
    177	value[15] = 0;
    178	*result = atoi(value);
    179	close(fd);
    180
    181	return 0;
    182}
    183
    184int write_debugfs_file(char *debugfs_file, int result)
    185{
    186	int rc = -1, fd;
    187	char path[PATH_MAX];
    188	char value[16];
    189
    190	strcpy(path, "/sys/kernel/debug/");
    191	strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
    192
    193	if ((fd = open(path, O_WRONLY)) < 0)
    194		return rc;
    195
    196	snprintf(value, 16, "%d", result);
    197
    198	if ((rc = write(fd, value, strlen(value))) < 0)
    199		return rc;
    200
    201	close(fd);
    202
    203	return 0;
    204}
    205
    206static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
    207		int cpu, int group_fd, unsigned long flags)
    208{
    209	return syscall(__NR_perf_event_open, hw_event, pid, cpu,
    210		      group_fd, flags);
    211}
    212
    213static void perf_event_attr_init(struct perf_event_attr *event_attr,
    214					unsigned int type,
    215					unsigned long config)
    216{
    217	memset(event_attr, 0, sizeof(*event_attr));
    218
    219	event_attr->type = type;
    220	event_attr->size = sizeof(struct perf_event_attr);
    221	event_attr->config = config;
    222	event_attr->read_format = PERF_FORMAT_GROUP;
    223	event_attr->disabled = 1;
    224	event_attr->exclude_kernel = 1;
    225	event_attr->exclude_hv = 1;
    226	event_attr->exclude_guest = 1;
    227}
    228
    229int perf_event_open_counter(unsigned int type,
    230			    unsigned long config, int group_fd)
    231{
    232	int fd;
    233	struct perf_event_attr event_attr;
    234
    235	perf_event_attr_init(&event_attr, type, config);
    236
    237	fd = perf_event_open(&event_attr, 0, -1, group_fd, 0);
    238
    239	if (fd < 0)
    240		perror("perf_event_open() failed");
    241
    242	return fd;
    243}
    244
    245int perf_event_enable(int fd)
    246{
    247	if (ioctl(fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) == -1) {
    248		perror("error while enabling perf events");
    249		return -1;
    250	}
    251
    252	return 0;
    253}
    254
    255int perf_event_disable(int fd)
    256{
    257	if (ioctl(fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) == -1) {
    258		perror("error disabling perf events");
    259		return -1;
    260	}
    261
    262	return 0;
    263}
    264
    265int perf_event_reset(int fd)
    266{
    267	if (ioctl(fd, PERF_EVENT_IOC_RESET, PERF_IOC_FLAG_GROUP) == -1) {
    268		perror("error resetting perf events");
    269		return -1;
    270	}
    271
    272	return 0;
    273}
    274
    275int using_hash_mmu(bool *using_hash)
    276{
    277	char line[128];
    278	FILE *f;
    279	int rc;
    280
    281	f = fopen("/proc/cpuinfo", "r");
    282	FAIL_IF(!f);
    283
    284	rc = 0;
    285	while (fgets(line, sizeof(line), f) != NULL) {
    286		if (!strcmp(line, "MMU		: Hash\n") ||
    287		    !strcmp(line, "platform	: Cell\n") ||
    288		    !strcmp(line, "platform	: PowerMac\n")) {
    289			*using_hash = true;
    290			goto out;
    291		}
    292
    293		if (strcmp(line, "MMU		: Radix\n") == 0) {
    294			*using_hash = false;
    295			goto out;
    296		}
    297	}
    298
    299	rc = -1;
    300out:
    301	fclose(f);
    302	return rc;
    303}