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

cpupower.c (4782B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
      4 */
      5
      6#include <sys/types.h>
      7#include <sys/stat.h>
      8#include <fcntl.h>
      9#include <unistd.h>
     10#include <stdio.h>
     11#include <errno.h>
     12#include <stdlib.h>
     13
     14#include "cpupower.h"
     15#include "cpupower_intern.h"
     16
     17unsigned int cpupower_read_sysfs(const char *path, char *buf, size_t buflen)
     18{
     19	ssize_t numread;
     20	int fd;
     21
     22	fd = open(path, O_RDONLY);
     23	if (fd == -1)
     24		return 0;
     25
     26	numread = read(fd, buf, buflen - 1);
     27	if (numread < 1) {
     28		close(fd);
     29		return 0;
     30	}
     31
     32	buf[numread] = '\0';
     33	close(fd);
     34
     35	return (unsigned int) numread;
     36}
     37
     38unsigned int cpupower_write_sysfs(const char *path, char *buf, size_t buflen)
     39{
     40	ssize_t numwritten;
     41	int fd;
     42
     43	fd = open(path, O_WRONLY);
     44	if (fd == -1)
     45		return 0;
     46
     47	numwritten = write(fd, buf, buflen - 1);
     48	if (numwritten < 1) {
     49		perror(path);
     50		close(fd);
     51		return -1;
     52	}
     53
     54	close(fd);
     55
     56	return (unsigned int) numwritten;
     57}
     58
     59/*
     60 * Detect whether a CPU is online
     61 *
     62 * Returns:
     63 *     1 -> if CPU is online
     64 *     0 -> if CPU is offline
     65 *     negative errno values in error case
     66 */
     67int cpupower_is_cpu_online(unsigned int cpu)
     68{
     69	char path[SYSFS_PATH_MAX];
     70	int fd;
     71	ssize_t numread;
     72	unsigned long long value;
     73	char linebuf[MAX_LINE_LEN];
     74	char *endp;
     75	struct stat statbuf;
     76
     77	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
     78
     79	if (stat(path, &statbuf) != 0)
     80		return 0;
     81
     82	/*
     83	 * kernel without CONFIG_HOTPLUG_CPU
     84	 * -> cpuX directory exists, but not cpuX/online file
     85	 */
     86	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
     87	if (stat(path, &statbuf) != 0)
     88		return 1;
     89
     90	fd = open(path, O_RDONLY);
     91	if (fd == -1)
     92		return -errno;
     93
     94	numread = read(fd, linebuf, MAX_LINE_LEN - 1);
     95	if (numread < 1) {
     96		close(fd);
     97		return -EIO;
     98	}
     99	linebuf[numread] = '\0';
    100	close(fd);
    101
    102	value = strtoull(linebuf, &endp, 0);
    103	if (value > 1)
    104		return -EINVAL;
    105
    106	return value;
    107}
    108
    109/* returns -1 on failure, 0 on success */
    110static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result)
    111{
    112	char linebuf[MAX_LINE_LEN];
    113	char *endp;
    114	char path[SYSFS_PATH_MAX];
    115
    116	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s",
    117			 cpu, fname);
    118	if (cpupower_read_sysfs(path, linebuf, MAX_LINE_LEN) == 0)
    119		return -1;
    120	*result = strtol(linebuf, &endp, 0);
    121	if (endp == linebuf || errno == ERANGE)
    122		return -1;
    123	return 0;
    124}
    125
    126static int __compare(const void *t1, const void *t2)
    127{
    128	struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1;
    129	struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2;
    130	if (top1->pkg < top2->pkg)
    131		return -1;
    132	else if (top1->pkg > top2->pkg)
    133		return 1;
    134	else if (top1->core < top2->core)
    135		return -1;
    136	else if (top1->core > top2->core)
    137		return 1;
    138	else if (top1->cpu < top2->cpu)
    139		return -1;
    140	else if (top1->cpu > top2->cpu)
    141		return 1;
    142	else
    143		return 0;
    144}
    145
    146/*
    147 * Returns amount of cpus, negative on error, cpu_top must be
    148 * passed to cpu_topology_release to free resources
    149 *
    150 * Array is sorted after ->pkg, ->core, then ->cpu
    151 */
    152int get_cpu_topology(struct cpupower_topology *cpu_top)
    153{
    154	int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF);
    155
    156	cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus);
    157	if (cpu_top->core_info == NULL)
    158		return -ENOMEM;
    159	cpu_top->pkgs = cpu_top->cores = 0;
    160	for (cpu = 0; cpu < cpus; cpu++) {
    161		cpu_top->core_info[cpu].cpu = cpu;
    162		cpu_top->core_info[cpu].is_online = cpupower_is_cpu_online(cpu);
    163		if(sysfs_topology_read_file(
    164			cpu,
    165			"physical_package_id",
    166			&(cpu_top->core_info[cpu].pkg)) < 0) {
    167			cpu_top->core_info[cpu].pkg = -1;
    168			cpu_top->core_info[cpu].core = -1;
    169			continue;
    170		}
    171		if(sysfs_topology_read_file(
    172			cpu,
    173			"core_id",
    174			&(cpu_top->core_info[cpu].core)) < 0) {
    175			cpu_top->core_info[cpu].pkg = -1;
    176			cpu_top->core_info[cpu].core = -1;
    177			continue;
    178		}
    179	}
    180
    181	qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
    182	      __compare);
    183
    184	/* Count the number of distinct pkgs values. This works
    185	   because the primary sort of the core_info struct was just
    186	   done by pkg value. */
    187	last_pkg = cpu_top->core_info[0].pkg;
    188	for(cpu = 1; cpu < cpus; cpu++) {
    189		if (cpu_top->core_info[cpu].pkg != last_pkg &&
    190				cpu_top->core_info[cpu].pkg != -1) {
    191
    192			last_pkg = cpu_top->core_info[cpu].pkg;
    193			cpu_top->pkgs++;
    194		}
    195	}
    196	if (!(cpu_top->core_info[0].pkg == -1))
    197		cpu_top->pkgs++;
    198
    199	/* Intel's cores count is not consecutively numbered, there may
    200	 * be a core_id of 3, but none of 2. Assume there always is 0
    201	 * Get amount of cores by counting duplicates in a package
    202	for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) {
    203		if (cpu_top->core_info[cpu].core == 0)
    204	cpu_top->cores++;
    205	*/
    206	return cpus;
    207}
    208
    209void cpu_topology_release(struct cpupower_topology cpu_top)
    210{
    211	free(cpu_top.core_info);
    212}