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

cpuid.c (5562B)


      1// SPDX-License-Identifier: GPL-2.0
      2#include <stdio.h>
      3#include <errno.h>
      4#include <string.h>
      5#include <unistd.h>
      6#include <stdlib.h>
      7
      8#include "helpers/helpers.h"
      9
     10static const char *cpu_vendor_table[X86_VENDOR_MAX] = {
     11	"Unknown", "GenuineIntel", "AuthenticAMD", "HygonGenuine",
     12};
     13
     14#if defined(__i386__) || defined(__x86_64__)
     15
     16/* from gcc */
     17#include <cpuid.h>
     18
     19/*
     20 * CPUID functions returning a single datum
     21 *
     22 * Define unsigned int cpuid_e[abcd]x(unsigned int op)
     23 */
     24#define cpuid_func(reg)					\
     25	unsigned int cpuid_##reg(unsigned int op)	\
     26	{						\
     27	unsigned int eax, ebx, ecx, edx;		\
     28	__cpuid(op, eax, ebx, ecx, edx);		\
     29	return reg;					\
     30	}
     31cpuid_func(eax);
     32cpuid_func(ebx);
     33cpuid_func(ecx);
     34cpuid_func(edx);
     35
     36#endif /* defined(__i386__) || defined(__x86_64__) */
     37
     38/* get_cpu_info
     39 *
     40 * Extract CPU vendor, family, model, stepping info from /proc/cpuinfo
     41 *
     42 * Returns 0 on success or a negativ error code
     43 *
     44 * TBD: Should there be a cpuid alternative for this if /proc is not mounted?
     45 */
     46int get_cpu_info(struct cpupower_cpu_info *cpu_info)
     47{
     48	FILE *fp;
     49	char value[64];
     50	unsigned int proc, x;
     51	unsigned int unknown = 0xffffff;
     52	unsigned int cpuid_level, ext_cpuid_level;
     53
     54	int ret = -EINVAL;
     55
     56	cpu_info->vendor		= X86_VENDOR_UNKNOWN;
     57	cpu_info->family		= unknown;
     58	cpu_info->model			= unknown;
     59	cpu_info->stepping		= unknown;
     60	cpu_info->caps			= 0;
     61
     62	fp = fopen("/proc/cpuinfo", "r");
     63	if (!fp)
     64		return -EIO;
     65
     66	while (!feof(fp)) {
     67		if (!fgets(value, 64, fp))
     68			continue;
     69		value[63 - 1] = '\0';
     70
     71		if (!strncmp(value, "processor\t: ", 12))
     72			sscanf(value, "processor\t: %u", &proc);
     73
     74		if (proc != (unsigned int)base_cpu)
     75			continue;
     76
     77		/* Get CPU vendor */
     78		if (!strncmp(value, "vendor_id", 9)) {
     79			for (x = 1; x < X86_VENDOR_MAX; x++) {
     80				if (strstr(value, cpu_vendor_table[x]))
     81					cpu_info->vendor = x;
     82			}
     83		/* Get CPU family, etc. */
     84		} else if (!strncmp(value, "cpu family\t: ", 13)) {
     85			sscanf(value, "cpu family\t: %u",
     86			       &cpu_info->family);
     87		} else if (!strncmp(value, "model\t\t: ", 9)) {
     88			sscanf(value, "model\t\t: %u",
     89			       &cpu_info->model);
     90		} else if (!strncmp(value, "stepping\t: ", 10)) {
     91			sscanf(value, "stepping\t: %u",
     92			       &cpu_info->stepping);
     93
     94			/* Exit -> all values must have been set */
     95			if (cpu_info->vendor == X86_VENDOR_UNKNOWN ||
     96			    cpu_info->family == unknown ||
     97			    cpu_info->model == unknown ||
     98			    cpu_info->stepping == unknown) {
     99				ret = -EINVAL;
    100				goto out;
    101			}
    102
    103			ret = 0;
    104			goto out;
    105		}
    106	}
    107	ret = -ENODEV;
    108out:
    109	fclose(fp);
    110	/* Get some useful CPU capabilities from cpuid */
    111	if (cpu_info->vendor != X86_VENDOR_AMD &&
    112	    cpu_info->vendor != X86_VENDOR_HYGON &&
    113	    cpu_info->vendor != X86_VENDOR_INTEL)
    114		return ret;
    115
    116	cpuid_level	= cpuid_eax(0);
    117	ext_cpuid_level	= cpuid_eax(0x80000000);
    118
    119	/* Invariant TSC */
    120	if (ext_cpuid_level >= 0x80000007 &&
    121	    (cpuid_edx(0x80000007) & (1 << 8)))
    122		cpu_info->caps |= CPUPOWER_CAP_INV_TSC;
    123
    124	/* Aperf/Mperf registers support */
    125	if (cpuid_level >= 6 && (cpuid_ecx(6) & 0x1))
    126		cpu_info->caps |= CPUPOWER_CAP_APERF;
    127
    128	/* AMD or Hygon Boost state enable/disable register */
    129	if (cpu_info->vendor == X86_VENDOR_AMD ||
    130	    cpu_info->vendor == X86_VENDOR_HYGON) {
    131		if (ext_cpuid_level >= 0x80000007) {
    132			if (cpuid_edx(0x80000007) & (1 << 9)) {
    133				cpu_info->caps |= CPUPOWER_CAP_AMD_CPB;
    134
    135				if (cpu_info->family >= 0x17)
    136					cpu_info->caps |= CPUPOWER_CAP_AMD_CPB_MSR;
    137			}
    138
    139			if ((cpuid_edx(0x80000007) & (1 << 7)) &&
    140			    cpu_info->family != 0x14) {
    141				/* HW pstate was not implemented in family 0x14 */
    142				cpu_info->caps |= CPUPOWER_CAP_AMD_HW_PSTATE;
    143
    144				if (cpu_info->family >= 0x17)
    145					cpu_info->caps |= CPUPOWER_CAP_AMD_PSTATEDEF;
    146			}
    147		}
    148
    149		if (ext_cpuid_level >= 0x80000008 &&
    150		    cpuid_ebx(0x80000008) & (1 << 4))
    151			cpu_info->caps |= CPUPOWER_CAP_AMD_RDPRU;
    152
    153		if (cpupower_amd_pstate_enabled()) {
    154			cpu_info->caps |= CPUPOWER_CAP_AMD_PSTATE;
    155
    156			/*
    157			 * If AMD P-State is enabled, the firmware will treat
    158			 * AMD P-State function as high priority.
    159			 */
    160			cpu_info->caps &= ~CPUPOWER_CAP_AMD_CPB;
    161			cpu_info->caps &= ~CPUPOWER_CAP_AMD_CPB_MSR;
    162			cpu_info->caps &= ~CPUPOWER_CAP_AMD_HW_PSTATE;
    163			cpu_info->caps &= ~CPUPOWER_CAP_AMD_PSTATEDEF;
    164		}
    165	}
    166
    167	if (cpu_info->vendor == X86_VENDOR_INTEL) {
    168		if (cpuid_level >= 6 &&
    169		    (cpuid_eax(6) & (1 << 1)))
    170			cpu_info->caps |= CPUPOWER_CAP_INTEL_IDA;
    171	}
    172
    173	if (cpu_info->vendor == X86_VENDOR_INTEL) {
    174		/* Intel's perf-bias MSR support */
    175		if (cpuid_level >= 6 && (cpuid_ecx(6) & (1 << 3)))
    176			cpu_info->caps |= CPUPOWER_CAP_PERF_BIAS;
    177
    178		/* Intel's Turbo Ratio Limit support */
    179		if (cpu_info->family == 6) {
    180			switch (cpu_info->model) {
    181			case 0x1A:	/* Core i7, Xeon 5500 series
    182					 * Bloomfield, Gainstown NHM-EP
    183					 */
    184			case 0x1E:	/* Core i7 and i5 Processor
    185					 * Clarksfield, Lynnfield, Jasper Forest
    186					 */
    187			case 0x1F:	/* Core i7 and i5 Processor - Nehalem */
    188			case 0x25:	/* Westmere Client
    189					 * Clarkdale, Arrandale
    190					 */
    191			case 0x2C:	/* Westmere EP - Gulftown */
    192				cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
    193				break;
    194			case 0x2A:	/* SNB */
    195			case 0x2D:	/* SNB Xeon */
    196			case 0x3A:	/* IVB */
    197			case 0x3E:	/* IVB Xeon */
    198				cpu_info->caps |= CPUPOWER_CAP_HAS_TURBO_RATIO;
    199				cpu_info->caps |= CPUPOWER_CAP_IS_SNB;
    200				break;
    201			case 0x2E:	/* Nehalem-EX Xeon - Beckton */
    202			case 0x2F:	/* Westmere-EX Xeon - Eagleton */
    203			default:
    204				break;
    205			}
    206		}
    207	}
    208
    209	/*	printf("ID: %u - Extid: 0x%x - Caps: 0x%llx\n",
    210		cpuid_level, ext_cpuid_level, cpu_info->caps);
    211	*/
    212	return ret;
    213}